diff options
Diffstat (limited to 'hw/arm')
| -rw-r--r-- | hw/arm/aspeed.c | 111 | ||||
| -rw-r--r-- | hw/arm/aspeed_soc.c | 95 | ||||
| -rw-r--r-- | hw/arm/imx25_pdk.c | 2 | ||||
| -rw-r--r-- | hw/arm/pxa2xx.c | 13 | ||||
| -rw-r--r-- | hw/arm/tosa.c | 11 | ||||
| -rw-r--r-- | hw/arm/virt-acpi-build.c | 168 | ||||
| -rw-r--r-- | hw/arm/virt.c | 788 | ||||
| -rw-r--r-- | hw/arm/xlnx-zynqmp.c | 2 | ||||
| -rw-r--r-- | hw/arm/z2.c | 11 |
9 files changed, 708 insertions, 493 deletions
diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index c7206fda6d..a92c2f1c36 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -20,6 +20,8 @@ #include "qemu/log.h" #include "sysemu/block-backend.h" #include "sysemu/blockdev.h" +#include "hw/loader.h" +#include "qemu/error-report.h" static struct arm_boot_info aspeed_board_binfo = { .board_id = -1, /* device-tree-only board */ @@ -34,13 +36,18 @@ typedef struct AspeedBoardState { typedef struct AspeedBoardConfig { const char *soc_name; uint32_t hw_strap1; + const char *fmc_model; + const char *spi_model; + uint32_t num_cs; } AspeedBoardConfig; enum { PALMETTO_BMC, AST2500_EVB, + ROMULUS_BMC, }; +/* Palmetto hardware value: 0x120CE416 */ #define PALMETTO_BMC_HW_STRAP1 ( \ SCU_AST2400_HW_STRAP_DRAM_SIZE(DRAM_SIZE_256MB) | \ SCU_AST2400_HW_STRAP_DRAM_CONFIG(2 /* DDR3 with CL=6, CWL=5 */) | \ @@ -54,6 +61,7 @@ enum { SCU_HW_STRAP_VGA_SIZE_SET(VGA_16M_DRAM) | \ SCU_AST2400_HW_STRAP_BOOT_MODE(AST2400_SPI_BOOT)) +/* AST2500 evb hardware value: 0xF100C2E6 */ #define AST2500_EVB_HW_STRAP1 (( \ AST2500_HW_STRAP1_DEFAULTS | \ SCU_AST2500_HW_STRAP_SPI_AUTOFETCH_ENABLE | \ @@ -64,11 +72,62 @@ enum { SCU_HW_STRAP_MAC0_RGMII) & \ ~SCU_HW_STRAP_2ND_BOOT_WDT) +/* Romulus hardware value: 0xF10AD206 */ +#define ROMULUS_BMC_HW_STRAP1 ( \ + AST2500_HW_STRAP1_DEFAULTS | \ + SCU_AST2500_HW_STRAP_SPI_AUTOFETCH_ENABLE | \ + SCU_AST2500_HW_STRAP_GPIO_STRAP_ENABLE | \ + SCU_AST2500_HW_STRAP_UART_DEBUG | \ + SCU_AST2500_HW_STRAP_DDR4_ENABLE | \ + SCU_AST2500_HW_STRAP_ACPI_ENABLE | \ + SCU_HW_STRAP_SPI_MODE(SCU_HW_STRAP_SPI_MASTER)) + static const AspeedBoardConfig aspeed_boards[] = { - [PALMETTO_BMC] = { "ast2400-a0", PALMETTO_BMC_HW_STRAP1 }, - [AST2500_EVB] = { "ast2500-a1", AST2500_EVB_HW_STRAP1 }, + [PALMETTO_BMC] = { + .soc_name = "ast2400-a1", + .hw_strap1 = PALMETTO_BMC_HW_STRAP1, + .fmc_model = "n25q256a", + .spi_model = "mx25l25635e", + .num_cs = 1, + }, + [AST2500_EVB] = { + .soc_name = "ast2500-a1", + .hw_strap1 = AST2500_EVB_HW_STRAP1, + .fmc_model = "n25q256a", + .spi_model = "mx25l25635e", + .num_cs = 1, + }, + [ROMULUS_BMC] = { + .soc_name = "ast2500-a1", + .hw_strap1 = ROMULUS_BMC_HW_STRAP1, + .fmc_model = "n25q256a", + .spi_model = "mx66l1g45g", + .num_cs = 2, + }, }; +#define FIRMWARE_ADDR 0x0 + +static void write_boot_rom(DriveInfo *dinfo, hwaddr addr, size_t rom_size, + Error **errp) +{ + BlockBackend *blk = blk_by_legacy_dinfo(dinfo); + uint8_t *storage; + + if (rom_size > blk_getlength(blk)) { + rom_size = blk_getlength(blk); + } + + storage = g_new0(uint8_t, rom_size); + if (blk_pread(blk, 0, storage, rom_size) < 0) { + error_setg(errp, "failed to read the initial flash content"); + return; + } + + rom_add_blob_fixed("aspeed.boot_rom", storage, rom_size, addr); + g_free(storage); +} + static void aspeed_board_init_flashes(AspeedSMCState *s, const char *flashtype, Error **errp) { @@ -100,6 +159,7 @@ static void aspeed_board_init(MachineState *machine, { AspeedBoardState *bmc; AspeedSoCClass *sc; + DriveInfo *drive0 = drive_get(IF_MTD, 0, 0); bmc = g_new0(AspeedBoardState, 1); object_initialize(&bmc->soc, (sizeof(bmc->soc)), cfg->soc_name); @@ -112,6 +172,8 @@ static void aspeed_board_init(MachineState *machine, &error_abort); object_property_set_int(OBJECT(&bmc->soc), cfg->hw_strap1, "hw-strap1", &error_abort); + object_property_set_int(OBJECT(&bmc->soc), cfg->num_cs, "num-cs", + &error_abort); object_property_set_bool(OBJECT(&bmc->soc), true, "realized", &error_abort); @@ -128,8 +190,24 @@ static void aspeed_board_init(MachineState *machine, object_property_add_const_link(OBJECT(&bmc->soc), "ram", OBJECT(&bmc->ram), &error_abort); - aspeed_board_init_flashes(&bmc->soc.fmc, "n25q256a", &error_abort); - aspeed_board_init_flashes(&bmc->soc.spi[0], "mx25l25635e", &error_abort); + aspeed_board_init_flashes(&bmc->soc.fmc, cfg->fmc_model, &error_abort); + aspeed_board_init_flashes(&bmc->soc.spi[0], cfg->spi_model, &error_abort); + + /* Install first FMC flash content as a boot rom. */ + if (drive0) { + AspeedSMCFlash *fl = &bmc->soc.fmc.flashes[0]; + MemoryRegion *boot_rom = g_new(MemoryRegion, 1); + + /* + * create a ROM region using the default mapping window size of + * the flash module. + */ + memory_region_init_rom(boot_rom, OBJECT(bmc), "aspeed.boot_rom", + fl->size, &error_abort); + memory_region_add_subregion(get_system_memory(), FIRMWARE_ADDR, + boot_rom); + write_boot_rom(drive0, FIRMWARE_ADDR, fl->size, &error_abort); + } aspeed_board_binfo.kernel_filename = machine->kernel_filename; aspeed_board_binfo.initrd_filename = machine->initrd_filename; @@ -188,10 +266,35 @@ static const TypeInfo ast2500_evb_type = { .class_init = ast2500_evb_class_init, }; +static void romulus_bmc_init(MachineState *machine) +{ + aspeed_board_init(machine, &aspeed_boards[ROMULUS_BMC]); +} + +static void romulus_bmc_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + + mc->desc = "OpenPOWER Romulus BMC (ARM1176)"; + mc->init = romulus_bmc_init; + mc->max_cpus = 1; + mc->no_sdcard = 1; + mc->no_floppy = 1; + mc->no_cdrom = 1; + mc->no_parallel = 1; +} + +static const TypeInfo romulus_bmc_type = { + .name = MACHINE_TYPE_NAME("romulus-bmc"), + .parent = TYPE_MACHINE, + .class_init = romulus_bmc_class_init, +}; + static void aspeed_machine_init(void) { type_register_static(&palmetto_bmc_type); type_register_static(&ast2500_evb_type); + type_register_static(&romulus_bmc_type); } type_init(aspeed_machine_init) diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c index e14f5c217e..b3e7f07b61 100644 --- a/hw/arm/aspeed_soc.c +++ b/hw/arm/aspeed_soc.c @@ -29,6 +29,7 @@ #define ASPEED_SOC_VIC_BASE 0x1E6C0000 #define ASPEED_SOC_SDMC_BASE 0x1E6E0000 #define ASPEED_SOC_SCU_BASE 0x1E6E2000 +#define ASPEED_SOC_SRAM_BASE 0x1E720000 #define ASPEED_SOC_TIMER_BASE 0x1E782000 #define ASPEED_SOC_I2C_BASE 0x1E78A000 @@ -47,15 +48,47 @@ static const char *aspeed_soc_ast2500_typenames[] = { "aspeed.smc.ast2500-spi1", "aspeed.smc.ast2500-spi2" }; static const AspeedSoCInfo aspeed_socs[] = { - { "ast2400-a0", "arm926", AST2400_A0_SILICON_REV, AST2400_SDRAM_BASE, - 1, aspeed_soc_ast2400_spi_bases, - "aspeed.smc.fmc", aspeed_soc_ast2400_typenames }, - { "ast2400", "arm926", AST2400_A0_SILICON_REV, AST2400_SDRAM_BASE, - 1, aspeed_soc_ast2400_spi_bases, - "aspeed.smc.fmc", aspeed_soc_ast2400_typenames }, - { "ast2500-a1", "arm1176", AST2500_A1_SILICON_REV, AST2500_SDRAM_BASE, - 2, aspeed_soc_ast2500_spi_bases, - "aspeed.smc.ast2500-fmc", aspeed_soc_ast2500_typenames }, + { + .name = "ast2400-a0", + .cpu_model = "arm926", + .silicon_rev = AST2400_A0_SILICON_REV, + .sdram_base = AST2400_SDRAM_BASE, + .sram_size = 0x8000, + .spis_num = 1, + .spi_bases = aspeed_soc_ast2400_spi_bases, + .fmc_typename = "aspeed.smc.fmc", + .spi_typename = aspeed_soc_ast2400_typenames, + }, { + .name = "ast2400-a1", + .cpu_model = "arm926", + .silicon_rev = AST2400_A1_SILICON_REV, + .sdram_base = AST2400_SDRAM_BASE, + .sram_size = 0x8000, + .spis_num = 1, + .spi_bases = aspeed_soc_ast2400_spi_bases, + .fmc_typename = "aspeed.smc.fmc", + .spi_typename = aspeed_soc_ast2400_typenames, + }, { + .name = "ast2400", + .cpu_model = "arm926", + .silicon_rev = AST2400_A0_SILICON_REV, + .sdram_base = AST2400_SDRAM_BASE, + .sram_size = 0x8000, + .spis_num = 1, + .spi_bases = aspeed_soc_ast2400_spi_bases, + .fmc_typename = "aspeed.smc.fmc", + .spi_typename = aspeed_soc_ast2400_typenames, + }, { + .name = "ast2500-a1", + .cpu_model = "arm1176", + .silicon_rev = AST2500_A1_SILICON_REV, + .sdram_base = AST2500_SDRAM_BASE, + .sram_size = 0x9000, + .spis_num = 2, + .spi_bases = aspeed_soc_ast2500_spi_bases, + .fmc_typename = "aspeed.smc.ast2500-fmc", + .spi_typename = aspeed_soc_ast2500_typenames, + }, }; /* @@ -87,9 +120,13 @@ static void aspeed_soc_init(Object *obj) { AspeedSoCState *s = ASPEED_SOC(obj); AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s); + char *cpu_typename; int i; - s->cpu = cpu_arm_init(sc->info->cpu_model); + cpu_typename = g_strdup_printf("%s-" TYPE_ARM_CPU, sc->info->cpu_model); + object_initialize(&s->cpu, sizeof(s->cpu), cpu_typename); + object_property_add_child(obj, "cpu", OBJECT(&s->cpu), NULL); + g_free(cpu_typename); object_initialize(&s->vic, sizeof(s->vic), TYPE_ASPEED_VIC); object_property_add_child(obj, "vic", OBJECT(&s->vic), NULL); @@ -116,11 +153,13 @@ static void aspeed_soc_init(Object *obj) object_initialize(&s->fmc, sizeof(s->fmc), sc->info->fmc_typename); object_property_add_child(obj, "fmc", OBJECT(&s->fmc), NULL); qdev_set_parent_bus(DEVICE(&s->fmc), sysbus_get_default()); + object_property_add_alias(obj, "num-cs", OBJECT(&s->fmc), "num-cs", + &error_abort); for (i = 0; i < sc->info->spis_num; i++) { object_initialize(&s->spi[i], sizeof(s->spi[i]), sc->info->spi_typename[i]); - object_property_add_child(obj, "spi", OBJECT(&s->spi[i]), NULL); + object_property_add_child(obj, "spi[*]", OBJECT(&s->spi[i]), NULL); qdev_set_parent_bus(DEVICE(&s->spi[i]), sysbus_get_default()); } @@ -146,6 +185,24 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) memory_region_add_subregion_overlap(get_system_memory(), ASPEED_SOC_IOMEM_BASE, &s->iomem, -1); + /* CPU */ + object_property_set_bool(OBJECT(&s->cpu), true, "realized", &err); + if (err) { + error_propagate(errp, err); + return; + } + + /* SRAM */ + memory_region_init_ram(&s->sram, OBJECT(dev), "aspeed.sram", + sc->info->sram_size, &err); + if (err) { + error_propagate(errp, err); + return; + } + vmstate_register_ram_global(&s->sram); + memory_region_add_subregion(get_system_memory(), ASPEED_SOC_SRAM_BASE, + &s->sram); + /* VIC */ object_property_set_bool(OBJECT(&s->vic), true, "realized", &err); if (err) { @@ -154,9 +211,9 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) } sysbus_mmio_map(SYS_BUS_DEVICE(&s->vic), 0, ASPEED_SOC_VIC_BASE); sysbus_connect_irq(SYS_BUS_DEVICE(&s->vic), 0, - qdev_get_gpio_in(DEVICE(s->cpu), ARM_CPU_IRQ)); + qdev_get_gpio_in(DEVICE(&s->cpu), ARM_CPU_IRQ)); sysbus_connect_irq(SYS_BUS_DEVICE(&s->vic), 1, - qdev_get_gpio_in(DEVICE(s->cpu), ARM_CPU_FIQ)); + qdev_get_gpio_in(DEVICE(&s->cpu), ARM_CPU_FIQ)); /* Timer */ object_property_set_bool(OBJECT(&s->timerctrl), true, "realized", &err); @@ -195,10 +252,8 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c), 0, qdev_get_gpio_in(DEVICE(&s->vic), 12)); - /* FMC */ - object_property_set_int(OBJECT(&s->fmc), 1, "num-cs", &err); - object_property_set_bool(OBJECT(&s->fmc), true, "realized", &local_err); - error_propagate(&err, local_err); + /* FMC, The number of CS is set at the board level */ + object_property_set_bool(OBJECT(&s->fmc), true, "realized", &err); if (err) { error_propagate(errp, err); return; @@ -240,12 +295,6 @@ static void aspeed_soc_class_init(ObjectClass *oc, void *data) sc->info = (AspeedSoCInfo *) data; dc->realize = aspeed_soc_realize; - - /* - * Reason: creates an ARM CPU, thus use after free(), see - * arm_cpu_class_init() - */ - dc->cannot_destroy_with_object_finalize_yet = true; } static const TypeInfo aspeed_soc_type_info = { diff --git a/hw/arm/imx25_pdk.c b/hw/arm/imx25_pdk.c index 025b60843e..44e741fde3 100644 --- a/hw/arm/imx25_pdk.c +++ b/hw/arm/imx25_pdk.c @@ -139,7 +139,7 @@ static void imx25_pdk_init(MachineState *machine) * of simple qtest. See "make check" for details. */ i2c_create_slave((I2CBus *)qdev_get_child_bus(DEVICE(&s->soc.i2c[0]), - "i2c"), + "i2c-bus.0"), "ds1338", 0x68); } } diff --git a/hw/arm/pxa2xx.c b/hw/arm/pxa2xx.c index 21ea1d6210..d31b4577f0 100644 --- a/hw/arm/pxa2xx.c +++ b/hw/arm/pxa2xx.c @@ -1258,7 +1258,7 @@ static void pxa2xx_i2c_update(PXA2xxI2CState *s) } /* These are only stubs now. */ -static void pxa2xx_i2c_event(I2CSlave *i2c, enum i2c_event event) +static int pxa2xx_i2c_event(I2CSlave *i2c, enum i2c_event event) { PXA2xxI2CSlaveState *slave = PXA2XX_I2C_SLAVE(i2c); PXA2xxI2CState *s = slave->host; @@ -1280,6 +1280,8 @@ static void pxa2xx_i2c_event(I2CSlave *i2c, enum i2c_event event) break; } pxa2xx_i2c_update(s); + + return 0; } static int pxa2xx_i2c_rx(I2CSlave *i2c) @@ -1449,17 +1451,10 @@ static const VMStateDescription vmstate_pxa2xx_i2c = { } }; -static int pxa2xx_i2c_slave_init(I2CSlave *i2c) -{ - /* Nothing to do. */ - return 0; -} - static void pxa2xx_i2c_slave_class_init(ObjectClass *klass, void *data) { I2CSlaveClass *k = I2C_SLAVE_CLASS(klass); - k->init = pxa2xx_i2c_slave_init; k->event = pxa2xx_i2c_event; k->recv = pxa2xx_i2c_rx; k->send = pxa2xx_i2c_tx; @@ -2070,7 +2065,7 @@ PXA2xxState *pxa270_init(MemoryRegion *address_space, } if (!revision) revision = "pxa270"; - + s->cpu = cpu_arm_init(revision); if (s->cpu == NULL) { fprintf(stderr, "Unable to find CPU definition\n"); diff --git a/hw/arm/tosa.c b/hw/arm/tosa.c index 1ee12f49b3..c3db996930 100644 --- a/hw/arm/tosa.c +++ b/hw/arm/tosa.c @@ -172,7 +172,7 @@ static int tosa_dac_send(I2CSlave *i2c, uint8_t data) return 0; } -static void tosa_dac_event(I2CSlave *i2c, enum i2c_event event) +static int tosa_dac_event(I2CSlave *i2c, enum i2c_event event) { TosaDACState *s = TOSA_DAC(i2c); @@ -194,6 +194,8 @@ static void tosa_dac_event(I2CSlave *i2c, enum i2c_event event) default: break; } + + return 0; } static int tosa_dac_recv(I2CSlave *s) @@ -202,12 +204,6 @@ static int tosa_dac_recv(I2CSlave *s) return -1; } -static int tosa_dac_init(I2CSlave *i2c) -{ - /* Nothing to do. */ - return 0; -} - static void tosa_tg_init(PXA2xxState *cpu) { I2CBus *bus = pxa2xx_i2c_bus(cpu->i2c[0]); @@ -275,7 +271,6 @@ static void tosa_dac_class_init(ObjectClass *klass, void *data) { I2CSlaveClass *k = I2C_SLAVE_CLASS(klass); - k->init = tosa_dac_init; k->event = tosa_dac_event; k->recv = tosa_dac_recv; k->send = tosa_dac_send; diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c index 7102686882..07a10aca40 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c @@ -29,7 +29,6 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "qemu-common.h" -#include "hw/arm/virt-acpi-build.h" #include "qemu/bitmap.h" #include "trace.h" #include "qom/cpu.h" @@ -43,6 +42,7 @@ #include "hw/acpi/aml-build.h" #include "hw/pci/pcie_host.h" #include "hw/pci/pci.h" +#include "hw/arm/virt.h" #include "sysemu/numa.h" #include "kvm_arm.h" @@ -310,6 +310,13 @@ static void acpi_dsdt_add_pci(Aml *scope, const MemMapEntry *memmap, Aml *dev_rp0 = aml_device("%s", "RP0"); aml_append(dev_rp0, aml_name_decl("_ADR", aml_int(0))); aml_append(dev, dev_rp0); + + Aml *dev_res0 = aml_device("%s", "RES0"); + aml_append(dev_res0, aml_name_decl("_HID", aml_string("PNP0C02"))); + crs = aml_resource_template(); + aml_append(crs, aml_memory32_fixed(base_ecam, size_ecam, AML_READ_WRITE)); + aml_append(dev_res0, aml_name_decl("_CRS", crs)); + aml_append(dev, dev_res0); aml_append(scope, dev); } @@ -384,7 +391,7 @@ build_rsdp(GArray *rsdp_table, BIOSLinker *linker, unsigned rsdt_tbl_offset) } static void -build_iort(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info) +build_iort(GArray *table_data, BIOSLinker *linker) { int iort_start = table_data->len; AcpiIortIdMapping *idmap; @@ -439,11 +446,11 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info) } static void -build_spcr(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info) +build_spcr(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) { AcpiSerialPortConsoleRedirection *spcr; - const MemMapEntry *uart_memmap = &guest_info->memmap[VIRT_UART]; - int irq = guest_info->irqmap[VIRT_UART] + ARM_SPI_BASE; + const MemMapEntry *uart_memmap = &vms->memmap[VIRT_UART]; + int irq = vms->irqmap[VIRT_UART] + ARM_SPI_BASE; spcr = acpi_data_push(table_data, sizeof(*spcr)); @@ -472,16 +479,16 @@ build_spcr(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info) } static void -build_srat(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info) +build_srat(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) { AcpiSystemResourceAffinityTable *srat; AcpiSratProcessorGiccAffinity *core; AcpiSratMemoryAffinity *numamem; int i, j, srat_start; uint64_t mem_base; - uint32_t *cpu_node = g_malloc0(guest_info->smp_cpus * sizeof(uint32_t)); + uint32_t *cpu_node = g_malloc0(vms->smp_cpus * sizeof(uint32_t)); - for (i = 0; i < guest_info->smp_cpus; i++) { + for (i = 0; i < vms->smp_cpus; i++) { j = numa_get_node_for_cpu(i); if (j < nb_numa_nodes) { cpu_node[i] = j; @@ -492,7 +499,7 @@ build_srat(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info) srat = acpi_data_push(table_data, sizeof(*srat)); srat->reserved1 = cpu_to_le32(1); - for (i = 0; i < guest_info->smp_cpus; ++i) { + for (i = 0; i < vms->smp_cpus; ++i) { core = acpi_data_push(table_data, sizeof(*core)); core->type = ACPI_SRAT_PROCESSOR_GICC; core->length = sizeof(*core); @@ -502,7 +509,7 @@ build_srat(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info) } g_free(cpu_node); - mem_base = guest_info->memmap[VIRT_MEM].base; + mem_base = vms->memmap[VIRT_MEM].base; for (i = 0; i < nb_numa_nodes; ++i) { numamem = acpi_data_push(table_data, sizeof(*numamem)); build_srat_memory(numamem, mem_base, numa_info[i].node_mem, i, @@ -515,10 +522,10 @@ build_srat(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info) } static void -build_mcfg(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info) +build_mcfg(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) { AcpiTableMcfg *mcfg; - const MemMapEntry *memmap = guest_info->memmap; + const MemMapEntry *memmap = vms->memmap; int len = sizeof(*mcfg) + sizeof(mcfg->allocation[0]); mcfg = acpi_data_push(table_data, len); @@ -535,24 +542,33 @@ build_mcfg(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info) /* GTDT */ static void -build_gtdt(GArray *table_data, BIOSLinker *linker) +build_gtdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) { + VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(vms); int gtdt_start = table_data->len; AcpiGenericTimerTable *gtdt; + uint32_t irqflags; + + if (vmc->claim_edge_triggered_timers) { + irqflags = ACPI_GTDT_INTERRUPT_MODE_EDGE; + } else { + irqflags = ACPI_GTDT_INTERRUPT_MODE_LEVEL; + } gtdt = acpi_data_push(table_data, sizeof *gtdt); /* The interrupt values are the same with the device tree when adding 16 */ - gtdt->secure_el1_interrupt = ARCH_TIMER_S_EL1_IRQ + 16; - gtdt->secure_el1_flags = ACPI_EDGE_SENSITIVE; + gtdt->secure_el1_interrupt = cpu_to_le32(ARCH_TIMER_S_EL1_IRQ + 16); + gtdt->secure_el1_flags = cpu_to_le32(irqflags); - gtdt->non_secure_el1_interrupt = ARCH_TIMER_NS_EL1_IRQ + 16; - gtdt->non_secure_el1_flags = ACPI_EDGE_SENSITIVE | ACPI_GTDT_ALWAYS_ON; + gtdt->non_secure_el1_interrupt = cpu_to_le32(ARCH_TIMER_NS_EL1_IRQ + 16); + gtdt->non_secure_el1_flags = cpu_to_le32(irqflags | + ACPI_GTDT_CAP_ALWAYS_ON); - gtdt->virtual_timer_interrupt = ARCH_TIMER_VIRT_IRQ + 16; - gtdt->virtual_timer_flags = ACPI_EDGE_SENSITIVE; + gtdt->virtual_timer_interrupt = cpu_to_le32(ARCH_TIMER_VIRT_IRQ + 16); + gtdt->virtual_timer_flags = cpu_to_le32(irqflags); - gtdt->non_secure_el2_interrupt = ARCH_TIMER_NS_EL2_IRQ + 16; - gtdt->non_secure_el2_flags = ACPI_EDGE_SENSITIVE; + gtdt->non_secure_el2_interrupt = cpu_to_le32(ARCH_TIMER_NS_EL2_IRQ + 16); + gtdt->non_secure_el2_flags = cpu_to_le32(irqflags); build_header(linker, table_data, (void *)(table_data->data + gtdt_start), "GTDT", @@ -561,11 +577,12 @@ build_gtdt(GArray *table_data, BIOSLinker *linker) /* MADT */ static void -build_madt(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info) +build_madt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) { + VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(vms); int madt_start = table_data->len; - const MemMapEntry *memmap = guest_info->memmap; - const int *irqmap = guest_info->irqmap; + const MemMapEntry *memmap = vms->memmap; + const int *irqmap = vms->irqmap; AcpiMultipleApicTable *madt; AcpiMadtGenericDistributor *gicd; AcpiMadtGenericMsiFrame *gic_msi; @@ -576,30 +593,33 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info) gicd = acpi_data_push(table_data, sizeof *gicd); gicd->type = ACPI_APIC_GENERIC_DISTRIBUTOR; gicd->length = sizeof(*gicd); - gicd->base_address = memmap[VIRT_GIC_DIST].base; - gicd->version = guest_info->gic_version; + gicd->base_address = cpu_to_le64(memmap[VIRT_GIC_DIST].base); + gicd->version = vms->gic_version; - for (i = 0; i < guest_info->smp_cpus; i++) { - AcpiMadtGenericInterrupt *gicc = acpi_data_push(table_data, - sizeof *gicc); + for (i = 0; i < vms->smp_cpus; i++) { + AcpiMadtGenericCpuInterface *gicc = acpi_data_push(table_data, + sizeof(*gicc)); ARMCPU *armcpu = ARM_CPU(qemu_get_cpu(i)); - gicc->type = ACPI_APIC_GENERIC_INTERRUPT; + gicc->type = ACPI_APIC_GENERIC_CPU_INTERFACE; gicc->length = sizeof(*gicc); - if (guest_info->gic_version == 2) { - gicc->base_address = memmap[VIRT_GIC_CPU].base; + if (vms->gic_version == 2) { + gicc->base_address = cpu_to_le64(memmap[VIRT_GIC_CPU].base); } - gicc->cpu_interface_number = i; - gicc->arm_mpidr = armcpu->mp_affinity; - gicc->uid = i; - gicc->flags = cpu_to_le32(ACPI_GICC_ENABLED); + gicc->cpu_interface_number = cpu_to_le32(i); + gicc->arm_mpidr = cpu_to_le64(armcpu->mp_affinity); + gicc->uid = cpu_to_le32(i); + gicc->flags = cpu_to_le32(ACPI_MADT_GICC_ENABLED); if (arm_feature(&armcpu->env, ARM_FEATURE_PMU)) { gicc->performance_interrupt = cpu_to_le32(PPI(VIRTUAL_PMU_IRQ)); } + if (vms->virt && vms->gic_version == 3) { + gicc->vgic_interrupt = cpu_to_le32(PPI(ARCH_GICV3_MAINT_IRQ)); + } } - if (guest_info->gic_version == 3) { + if (vms->gic_version == 3) { AcpiMadtGenericTranslator *gic_its; AcpiMadtGenericRedistributor *gicr = acpi_data_push(table_data, sizeof *gicr); @@ -609,7 +629,7 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info) gicr->base_address = cpu_to_le64(memmap[VIRT_GIC_REDIST].base); gicr->range_length = cpu_to_le32(memmap[VIRT_GIC_REDIST].size); - if (its_class_name() && !guest_info->no_its) { + if (its_class_name() && !vmc->no_its) { gic_its = acpi_data_push(table_data, sizeof *gic_its); gic_its->type = ACPI_APIC_GENERIC_TRANSLATOR; gic_its->length = sizeof(*gic_its); @@ -633,16 +653,30 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info) } /* FADT */ -static void -build_fadt(GArray *table_data, BIOSLinker *linker, unsigned dsdt_tbl_offset) +static void build_fadt(GArray *table_data, BIOSLinker *linker, + VirtMachineState *vms, unsigned dsdt_tbl_offset) { AcpiFadtDescriptorRev5_1 *fadt = acpi_data_push(table_data, sizeof(*fadt)); unsigned dsdt_entry_offset = (char *)&fadt->dsdt - table_data->data; + uint16_t bootflags; + + switch (vms->psci_conduit) { + case QEMU_PSCI_CONDUIT_DISABLED: + bootflags = 0; + break; + case QEMU_PSCI_CONDUIT_HVC: + bootflags = ACPI_FADT_ARM_PSCI_COMPLIANT | ACPI_FADT_ARM_PSCI_USE_HVC; + break; + case QEMU_PSCI_CONDUIT_SMC: + bootflags = ACPI_FADT_ARM_PSCI_COMPLIANT; + break; + default: + g_assert_not_reached(); + } - /* Hardware Reduced = 1 and use PSCI 0.2+ and with HVC */ + /* Hardware Reduced = 1 and use PSCI 0.2+ */ fadt->flags = cpu_to_le32(1 << ACPI_FADT_F_HW_REDUCED_ACPI); - fadt->arm_boot_flags = cpu_to_le16((1 << ACPI_FADT_ARM_USE_PSCI_G_0_2) | - (1 << ACPI_FADT_ARM_PSCI_USE_HVC)); + fadt->arm_boot_flags = cpu_to_le16(bootflags); /* ACPI v5.1 (fadt->revision.fadt->minor_revision) */ fadt->minor_revision = 0x1; @@ -658,11 +692,11 @@ build_fadt(GArray *table_data, BIOSLinker *linker, unsigned dsdt_tbl_offset) /* DSDT */ static void -build_dsdt(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info) +build_dsdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) { Aml *scope, *dsdt; - const MemMapEntry *memmap = guest_info->memmap; - const int *irqmap = guest_info->irqmap; + const MemMapEntry *memmap = vms->memmap; + const int *irqmap = vms->irqmap; dsdt = init_aml_allocator(); /* Reserve space for header */ @@ -674,7 +708,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info) * the RTC ACPI device at all when using UEFI. */ scope = aml_scope("\\_SB"); - acpi_dsdt_add_cpus(scope, guest_info->smp_cpus); + acpi_dsdt_add_cpus(scope, vms->smp_cpus); acpi_dsdt_add_uart(scope, &memmap[VIRT_UART], (irqmap[VIRT_UART] + ARM_SPI_BASE)); acpi_dsdt_add_flash(scope, &memmap[VIRT_FLASH]); @@ -682,7 +716,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info) acpi_dsdt_add_virtio(scope, &memmap[VIRT_MMIO], (irqmap[VIRT_MMIO] + ARM_SPI_BASE), NUM_VIRTIO_TRANSPORTS); acpi_dsdt_add_pci(scope, memmap, (irqmap[VIRT_PCIE] + ARM_SPI_BASE), - guest_info->use_highmem); + vms->highmem); acpi_dsdt_add_gpio(scope, &memmap[VIRT_GPIO], (irqmap[VIRT_GPIO] + ARM_SPI_BASE)); acpi_dsdt_add_power_button(scope); @@ -705,12 +739,12 @@ struct AcpiBuildState { MemoryRegion *linker_mr; /* Is table patched? */ bool patched; - VirtGuestInfo *guest_info; } AcpiBuildState; static -void virt_acpi_build(VirtGuestInfo *guest_info, AcpiBuildTables *tables) +void virt_acpi_build(VirtMachineState *vms, AcpiBuildTables *tables) { + VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(vms); GArray *table_offsets; unsigned dsdt, rsdt; GArray *tables_blob = tables->table_data; @@ -724,32 +758,32 @@ void virt_acpi_build(VirtGuestInfo *guest_info, AcpiBuildTables *tables) /* DSDT is pointed to by FADT */ dsdt = tables_blob->len; - build_dsdt(tables_blob, tables->linker, guest_info); + build_dsdt(tables_blob, tables->linker, vms); /* FADT MADT GTDT MCFG SPCR pointed to by RSDT */ acpi_add_table(table_offsets, tables_blob); - build_fadt(tables_blob, tables->linker, dsdt); + build_fadt(tables_blob, tables->linker, vms, dsdt); acpi_add_table(table_offsets, tables_blob); - build_madt(tables_blob, tables->linker, guest_info); + build_madt(tables_blob, tables->linker, vms); acpi_add_table(table_offsets, tables_blob); - build_gtdt(tables_blob, tables->linker); + build_gtdt(tables_blob, tables->linker, vms); acpi_add_table(table_offsets, tables_blob); - build_mcfg(tables_blob, tables->linker, guest_info); + build_mcfg(tables_blob, tables->linker, vms); acpi_add_table(table_offsets, tables_blob); - build_spcr(tables_blob, tables->linker, guest_info); + build_spcr(tables_blob, tables->linker, vms); if (nb_numa_nodes > 0) { acpi_add_table(table_offsets, tables_blob); - build_srat(tables_blob, tables->linker, guest_info); + build_srat(tables_blob, tables->linker, vms); } - if (its_class_name() && !guest_info->no_its) { + if (its_class_name() && !vmc->no_its) { acpi_add_table(table_offsets, tables_blob); - build_iort(tables_blob, tables->linker, guest_info); + build_iort(tables_blob, tables->linker); } /* RSDT is pointed to by RSDP */ @@ -788,13 +822,12 @@ static void virt_acpi_build_update(void *build_opaque) acpi_build_tables_init(&tables); - virt_acpi_build(build_state->guest_info, &tables); + virt_acpi_build(VIRT_MACHINE(qdev_get_machine()), &tables); acpi_ram_update(build_state->table_mr, tables.table_data); acpi_ram_update(build_state->rsdp_mr, tables.rsdp); acpi_ram_update(build_state->linker_mr, tables.linker->cmd_blob); - acpi_build_tables_cleanup(&tables, true); } @@ -809,7 +842,7 @@ static MemoryRegion *acpi_add_rom_blob(AcpiBuildState *build_state, uint64_t max_size) { return rom_add_blob(name, blob->data, acpi_data_len(blob), max_size, -1, - name, virt_acpi_build_update, build_state, NULL); + name, virt_acpi_build_update, build_state, NULL, true); } static const VMStateDescription vmstate_virt_acpi_build = { @@ -822,12 +855,12 @@ static const VMStateDescription vmstate_virt_acpi_build = { }, }; -void virt_acpi_setup(VirtGuestInfo *guest_info) +void virt_acpi_setup(VirtMachineState *vms) { AcpiBuildTables tables; AcpiBuildState *build_state; - if (!guest_info->fw_cfg) { + if (!vms->fw_cfg) { trace_virt_acpi_setup(); return; } @@ -838,10 +871,9 @@ void virt_acpi_setup(VirtGuestInfo *guest_info) } build_state = g_malloc0(sizeof *build_state); - build_state->guest_info = guest_info; acpi_build_tables_init(&tables); - virt_acpi_build(build_state->guest_info, &tables); + virt_acpi_build(vms, &tables); /* Now expose it all to Guest */ build_state->table_mr = acpi_add_rom_blob(build_state, tables.table_data, @@ -853,8 +885,8 @@ void virt_acpi_setup(VirtGuestInfo *guest_info) acpi_add_rom_blob(build_state, tables.linker->cmd_blob, "etc/table-loader", 0); - fw_cfg_add_file(guest_info->fw_cfg, ACPI_BUILD_TPMLOG_FILE, - tables.tcpalog->data, acpi_data_len(tables.tcpalog)); + fw_cfg_add_file(vms->fw_cfg, ACPI_BUILD_TPMLOG_FILE, tables.tcpalog->data, + acpi_data_len(tables.tcpalog)); build_state->rsdp_mr = acpi_add_rom_blob(build_state, tables.rsdp, ACPI_BUILD_RSDP_FILE, 0); diff --git a/hw/arm/virt.c b/hw/arm/virt.c index d04e4acbd9..6c9e8985bf 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -41,14 +41,12 @@ #include "sysemu/numa.h" #include "sysemu/sysemu.h" #include "sysemu/kvm.h" -#include "hw/boards.h" #include "hw/compat.h" #include "hw/loader.h" #include "exec/address-spaces.h" #include "qemu/bitops.h" #include "qemu/error-report.h" #include "hw/pci-host/gpex.h" -#include "hw/arm/virt-acpi-build.h" #include "hw/arm/sysbus-fdt.h" #include "hw/platform-bus.h" #include "hw/arm/fdt.h" @@ -59,51 +57,6 @@ #include "qapi/visitor.h" #include "standard-headers/linux/input.h" -/* Number of external interrupt lines to configure the GIC with */ -#define NUM_IRQS 256 - -#define PLATFORM_BUS_NUM_IRQS 64 - -static ARMPlatformBusSystemParams platform_bus_params; - -typedef struct VirtBoardInfo { - struct arm_boot_info bootinfo; - const char *cpu_model; - const MemMapEntry *memmap; - const int *irqmap; - int smp_cpus; - void *fdt; - int fdt_size; - uint32_t clock_phandle; - uint32_t gic_phandle; - uint32_t msi_phandle; - bool using_psci; -} VirtBoardInfo; - -typedef struct { - MachineClass parent; - VirtBoardInfo *daughterboard; - bool disallow_affinity_adjustment; - bool no_its; - bool no_pmu; -} VirtMachineClass; - -typedef struct { - MachineState parent; - bool secure; - bool highmem; - int32_t gic_version; -} VirtMachineState; - -#define TYPE_VIRT_MACHINE MACHINE_TYPE_NAME("virt") -#define VIRT_MACHINE(obj) \ - OBJECT_CHECK(VirtMachineState, (obj), TYPE_VIRT_MACHINE) -#define VIRT_MACHINE_GET_CLASS(obj) \ - OBJECT_GET_CLASS(VirtMachineClass, obj, TYPE_VIRT_MACHINE) -#define VIRT_MACHINE_CLASS(klass) \ - OBJECT_CLASS_CHECK(VirtMachineClass, klass, TYPE_VIRT_MACHINE) - - #define DEFINE_VIRT_MACHINE_LATEST(major, minor, latest) \ static void virt_##major##_##minor##_class_init(ObjectClass *oc, \ void *data) \ @@ -133,6 +86,13 @@ typedef struct { DEFINE_VIRT_MACHINE_LATEST(major, minor, false) +/* Number of external interrupt lines to configure the GIC with */ +#define NUM_IRQS 256 + +#define PLATFORM_BUS_NUM_IRQS 64 + +static ARMPlatformBusSystemParams platform_bus_params; + /* RAM limit in GB. Since VIRT_MEM starts at the 1GB mark, this means * RAM can go up to the 256GB mark, leaving 256GB of the physical * address space unallocated and free for future use between 256G and 512G. @@ -202,51 +162,35 @@ static const int a15irqmap[] = { [VIRT_PLATFORM_BUS] = 112, /* ...to 112 + PLATFORM_BUS_NUM_IRQS -1 */ }; -static VirtBoardInfo machines[] = { - { - .cpu_model = "cortex-a15", - .memmap = a15memmap, - .irqmap = a15irqmap, - }, - { - .cpu_model = "cortex-a53", - .memmap = a15memmap, - .irqmap = a15irqmap, - }, - { - .cpu_model = "cortex-a57", - .memmap = a15memmap, - .irqmap = a15irqmap, - }, - { - .cpu_model = "host", - .memmap = a15memmap, - .irqmap = a15irqmap, - }, +static const char *valid_cpus[] = { + "cortex-a15", + "cortex-a53", + "cortex-a57", + "host", }; -static VirtBoardInfo *find_machine_info(const char *cpu) +static bool cpuname_valid(const char *cpu) { int i; - for (i = 0; i < ARRAY_SIZE(machines); i++) { - if (strcmp(cpu, machines[i].cpu_model) == 0) { - return &machines[i]; + for (i = 0; i < ARRAY_SIZE(valid_cpus); i++) { + if (strcmp(cpu, valid_cpus[i]) == 0) { + return true; } } - return NULL; + return false; } -static void create_fdt(VirtBoardInfo *vbi) +static void create_fdt(VirtMachineState *vms) { - void *fdt = create_device_tree(&vbi->fdt_size); + void *fdt = create_device_tree(&vms->fdt_size); if (!fdt) { error_report("create_device_tree() failed"); exit(1); } - vbi->fdt = fdt; + vms->fdt = fdt; /* Header */ qemu_fdt_setprop_string(fdt, "/", "compatible", "linux,dummy-virt"); @@ -266,28 +210,38 @@ static void create_fdt(VirtBoardInfo *vbi) * optional but in practice if you omit them the kernel refuses to * probe for the device. */ - vbi->clock_phandle = qemu_fdt_alloc_phandle(fdt); + vms->clock_phandle = qemu_fdt_alloc_phandle(fdt); qemu_fdt_add_subnode(fdt, "/apb-pclk"); qemu_fdt_setprop_string(fdt, "/apb-pclk", "compatible", "fixed-clock"); qemu_fdt_setprop_cell(fdt, "/apb-pclk", "#clock-cells", 0x0); qemu_fdt_setprop_cell(fdt, "/apb-pclk", "clock-frequency", 24000000); qemu_fdt_setprop_string(fdt, "/apb-pclk", "clock-output-names", "clk24mhz"); - qemu_fdt_setprop_cell(fdt, "/apb-pclk", "phandle", vbi->clock_phandle); + qemu_fdt_setprop_cell(fdt, "/apb-pclk", "phandle", vms->clock_phandle); } -static void fdt_add_psci_node(const VirtBoardInfo *vbi) +static void fdt_add_psci_node(const VirtMachineState *vms) { uint32_t cpu_suspend_fn; uint32_t cpu_off_fn; uint32_t cpu_on_fn; uint32_t migrate_fn; - void *fdt = vbi->fdt; + void *fdt = vms->fdt; ARMCPU *armcpu = ARM_CPU(qemu_get_cpu(0)); + const char *psci_method; - if (!vbi->using_psci) { + switch (vms->psci_conduit) { + case QEMU_PSCI_CONDUIT_DISABLED: return; + case QEMU_PSCI_CONDUIT_HVC: + psci_method = "hvc"; + break; + case QEMU_PSCI_CONDUIT_SMC: + psci_method = "smc"; + break; + default: + g_assert_not_reached(); } qemu_fdt_add_subnode(fdt, "/psci"); @@ -319,7 +273,7 @@ static void fdt_add_psci_node(const VirtBoardInfo *vbi) * However, the device tree binding uses 'method' instead, so that is * what we should use here. */ - qemu_fdt_setprop_string(fdt, "/psci", "method", "hvc"); + qemu_fdt_setprop_string(fdt, "/psci", "method", psci_method); qemu_fdt_setprop_cell(fdt, "/psci", "cpu_suspend", cpu_suspend_fn); qemu_fdt_setprop_cell(fdt, "/psci", "cpu_off", cpu_off_fn); @@ -327,41 +281,60 @@ static void fdt_add_psci_node(const VirtBoardInfo *vbi) qemu_fdt_setprop_cell(fdt, "/psci", "migrate", migrate_fn); } -static void fdt_add_timer_nodes(const VirtBoardInfo *vbi, int gictype) +static void fdt_add_timer_nodes(const VirtMachineState *vms) { - /* Note that on A15 h/w these interrupts are level-triggered, - * but for the GIC implementation provided by both QEMU and KVM - * they are edge-triggered. + /* On real hardware these interrupts are level-triggered. + * On KVM they were edge-triggered before host kernel version 4.4, + * and level-triggered afterwards. + * On emulated QEMU they are level-triggered. + * + * Getting the DTB info about them wrong is awkward for some + * guest kernels: + * pre-4.8 ignore the DT and leave the interrupt configured + * with whatever the GIC reset value (or the bootloader) left it at + * 4.8 before rc6 honour the incorrect data by programming it back + * into the GIC, causing problems + * 4.8rc6 and later ignore the DT and always write "level triggered" + * into the GIC + * + * For backwards-compatibility, virt-2.8 and earlier will continue + * to say these are edge-triggered, but later machines will report + * the correct information. */ ARMCPU *armcpu; - uint32_t irqflags = GIC_FDT_IRQ_FLAGS_EDGE_LO_HI; + VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(vms); + uint32_t irqflags = GIC_FDT_IRQ_FLAGS_LEVEL_HI; + + if (vmc->claim_edge_triggered_timers) { + irqflags = GIC_FDT_IRQ_FLAGS_EDGE_LO_HI; + } - if (gictype == 2) { + if (vms->gic_version == 2) { irqflags = deposit32(irqflags, GIC_FDT_IRQ_PPI_CPU_START, GIC_FDT_IRQ_PPI_CPU_WIDTH, - (1 << vbi->smp_cpus) - 1); + (1 << vms->smp_cpus) - 1); } - qemu_fdt_add_subnode(vbi->fdt, "/timer"); + qemu_fdt_add_subnode(vms->fdt, "/timer"); armcpu = ARM_CPU(qemu_get_cpu(0)); if (arm_feature(&armcpu->env, ARM_FEATURE_V8)) { const char compat[] = "arm,armv8-timer\0arm,armv7-timer"; - qemu_fdt_setprop(vbi->fdt, "/timer", "compatible", + qemu_fdt_setprop(vms->fdt, "/timer", "compatible", compat, sizeof(compat)); } else { - qemu_fdt_setprop_string(vbi->fdt, "/timer", "compatible", + qemu_fdt_setprop_string(vms->fdt, "/timer", "compatible", "arm,armv7-timer"); } - qemu_fdt_setprop(vbi->fdt, "/timer", "always-on", NULL, 0); - qemu_fdt_setprop_cells(vbi->fdt, "/timer", "interrupts", + qemu_fdt_setprop(vms->fdt, "/timer", "always-on", NULL, 0); + qemu_fdt_setprop_cells(vms->fdt, "/timer", "interrupts", GIC_FDT_IRQ_TYPE_PPI, ARCH_TIMER_S_EL1_IRQ, irqflags, GIC_FDT_IRQ_TYPE_PPI, ARCH_TIMER_NS_EL1_IRQ, irqflags, GIC_FDT_IRQ_TYPE_PPI, ARCH_TIMER_VIRT_IRQ, irqflags, GIC_FDT_IRQ_TYPE_PPI, ARCH_TIMER_NS_EL2_IRQ, irqflags); } -static void fdt_add_cpu_nodes(const VirtBoardInfo *vbi) +static void fdt_add_cpu_nodes(const VirtMachineState *vms) { int cpu; int addr_cells = 1; @@ -380,7 +353,7 @@ static void fdt_add_cpu_nodes(const VirtBoardInfo *vbi) * The simplest way to go is to examine affinity IDs of all our CPUs. If * at least one of them has Aff3 populated, we set #address-cells to 2. */ - for (cpu = 0; cpu < vbi->smp_cpus; cpu++) { + for (cpu = 0; cpu < vms->smp_cpus; cpu++) { ARMCPU *armcpu = ARM_CPU(qemu_get_cpu(cpu)); if (armcpu->mp_affinity & ARM_AFF3_MASK) { @@ -389,101 +362,107 @@ static void fdt_add_cpu_nodes(const VirtBoardInfo *vbi) } } - qemu_fdt_add_subnode(vbi->fdt, "/cpus"); - qemu_fdt_setprop_cell(vbi->fdt, "/cpus", "#address-cells", addr_cells); - qemu_fdt_setprop_cell(vbi->fdt, "/cpus", "#size-cells", 0x0); + qemu_fdt_add_subnode(vms->fdt, "/cpus"); + qemu_fdt_setprop_cell(vms->fdt, "/cpus", "#address-cells", addr_cells); + qemu_fdt_setprop_cell(vms->fdt, "/cpus", "#size-cells", 0x0); - for (cpu = vbi->smp_cpus - 1; cpu >= 0; cpu--) { + for (cpu = vms->smp_cpus - 1; cpu >= 0; cpu--) { char *nodename = g_strdup_printf("/cpus/cpu@%d", cpu); ARMCPU *armcpu = ARM_CPU(qemu_get_cpu(cpu)); - qemu_fdt_add_subnode(vbi->fdt, nodename); - qemu_fdt_setprop_string(vbi->fdt, nodename, "device_type", "cpu"); - qemu_fdt_setprop_string(vbi->fdt, nodename, "compatible", + qemu_fdt_add_subnode(vms->fdt, nodename); + qemu_fdt_setprop_string(vms->fdt, nodename, "device_type", "cpu"); + qemu_fdt_setprop_string(vms->fdt, nodename, "compatible", armcpu->dtb_compatible); - if (vbi->using_psci && vbi->smp_cpus > 1) { - qemu_fdt_setprop_string(vbi->fdt, nodename, + if (vms->psci_conduit != QEMU_PSCI_CONDUIT_DISABLED + && vms->smp_cpus > 1) { + qemu_fdt_setprop_string(vms->fdt, nodename, "enable-method", "psci"); } if (addr_cells == 2) { - qemu_fdt_setprop_u64(vbi->fdt, nodename, "reg", + qemu_fdt_setprop_u64(vms->fdt, nodename, "reg", armcpu->mp_affinity); } else { - qemu_fdt_setprop_cell(vbi->fdt, nodename, "reg", + qemu_fdt_setprop_cell(vms->fdt, nodename, "reg", armcpu->mp_affinity); } i = numa_get_node_for_cpu(cpu); if (i < nb_numa_nodes) { - qemu_fdt_setprop_cell(vbi->fdt, nodename, "numa-node-id", i); + qemu_fdt_setprop_cell(vms->fdt, nodename, "numa-node-id", i); } g_free(nodename); } } -static void fdt_add_its_gic_node(VirtBoardInfo *vbi) +static void fdt_add_its_gic_node(VirtMachineState *vms) { - vbi->msi_phandle = qemu_fdt_alloc_phandle(vbi->fdt); - qemu_fdt_add_subnode(vbi->fdt, "/intc/its"); - qemu_fdt_setprop_string(vbi->fdt, "/intc/its", "compatible", + vms->msi_phandle = qemu_fdt_alloc_phandle(vms->fdt); + qemu_fdt_add_subnode(vms->fdt, "/intc/its"); + qemu_fdt_setprop_string(vms->fdt, "/intc/its", "compatible", "arm,gic-v3-its"); - qemu_fdt_setprop(vbi->fdt, "/intc/its", "msi-controller", NULL, 0); - qemu_fdt_setprop_sized_cells(vbi->fdt, "/intc/its", "reg", - 2, vbi->memmap[VIRT_GIC_ITS].base, - 2, vbi->memmap[VIRT_GIC_ITS].size); - qemu_fdt_setprop_cell(vbi->fdt, "/intc/its", "phandle", vbi->msi_phandle); + qemu_fdt_setprop(vms->fdt, "/intc/its", "msi-controller", NULL, 0); + qemu_fdt_setprop_sized_cells(vms->fdt, "/intc/its", "reg", + 2, vms->memmap[VIRT_GIC_ITS].base, + 2, vms->memmap[VIRT_GIC_ITS].size); + qemu_fdt_setprop_cell(vms->fdt, "/intc/its", "phandle", vms->msi_phandle); } -static void fdt_add_v2m_gic_node(VirtBoardInfo *vbi) +static void fdt_add_v2m_gic_node(VirtMachineState *vms) { - vbi->msi_phandle = qemu_fdt_alloc_phandle(vbi->fdt); - qemu_fdt_add_subnode(vbi->fdt, "/intc/v2m"); - qemu_fdt_setprop_string(vbi->fdt, "/intc/v2m", "compatible", + vms->msi_phandle = qemu_fdt_alloc_phandle(vms->fdt); + qemu_fdt_add_subnode(vms->fdt, "/intc/v2m"); + qemu_fdt_setprop_string(vms->fdt, "/intc/v2m", "compatible", "arm,gic-v2m-frame"); - qemu_fdt_setprop(vbi->fdt, "/intc/v2m", "msi-controller", NULL, 0); - qemu_fdt_setprop_sized_cells(vbi->fdt, "/intc/v2m", "reg", - 2, vbi->memmap[VIRT_GIC_V2M].base, - 2, vbi->memmap[VIRT_GIC_V2M].size); - qemu_fdt_setprop_cell(vbi->fdt, "/intc/v2m", "phandle", vbi->msi_phandle); + qemu_fdt_setprop(vms->fdt, "/intc/v2m", "msi-controller", NULL, 0); + qemu_fdt_setprop_sized_cells(vms->fdt, "/intc/v2m", "reg", + 2, vms->memmap[VIRT_GIC_V2M].base, + 2, vms->memmap[VIRT_GIC_V2M].size); + qemu_fdt_setprop_cell(vms->fdt, "/intc/v2m", "phandle", vms->msi_phandle); } -static void fdt_add_gic_node(VirtBoardInfo *vbi, int type) +static void fdt_add_gic_node(VirtMachineState *vms) { - vbi->gic_phandle = qemu_fdt_alloc_phandle(vbi->fdt); - qemu_fdt_setprop_cell(vbi->fdt, "/", "interrupt-parent", vbi->gic_phandle); - - qemu_fdt_add_subnode(vbi->fdt, "/intc"); - qemu_fdt_setprop_cell(vbi->fdt, "/intc", "#interrupt-cells", 3); - qemu_fdt_setprop(vbi->fdt, "/intc", "interrupt-controller", NULL, 0); - qemu_fdt_setprop_cell(vbi->fdt, "/intc", "#address-cells", 0x2); - qemu_fdt_setprop_cell(vbi->fdt, "/intc", "#size-cells", 0x2); - qemu_fdt_setprop(vbi->fdt, "/intc", "ranges", NULL, 0); - if (type == 3) { - qemu_fdt_setprop_string(vbi->fdt, "/intc", "compatible", + vms->gic_phandle = qemu_fdt_alloc_phandle(vms->fdt); + qemu_fdt_setprop_cell(vms->fdt, "/", "interrupt-parent", vms->gic_phandle); + + qemu_fdt_add_subnode(vms->fdt, "/intc"); + qemu_fdt_setprop_cell(vms->fdt, "/intc", "#interrupt-cells", 3); + qemu_fdt_setprop(vms->fdt, "/intc", "interrupt-controller", NULL, 0); + qemu_fdt_setprop_cell(vms->fdt, "/intc", "#address-cells", 0x2); + qemu_fdt_setprop_cell(vms->fdt, "/intc", "#size-cells", 0x2); + qemu_fdt_setprop(vms->fdt, "/intc", "ranges", NULL, 0); + if (vms->gic_version == 3) { + qemu_fdt_setprop_string(vms->fdt, "/intc", "compatible", "arm,gic-v3"); - qemu_fdt_setprop_sized_cells(vbi->fdt, "/intc", "reg", - 2, vbi->memmap[VIRT_GIC_DIST].base, - 2, vbi->memmap[VIRT_GIC_DIST].size, - 2, vbi->memmap[VIRT_GIC_REDIST].base, - 2, vbi->memmap[VIRT_GIC_REDIST].size); + qemu_fdt_setprop_sized_cells(vms->fdt, "/intc", "reg", + 2, vms->memmap[VIRT_GIC_DIST].base, + 2, vms->memmap[VIRT_GIC_DIST].size, + 2, vms->memmap[VIRT_GIC_REDIST].base, + 2, vms->memmap[VIRT_GIC_REDIST].size); + if (vms->virt) { + qemu_fdt_setprop_cells(vms->fdt, "/intc", "interrupts", + GIC_FDT_IRQ_TYPE_PPI, ARCH_GICV3_MAINT_IRQ, + GIC_FDT_IRQ_FLAGS_LEVEL_HI); + } } else { /* 'cortex-a15-gic' means 'GIC v2' */ - qemu_fdt_setprop_string(vbi->fdt, "/intc", "compatible", + qemu_fdt_setprop_string(vms->fdt, "/intc", "compatible", "arm,cortex-a15-gic"); - qemu_fdt_setprop_sized_cells(vbi->fdt, "/intc", "reg", - 2, vbi->memmap[VIRT_GIC_DIST].base, - 2, vbi->memmap[VIRT_GIC_DIST].size, - 2, vbi->memmap[VIRT_GIC_CPU].base, - 2, vbi->memmap[VIRT_GIC_CPU].size); + qemu_fdt_setprop_sized_cells(vms->fdt, "/intc", "reg", + 2, vms->memmap[VIRT_GIC_DIST].base, + 2, vms->memmap[VIRT_GIC_DIST].size, + 2, vms->memmap[VIRT_GIC_CPU].base, + 2, vms->memmap[VIRT_GIC_CPU].size); } - qemu_fdt_setprop_cell(vbi->fdt, "/intc", "phandle", vbi->gic_phandle); + qemu_fdt_setprop_cell(vms->fdt, "/intc", "phandle", vms->gic_phandle); } -static void fdt_add_pmu_nodes(const VirtBoardInfo *vbi, int gictype) +static void fdt_add_pmu_nodes(const VirtMachineState *vms) { CPUState *cpu; ARMCPU *armcpu; @@ -497,24 +476,24 @@ static void fdt_add_pmu_nodes(const VirtBoardInfo *vbi, int gictype) } } - if (gictype == 2) { + if (vms->gic_version == 2) { irqflags = deposit32(irqflags, GIC_FDT_IRQ_PPI_CPU_START, GIC_FDT_IRQ_PPI_CPU_WIDTH, - (1 << vbi->smp_cpus) - 1); + (1 << vms->smp_cpus) - 1); } armcpu = ARM_CPU(qemu_get_cpu(0)); - qemu_fdt_add_subnode(vbi->fdt, "/pmu"); + qemu_fdt_add_subnode(vms->fdt, "/pmu"); if (arm_feature(&armcpu->env, ARM_FEATURE_V8)) { const char compat[] = "arm,armv8-pmuv3"; - qemu_fdt_setprop(vbi->fdt, "/pmu", "compatible", + qemu_fdt_setprop(vms->fdt, "/pmu", "compatible", compat, sizeof(compat)); - qemu_fdt_setprop_cells(vbi->fdt, "/pmu", "interrupts", + qemu_fdt_setprop_cells(vms->fdt, "/pmu", "interrupts", GIC_FDT_IRQ_TYPE_PPI, VIRTUAL_PMU_IRQ, irqflags); } } -static void create_its(VirtBoardInfo *vbi, DeviceState *gicdev) +static void create_its(VirtMachineState *vms, DeviceState *gicdev) { const char *itsclass = its_class_name(); DeviceState *dev; @@ -529,19 +508,19 @@ static void create_its(VirtBoardInfo *vbi, DeviceState *gicdev) object_property_set_link(OBJECT(dev), OBJECT(gicdev), "parent-gicv3", &error_abort); qdev_init_nofail(dev); - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, vbi->memmap[VIRT_GIC_ITS].base); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, vms->memmap[VIRT_GIC_ITS].base); - fdt_add_its_gic_node(vbi); + fdt_add_its_gic_node(vms); } -static void create_v2m(VirtBoardInfo *vbi, qemu_irq *pic) +static void create_v2m(VirtMachineState *vms, qemu_irq *pic) { int i; - int irq = vbi->irqmap[VIRT_GIC_V2M]; + int irq = vms->irqmap[VIRT_GIC_V2M]; DeviceState *dev; dev = qdev_create(NULL, "arm-gicv2m"); - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, vbi->memmap[VIRT_GIC_V2M].base); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, vms->memmap[VIRT_GIC_V2M].base); qdev_prop_set_uint32(dev, "base-spi", irq); qdev_prop_set_uint32(dev, "num-spi", NUM_GICV2M_SPIS); qdev_init_nofail(dev); @@ -550,17 +529,17 @@ static void create_v2m(VirtBoardInfo *vbi, qemu_irq *pic) sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, pic[irq + i]); } - fdt_add_v2m_gic_node(vbi); + fdt_add_v2m_gic_node(vms); } -static void create_gic(VirtBoardInfo *vbi, qemu_irq *pic, int type, - bool secure, bool no_its) +static void create_gic(VirtMachineState *vms, qemu_irq *pic) { /* We create a standalone GIC */ + VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(vms); DeviceState *gicdev; SysBusDevice *gicbusdev; const char *gictype; - int i; + int type = vms->gic_version, i; gictype = (type == 3) ? gicv3_class_name() : gic_class_name(); @@ -572,20 +551,20 @@ static void create_gic(VirtBoardInfo *vbi, qemu_irq *pic, int type, */ qdev_prop_set_uint32(gicdev, "num-irq", NUM_IRQS + 32); if (!kvm_irqchip_in_kernel()) { - qdev_prop_set_bit(gicdev, "has-security-extensions", secure); + qdev_prop_set_bit(gicdev, "has-security-extensions", vms->secure); } qdev_init_nofail(gicdev); gicbusdev = SYS_BUS_DEVICE(gicdev); - sysbus_mmio_map(gicbusdev, 0, vbi->memmap[VIRT_GIC_DIST].base); + sysbus_mmio_map(gicbusdev, 0, vms->memmap[VIRT_GIC_DIST].base); if (type == 3) { - sysbus_mmio_map(gicbusdev, 1, vbi->memmap[VIRT_GIC_REDIST].base); + sysbus_mmio_map(gicbusdev, 1, vms->memmap[VIRT_GIC_REDIST].base); } else { - sysbus_mmio_map(gicbusdev, 1, vbi->memmap[VIRT_GIC_CPU].base); + sysbus_mmio_map(gicbusdev, 1, vms->memmap[VIRT_GIC_CPU].base); } - /* Wire the outputs from each CPU's generic timer to the - * appropriate GIC PPI inputs, and the GIC's IRQ output to - * the CPU's IRQ input. + /* Wire the outputs from each CPU's generic timer and the GICv3 + * maintenance interrupt signal to the appropriate GIC PPI inputs, + * and the GIC's IRQ/FIQ/VIRQ/VFIQ interrupt outputs to the CPU's inputs. */ for (i = 0; i < smp_cpus; i++) { DeviceState *cpudev = DEVICE(qemu_get_cpu(i)); @@ -607,31 +586,39 @@ static void create_gic(VirtBoardInfo *vbi, qemu_irq *pic, int type, ppibase + timer_irq[irq])); } + qdev_connect_gpio_out_named(cpudev, "gicv3-maintenance-interrupt", 0, + qdev_get_gpio_in(gicdev, ppibase + + ARCH_GICV3_MAINT_IRQ)); + sysbus_connect_irq(gicbusdev, i, qdev_get_gpio_in(cpudev, ARM_CPU_IRQ)); sysbus_connect_irq(gicbusdev, i + smp_cpus, qdev_get_gpio_in(cpudev, ARM_CPU_FIQ)); + sysbus_connect_irq(gicbusdev, i + 2 * smp_cpus, + qdev_get_gpio_in(cpudev, ARM_CPU_VIRQ)); + sysbus_connect_irq(gicbusdev, i + 3 * smp_cpus, + qdev_get_gpio_in(cpudev, ARM_CPU_VFIQ)); } for (i = 0; i < NUM_IRQS; i++) { pic[i] = qdev_get_gpio_in(gicdev, i); } - fdt_add_gic_node(vbi, type); + fdt_add_gic_node(vms); - if (type == 3 && !no_its) { - create_its(vbi, gicdev); + if (type == 3 && !vmc->no_its) { + create_its(vms, gicdev); } else if (type == 2) { - create_v2m(vbi, pic); + create_v2m(vms, pic); } } -static void create_uart(const VirtBoardInfo *vbi, qemu_irq *pic, int uart, +static void create_uart(const VirtMachineState *vms, qemu_irq *pic, int uart, MemoryRegion *mem, CharDriverState *chr) { char *nodename; - hwaddr base = vbi->memmap[uart].base; - hwaddr size = vbi->memmap[uart].size; - int irq = vbi->irqmap[uart]; + hwaddr base = vms->memmap[uart].base; + hwaddr size = vms->memmap[uart].size; + int irq = vms->irqmap[uart]; const char compat[] = "arm,pl011\0arm,primecell"; const char clocknames[] = "uartclk\0apb_pclk"; DeviceState *dev = qdev_create(NULL, "pl011"); @@ -644,51 +631,51 @@ static void create_uart(const VirtBoardInfo *vbi, qemu_irq *pic, int uart, sysbus_connect_irq(s, 0, pic[irq]); nodename = g_strdup_printf("/pl011@%" PRIx64, base); - qemu_fdt_add_subnode(vbi->fdt, nodename); + qemu_fdt_add_subnode(vms->fdt, nodename); /* Note that we can't use setprop_string because of the embedded NUL */ - qemu_fdt_setprop(vbi->fdt, nodename, "compatible", + qemu_fdt_setprop(vms->fdt, nodename, "compatible", compat, sizeof(compat)); - qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg", + qemu_fdt_setprop_sized_cells(vms->fdt, nodename, "reg", 2, base, 2, size); - qemu_fdt_setprop_cells(vbi->fdt, nodename, "interrupts", + qemu_fdt_setprop_cells(vms->fdt, nodename, "interrupts", GIC_FDT_IRQ_TYPE_SPI, irq, GIC_FDT_IRQ_FLAGS_LEVEL_HI); - qemu_fdt_setprop_cells(vbi->fdt, nodename, "clocks", - vbi->clock_phandle, vbi->clock_phandle); - qemu_fdt_setprop(vbi->fdt, nodename, "clock-names", + qemu_fdt_setprop_cells(vms->fdt, nodename, "clocks", + vms->clock_phandle, vms->clock_phandle); + qemu_fdt_setprop(vms->fdt, nodename, "clock-names", clocknames, sizeof(clocknames)); if (uart == VIRT_UART) { - qemu_fdt_setprop_string(vbi->fdt, "/chosen", "stdout-path", nodename); + qemu_fdt_setprop_string(vms->fdt, "/chosen", "stdout-path", nodename); } else { /* Mark as not usable by the normal world */ - qemu_fdt_setprop_string(vbi->fdt, nodename, "status", "disabled"); - qemu_fdt_setprop_string(vbi->fdt, nodename, "secure-status", "okay"); + qemu_fdt_setprop_string(vms->fdt, nodename, "status", "disabled"); + qemu_fdt_setprop_string(vms->fdt, nodename, "secure-status", "okay"); } g_free(nodename); } -static void create_rtc(const VirtBoardInfo *vbi, qemu_irq *pic) +static void create_rtc(const VirtMachineState *vms, qemu_irq *pic) { char *nodename; - hwaddr base = vbi->memmap[VIRT_RTC].base; - hwaddr size = vbi->memmap[VIRT_RTC].size; - int irq = vbi->irqmap[VIRT_RTC]; + hwaddr base = vms->memmap[VIRT_RTC].base; + hwaddr size = vms->memmap[VIRT_RTC].size; + int irq = vms->irqmap[VIRT_RTC]; const char compat[] = "arm,pl031\0arm,primecell"; sysbus_create_simple("pl031", base, pic[irq]); nodename = g_strdup_printf("/pl031@%" PRIx64, base); - qemu_fdt_add_subnode(vbi->fdt, nodename); - qemu_fdt_setprop(vbi->fdt, nodename, "compatible", compat, sizeof(compat)); - qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg", + qemu_fdt_add_subnode(vms->fdt, nodename); + qemu_fdt_setprop(vms->fdt, nodename, "compatible", compat, sizeof(compat)); + qemu_fdt_setprop_sized_cells(vms->fdt, nodename, "reg", 2, base, 2, size); - qemu_fdt_setprop_cells(vbi->fdt, nodename, "interrupts", + qemu_fdt_setprop_cells(vms->fdt, nodename, "interrupts", GIC_FDT_IRQ_TYPE_SPI, irq, GIC_FDT_IRQ_FLAGS_LEVEL_HI); - qemu_fdt_setprop_cell(vbi->fdt, nodename, "clocks", vbi->clock_phandle); - qemu_fdt_setprop_string(vbi->fdt, nodename, "clock-names", "apb_pclk"); + qemu_fdt_setprop_cell(vms->fdt, nodename, "clocks", vms->clock_phandle); + qemu_fdt_setprop_string(vms->fdt, nodename, "clock-names", "apb_pclk"); g_free(nodename); } @@ -703,45 +690,45 @@ static Notifier virt_system_powerdown_notifier = { .notify = virt_powerdown_req }; -static void create_gpio(const VirtBoardInfo *vbi, qemu_irq *pic) +static void create_gpio(const VirtMachineState *vms, qemu_irq *pic) { char *nodename; DeviceState *pl061_dev; - hwaddr base = vbi->memmap[VIRT_GPIO].base; - hwaddr size = vbi->memmap[VIRT_GPIO].size; - int irq = vbi->irqmap[VIRT_GPIO]; + hwaddr base = vms->memmap[VIRT_GPIO].base; + hwaddr size = vms->memmap[VIRT_GPIO].size; + int irq = vms->irqmap[VIRT_GPIO]; const char compat[] = "arm,pl061\0arm,primecell"; pl061_dev = sysbus_create_simple("pl061", base, pic[irq]); - uint32_t phandle = qemu_fdt_alloc_phandle(vbi->fdt); + uint32_t phandle = qemu_fdt_alloc_phandle(vms->fdt); nodename = g_strdup_printf("/pl061@%" PRIx64, base); - qemu_fdt_add_subnode(vbi->fdt, nodename); - qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg", + qemu_fdt_add_subnode(vms->fdt, nodename); + qemu_fdt_setprop_sized_cells(vms->fdt, nodename, "reg", 2, base, 2, size); - qemu_fdt_setprop(vbi->fdt, nodename, "compatible", compat, sizeof(compat)); - qemu_fdt_setprop_cell(vbi->fdt, nodename, "#gpio-cells", 2); - qemu_fdt_setprop(vbi->fdt, nodename, "gpio-controller", NULL, 0); - qemu_fdt_setprop_cells(vbi->fdt, nodename, "interrupts", + qemu_fdt_setprop(vms->fdt, nodename, "compatible", compat, sizeof(compat)); + qemu_fdt_setprop_cell(vms->fdt, nodename, "#gpio-cells", 2); + qemu_fdt_setprop(vms->fdt, nodename, "gpio-controller", NULL, 0); + qemu_fdt_setprop_cells(vms->fdt, nodename, "interrupts", GIC_FDT_IRQ_TYPE_SPI, irq, GIC_FDT_IRQ_FLAGS_LEVEL_HI); - qemu_fdt_setprop_cell(vbi->fdt, nodename, "clocks", vbi->clock_phandle); - qemu_fdt_setprop_string(vbi->fdt, nodename, "clock-names", "apb_pclk"); - qemu_fdt_setprop_cell(vbi->fdt, nodename, "phandle", phandle); + qemu_fdt_setprop_cell(vms->fdt, nodename, "clocks", vms->clock_phandle); + qemu_fdt_setprop_string(vms->fdt, nodename, "clock-names", "apb_pclk"); + qemu_fdt_setprop_cell(vms->fdt, nodename, "phandle", phandle); gpio_key_dev = sysbus_create_simple("gpio-key", -1, qdev_get_gpio_in(pl061_dev, 3)); - qemu_fdt_add_subnode(vbi->fdt, "/gpio-keys"); - qemu_fdt_setprop_string(vbi->fdt, "/gpio-keys", "compatible", "gpio-keys"); - qemu_fdt_setprop_cell(vbi->fdt, "/gpio-keys", "#size-cells", 0); - qemu_fdt_setprop_cell(vbi->fdt, "/gpio-keys", "#address-cells", 1); + qemu_fdt_add_subnode(vms->fdt, "/gpio-keys"); + qemu_fdt_setprop_string(vms->fdt, "/gpio-keys", "compatible", "gpio-keys"); + qemu_fdt_setprop_cell(vms->fdt, "/gpio-keys", "#size-cells", 0); + qemu_fdt_setprop_cell(vms->fdt, "/gpio-keys", "#address-cells", 1); - qemu_fdt_add_subnode(vbi->fdt, "/gpio-keys/poweroff"); - qemu_fdt_setprop_string(vbi->fdt, "/gpio-keys/poweroff", + qemu_fdt_add_subnode(vms->fdt, "/gpio-keys/poweroff"); + qemu_fdt_setprop_string(vms->fdt, "/gpio-keys/poweroff", "label", "GPIO Key Poweroff"); - qemu_fdt_setprop_cell(vbi->fdt, "/gpio-keys/poweroff", "linux,code", + qemu_fdt_setprop_cell(vms->fdt, "/gpio-keys/poweroff", "linux,code", KEY_POWER); - qemu_fdt_setprop_cells(vbi->fdt, "/gpio-keys/poweroff", + qemu_fdt_setprop_cells(vms->fdt, "/gpio-keys/poweroff", "gpios", phandle, 3, 0); /* connect powerdown request */ @@ -750,10 +737,10 @@ static void create_gpio(const VirtBoardInfo *vbi, qemu_irq *pic) g_free(nodename); } -static void create_virtio_devices(const VirtBoardInfo *vbi, qemu_irq *pic) +static void create_virtio_devices(const VirtMachineState *vms, qemu_irq *pic) { int i; - hwaddr size = vbi->memmap[VIRT_MMIO].size; + hwaddr size = vms->memmap[VIRT_MMIO].size; /* We create the transports in forwards order. Since qbus_realize() * prepends (not appends) new child buses, the incrementing loop below will @@ -783,8 +770,8 @@ static void create_virtio_devices(const VirtBoardInfo *vbi, qemu_irq *pic) * of disks users must use UUIDs or similar mechanisms. */ for (i = 0; i < NUM_VIRTIO_TRANSPORTS; i++) { - int irq = vbi->irqmap[VIRT_MMIO] + i; - hwaddr base = vbi->memmap[VIRT_MMIO].base + i * size; + int irq = vms->irqmap[VIRT_MMIO] + i; + hwaddr base = vms->memmap[VIRT_MMIO].base + i * size; sysbus_create_simple("virtio-mmio", base, pic[irq]); } @@ -798,16 +785,16 @@ static void create_virtio_devices(const VirtBoardInfo *vbi, qemu_irq *pic) */ for (i = NUM_VIRTIO_TRANSPORTS - 1; i >= 0; i--) { char *nodename; - int irq = vbi->irqmap[VIRT_MMIO] + i; - hwaddr base = vbi->memmap[VIRT_MMIO].base + i * size; + int irq = vms->irqmap[VIRT_MMIO] + i; + hwaddr base = vms->memmap[VIRT_MMIO].base + i * size; nodename = g_strdup_printf("/virtio_mmio@%" PRIx64, base); - qemu_fdt_add_subnode(vbi->fdt, nodename); - qemu_fdt_setprop_string(vbi->fdt, nodename, + qemu_fdt_add_subnode(vms->fdt, nodename); + qemu_fdt_setprop_string(vms->fdt, nodename, "compatible", "virtio,mmio"); - qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg", + qemu_fdt_setprop_sized_cells(vms->fdt, nodename, "reg", 2, base, 2, size); - qemu_fdt_setprop_cells(vbi->fdt, nodename, "interrupts", + qemu_fdt_setprop_cells(vms->fdt, nodename, "interrupts", GIC_FDT_IRQ_TYPE_SPI, irq, GIC_FDT_IRQ_FLAGS_EDGE_LO_HI); g_free(nodename); @@ -870,7 +857,7 @@ static void create_one_flash(const char *name, hwaddr flashbase, } } -static void create_flash(const VirtBoardInfo *vbi, +static void create_flash(const VirtMachineState *vms, MemoryRegion *sysmem, MemoryRegion *secure_sysmem) { @@ -882,8 +869,8 @@ static void create_flash(const VirtBoardInfo *vbi, * If sysmem == secure_sysmem this means there is no separate Secure * address space and both flash devices are generally visible. */ - hwaddr flashsize = vbi->memmap[VIRT_FLASH].size / 2; - hwaddr flashbase = vbi->memmap[VIRT_FLASH].base; + hwaddr flashsize = vms->memmap[VIRT_FLASH].size / 2; + hwaddr flashbase = vms->memmap[VIRT_FLASH].base; char *nodename; create_one_flash("virt.flash0", flashbase, flashsize, @@ -894,41 +881,41 @@ static void create_flash(const VirtBoardInfo *vbi, if (sysmem == secure_sysmem) { /* Report both flash devices as a single node in the DT */ nodename = g_strdup_printf("/flash@%" PRIx64, flashbase); - qemu_fdt_add_subnode(vbi->fdt, nodename); - qemu_fdt_setprop_string(vbi->fdt, nodename, "compatible", "cfi-flash"); - qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg", + qemu_fdt_add_subnode(vms->fdt, nodename); + qemu_fdt_setprop_string(vms->fdt, nodename, "compatible", "cfi-flash"); + qemu_fdt_setprop_sized_cells(vms->fdt, nodename, "reg", 2, flashbase, 2, flashsize, 2, flashbase + flashsize, 2, flashsize); - qemu_fdt_setprop_cell(vbi->fdt, nodename, "bank-width", 4); + qemu_fdt_setprop_cell(vms->fdt, nodename, "bank-width", 4); g_free(nodename); } else { /* Report the devices as separate nodes so we can mark one as * only visible to the secure world. */ nodename = g_strdup_printf("/secflash@%" PRIx64, flashbase); - qemu_fdt_add_subnode(vbi->fdt, nodename); - qemu_fdt_setprop_string(vbi->fdt, nodename, "compatible", "cfi-flash"); - qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg", + qemu_fdt_add_subnode(vms->fdt, nodename); + qemu_fdt_setprop_string(vms->fdt, nodename, "compatible", "cfi-flash"); + qemu_fdt_setprop_sized_cells(vms->fdt, nodename, "reg", 2, flashbase, 2, flashsize); - qemu_fdt_setprop_cell(vbi->fdt, nodename, "bank-width", 4); - qemu_fdt_setprop_string(vbi->fdt, nodename, "status", "disabled"); - qemu_fdt_setprop_string(vbi->fdt, nodename, "secure-status", "okay"); + qemu_fdt_setprop_cell(vms->fdt, nodename, "bank-width", 4); + qemu_fdt_setprop_string(vms->fdt, nodename, "status", "disabled"); + qemu_fdt_setprop_string(vms->fdt, nodename, "secure-status", "okay"); g_free(nodename); nodename = g_strdup_printf("/flash@%" PRIx64, flashbase); - qemu_fdt_add_subnode(vbi->fdt, nodename); - qemu_fdt_setprop_string(vbi->fdt, nodename, "compatible", "cfi-flash"); - qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg", + qemu_fdt_add_subnode(vms->fdt, nodename); + qemu_fdt_setprop_string(vms->fdt, nodename, "compatible", "cfi-flash"); + qemu_fdt_setprop_sized_cells(vms->fdt, nodename, "reg", 2, flashbase + flashsize, 2, flashsize); - qemu_fdt_setprop_cell(vbi->fdt, nodename, "bank-width", 4); + qemu_fdt_setprop_cell(vms->fdt, nodename, "bank-width", 4); g_free(nodename); } } -static void create_fw_cfg(const VirtBoardInfo *vbi, AddressSpace *as) +static FWCfgState *create_fw_cfg(const VirtMachineState *vms, AddressSpace *as) { - hwaddr base = vbi->memmap[VIRT_FW_CFG].base; - hwaddr size = vbi->memmap[VIRT_FW_CFG].size; + hwaddr base = vms->memmap[VIRT_FW_CFG].base; + hwaddr size = vms->memmap[VIRT_FW_CFG].size; FWCfgState *fw_cfg; char *nodename; @@ -936,15 +923,17 @@ static void create_fw_cfg(const VirtBoardInfo *vbi, AddressSpace *as) fw_cfg_add_i16(fw_cfg, FW_CFG_NB_CPUS, (uint16_t)smp_cpus); nodename = g_strdup_printf("/fw-cfg@%" PRIx64, base); - qemu_fdt_add_subnode(vbi->fdt, nodename); - qemu_fdt_setprop_string(vbi->fdt, nodename, + qemu_fdt_add_subnode(vms->fdt, nodename); + qemu_fdt_setprop_string(vms->fdt, nodename, "compatible", "qemu,fw-cfg-mmio"); - qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg", + qemu_fdt_setprop_sized_cells(vms->fdt, nodename, "reg", 2, base, 2, size); g_free(nodename); + return fw_cfg; } -static void create_pcie_irq_map(const VirtBoardInfo *vbi, uint32_t gic_phandle, +static void create_pcie_irq_map(const VirtMachineState *vms, + uint32_t gic_phandle, int first_irq, const char *nodename) { int devfn, pin; @@ -971,28 +960,27 @@ static void create_pcie_irq_map(const VirtBoardInfo *vbi, uint32_t gic_phandle, } } - qemu_fdt_setprop(vbi->fdt, nodename, "interrupt-map", + qemu_fdt_setprop(vms->fdt, nodename, "interrupt-map", full_irq_map, sizeof(full_irq_map)); - qemu_fdt_setprop_cells(vbi->fdt, nodename, "interrupt-map-mask", + qemu_fdt_setprop_cells(vms->fdt, nodename, "interrupt-map-mask", 0x1800, 0, 0, /* devfn (PCI_SLOT(3)) */ 0x7 /* PCI irq */); } -static void create_pcie(const VirtBoardInfo *vbi, qemu_irq *pic, - bool use_highmem) +static void create_pcie(const VirtMachineState *vms, qemu_irq *pic) { - hwaddr base_mmio = vbi->memmap[VIRT_PCIE_MMIO].base; - hwaddr size_mmio = vbi->memmap[VIRT_PCIE_MMIO].size; - hwaddr base_mmio_high = vbi->memmap[VIRT_PCIE_MMIO_HIGH].base; - hwaddr size_mmio_high = vbi->memmap[VIRT_PCIE_MMIO_HIGH].size; - hwaddr base_pio = vbi->memmap[VIRT_PCIE_PIO].base; - hwaddr size_pio = vbi->memmap[VIRT_PCIE_PIO].size; - hwaddr base_ecam = vbi->memmap[VIRT_PCIE_ECAM].base; - hwaddr size_ecam = vbi->memmap[VIRT_PCIE_ECAM].size; + hwaddr base_mmio = vms->memmap[VIRT_PCIE_MMIO].base; + hwaddr size_mmio = vms->memmap[VIRT_PCIE_MMIO].size; + hwaddr base_mmio_high = vms->memmap[VIRT_PCIE_MMIO_HIGH].base; + hwaddr size_mmio_high = vms->memmap[VIRT_PCIE_MMIO_HIGH].size; + hwaddr base_pio = vms->memmap[VIRT_PCIE_PIO].base; + hwaddr size_pio = vms->memmap[VIRT_PCIE_PIO].size; + hwaddr base_ecam = vms->memmap[VIRT_PCIE_ECAM].base; + hwaddr size_ecam = vms->memmap[VIRT_PCIE_ECAM].size; hwaddr base = base_mmio; int nr_pcie_buses = size_ecam / PCIE_MMCFG_SIZE_MIN; - int irq = vbi->irqmap[VIRT_PCIE]; + int irq = vms->irqmap[VIRT_PCIE]; MemoryRegion *mmio_alias; MemoryRegion *mmio_reg; MemoryRegion *ecam_alias; @@ -1023,7 +1011,7 @@ static void create_pcie(const VirtBoardInfo *vbi, qemu_irq *pic, mmio_reg, base_mmio, size_mmio); memory_region_add_subregion(get_system_memory(), base_mmio, mmio_alias); - if (use_highmem) { + if (vms->highmem) { /* Map high MMIO space */ MemoryRegion *high_mmio_alias = g_new0(MemoryRegion, 1); @@ -1054,26 +1042,26 @@ static void create_pcie(const VirtBoardInfo *vbi, qemu_irq *pic, } nodename = g_strdup_printf("/pcie@%" PRIx64, base); - qemu_fdt_add_subnode(vbi->fdt, nodename); - qemu_fdt_setprop_string(vbi->fdt, nodename, + qemu_fdt_add_subnode(vms->fdt, nodename); + qemu_fdt_setprop_string(vms->fdt, nodename, "compatible", "pci-host-ecam-generic"); - qemu_fdt_setprop_string(vbi->fdt, nodename, "device_type", "pci"); - qemu_fdt_setprop_cell(vbi->fdt, nodename, "#address-cells", 3); - qemu_fdt_setprop_cell(vbi->fdt, nodename, "#size-cells", 2); - qemu_fdt_setprop_cells(vbi->fdt, nodename, "bus-range", 0, + qemu_fdt_setprop_string(vms->fdt, nodename, "device_type", "pci"); + qemu_fdt_setprop_cell(vms->fdt, nodename, "#address-cells", 3); + qemu_fdt_setprop_cell(vms->fdt, nodename, "#size-cells", 2); + qemu_fdt_setprop_cells(vms->fdt, nodename, "bus-range", 0, nr_pcie_buses - 1); - qemu_fdt_setprop(vbi->fdt, nodename, "dma-coherent", NULL, 0); + qemu_fdt_setprop(vms->fdt, nodename, "dma-coherent", NULL, 0); - if (vbi->msi_phandle) { - qemu_fdt_setprop_cells(vbi->fdt, nodename, "msi-parent", - vbi->msi_phandle); + if (vms->msi_phandle) { + qemu_fdt_setprop_cells(vms->fdt, nodename, "msi-parent", + vms->msi_phandle); } - qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg", + qemu_fdt_setprop_sized_cells(vms->fdt, nodename, "reg", 2, base_ecam, 2, size_ecam); - if (use_highmem) { - qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "ranges", + if (vms->highmem) { + qemu_fdt_setprop_sized_cells(vms->fdt, nodename, "ranges", 1, FDT_PCI_RANGE_IOPORT, 2, 0, 2, base_pio, 2, size_pio, 1, FDT_PCI_RANGE_MMIO, 2, base_mmio, @@ -1082,20 +1070,20 @@ static void create_pcie(const VirtBoardInfo *vbi, qemu_irq *pic, 2, base_mmio_high, 2, base_mmio_high, 2, size_mmio_high); } else { - qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "ranges", + qemu_fdt_setprop_sized_cells(vms->fdt, nodename, "ranges", 1, FDT_PCI_RANGE_IOPORT, 2, 0, 2, base_pio, 2, size_pio, 1, FDT_PCI_RANGE_MMIO, 2, base_mmio, 2, base_mmio, 2, size_mmio); } - qemu_fdt_setprop_cell(vbi->fdt, nodename, "#interrupt-cells", 1); - create_pcie_irq_map(vbi, vbi->gic_phandle, irq, nodename); + qemu_fdt_setprop_cell(vms->fdt, nodename, "#interrupt-cells", 1); + create_pcie_irq_map(vms, vms->gic_phandle, irq, nodename); g_free(nodename); } -static void create_platform_bus(VirtBoardInfo *vbi, qemu_irq *pic) +static void create_platform_bus(VirtMachineState *vms, qemu_irq *pic) { DeviceState *dev; SysBusDevice *s; @@ -1103,13 +1091,13 @@ static void create_platform_bus(VirtBoardInfo *vbi, qemu_irq *pic) ARMPlatformBusFDTParams *fdt_params = g_new(ARMPlatformBusFDTParams, 1); MemoryRegion *sysmem = get_system_memory(); - platform_bus_params.platform_bus_base = vbi->memmap[VIRT_PLATFORM_BUS].base; - platform_bus_params.platform_bus_size = vbi->memmap[VIRT_PLATFORM_BUS].size; - platform_bus_params.platform_bus_first_irq = vbi->irqmap[VIRT_PLATFORM_BUS]; + platform_bus_params.platform_bus_base = vms->memmap[VIRT_PLATFORM_BUS].base; + platform_bus_params.platform_bus_size = vms->memmap[VIRT_PLATFORM_BUS].size; + platform_bus_params.platform_bus_first_irq = vms->irqmap[VIRT_PLATFORM_BUS]; platform_bus_params.platform_bus_num_irqs = PLATFORM_BUS_NUM_IRQS; fdt_params->system_params = &platform_bus_params; - fdt_params->binfo = &vbi->bootinfo; + fdt_params->binfo = &vms->bootinfo; fdt_params->intc = "/intc"; /* * register a machine init done notifier that creates the device tree @@ -1136,43 +1124,44 @@ static void create_platform_bus(VirtBoardInfo *vbi, qemu_irq *pic) sysbus_mmio_get_region(s, 0)); } -static void create_secure_ram(VirtBoardInfo *vbi, MemoryRegion *secure_sysmem) +static void create_secure_ram(VirtMachineState *vms, + MemoryRegion *secure_sysmem) { MemoryRegion *secram = g_new(MemoryRegion, 1); char *nodename; - hwaddr base = vbi->memmap[VIRT_SECURE_MEM].base; - hwaddr size = vbi->memmap[VIRT_SECURE_MEM].size; + hwaddr base = vms->memmap[VIRT_SECURE_MEM].base; + hwaddr size = vms->memmap[VIRT_SECURE_MEM].size; memory_region_init_ram(secram, NULL, "virt.secure-ram", size, &error_fatal); vmstate_register_ram_global(secram); memory_region_add_subregion(secure_sysmem, base, secram); nodename = g_strdup_printf("/secram@%" PRIx64, base); - qemu_fdt_add_subnode(vbi->fdt, nodename); - qemu_fdt_setprop_string(vbi->fdt, nodename, "device_type", "memory"); - qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg", 2, base, 2, size); - qemu_fdt_setprop_string(vbi->fdt, nodename, "status", "disabled"); - qemu_fdt_setprop_string(vbi->fdt, nodename, "secure-status", "okay"); + qemu_fdt_add_subnode(vms->fdt, nodename); + qemu_fdt_setprop_string(vms->fdt, nodename, "device_type", "memory"); + qemu_fdt_setprop_sized_cells(vms->fdt, nodename, "reg", 2, base, 2, size); + qemu_fdt_setprop_string(vms->fdt, nodename, "status", "disabled"); + qemu_fdt_setprop_string(vms->fdt, nodename, "secure-status", "okay"); g_free(nodename); } static void *machvirt_dtb(const struct arm_boot_info *binfo, int *fdt_size) { - const VirtBoardInfo *board = (const VirtBoardInfo *)binfo; + const VirtMachineState *board = container_of(binfo, VirtMachineState, + bootinfo); *fdt_size = board->fdt_size; return board->fdt; } -static void virt_build_smbios(VirtGuestInfo *guest_info) +static void virt_build_smbios(VirtMachineState *vms) { - FWCfgState *fw_cfg = guest_info->fw_cfg; uint8_t *smbios_tables, *smbios_anchor; size_t smbios_tables_len, smbios_anchor_len; const char *product = "QEMU Virtual Machine"; - if (!fw_cfg) { + if (!vms->fw_cfg) { return; } @@ -1187,20 +1176,21 @@ static void virt_build_smbios(VirtGuestInfo *guest_info) &smbios_anchor, &smbios_anchor_len); if (smbios_anchor) { - fw_cfg_add_file(fw_cfg, "etc/smbios/smbios-tables", + fw_cfg_add_file(vms->fw_cfg, "etc/smbios/smbios-tables", smbios_tables, smbios_tables_len); - fw_cfg_add_file(fw_cfg, "etc/smbios/smbios-anchor", + fw_cfg_add_file(vms->fw_cfg, "etc/smbios/smbios-anchor", smbios_anchor, smbios_anchor_len); } } static -void virt_guest_info_machine_done(Notifier *notifier, void *data) +void virt_machine_done(Notifier *notifier, void *data) { - VirtGuestInfoState *guest_info_state = container_of(notifier, - VirtGuestInfoState, machine_done); - virt_acpi_setup(&guest_info_state->info); - virt_build_smbios(&guest_info_state->info); + VirtMachineState *vms = container_of(notifier, VirtMachineState, + machine_done); + + virt_acpi_setup(vms); + virt_build_smbios(vms); } static void machvirt_init(MachineState *machine) @@ -1210,13 +1200,9 @@ static void machvirt_init(MachineState *machine) qemu_irq pic[NUM_IRQS]; MemoryRegion *sysmem = get_system_memory(); MemoryRegion *secure_sysmem = NULL; - int gic_version = vms->gic_version; int n, virt_max_cpus; MemoryRegion *ram = g_new(MemoryRegion, 1); const char *cpu_model = machine->cpu_model; - VirtBoardInfo *vbi; - VirtGuestInfoState *guest_info_state = g_malloc0(sizeof *guest_info_state); - VirtGuestInfo *guest_info = &guest_info_state->info; char **cpustr; ObjectClass *oc; const char *typename; @@ -1232,14 +1218,14 @@ static void machvirt_init(MachineState *machine) /* We can probe only here because during property set * KVM is not available yet */ - if (!gic_version) { + if (!vms->gic_version) { if (!kvm_enabled()) { error_report("gic-version=host requires KVM"); exit(1); } - gic_version = kvm_arm_vgic_probe(); - if (!gic_version) { + vms->gic_version = kvm_arm_vgic_probe(); + if (!vms->gic_version) { error_report("Unable to determine GIC version supported by host"); exit(1); } @@ -1248,9 +1234,7 @@ static void machvirt_init(MachineState *machine) /* Separate the actual CPU model name from any appended features */ cpustr = g_strsplit(cpu_model, ",", 2); - vbi = find_machine_info(cpustr[0]); - - if (!vbi) { + if (!cpuname_valid(cpustr[0])) { error_report("mach-virt: CPU %s not supported", cpustr[0]); exit(1); } @@ -1260,15 +1244,24 @@ static void machvirt_init(MachineState *machine) * so it doesn't get in the way. Instead of starting secondary * CPUs in PSCI powerdown state we will start them all running and * let the boot ROM sort them out. - * The usual case is that we do use QEMU's PSCI implementation. + * The usual case is that we do use QEMU's PSCI implementation; + * if the guest has EL2 then we will use SMC as the conduit, + * and otherwise we will use HVC (for backwards compatibility and + * because if we're using KVM then we must use HVC). */ - vbi->using_psci = !(vms->secure && firmware_loaded); + if (vms->secure && firmware_loaded) { + vms->psci_conduit = QEMU_PSCI_CONDUIT_DISABLED; + } else if (vms->virt) { + vms->psci_conduit = QEMU_PSCI_CONDUIT_SMC; + } else { + vms->psci_conduit = QEMU_PSCI_CONDUIT_HVC; + } /* The maximum number of CPUs depends on the GIC version, or on how * many redistributors we can fit into the memory map. */ - if (gic_version == 3) { - virt_max_cpus = vbi->memmap[VIRT_GIC_REDIST].size / 0x20000; + if (vms->gic_version == 3) { + virt_max_cpus = vms->memmap[VIRT_GIC_REDIST].size / 0x20000; clustersz = GICV3_TARGETLIST_BITS; } else { virt_max_cpus = GIC_NCPU; @@ -1282,13 +1275,19 @@ static void machvirt_init(MachineState *machine) exit(1); } - vbi->smp_cpus = smp_cpus; + vms->smp_cpus = smp_cpus; - if (machine->ram_size > vbi->memmap[VIRT_MEM].size) { + if (machine->ram_size > vms->memmap[VIRT_MEM].size) { error_report("mach-virt: cannot model more than %dGB RAM", RAMLIMIT_GB); exit(1); } + if (vms->virt && kvm_enabled()) { + error_report("mach-virt: KVM does not support providing " + "Virtualization extensions to the guest CPU"); + exit(1); + } + if (vms->secure) { if (kvm_enabled()) { error_report("mach-virt: KVM does not support Security extensions"); @@ -1306,7 +1305,7 @@ static void machvirt_init(MachineState *machine) memory_region_add_subregion_overlap(secure_sysmem, 0, sysmem, -1); } - create_fdt(vbi); + create_fdt(vms); oc = cpu_class_by_name(TYPE_ARM_CPU, cpustr[0]); if (!oc) { @@ -1345,8 +1344,12 @@ static void machvirt_init(MachineState *machine) object_property_set_bool(cpuobj, false, "has_el3", NULL); } - if (vbi->using_psci) { - object_property_set_int(cpuobj, QEMU_PSCI_CONDUIT_HVC, + if (!vms->virt && object_property_find(cpuobj, "has_el2", NULL)) { + object_property_set_bool(cpuobj, false, "has_el2", NULL); + } + + if (vms->psci_conduit != QEMU_PSCI_CONDUIT_DISABLED) { + object_property_set_int(cpuobj, vms->psci_conduit, "psci-conduit", NULL); /* Secondary CPUs start in PSCI powered-down state */ @@ -1361,7 +1364,7 @@ static void machvirt_init(MachineState *machine) } if (object_property_find(cpuobj, "reset-cbar", NULL)) { - object_property_set_int(cpuobj, vbi->memmap[VIRT_CPUPERIPHS].base, + object_property_set_int(cpuobj, vms->memmap[VIRT_CPUPERIPHS].base, "reset-cbar", &error_abort); } @@ -1374,62 +1377,55 @@ static void machvirt_init(MachineState *machine) object_property_set_bool(cpuobj, true, "realized", NULL); } - fdt_add_timer_nodes(vbi, gic_version); - fdt_add_cpu_nodes(vbi); - fdt_add_psci_node(vbi); + fdt_add_timer_nodes(vms); + fdt_add_cpu_nodes(vms); + fdt_add_psci_node(vms); memory_region_allocate_system_memory(ram, NULL, "mach-virt.ram", machine->ram_size); - memory_region_add_subregion(sysmem, vbi->memmap[VIRT_MEM].base, ram); + memory_region_add_subregion(sysmem, vms->memmap[VIRT_MEM].base, ram); - create_flash(vbi, sysmem, secure_sysmem ? secure_sysmem : sysmem); + create_flash(vms, sysmem, secure_sysmem ? secure_sysmem : sysmem); - create_gic(vbi, pic, gic_version, vms->secure, vmc->no_its); + create_gic(vms, pic); - fdt_add_pmu_nodes(vbi, gic_version); + fdt_add_pmu_nodes(vms); - create_uart(vbi, pic, VIRT_UART, sysmem, serial_hds[0]); + create_uart(vms, pic, VIRT_UART, sysmem, serial_hds[0]); if (vms->secure) { - create_secure_ram(vbi, secure_sysmem); - create_uart(vbi, pic, VIRT_SECURE_UART, secure_sysmem, serial_hds[1]); + create_secure_ram(vms, secure_sysmem); + create_uart(vms, pic, VIRT_SECURE_UART, secure_sysmem, serial_hds[1]); } - create_rtc(vbi, pic); + create_rtc(vms, pic); - create_pcie(vbi, pic, vms->highmem); + create_pcie(vms, pic); - create_gpio(vbi, pic); + create_gpio(vms, pic); /* Create mmio transports, so the user can create virtio backends * (which will be automatically plugged in to the transports). If * no backend is created the transport will just sit harmlessly idle. */ - create_virtio_devices(vbi, pic); - - create_fw_cfg(vbi, &address_space_memory); - rom_set_fw(fw_cfg_find()); - - guest_info->smp_cpus = smp_cpus; - guest_info->fw_cfg = fw_cfg_find(); - guest_info->memmap = vbi->memmap; - guest_info->irqmap = vbi->irqmap; - guest_info->use_highmem = vms->highmem; - guest_info->gic_version = gic_version; - guest_info->no_its = vmc->no_its; - guest_info_state->machine_done.notify = virt_guest_info_machine_done; - qemu_add_machine_init_done_notifier(&guest_info_state->machine_done); - - vbi->bootinfo.ram_size = machine->ram_size; - vbi->bootinfo.kernel_filename = machine->kernel_filename; - vbi->bootinfo.kernel_cmdline = machine->kernel_cmdline; - vbi->bootinfo.initrd_filename = machine->initrd_filename; - vbi->bootinfo.nb_cpus = smp_cpus; - vbi->bootinfo.board_id = -1; - vbi->bootinfo.loader_start = vbi->memmap[VIRT_MEM].base; - vbi->bootinfo.get_dtb = machvirt_dtb; - vbi->bootinfo.firmware_loaded = firmware_loaded; - arm_load_kernel(ARM_CPU(first_cpu), &vbi->bootinfo); + create_virtio_devices(vms, pic); + + vms->fw_cfg = create_fw_cfg(vms, &address_space_memory); + rom_set_fw(vms->fw_cfg); + + vms->machine_done.notify = virt_machine_done; + qemu_add_machine_init_done_notifier(&vms->machine_done); + + vms->bootinfo.ram_size = machine->ram_size; + vms->bootinfo.kernel_filename = machine->kernel_filename; + vms->bootinfo.kernel_cmdline = machine->kernel_cmdline; + vms->bootinfo.initrd_filename = machine->initrd_filename; + vms->bootinfo.nb_cpus = smp_cpus; + vms->bootinfo.board_id = -1; + vms->bootinfo.loader_start = vms->memmap[VIRT_MEM].base; + vms->bootinfo.get_dtb = machvirt_dtb; + vms->bootinfo.firmware_loaded = firmware_loaded; + arm_load_kernel(ARM_CPU(first_cpu), &vms->bootinfo); /* * arm_load_kernel machine init done notifier registration must @@ -1437,7 +1433,7 @@ static void machvirt_init(MachineState *machine) * another notifier is registered which adds platform bus nodes. * Notifiers are executed in registration reverse order. */ - create_platform_bus(vbi, pic); + create_platform_bus(vms, pic); } static bool virt_get_secure(Object *obj, Error **errp) @@ -1454,6 +1450,20 @@ static void virt_set_secure(Object *obj, bool value, Error **errp) vms->secure = value; } +static bool virt_get_virt(Object *obj, Error **errp) +{ + VirtMachineState *vms = VIRT_MACHINE(obj); + + return vms->virt; +} + +static void virt_set_virt(Object *obj, bool value, Error **errp) +{ + VirtMachineState *vms = VIRT_MACHINE(obj); + + vms->virt = value; +} + static bool virt_get_highmem(Object *obj, Error **errp) { VirtMachineState *vms = VIRT_MACHINE(obj); @@ -1525,7 +1535,7 @@ static void machvirt_machine_init(void) } type_init(machvirt_machine_init); -static void virt_2_8_instance_init(Object *obj) +static void virt_2_9_instance_init(Object *obj) { VirtMachineState *vms = VIRT_MACHINE(obj); @@ -1541,6 +1551,16 @@ static void virt_2_8_instance_init(Object *obj) "Security Extensions (TrustZone)", NULL); + /* EL2 is also disabled by default, for similar reasons */ + vms->virt = false; + object_property_add_bool(obj, "virtualization", virt_get_virt, + virt_set_virt, NULL); + object_property_set_description(obj, "virtualization", + "Set on/off to enable/disable emulating a " + "guest CPU which implements the ARM " + "Virtualization Extensions", + NULL); + /* High memory is enabled by default */ vms->highmem = true; object_property_add_bool(obj, "highmem", virt_get_highmem, @@ -1556,12 +1576,36 @@ static void virt_2_8_instance_init(Object *obj) object_property_set_description(obj, "gic-version", "Set GIC version. " "Valid values are 2, 3 and host", NULL); + + vms->memmap = a15memmap; + vms->irqmap = a15irqmap; +} + +static void virt_machine_2_9_options(MachineClass *mc) +{ +} +DEFINE_VIRT_MACHINE_AS_LATEST(2, 9) + +#define VIRT_COMPAT_2_8 \ + HW_COMPAT_2_8 + +static void virt_2_8_instance_init(Object *obj) +{ + virt_2_9_instance_init(obj); } static void virt_machine_2_8_options(MachineClass *mc) { + VirtMachineClass *vmc = VIRT_MACHINE_CLASS(OBJECT_CLASS(mc)); + + virt_machine_2_9_options(mc); + SET_MACHINE_COMPAT(mc, VIRT_COMPAT_2_8); + /* For 2.8 and earlier we falsely claimed in the DT that + * our timers were edge-triggered, not level-triggered. + */ + vmc->claim_edge_triggered_timers = true; } -DEFINE_VIRT_MACHINE_AS_LATEST(2, 8) +DEFINE_VIRT_MACHINE(2, 8) #define VIRT_COMPAT_2_7 \ HW_COMPAT_2_7 diff --git a/hw/arm/xlnx-zynqmp.c b/hw/arm/xlnx-zynqmp.c index 0d86ba35ae..bc4e66b862 100644 --- a/hw/arm/xlnx-zynqmp.c +++ b/hw/arm/xlnx-zynqmp.c @@ -258,6 +258,8 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) object_property_set_bool(OBJECT(&s->apu_cpu[i]), s->secure, "has_el3", NULL); + object_property_set_bool(OBJECT(&s->apu_cpu[i]), + false, "has_el2", NULL); object_property_set_int(OBJECT(&s->apu_cpu[i]), GIC_BASE_ADDR, "reset-cbar", &error_abort); object_property_set_bool(OBJECT(&s->apu_cpu[i]), true, "realized", diff --git a/hw/arm/z2.c b/hw/arm/z2.c index 68a92f3184..1607cbdb03 100644 --- a/hw/arm/z2.c +++ b/hw/arm/z2.c @@ -220,7 +220,7 @@ static int aer915_send(I2CSlave *i2c, uint8_t data) return 0; } -static void aer915_event(I2CSlave *i2c, enum i2c_event event) +static int aer915_event(I2CSlave *i2c, enum i2c_event event) { AER915State *s = AER915(i2c); @@ -238,6 +238,8 @@ static void aer915_event(I2CSlave *i2c, enum i2c_event event) default: break; } + + return 0; } static int aer915_recv(I2CSlave *slave) @@ -263,12 +265,6 @@ static int aer915_recv(I2CSlave *slave) return retval; } -static int aer915_init(I2CSlave *i2c) -{ - /* Nothing to do. */ - return 0; -} - static VMStateDescription vmstate_aer915_state = { .name = "aer915", .version_id = 1, @@ -285,7 +281,6 @@ static void aer915_class_init(ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS(klass); I2CSlaveClass *k = I2C_SLAVE_CLASS(klass); - k->init = aer915_init; k->event = aer915_event; k->recv = aer915_recv; k->send = aer915_send; |