aboutsummaryrefslogtreecommitdiff
path: root/hw/arm/virt.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/arm/virt.c')
-rw-r--r--hw/arm/virt.c196
1 files changed, 127 insertions, 69 deletions
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 16ba67f7a7..5331ab71e2 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -30,6 +30,7 @@
#include "qemu/osdep.h"
#include "qemu/units.h"
+#include "qemu/option.h"
#include "qapi/error.h"
#include "hw/sysbus.h"
#include "hw/arm/arm.h"
@@ -871,25 +872,19 @@ static void create_virtio_devices(const VirtMachineState *vms, qemu_irq *pic)
}
}
-static void create_one_flash(const char *name, hwaddr flashbase,
- hwaddr flashsize, const char *file,
- MemoryRegion *sysmem)
+#define VIRT_FLASH_SECTOR_SIZE (256 * KiB)
+
+static PFlashCFI01 *virt_flash_create1(VirtMachineState *vms,
+ const char *name,
+ const char *alias_prop_name)
{
- /* Create and map a single flash device. We use the same
- * parameters as the flash devices on the Versatile Express board.
+ /*
+ * Create a single flash device. We use the same parameters as
+ * the flash devices on the Versatile Express board.
*/
- DriveInfo *dinfo = drive_get_next(IF_PFLASH);
DeviceState *dev = qdev_create(NULL, TYPE_PFLASH_CFI01);
- SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
- const uint64_t sectorlength = 256 * 1024;
-
- if (dinfo) {
- qdev_prop_set_drive(dev, "drive", blk_by_legacy_dinfo(dinfo),
- &error_abort);
- }
- qdev_prop_set_uint32(dev, "num-blocks", flashsize / sectorlength);
- qdev_prop_set_uint64(dev, "sector-length", sectorlength);
+ qdev_prop_set_uint64(dev, "sector-length", VIRT_FLASH_SECTOR_SIZE);
qdev_prop_set_uint8(dev, "width", 4);
qdev_prop_set_uint8(dev, "device-width", 2);
qdev_prop_set_bit(dev, "big-endian", false);
@@ -898,41 +893,41 @@ static void create_one_flash(const char *name, hwaddr flashbase,
qdev_prop_set_uint16(dev, "id2", 0x00);
qdev_prop_set_uint16(dev, "id3", 0x00);
qdev_prop_set_string(dev, "name", name);
- qdev_init_nofail(dev);
+ object_property_add_child(OBJECT(vms), name, OBJECT(dev),
+ &error_abort);
+ object_property_add_alias(OBJECT(vms), alias_prop_name,
+ OBJECT(dev), "drive", &error_abort);
+ return PFLASH_CFI01(dev);
+}
- memory_region_add_subregion(sysmem, flashbase,
- sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0));
+static void virt_flash_create(VirtMachineState *vms)
+{
+ vms->flash[0] = virt_flash_create1(vms, "virt.flash0", "pflash0");
+ vms->flash[1] = virt_flash_create1(vms, "virt.flash1", "pflash1");
+}
- if (file) {
- char *fn;
- int image_size;
+static void virt_flash_map1(PFlashCFI01 *flash,
+ hwaddr base, hwaddr size,
+ MemoryRegion *sysmem)
+{
+ DeviceState *dev = DEVICE(flash);
- if (drive_get(IF_PFLASH, 0, 0)) {
- error_report("The contents of the first flash device may be "
- "specified with -bios or with -drive if=pflash... "
- "but you cannot use both options at once");
- exit(1);
- }
- fn = qemu_find_file(QEMU_FILE_TYPE_BIOS, file);
- if (!fn) {
- error_report("Could not find ROM image '%s'", file);
- exit(1);
- }
- image_size = load_image_mr(fn, sysbus_mmio_get_region(sbd, 0));
- g_free(fn);
- if (image_size < 0) {
- error_report("Could not load ROM image '%s'", file);
- exit(1);
- }
- }
+ assert(size % VIRT_FLASH_SECTOR_SIZE == 0);
+ assert(size / VIRT_FLASH_SECTOR_SIZE <= UINT32_MAX);
+ qdev_prop_set_uint32(dev, "num-blocks", size / VIRT_FLASH_SECTOR_SIZE);
+ qdev_init_nofail(dev);
+
+ memory_region_add_subregion(sysmem, base,
+ sysbus_mmio_get_region(SYS_BUS_DEVICE(dev),
+ 0));
}
-static void create_flash(const VirtMachineState *vms,
- MemoryRegion *sysmem,
- MemoryRegion *secure_sysmem)
+static void virt_flash_map(VirtMachineState *vms,
+ MemoryRegion *sysmem,
+ MemoryRegion *secure_sysmem)
{
- /* Create two flash devices to fill the VIRT_FLASH space in the memmap.
- * Any file passed via -bios goes in the first of these.
+ /*
+ * Map two flash devices to fill the VIRT_FLASH space in the memmap.
* sysmem is the system memory space. secure_sysmem is the secure view
* of the system, and the first flash device should be made visible only
* there. The second flash device is visible to both secure and nonsecure.
@@ -941,12 +936,20 @@ static void create_flash(const VirtMachineState *vms,
*/
hwaddr flashsize = vms->memmap[VIRT_FLASH].size / 2;
hwaddr flashbase = vms->memmap[VIRT_FLASH].base;
- char *nodename;
- create_one_flash("virt.flash0", flashbase, flashsize,
- bios_name, secure_sysmem);
- create_one_flash("virt.flash1", flashbase + flashsize, flashsize,
- NULL, sysmem);
+ virt_flash_map1(vms->flash[0], flashbase, flashsize,
+ secure_sysmem);
+ virt_flash_map1(vms->flash[1], flashbase + flashsize, flashsize,
+ sysmem);
+}
+
+static void virt_flash_fdt(VirtMachineState *vms,
+ MemoryRegion *sysmem,
+ MemoryRegion *secure_sysmem)
+{
+ hwaddr flashsize = vms->memmap[VIRT_FLASH].size / 2;
+ hwaddr flashbase = vms->memmap[VIRT_FLASH].base;
+ char *nodename;
if (sysmem == secure_sysmem) {
/* Report both flash devices as a single node in the DT */
@@ -959,7 +962,8 @@ static void create_flash(const VirtMachineState *vms,
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
+ /*
+ * 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);
@@ -982,6 +986,54 @@ static void create_flash(const VirtMachineState *vms,
}
}
+static bool virt_firmware_init(VirtMachineState *vms,
+ MemoryRegion *sysmem,
+ MemoryRegion *secure_sysmem)
+{
+ int i;
+ BlockBackend *pflash_blk0;
+
+ /* Map legacy -drive if=pflash to machine properties */
+ for (i = 0; i < ARRAY_SIZE(vms->flash); i++) {
+ pflash_cfi01_legacy_drive(vms->flash[i],
+ drive_get(IF_PFLASH, 0, i));
+ }
+
+ virt_flash_map(vms, sysmem, secure_sysmem);
+
+ pflash_blk0 = pflash_cfi01_get_blk(vms->flash[0]);
+
+ if (bios_name) {
+ char *fname;
+ MemoryRegion *mr;
+ int image_size;
+
+ if (pflash_blk0) {
+ error_report("The contents of the first flash device may be "
+ "specified with -bios or with -drive if=pflash... "
+ "but you cannot use both options at once");
+ exit(1);
+ }
+
+ /* Fall back to -bios */
+
+ fname = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
+ if (!fname) {
+ error_report("Could not find ROM image '%s'", bios_name);
+ exit(1);
+ }
+ mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(vms->flash[0]), 0);
+ image_size = load_image_mr(fname, mr);
+ g_free(fname);
+ if (image_size < 0) {
+ error_report("Could not load ROM image '%s'", bios_name);
+ exit(1);
+ }
+ }
+
+ return pflash_blk0 || bios_name;
+}
+
static FWCfgState *create_fw_cfg(const VirtMachineState *vms, AddressSpace *as)
{
hwaddr base = vms->memmap[VIRT_FW_CFG].base;
@@ -1421,7 +1473,7 @@ static void machvirt_init(MachineState *machine)
MemoryRegion *secure_sysmem = NULL;
int n, virt_max_cpus;
MemoryRegion *ram = g_new(MemoryRegion, 1);
- bool firmware_loaded = bios_name || drive_get(IF_PFLASH, 0, 0);
+ bool firmware_loaded;
bool aarch64 = true;
/*
@@ -1460,6 +1512,27 @@ static void machvirt_init(MachineState *machine)
exit(1);
}
+ if (vms->secure) {
+ if (kvm_enabled()) {
+ error_report("mach-virt: KVM does not support Security extensions");
+ exit(1);
+ }
+
+ /*
+ * The Secure view of the world is the same as the NonSecure,
+ * but with a few extra devices. Create it as a container region
+ * containing the system memory at low priority; any secure-only
+ * devices go in at higher priority and take precedence.
+ */
+ secure_sysmem = g_new(MemoryRegion, 1);
+ memory_region_init(secure_sysmem, OBJECT(machine), "secure-memory",
+ UINT64_MAX);
+ memory_region_add_subregion_overlap(secure_sysmem, 0, sysmem, -1);
+ }
+
+ firmware_loaded = virt_firmware_init(vms, sysmem,
+ secure_sysmem ?: sysmem);
+
/* If we have an EL3 boot ROM then the assumption is that it will
* implement PSCI itself, so disable QEMU's internal implementation
* so it doesn't get in the way. Instead of starting secondary
@@ -1505,23 +1578,6 @@ static void machvirt_init(MachineState *machine)
exit(1);
}
- if (vms->secure) {
- if (kvm_enabled()) {
- error_report("mach-virt: KVM does not support Security extensions");
- exit(1);
- }
-
- /* The Secure view of the world is the same as the NonSecure,
- * but with a few extra devices. Create it as a container region
- * containing the system memory at low priority; any secure-only
- * devices go in at higher priority and take precedence.
- */
- secure_sysmem = g_new(MemoryRegion, 1);
- memory_region_init(secure_sysmem, OBJECT(machine), "secure-memory",
- UINT64_MAX);
- memory_region_add_subregion_overlap(secure_sysmem, 0, sysmem, -1);
- }
-
create_fdt(vms);
possible_cpus = mc->possible_cpu_arch_ids(machine);
@@ -1610,7 +1666,7 @@ static void machvirt_init(MachineState *machine)
&machine->device_memory->mr);
}
- create_flash(vms, sysmem, secure_sysmem ? secure_sysmem : sysmem);
+ virt_flash_fdt(vms, sysmem, secure_sysmem);
create_gic(vms, pic);
@@ -1956,6 +2012,8 @@ static void virt_instance_init(Object *obj)
NULL);
vms->irqmap = a15irqmap;
+
+ virt_flash_create(vms);
}
static const TypeInfo virt_machine_info = {