*/
#include "qemu/osdep.h"
+#include "qemu/units.h"
#include "qapi/error.h"
#include "hw/sysbus.h"
#include "hw/arm/arm.h"
#include "hw/arm/primecell.h"
#include "hw/arm/virt.h"
+#include "hw/block/flash.h"
#include "hw/vfio/vfio-calxeda-xgmac.h"
#include "hw/vfio/vfio-amd-xgbe.h"
#include "hw/display/ramfb.h"
-#include "hw/devices.h"
#include "net/net.h"
#include "sysemu/device_tree.h"
#include "sysemu/numa.h"
#include "sysemu/sysemu.h"
#include "sysemu/kvm.h"
-#include "hw/compat.h"
#include "hw/loader.h"
#include "exec/address-spaces.h"
#include "qemu/bitops.h"
#include "hw/intc/arm_gic.h"
#include "hw/intc/arm_gicv3_common.h"
#include "kvm_arm.h"
-#include "hw/smbios/smbios.h"
+#include "hw/firmware/smbios.h"
#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, \
static const TypeInfo machvirt_##major##_##minor##_info = { \
.name = MACHINE_TYPE_NAME("virt-" # major "." # minor), \
.parent = TYPE_VIRT_MACHINE, \
- .instance_init = virt_##major##_##minor##_instance_init, \
.class_init = virt_##major##_##minor##_class_init, \
}; \
static void machvirt_machine_##major##_##minor##_init(void) \
#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.
* 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 },
[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[] = {
ARM_CPU_TYPE_NAME("cortex-a15"),
ARM_CPU_TYPE_NAME("cortex-a53"),
ARM_CPU_TYPE_NAME("cortex-a57"),
+ ARM_CPU_TYPE_NAME("cortex-a72"),
ARM_CPU_TYPE_NAME("host"),
ARM_CPU_TYPE_NAME("max"),
};
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) {
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));
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);
/* Mark as not usable by the normal world */
qemu_fdt_setprop_string(vms->fdt, nodename, "status", "disabled");
qemu_fdt_setprop_string(vms->fdt, nodename, "secure-status", "okay");
+
+ qemu_fdt_add_subnode(vms->fdt, "/secure-chosen");
+ qemu_fdt_setprop_string(vms->fdt, "/secure-chosen", "stdout-path",
+ nodename);
}
g_free(nodename);
* parameters as the flash devices on the Versatile Express board.
*/
DriveInfo *dinfo = drive_get_next(IF_PFLASH);
- DeviceState *dev = qdev_create(NULL, "cfi.pflash01");
+ DeviceState *dev = qdev_create(NULL, TYPE_PFLASH_CFI01);
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
const uint64_t sectorlength = 256 * 1024;
{
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;
size_t smbios_tables_len, smbios_anchor_len;
const char *product = "QEMU Virtual Machine";
- if (!vms->fw_cfg) {
- return;
- }
-
if (kvm_enabled()) {
product = "KVM Virtual Machine";
}
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);
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
*/
* 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;
}
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");
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);
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);
machine_class_allow_dynamic_sysbus_dev(mc, TYPE_VFIO_CALXEDA_XGMAC);
machine_class_allow_dynamic_sysbus_dev(mc, TYPE_VFIO_AMD_XGBE);
machine_class_allow_dynamic_sysbus_dev(mc, TYPE_RAMFB_DEVICE);
+ machine_class_allow_dynamic_sysbus_dev(mc, TYPE_VFIO_PLATFORM);
mc->block_default_type = IF_VIRTIO;
mc->no_cdrom = 1;
mc->pci_allow_0_address = true;
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;
}
-static const TypeInfo virt_machine_info = {
- .name = TYPE_VIRT_MACHINE,
- .parent = TYPE_MACHINE,
- .abstract = true,
- .instance_size = sizeof(VirtMachineState),
- .class_size = sizeof(VirtMachineClass),
- .class_init = virt_machine_class_init,
- .interfaces = (InterfaceInfo[]) {
- { TYPE_HOTPLUG_HANDLER },
- { }
- },
-};
-
-static void machvirt_machine_init(void)
-{
- type_register_static(&virt_machine_info);
-}
-type_init(machvirt_machine_init);
-
-#define VIRT_COMPAT_2_12 \
- HW_COMPAT_2_12
-
-static void virt_3_0_instance_init(Object *obj)
+static void virt_instance_init(Object *obj)
{
VirtMachineState *vms = VIRT_MACHINE(obj);
VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(vms);
"Valid values are none and smmuv3",
NULL);
- vms->memmap = a15memmap;
vms->irqmap = a15irqmap;
}
-static void virt_machine_3_0_options(MachineClass *mc)
+static const TypeInfo virt_machine_info = {
+ .name = TYPE_VIRT_MACHINE,
+ .parent = TYPE_MACHINE,
+ .abstract = true,
+ .instance_size = sizeof(VirtMachineState),
+ .class_size = sizeof(VirtMachineClass),
+ .class_init = virt_machine_class_init,
+ .instance_init = virt_instance_init,
+ .interfaces = (InterfaceInfo[]) {
+ { TYPE_HOTPLUG_HANDLER },
+ { }
+ },
+};
+
+static void machvirt_machine_init(void)
+{
+ type_register_static(&virt_machine_info);
+}
+type_init(machvirt_machine_init);
+
+static void virt_machine_4_0_options(MachineClass *mc)
+{
+}
+DEFINE_VIRT_MACHINE_AS_LATEST(4, 0)
+
+static void virt_machine_3_1_options(MachineClass *mc)
{
+ virt_machine_4_0_options(mc);
+ compat_props_add(mc->compat_props, hw_compat_3_1, hw_compat_3_1_len);
}
-DEFINE_VIRT_MACHINE_AS_LATEST(3, 0)
+DEFINE_VIRT_MACHINE(3, 1)
-static void virt_2_12_instance_init(Object *obj)
+static void virt_machine_3_0_options(MachineClass *mc)
{
- virt_3_0_instance_init(obj);
+ virt_machine_3_1_options(mc);
+ compat_props_add(mc->compat_props, hw_compat_3_0, hw_compat_3_0_len);
}
+DEFINE_VIRT_MACHINE(3, 0)
static void virt_machine_2_12_options(MachineClass *mc)
{
VirtMachineClass *vmc = VIRT_MACHINE_CLASS(OBJECT_CLASS(mc));
virt_machine_3_0_options(mc);
- SET_MACHINE_COMPAT(mc, VIRT_COMPAT_2_12);
+ compat_props_add(mc->compat_props, hw_compat_2_12, hw_compat_2_12_len);
vmc->no_highmem_ecam = true;
mc->max_cpus = 255;
}
DEFINE_VIRT_MACHINE(2, 12)
-#define VIRT_COMPAT_2_11 \
- HW_COMPAT_2_11
-
-static void virt_2_11_instance_init(Object *obj)
-{
- virt_2_12_instance_init(obj);
-}
-
static void virt_machine_2_11_options(MachineClass *mc)
{
VirtMachineClass *vmc = VIRT_MACHINE_CLASS(OBJECT_CLASS(mc));
virt_machine_2_12_options(mc);
- SET_MACHINE_COMPAT(mc, VIRT_COMPAT_2_11);
+ compat_props_add(mc->compat_props, hw_compat_2_11, hw_compat_2_11_len);
vmc->smbios_old_sys_ver = true;
}
DEFINE_VIRT_MACHINE(2, 11)
-#define VIRT_COMPAT_2_10 \
- HW_COMPAT_2_10
-
-static void virt_2_10_instance_init(Object *obj)
-{
- virt_2_11_instance_init(obj);
-}
-
static void virt_machine_2_10_options(MachineClass *mc)
{
virt_machine_2_11_options(mc);
- SET_MACHINE_COMPAT(mc, VIRT_COMPAT_2_10);
+ compat_props_add(mc->compat_props, hw_compat_2_10, hw_compat_2_10_len);
+ /* before 2.11 we never faulted accesses to bad addresses */
+ mc->ignore_memory_transaction_failures = true;
}
DEFINE_VIRT_MACHINE(2, 10)
-#define VIRT_COMPAT_2_9 \
- HW_COMPAT_2_9
-
-static void virt_2_9_instance_init(Object *obj)
-{
- virt_2_10_instance_init(obj);
-}
-
static void virt_machine_2_9_options(MachineClass *mc)
{
virt_machine_2_10_options(mc);
- SET_MACHINE_COMPAT(mc, VIRT_COMPAT_2_9);
+ compat_props_add(mc->compat_props, hw_compat_2_9, hw_compat_2_9_len);
}
DEFINE_VIRT_MACHINE(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);
+ compat_props_add(mc->compat_props, hw_compat_2_8, hw_compat_2_8_len);
/* For 2.8 and earlier we falsely claimed in the DT that
* our timers were edge-triggered, not level-triggered.
*/
}
DEFINE_VIRT_MACHINE(2, 8)
-#define VIRT_COMPAT_2_7 \
- HW_COMPAT_2_7
-
-static void virt_2_7_instance_init(Object *obj)
-{
- virt_2_8_instance_init(obj);
-}
-
static void virt_machine_2_7_options(MachineClass *mc)
{
VirtMachineClass *vmc = VIRT_MACHINE_CLASS(OBJECT_CLASS(mc));
virt_machine_2_8_options(mc);
- SET_MACHINE_COMPAT(mc, VIRT_COMPAT_2_7);
+ compat_props_add(mc->compat_props, hw_compat_2_7, hw_compat_2_7_len);
/* ITS was introduced with 2.8 */
vmc->no_its = true;
/* Stick with 1K pages for migration compatibility */
}
DEFINE_VIRT_MACHINE(2, 7)
-#define VIRT_COMPAT_2_6 \
- HW_COMPAT_2_6
-
-static void virt_2_6_instance_init(Object *obj)
-{
- virt_2_7_instance_init(obj);
-}
-
static void virt_machine_2_6_options(MachineClass *mc)
{
VirtMachineClass *vmc = VIRT_MACHINE_CLASS(OBJECT_CLASS(mc));
virt_machine_2_7_options(mc);
- SET_MACHINE_COMPAT(mc, VIRT_COMPAT_2_6);
+ compat_props_add(mc->compat_props, hw_compat_2_6, hw_compat_2_6_len);
vmc->disallow_affinity_adjustment = true;
/* Disable PMU for 2.6 as PMU support was first introduced in 2.7 */
vmc->no_pmu = true;