diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2019-03-05 17:23:25 +0000 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2019-03-05 17:23:25 +0000 |
commit | c99b58326d92034a00003c4f2e019f662c3dbee5 (patch) | |
tree | 6053513cce22b4be037227e99a16f1487e711307 /hw | |
parent | 0984a157c1c053394adbf64ed7de97f1aebe6a2d (diff) | |
parent | 566528f823d1a2e9eb2d7b2ed839547cb31bfc34 (diff) | |
download | qemu-c99b58326d92034a00003c4f2e019f662c3dbee5.zip qemu-c99b58326d92034a00003c4f2e019f662c3dbee5.tar.gz qemu-c99b58326d92034a00003c4f2e019f662c3dbee5.tar.bz2 |
Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20190305' into staging
target-arm queue:
* Fix PC test for LDM (exception return)
* Implement ARMv8.0-SB
* Implement ARMv8.0-PredInv
* Implement ARMv8.4-CondM
* Implement ARMv8.5-CondM
* Implement ARMv8.5-FRINT
* hw/arm/stellaris: Implement watchdog timer
* virt: support more than 255GB of RAM
# gpg: Signature made Tue 05 Mar 2019 16:49:47 GMT
# gpg: using RSA key E1A5C593CD419DE28E8315CF3C2525ED14360CDE
# gpg: issuer "peter.maydell@linaro.org"
# gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" [ultimate]
# gpg: aka "Peter Maydell <pmaydell@gmail.com>" [ultimate]
# gpg: aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>" [ultimate]
# Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83 15CF 3C25 25ED 1436 0CDE
* remotes/pmaydell/tags/pull-target-arm-20190305: (22 commits)
hw/arm/stellaris: Implement watchdog timer
hw/arm/virt: Bump the 255GB initial RAM limit
hw/arm/virt: Check the VCPU PA range in TCG mode
hw/arm/virt: Implement kvm_type function for 4.0 machine
hw/arm/virt: Dynamic memory map depending on RAM requirements
vl: Set machine ram_size, maxram_size and ram_slots earlier
kvm: add kvm_arm_get_max_vm_ipa_size
hw/boards: Add a MachineState parameter to kvm_type callback
hw/arm/virt: Split the memory map description
hw/arm/virt: Rename highmem IO regions
hw/arm/boot: introduce fdt_add_memory_node helper
target/arm: Implement ARMv8.5-FRINT
target/arm: Restructure handle_fp_1src_{single, double}
target/arm: Implement ARMv8.5-CondM
target/arm: Implement ARMv8.4-CondM
target/arm: Rearrange disas_data_proc_reg
target/arm: Add set/clear_pstate_bits, share gen_ss_advance
target/arm: Split helper_msr_i_pstate into 3
target/arm: Implement ARMv8.0-PredInv
target/arm: Implement ARMv8.0-SB
...
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw')
-rw-r--r-- | hw/arm/boot.c | 54 | ||||
-rw-r--r-- | hw/arm/stellaris.c | 22 | ||||
-rw-r--r-- | hw/arm/virt-acpi-build.c | 10 | ||||
-rw-r--r-- | hw/arm/virt.c | 196 | ||||
-rw-r--r-- | hw/ppc/mac_newworld.c | 3 | ||||
-rw-r--r-- | hw/ppc/mac_oldworld.c | 2 | ||||
-rw-r--r-- | hw/ppc/spapr.c | 2 | ||||
-rw-r--r-- | hw/watchdog/cmsdk-apb-watchdog.c | 74 |
8 files changed, 291 insertions, 72 deletions
diff --git a/hw/arm/boot.c b/hw/arm/boot.c index d90af2f..a830655 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/stellaris.c b/hw/arm/stellaris.c index 7b45fe3..05f8674 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" @@ -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/virt-acpi-build.c b/hw/arm/virt-acpi-build.c index 04b62c7..d7e2e48 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 99c2b6e..c7fb534 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/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c index 9846105..97e8817 100644 --- a/hw/ppc/mac_newworld.c +++ b/hw/ppc/mac_newworld.c @@ -564,8 +564,7 @@ static char *core99_fw_dev_path(FWPathProvider *p, BusState *bus, return NULL; } - -static int core99_kvm_type(const char *arg) +static int core99_kvm_type(MachineState *machine, const char *arg) { /* Always force PR KVM */ return 2; diff --git a/hw/ppc/mac_oldworld.c b/hw/ppc/mac_oldworld.c index 284431d..cc1e463 100644 --- a/hw/ppc/mac_oldworld.c +++ b/hw/ppc/mac_oldworld.c @@ -420,7 +420,7 @@ static char *heathrow_fw_dev_path(FWPathProvider *p, BusState *bus, return NULL; } -static int heathrow_kvm_type(const char *arg) +static int heathrow_kvm_type(MachineState *machine, const char *arg) { /* Always force PR KVM */ return 2; diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index b6a571b..d7850ad 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -3023,7 +3023,7 @@ static void spapr_machine_init(MachineState *machine) } } -static int spapr_kvm_type(const char *vm_type) +static int spapr_kvm_type(MachineState *machine, const char *vm_type) { if (!vm_type) { return 0; diff --git a/hw/watchdog/cmsdk-apb-watchdog.c b/hw/watchdog/cmsdk-apb-watchdog.c index eb79a73..9c865bc 100644 --- a/hw/watchdog/cmsdk-apb-watchdog.c +++ b/hw/watchdog/cmsdk-apb-watchdog.c @@ -14,6 +14,10 @@ * System Design Kit (CMSDK) and documented in the Cortex-M System * Design Kit Technical Reference Manual (ARM DDI0479C): * https://developer.arm.com/products/system-design/system-design-kits/cortex-m-system-design-kit + * + * We also support the variant of this device found in the TI + * Stellaris/Luminary boards and documented in: + * http://www.ti.com/lit/ds/symlink/lm3s6965.pdf */ #include "qemu/osdep.h" @@ -37,6 +41,7 @@ REG32(WDOGINTCLR, 0xc) REG32(WDOGRIS, 0x10) FIELD(WDOGRIS, INT, 0, 1) REG32(WDOGMIS, 0x14) +REG32(WDOGTEST, 0x418) /* only in Stellaris/Luminary version of the device */ REG32(WDOGLOCK, 0xc00) #define WDOG_UNLOCK_VALUE 0x1ACCE551 REG32(WDOGITCR, 0xf00) @@ -61,12 +66,18 @@ REG32(CID2, 0xff8) REG32(CID3, 0xffc) /* PID/CID values */ -static const int watchdog_id[] = { +static const uint32_t cmsdk_apb_watchdog_id[] = { 0x04, 0x00, 0x00, 0x00, /* PID4..PID7 */ 0x24, 0xb8, 0x1b, 0x00, /* PID0..PID3 */ 0x0d, 0xf0, 0x05, 0xb1, /* CID0..CID3 */ }; +static const uint32_t luminary_watchdog_id[] = { + 0x00, 0x00, 0x00, 0x00, /* PID4..PID7 */ + 0x05, 0x18, 0x18, 0x01, /* PID0..PID3 */ + 0x0d, 0xf0, 0x05, 0xb1, /* CID0..CID3 */ +}; + static bool cmsdk_apb_watchdog_intstatus(CMSDKAPBWatchdog *s) { /* Return masked interrupt status */ @@ -85,6 +96,10 @@ static void cmsdk_apb_watchdog_update(CMSDKAPBWatchdog *s) bool wdogres; if (s->itcr) { + /* + * Not checking that !s->is_luminary since s->itcr can't be written + * when s->is_luminary in the first place. + */ wdogint = s->itop & R_WDOGITOP_WDOGINT_MASK; wdogres = s->itop & R_WDOGITOP_WDOGRES_MASK; } else { @@ -124,19 +139,34 @@ static uint64_t cmsdk_apb_watchdog_read(void *opaque, hwaddr offset, r = s->lock; break; case A_WDOGITCR: + if (s->is_luminary) { + goto bad_offset; + } r = s->itcr; break; case A_PID4 ... A_CID3: - r = watchdog_id[(offset - A_PID4) / 4]; + r = s->id[(offset - A_PID4) / 4]; break; case A_WDOGINTCLR: case A_WDOGITOP: + if (s->is_luminary) { + goto bad_offset; + } qemu_log_mask(LOG_GUEST_ERROR, "CMSDK APB watchdog read: read of WO offset %x\n", (int)offset); r = 0; break; + case A_WDOGTEST: + if (!s->is_luminary) { + goto bad_offset; + } + qemu_log_mask(LOG_UNIMP, + "Luminary watchdog read: stall not implemented\n"); + r = 0; + break; default: +bad_offset: qemu_log_mask(LOG_GUEST_ERROR, "CMSDK APB watchdog read: bad offset %x\n", (int)offset); r = 0; @@ -170,6 +200,14 @@ static void cmsdk_apb_watchdog_write(void *opaque, hwaddr offset, ptimer_run(s->timer, 0); break; case A_WDOGCONTROL: + if (s->is_luminary && 0 != (R_WDOGCONTROL_INTEN_MASK & s->control)) { + /* + * The Luminary version of this device ignores writes to + * this register after the guest has enabled interrupts + * (so they can only be disabled again via reset). + */ + break; + } s->control = value & R_WDOGCONTROL_VALID_MASK; cmsdk_apb_watchdog_update(s); break; @@ -182,10 +220,16 @@ static void cmsdk_apb_watchdog_write(void *opaque, hwaddr offset, s->lock = (value != WDOG_UNLOCK_VALUE); break; case A_WDOGITCR: + if (s->is_luminary) { + goto bad_offset; + } s->itcr = value & R_WDOGITCR_VALID_MASK; cmsdk_apb_watchdog_update(s); break; case A_WDOGITOP: + if (s->is_luminary) { + goto bad_offset; + } s->itop = value & R_WDOGITOP_VALID_MASK; cmsdk_apb_watchdog_update(s); break; @@ -197,7 +241,15 @@ static void cmsdk_apb_watchdog_write(void *opaque, hwaddr offset, "CMSDK APB watchdog write: write to RO offset 0x%x\n", (int)offset); break; + case A_WDOGTEST: + if (!s->is_luminary) { + goto bad_offset; + } + qemu_log_mask(LOG_UNIMP, + "Luminary watchdog write: stall not implemented\n"); + break; default: +bad_offset: qemu_log_mask(LOG_GUEST_ERROR, "CMSDK APB watchdog write: bad offset 0x%x\n", (int)offset); @@ -256,6 +308,9 @@ static void cmsdk_apb_watchdog_init(Object *obj) s, "cmsdk-apb-watchdog", 0x1000); sysbus_init_mmio(sbd, &s->iomem); sysbus_init_irq(sbd, &s->wdogint); + + s->is_luminary = false; + s->id = cmsdk_apb_watchdog_id; } static void cmsdk_apb_watchdog_realize(DeviceState *dev, Error **errp) @@ -318,9 +373,24 @@ static const TypeInfo cmsdk_apb_watchdog_info = { .class_init = cmsdk_apb_watchdog_class_init, }; +static void luminary_watchdog_init(Object *obj) +{ + CMSDKAPBWatchdog *s = CMSDK_APB_WATCHDOG(obj); + + s->is_luminary = true; + s->id = luminary_watchdog_id; +} + +static const TypeInfo luminary_watchdog_info = { + .name = TYPE_LUMINARY_WATCHDOG, + .parent = TYPE_CMSDK_APB_WATCHDOG, + .instance_init = luminary_watchdog_init +}; + static void cmsdk_apb_watchdog_register_types(void) { type_register_static(&cmsdk_apb_watchdog_info); + type_register_static(&luminary_watchdog_info); } type_init(cmsdk_apb_watchdog_register_types); |