diff options
Diffstat (limited to 'hw/arm')
-rw-r--r-- | hw/arm/armsse.c | 87 | ||||
-rw-r--r-- | hw/arm/aspeed.c | 2 | ||||
-rw-r--r-- | hw/arm/boot.c | 54 | ||||
-rw-r--r-- | hw/arm/pxa2xx.c | 2 | ||||
-rw-r--r-- | hw/arm/stellaris.c | 24 | ||||
-rw-r--r-- | hw/arm/tosa.c | 4 | ||||
-rw-r--r-- | hw/arm/virt-acpi-build.c | 10 | ||||
-rw-r--r-- | hw/arm/virt.c | 196 | ||||
-rw-r--r-- | hw/arm/z2.c | 2 |
9 files changed, 283 insertions, 98 deletions
diff --git a/hw/arm/armsse.c b/hw/arm/armsse.c index 129e7ea7fe..76cc690579 100644 --- a/hw/arm/armsse.c +++ b/hw/arm/armsse.c @@ -11,6 +11,7 @@ #include "qemu/osdep.h" #include "qemu/log.h" +#include "qemu/bitops.h" #include "qapi/error.h" #include "trace.h" #include "hw/sysbus.h" @@ -29,6 +30,7 @@ struct ARMSSEInfo { int sram_banks; int num_cpus; uint32_t sys_version; + uint32_t cpuwait_rst; SysConfigFormat sys_config_format; bool has_mhus; bool has_ppus; @@ -43,6 +45,7 @@ static const ARMSSEInfo armsse_variants[] = { .sram_banks = 1, .num_cpus = 1, .sys_version = 0x41743, + .cpuwait_rst = 0, .sys_config_format = IoTKitFormat, .has_mhus = false, .has_ppus = false, @@ -55,6 +58,7 @@ static const ARMSSEInfo armsse_variants[] = { .sram_banks = 4, .num_cpus = 2, .sys_version = 0x22041743, + .cpuwait_rst = 2, .sys_config_format = SSE200Format, .has_mhus = true, .has_ppus = true, @@ -282,9 +286,9 @@ static void armsse_init(Object *obj) sizeof(s->sysinfo), TYPE_IOTKIT_SYSINFO); if (info->has_mhus) { sysbus_init_child_obj(obj, "mhu0", &s->mhu[0], sizeof(s->mhu[0]), - TYPE_UNIMPLEMENTED_DEVICE); + TYPE_ARMSSE_MHU); sysbus_init_child_obj(obj, "mhu1", &s->mhu[1], sizeof(s->mhu[1]), - TYPE_UNIMPLEMENTED_DEVICE); + TYPE_ARMSSE_MHU); } if (info->has_ppus) { for (i = 0; i < info->num_cpus; i++) { @@ -495,30 +499,33 @@ static void armsse_realize(DeviceState *dev, Error **errp) qdev_prop_set_uint32(cpudev, "num-irq", s->exp_numirq + 32); /* - * In real hardware the initial Secure VTOR is set from the INITSVTOR0 - * register in the IoT Kit System Control Register block, and the - * initial value of that is in turn specifiable by the FPGA that - * instantiates the IoT Kit. In QEMU we don't implement this wrinkle, - * and simply set the CPU's init-svtor to the IoT Kit default value. - * In SSE-200 the situation is similar, except that the default value - * is a reset-time signal input. Typically a board using the SSE-200 - * will have a system control processor whose boot firmware initializes - * the INITSVTOR* registers before powering up the CPUs in any case, - * so the hardware's default value doesn't matter. QEMU doesn't emulate + * In real hardware the initial Secure VTOR is set from the INITSVTOR* + * registers in the IoT Kit System Control Register block. In QEMU + * we set the initial value here, and also the reset value of the + * sysctl register, from this object's QOM init-svtor property. + * If the guest changes the INITSVTOR* registers at runtime then the + * code in iotkit-sysctl.c will update the CPU init-svtor property + * (which will then take effect on the next CPU warm-reset). + * + * Note that typically a board using the SSE-200 will have a system + * control processor whose boot firmware initializes the INITSVTOR* + * registers before powering up the CPUs. QEMU doesn't emulate * the control processor, so instead we behave in the way that the - * firmware does. The initial value is configurable by the board code - * to match whatever its firmware does. + * firmware does: the initial value should be set by the board code + * (using the init-svtor property on the ARMSSE object) to match + * whatever its firmware does. */ qdev_prop_set_uint32(cpudev, "init-svtor", s->init_svtor); /* - * Start all CPUs except CPU0 powered down. In real hardware it is - * a configurable property of the SSE-200 which CPUs start powered up - * (via the CPUWAIT0_RST and CPUWAIT1_RST parameters), but since all - * the boards we care about start CPU0 and leave CPU1 powered off, - * we hard-code that for now. We can add QOM properties for this + * CPUs start powered down if the corresponding bit in the CPUWAIT + * register is 1. In real hardware the CPUWAIT register reset value is + * a configurable property of the SSE-200 (via the CPUWAIT0_RST and + * CPUWAIT1_RST parameters), but since all the boards we care about + * start CPU0 and leave CPU1 powered off, we hard-code that in + * info->cpuwait_rst for now. We can add QOM properties for this * later if necessary. */ - if (i > 0) { + if (extract32(info->cpuwait_rst, i, 1)) { object_property_set_bool(cpuobj, true, "start-powered-off", &err); if (err) { error_propagate(errp, err); @@ -766,22 +773,28 @@ static void armsse_realize(DeviceState *dev, Error **errp) } if (info->has_mhus) { + /* + * An SSE-200 with only one CPU should have only one MHU created, + * with the region where the second MHU usually is being RAZ/WI. + * We don't implement that SSE-200 config; if we want to support + * it then this code needs to be enhanced to handle creating the + * RAZ/WI region instead of the second MHU. + */ + assert(info->num_cpus == ARRAY_SIZE(s->mhu)); + for (i = 0; i < ARRAY_SIZE(s->mhu); i++) { - char *name; char *port; + int cpunum; + SysBusDevice *mhu_sbd = SYS_BUS_DEVICE(&s->mhu[i]); - name = g_strdup_printf("MHU%d", i); - qdev_prop_set_string(DEVICE(&s->mhu[i]), "name", name); - qdev_prop_set_uint64(DEVICE(&s->mhu[i]), "size", 0x1000); object_property_set_bool(OBJECT(&s->mhu[i]), true, "realized", &err); - g_free(name); if (err) { error_propagate(errp, err); return; } port = g_strdup_printf("port[%d]", i + 3); - mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->mhu[i]), 0); + mr = sysbus_mmio_get_region(mhu_sbd, 0); object_property_set_link(OBJECT(&s->apb_ppc0), OBJECT(mr), port, &err); g_free(port); @@ -789,6 +802,20 @@ static void armsse_realize(DeviceState *dev, Error **errp) error_propagate(errp, err); return; } + + /* + * Each MHU has an irq line for each CPU: + * MHU 0 irq line 0 -> CPU 0 IRQ 6 + * MHU 0 irq line 1 -> CPU 1 IRQ 6 + * MHU 1 irq line 0 -> CPU 0 IRQ 7 + * MHU 1 irq line 1 -> CPU 1 IRQ 7 + */ + for (cpunum = 0; cpunum < info->num_cpus; cpunum++) { + DeviceState *cpudev = DEVICE(&s->armv7m[cpunum]); + + sysbus_connect_irq(mhu_sbd, cpunum, + qdev_get_gpio_in(cpudev, 6 + i)); + } } } @@ -977,6 +1004,14 @@ static void armsse_realize(DeviceState *dev, Error **errp) /* System information registers */ sysbus_mmio_map(SYS_BUS_DEVICE(&s->sysinfo), 0, 0x40020000); /* System control registers */ + object_property_set_int(OBJECT(&s->sysctl), info->sys_version, + "SYS_VERSION", &err); + object_property_set_int(OBJECT(&s->sysctl), info->cpuwait_rst, + "CPUWAIT_RST", &err); + object_property_set_int(OBJECT(&s->sysctl), s->init_svtor, + "INITSVTOR0_RST", &err); + object_property_set_int(OBJECT(&s->sysctl), s->init_svtor, + "INITSVTOR1_RST", &err); object_property_set_bool(OBJECT(&s->sysctl), true, "realized", &err); if (err) { error_propagate(errp, err); diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index 5158985482..996812498d 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -18,7 +18,7 @@ #include "hw/arm/aspeed.h" #include "hw/arm/aspeed_soc.h" #include "hw/boards.h" -#include "hw/i2c/smbus.h" +#include "hw/i2c/smbus_eeprom.h" #include "qemu/log.h" #include "sysemu/block-backend.h" #include "hw/loader.h" diff --git a/hw/arm/boot.c b/hw/arm/boot.c index d90af2f17d..a830655e1a 100644 --- a/hw/arm/boot.c +++ b/hw/arm/boot.c @@ -423,6 +423,32 @@ static void set_kernel_args_old(const struct arm_boot_info *info, } } +static int fdt_add_memory_node(void *fdt, uint32_t acells, hwaddr mem_base, + uint32_t scells, hwaddr mem_len, + int numa_node_id) +{ + char *nodename; + int ret; + + nodename = g_strdup_printf("/memory@%" PRIx64, mem_base); + qemu_fdt_add_subnode(fdt, nodename); + qemu_fdt_setprop_string(fdt, nodename, "device_type", "memory"); + ret = qemu_fdt_setprop_sized_cells(fdt, nodename, "reg", acells, mem_base, + scells, mem_len); + if (ret < 0) { + goto out; + } + + /* only set the NUMA ID if it is specified */ + if (numa_node_id >= 0) { + ret = qemu_fdt_setprop_cell(fdt, nodename, + "numa-node-id", numa_node_id); + } +out: + g_free(nodename); + return ret; +} + static void fdt_add_psci_node(void *fdt) { uint32_t cpu_suspend_fn; @@ -502,7 +528,6 @@ int arm_load_dtb(hwaddr addr, const struct arm_boot_info *binfo, void *fdt = NULL; int size, rc, n = 0; uint32_t acells, scells; - char *nodename; unsigned int i; hwaddr mem_base, mem_len; char **node_path; @@ -576,35 +601,24 @@ int arm_load_dtb(hwaddr addr, const struct arm_boot_info *binfo, mem_base = binfo->loader_start; for (i = 0; i < nb_numa_nodes; i++) { mem_len = numa_info[i].node_mem; - nodename = g_strdup_printf("/memory@%" PRIx64, mem_base); - qemu_fdt_add_subnode(fdt, nodename); - qemu_fdt_setprop_string(fdt, nodename, "device_type", "memory"); - rc = qemu_fdt_setprop_sized_cells(fdt, nodename, "reg", - acells, mem_base, - scells, mem_len); + rc = fdt_add_memory_node(fdt, acells, mem_base, + scells, mem_len, i); if (rc < 0) { - fprintf(stderr, "couldn't set %s/reg for node %d\n", nodename, - i); + fprintf(stderr, "couldn't add /memory@%"PRIx64" node\n", + mem_base); goto fail; } - qemu_fdt_setprop_cell(fdt, nodename, "numa-node-id", i); mem_base += mem_len; - g_free(nodename); } } else { - nodename = g_strdup_printf("/memory@%" PRIx64, binfo->loader_start); - qemu_fdt_add_subnode(fdt, nodename); - qemu_fdt_setprop_string(fdt, nodename, "device_type", "memory"); - - rc = qemu_fdt_setprop_sized_cells(fdt, nodename, "reg", - acells, binfo->loader_start, - scells, binfo->ram_size); + rc = fdt_add_memory_node(fdt, acells, binfo->loader_start, + scells, binfo->ram_size, -1); if (rc < 0) { - fprintf(stderr, "couldn't set %s reg\n", nodename); + fprintf(stderr, "couldn't add /memory@%"PRIx64" node\n", + binfo->loader_start); goto fail; } - g_free(nodename); } rc = fdt_path_offset(fdt, "/chosen"); diff --git a/hw/arm/pxa2xx.c b/hw/arm/pxa2xx.c index f598a1c053..3d7c88910e 100644 --- a/hw/arm/pxa2xx.c +++ b/hw/arm/pxa2xx.c @@ -1286,7 +1286,7 @@ static int pxa2xx_i2c_event(I2CSlave *i2c, enum i2c_event event) return 0; } -static int pxa2xx_i2c_rx(I2CSlave *i2c) +static uint8_t pxa2xx_i2c_rx(I2CSlave *i2c) { PXA2xxI2CSlaveState *slave = PXA2XX_I2C_SLAVE(i2c); PXA2xxI2CState *s = slave->host; diff --git a/hw/arm/stellaris.c b/hw/arm/stellaris.c index 442529cc65..05f86749f4 100644 --- a/hw/arm/stellaris.c +++ b/hw/arm/stellaris.c @@ -22,6 +22,7 @@ #include "sysemu/sysemu.h" #include "hw/arm/armv7m.h" #include "hw/char/pl011.h" +#include "hw/watchdog/cmsdk-apb-watchdog.h" #include "hw/misc/unimp.h" #include "cpu.h" @@ -811,7 +812,7 @@ static void stellaris_i2c_write(void *opaque, hwaddr offset, /* TODO: Handle errors. */ if (s->msa & 1) { /* Recv */ - s->mdr = i2c_recv(s->bus) & 0xff; + s->mdr = i2c_recv(s->bus); } else { /* Send */ i2c_send(s->bus, s->mdr); @@ -1243,7 +1244,7 @@ static void stellaris_init(MachineState *ms, stellaris_board_info *board) * Stellaris LM3S6965 Microcontroller Data Sheet (rev I) * http://www.ti.com/lit/ds/symlink/lm3s6965.pdf * - * 40000000 wdtimer (unimplemented) + * 40000000 wdtimer * 40002000 i2c (unimplemented) * 40004000 GPIO * 40005000 GPIO @@ -1338,6 +1339,24 @@ static void stellaris_init(MachineState *ms, stellaris_board_info *board) stellaris_sys_init(0x400fe000, qdev_get_gpio_in(nvic, 28), board, nd_table[0].macaddr.a); + + if (board->dc1 & (1 << 3)) { /* watchdog present */ + dev = qdev_create(NULL, TYPE_LUMINARY_WATCHDOG); + + /* system_clock_scale is valid now */ + uint32_t mainclk = NANOSECONDS_PER_SECOND / system_clock_scale; + qdev_prop_set_uint32(dev, "wdogclk-frq", mainclk); + + qdev_init_nofail(dev); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), + 0, + 0x40000000u); + sysbus_connect_irq(SYS_BUS_DEVICE(dev), + 0, + qdev_get_gpio_in(nvic, 18)); + } + + for (i = 0; i < 7; i++) { if (board->dc4 & (1 << i)) { gpio_dev[i] = sysbus_create_simple("pl061_luminary", gpio_addr[i], @@ -1431,7 +1450,6 @@ static void stellaris_init(MachineState *ms, stellaris_board_info *board) /* Add dummy regions for the devices we don't implement yet, * so guest accesses don't cause unlogged crashes. */ - create_unimplemented_device("wdtimer", 0x40000000, 0x1000); create_unimplemented_device("i2c-0", 0x40002000, 0x1000); create_unimplemented_device("i2c-2", 0x40021000, 0x1000); create_unimplemented_device("PWM", 0x40028000, 0x1000); diff --git a/hw/arm/tosa.c b/hw/arm/tosa.c index 7a925fa5e6..eef9d427e7 100644 --- a/hw/arm/tosa.c +++ b/hw/arm/tosa.c @@ -197,10 +197,10 @@ static int tosa_dac_event(I2CSlave *i2c, enum i2c_event event) return 0; } -static int tosa_dac_recv(I2CSlave *s) +static uint8_t tosa_dac_recv(I2CSlave *s) { printf("%s: recv not supported!!!\n", __func__); - return -1; + return 0xff; } static void tosa_tg_init(PXA2xxState *cpu) diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c index 04b62c714d..d7e2e4885b 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c @@ -229,8 +229,8 @@ static void acpi_dsdt_add_pci(Aml *scope, const MemMapEntry *memmap, size_pio)); if (use_highmem) { - hwaddr base_mmio_high = memmap[VIRT_PCIE_MMIO_HIGH].base; - hwaddr size_mmio_high = memmap[VIRT_PCIE_MMIO_HIGH].size; + hwaddr base_mmio_high = memmap[VIRT_HIGH_PCIE_MMIO].base; + hwaddr size_mmio_high = memmap[VIRT_HIGH_PCIE_MMIO].size; aml_append(rbuf, aml_qword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED, @@ -663,8 +663,10 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) gicr = acpi_data_push(table_data, sizeof(*gicr)); gicr->type = ACPI_APIC_GENERIC_REDISTRIBUTOR; gicr->length = sizeof(*gicr); - gicr->base_address = cpu_to_le64(memmap[VIRT_GIC_REDIST2].base); - gicr->range_length = cpu_to_le32(memmap[VIRT_GIC_REDIST2].size); + gicr->base_address = + cpu_to_le64(memmap[VIRT_HIGH_GIC_REDIST2].base); + gicr->range_length = + cpu_to_le32(memmap[VIRT_HIGH_GIC_REDIST2].size); } if (its_class_name() && !vmc->no_its) { diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 99c2b6e60d..c7fb5348ae 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -29,6 +29,7 @@ */ #include "qemu/osdep.h" +#include "qemu/units.h" #include "qapi/error.h" #include "hw/sysbus.h" #include "hw/arm/arm.h" @@ -58,6 +59,8 @@ #include "qapi/visitor.h" #include "standard-headers/linux/input.h" #include "hw/arm/smmuv3.h" +#include "hw/acpi/acpi.h" +#include "target/arm/internals.h" #define DEFINE_VIRT_MACHINE_LATEST(major, minor, latest) \ static void virt_##major##_##minor##_class_init(ObjectClass *oc, \ @@ -92,22 +95,9 @@ #define PLATFORM_BUS_NUM_IRQS 64 -/* 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. - * If we need to provide more RAM to VMs in the future then we need to: - * * allocate a second bank of RAM starting at 2TB and working up - * * fix the DT and ACPI table generation code in QEMU to correctly - * report two split lumps of RAM to the guest - * * fix KVM in the host kernel to allow guests with >40 bit address spaces - * (We don't want to fill all the way up to 512GB with RAM because - * we might want it for non-RAM purposes later. Conversely it seems - * reasonable to assume that anybody configuring a VM with a quarter - * of a terabyte of RAM will be doing it on a host with more than a - * terabyte of physical address space.) - */ -#define RAMLIMIT_GB 255 -#define RAMLIMIT_BYTES (RAMLIMIT_GB * 1024ULL * 1024 * 1024) +/* Legacy RAM limit in GB (< version 4.0) */ +#define LEGACY_RAMLIMIT_GB 255 +#define LEGACY_RAMLIMIT_BYTES (LEGACY_RAMLIMIT_GB * GiB) /* Addresses and sizes of our components. * 0..128MB is space for a flash device so we can run bootrom code such as UEFI. @@ -121,7 +111,7 @@ * Note that devices should generally be placed at multiples of 0x10000, * to accommodate guests using 64K pages. */ -static const MemMapEntry a15memmap[] = { +static const MemMapEntry base_memmap[] = { /* Space up to 0x8000000 is reserved for a boot ROM */ [VIRT_FLASH] = { 0, 0x08000000 }, [VIRT_CPUPERIPHS] = { 0x08000000, 0x00020000 }, @@ -148,12 +138,26 @@ static const MemMapEntry a15memmap[] = { [VIRT_PCIE_MMIO] = { 0x10000000, 0x2eff0000 }, [VIRT_PCIE_PIO] = { 0x3eff0000, 0x00010000 }, [VIRT_PCIE_ECAM] = { 0x3f000000, 0x01000000 }, - [VIRT_MEM] = { 0x40000000, RAMLIMIT_BYTES }, + /* Actual RAM size depends on initial RAM and device memory settings */ + [VIRT_MEM] = { GiB, LEGACY_RAMLIMIT_BYTES }, +}; + +/* + * Highmem IO Regions: This memory map is floating, located after the RAM. + * Each MemMapEntry base (GPA) will be dynamically computed, depending on the + * top of the RAM, so that its base get the same alignment as the size, + * ie. a 512GiB entry will be aligned on a 512GiB boundary. If there is + * less than 256GiB of RAM, the floating area starts at the 256GiB mark. + * Note the extended_memmap is sized so that it eventually also includes the + * base_memmap entries (VIRT_HIGH_GIC_REDIST2 index is greater than the last + * index of base_memmap). + */ +static MemMapEntry extended_memmap[] = { /* Additional 64 MB redist region (can contain up to 512 redistributors) */ - [VIRT_GIC_REDIST2] = { 0x4000000000ULL, 0x4000000 }, - [VIRT_PCIE_ECAM_HIGH] = { 0x4010000000ULL, 0x10000000 }, - /* Second PCIe window, 512GB wide at the 512GB boundary */ - [VIRT_PCIE_MMIO_HIGH] = { 0x8000000000ULL, 0x8000000000ULL }, + [VIRT_HIGH_GIC_REDIST2] = { 0x0, 64 * MiB }, + [VIRT_HIGH_PCIE_ECAM] = { 0x0, 256 * MiB }, + /* Second PCIe window */ + [VIRT_HIGH_PCIE_MMIO] = { 0x0, 512 * GiB }, }; static const int a15irqmap[] = { @@ -431,12 +435,12 @@ static void fdt_add_gic_node(VirtMachineState *vms) 2, vms->memmap[VIRT_GIC_REDIST].size); } else { qemu_fdt_setprop_sized_cells(vms->fdt, nodename, "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, - 2, vms->memmap[VIRT_GIC_REDIST2].base, - 2, vms->memmap[VIRT_GIC_REDIST2].size); + 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, + 2, vms->memmap[VIRT_HIGH_GIC_REDIST2].base, + 2, vms->memmap[VIRT_HIGH_GIC_REDIST2].size); } if (vms->virt) { @@ -584,7 +588,7 @@ static void create_gic(VirtMachineState *vms, qemu_irq *pic) if (nb_redist_regions == 2) { uint32_t redist1_capacity = - vms->memmap[VIRT_GIC_REDIST2].size / GICV3_REDIST_SIZE; + vms->memmap[VIRT_HIGH_GIC_REDIST2].size / GICV3_REDIST_SIZE; qdev_prop_set_uint32(gicdev, "redist-region-count[1]", MIN(smp_cpus - redist0_count, redist1_capacity)); @@ -601,7 +605,8 @@ static void create_gic(VirtMachineState *vms, qemu_irq *pic) if (type == 3) { sysbus_mmio_map(gicbusdev, 1, vms->memmap[VIRT_GIC_REDIST].base); if (nb_redist_regions == 2) { - sysbus_mmio_map(gicbusdev, 2, vms->memmap[VIRT_GIC_REDIST2].base); + sysbus_mmio_map(gicbusdev, 2, + vms->memmap[VIRT_HIGH_GIC_REDIST2].base); } } else { sysbus_mmio_map(gicbusdev, 1, vms->memmap[VIRT_GIC_CPU].base); @@ -1088,8 +1093,8 @@ static void create_pcie(VirtMachineState *vms, qemu_irq *pic) { 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_mmio_high = vms->memmap[VIRT_HIGH_PCIE_MMIO].base; + hwaddr size_mmio_high = vms->memmap[VIRT_HIGH_PCIE_MMIO].size; hwaddr base_pio = vms->memmap[VIRT_PCIE_PIO].base; hwaddr size_pio = vms->memmap[VIRT_PCIE_PIO].size; hwaddr base_ecam, size_ecam; @@ -1353,6 +1358,62 @@ static uint64_t virt_cpu_mp_affinity(VirtMachineState *vms, int idx) return arm_cpu_mp_affinity(idx, clustersz); } +static void virt_set_memmap(VirtMachineState *vms) +{ + MachineState *ms = MACHINE(vms); + hwaddr base, device_memory_base, device_memory_size; + int i; + + vms->memmap = extended_memmap; + + for (i = 0; i < ARRAY_SIZE(base_memmap); i++) { + vms->memmap[i] = base_memmap[i]; + } + + if (ms->ram_slots > ACPI_MAX_RAM_SLOTS) { + error_report("unsupported number of memory slots: %"PRIu64, + ms->ram_slots); + exit(EXIT_FAILURE); + } + + /* + * We compute the base of the high IO region depending on the + * amount of initial and device memory. The device memory start/size + * is aligned on 1GiB. We never put the high IO region below 256GiB + * so that if maxram_size is < 255GiB we keep the legacy memory map. + * The device region size assumes 1GiB page max alignment per slot. + */ + device_memory_base = + ROUND_UP(vms->memmap[VIRT_MEM].base + ms->ram_size, GiB); + device_memory_size = ms->maxram_size - ms->ram_size + ms->ram_slots * GiB; + + /* Base address of the high IO region */ + base = device_memory_base + ROUND_UP(device_memory_size, GiB); + if (base < device_memory_base) { + error_report("maxmem/slots too huge"); + exit(EXIT_FAILURE); + } + if (base < vms->memmap[VIRT_MEM].base + LEGACY_RAMLIMIT_BYTES) { + base = vms->memmap[VIRT_MEM].base + LEGACY_RAMLIMIT_BYTES; + } + + for (i = VIRT_LOWMEMMAP_LAST; i < ARRAY_SIZE(extended_memmap); i++) { + hwaddr size = extended_memmap[i].size; + + base = ROUND_UP(base, size); + vms->memmap[i].base = base; + vms->memmap[i].size = size; + base += size; + } + vms->highest_gpa = base - 1; + if (device_memory_size > 0) { + ms->device_memory = g_malloc0(sizeof(*ms->device_memory)); + ms->device_memory->base = device_memory_base; + memory_region_init(&ms->device_memory->mr, OBJECT(vms), + "device-memory", device_memory_size); + } +} + static void machvirt_init(MachineState *machine) { VirtMachineState *vms = VIRT_MACHINE(machine); @@ -1367,6 +1428,14 @@ static void machvirt_init(MachineState *machine) bool firmware_loaded = bios_name || drive_get(IF_PFLASH, 0, 0); bool aarch64 = true; + /* + * In accelerated mode, the memory map is computed earlier in kvm_type() + * to create a VM with the right number of IPA bits. + */ + if (!vms->memmap) { + virt_set_memmap(vms); + } + /* We can probe only here because during property set * KVM is not available yet */ @@ -1417,8 +1486,10 @@ static void machvirt_init(MachineState *machine) * many redistributors we can fit into the memory map. */ if (vms->gic_version == 3) { - virt_max_cpus = vms->memmap[VIRT_GIC_REDIST].size / GICV3_REDIST_SIZE; - virt_max_cpus += vms->memmap[VIRT_GIC_REDIST2].size / GICV3_REDIST_SIZE; + virt_max_cpus = + vms->memmap[VIRT_GIC_REDIST].size / GICV3_REDIST_SIZE; + virt_max_cpus += + vms->memmap[VIRT_HIGH_GIC_REDIST2].size / GICV3_REDIST_SIZE; } else { virt_max_cpus = GIC_NCPU; } @@ -1432,11 +1503,6 @@ static void machvirt_init(MachineState *machine) vms->smp_cpus = smp_cpus; - 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"); @@ -1524,9 +1590,29 @@ static void machvirt_init(MachineState *machine) fdt_add_timer_nodes(vms); fdt_add_cpu_nodes(vms); + if (!kvm_enabled()) { + ARMCPU *cpu = ARM_CPU(first_cpu); + bool aarch64 = object_property_get_bool(OBJECT(cpu), "aarch64", NULL); + + if (aarch64 && vms->highmem) { + int requested_pa_size, pamax = arm_pamax(cpu); + + requested_pa_size = 64 - clz64(vms->highest_gpa); + if (pamax < requested_pa_size) { + error_report("VCPU supports less PA bits (%d) than requested " + "by the memory map (%d)", pamax, requested_pa_size); + exit(1); + } + } + } + memory_region_allocate_system_memory(ram, NULL, "mach-virt.ram", machine->ram_size); memory_region_add_subregion(sysmem, vms->memmap[VIRT_MEM].base, ram); + if (machine->device_memory) { + memory_region_add_subregion(sysmem, machine->device_memory->base, + &machine->device_memory->mr); + } create_flash(vms, sysmem, secure_sysmem ? secure_sysmem : sysmem); @@ -1747,6 +1833,36 @@ static HotplugHandler *virt_machine_get_hotplug_handler(MachineState *machine, return NULL; } +/* + * for arm64 kvm_type [7-0] encodes the requested number of bits + * in the IPA address space + */ +static int virt_kvm_type(MachineState *ms, const char *type_str) +{ + VirtMachineState *vms = VIRT_MACHINE(ms); + int max_vm_pa_size = kvm_arm_get_max_vm_ipa_size(ms); + int requested_pa_size; + + /* we freeze the memory map to compute the highest gpa */ + virt_set_memmap(vms); + + requested_pa_size = 64 - clz64(vms->highest_gpa); + + if (requested_pa_size > max_vm_pa_size) { + error_report("-m and ,maxmem option values " + "require an IPA range (%d bits) larger than " + "the one supported by the host (%d bits)", + requested_pa_size, max_vm_pa_size); + exit(1); + } + /* + * By default we return 0 which corresponds to an implicit legacy + * 40b IPA setting. Otherwise we return the actual requested PA + * logsize + */ + return requested_pa_size > 40 ? requested_pa_size : 0; +} + static void virt_machine_class_init(ObjectClass *oc, void *data) { MachineClass *mc = MACHINE_CLASS(oc); @@ -1771,6 +1887,7 @@ static void virt_machine_class_init(ObjectClass *oc, void *data) mc->cpu_index_to_instance_props = virt_cpu_index_to_props; mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-a15"); mc->get_default_cpu_node_id = virt_get_default_cpu_node_id; + mc->kvm_type = virt_kvm_type; assert(!mc->get_hotplug_handler); mc->get_hotplug_handler = virt_machine_get_hotplug_handler; hc->plug = virt_machine_device_plug_cb; @@ -1842,7 +1959,6 @@ static void virt_instance_init(Object *obj) "Valid values are none and smmuv3", NULL); - vms->memmap = a15memmap; vms->irqmap = a15irqmap; } diff --git a/hw/arm/z2.c b/hw/arm/z2.c index 697a822f1e..6f18d924df 100644 --- a/hw/arm/z2.c +++ b/hw/arm/z2.c @@ -243,7 +243,7 @@ static int aer915_event(I2CSlave *i2c, enum i2c_event event) return 0; } -static int aer915_recv(I2CSlave *slave) +static uint8_t aer915_recv(I2CSlave *slave) { AER915State *s = AER915(slave); int retval = 0x00; |