aboutsummaryrefslogtreecommitdiff
path: root/hw/arm
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2014-12-23 15:05:22 +0000
committerPeter Maydell <peter.maydell@linaro.org>2014-12-23 15:05:22 +0000
commitab0302ee764fd702465aef6d88612cdff4302809 (patch)
tree4f7ba47706d9e60c5dc731159030280c2cd7b5a9 /hw/arm
parent03de06dde54df1f64bb099efe22edfa773b16e8e (diff)
parentaa351061dbb0e3054db11c00a69395785c4186c8 (diff)
Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20141223' into staging
target-arm queue: * enable 32-bit EL3 (TrustZone) for vexpress and virt boards * add fw_cfg device to virt board for UEFI firmware config * support passing commandline kernel/initrd to firmware # gpg: Signature made Tue 23 Dec 2014 13:50:33 GMT using RSA key ID 14360CDE # gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" * remotes/pmaydell/tags/pull-target-arm-20141223: (31 commits) hw/arm/virt: enable passing of EFI-stubbed kernel to guest UEFI firmware hw/arm: pass pristine kernel image to guest firmware over fw_cfg hw/loader: split out load_image_gzipped_buffer() arm: add fw_cfg to "virt" board fw_cfg_mem: expose the "data_width" property with fw_cfg_init_mem_wide() fw_cfg_mem: introduce the "data_width" property exec: allows 8-byte accesses in subpage_ops fw_cfg_mem: flip ctl_mem_ops and data_mem_ops to DEVICE_BIG_ENDIAN fw_cfg_mem: max access size and region size are the same for data register fw_cfg: move boards to fw_cfg_init_io() / fw_cfg_init_mem() fw_cfg: hard separation between the MMIO and I/O port mappings target-arm: add cpu feature EL3 to CPUs with Security Extensions target-arm: Disable EL3 on unsupported machines target-arm: Breakout integratorcp and versatilepb cpu init target-arm: Set CPU has_el3 prop during virt init target-arm: Enable CPU has_el3 prop during VE init target-arm: Add arm_boot_info secure_boot control target-arm: Add ARMCPU secure property target-arm: Add feature unset function target-arm: Add virt machine secure property ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw/arm')
-rw-r--r--hw/arm/boot.c98
-rw-r--r--hw/arm/exynos4210.c11
-rw-r--r--hw/arm/highbank.c12
-rw-r--r--hw/arm/integratorcp.c31
-rw-r--r--hw/arm/realview.c12
-rw-r--r--hw/arm/versatilepb.c32
-rw-r--r--hw/arm/vexpress.c141
-rw-r--r--hw/arm/virt.c97
-rw-r--r--hw/arm/xilinx_zynq.c12
9 files changed, 403 insertions, 43 deletions
diff --git a/hw/arm/boot.c b/hw/arm/boot.c
index e6a3c5bcfb..52ebd8be9b 100644
--- a/hw/arm/boot.c
+++ b/hw/arm/boot.c
@@ -457,6 +457,16 @@ static void do_cpu_reset(void *opaque)
env->thumb = info->entry & 1;
}
} else {
+ /* If we are booting Linux then we need to check whether we are
+ * booting into secure or non-secure state and adjust the state
+ * accordingly. Out of reset, ARM is defined to be in secure state
+ * (SCR.NS = 0), we change that here if non-secure boot has been
+ * requested.
+ */
+ if (arm_feature(env, ARM_FEATURE_EL3) && !info->secure_boot) {
+ env->cp15.scr_el3 |= SCR_NS;
+ }
+
if (CPU(cpu) == first_cpu) {
if (env->aarch64) {
env->pc = info->loader_start;
@@ -478,6 +488,55 @@ static void do_cpu_reset(void *opaque)
}
}
+/**
+ * load_image_to_fw_cfg() - Load an image file into an fw_cfg entry identified
+ * by key.
+ * @fw_cfg: The firmware config instance to store the data in.
+ * @size_key: The firmware config key to store the size of the loaded
+ * data under, with fw_cfg_add_i32().
+ * @data_key: The firmware config key to store the loaded data under,
+ * with fw_cfg_add_bytes().
+ * @image_name: The name of the image file to load. If it is NULL, the
+ * function returns without doing anything.
+ * @try_decompress: Whether the image should be decompressed (gunzipped) before
+ * adding it to fw_cfg. If decompression fails, the image is
+ * loaded as-is.
+ *
+ * In case of failure, the function prints an error message to stderr and the
+ * process exits with status 1.
+ */
+static void load_image_to_fw_cfg(FWCfgState *fw_cfg, uint16_t size_key,
+ uint16_t data_key, const char *image_name,
+ bool try_decompress)
+{
+ size_t size = -1;
+ uint8_t *data;
+
+ if (image_name == NULL) {
+ return;
+ }
+
+ if (try_decompress) {
+ size = load_image_gzipped_buffer(image_name,
+ LOAD_IMAGE_MAX_GUNZIP_BYTES, &data);
+ }
+
+ if (size == (size_t)-1) {
+ gchar *contents;
+ gsize length;
+
+ if (!g_file_get_contents(image_name, &contents, &length, NULL)) {
+ fprintf(stderr, "failed to load \"%s\"\n", image_name);
+ exit(1);
+ }
+ size = length;
+ data = (uint8_t *)contents;
+ }
+
+ fw_cfg_add_i32(fw_cfg, size_key, size);
+ fw_cfg_add_bytes(fw_cfg, data_key, data, size);
+}
+
void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
{
CPUState *cs;
@@ -500,19 +559,48 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
}
/* Load the kernel. */
- if (!info->kernel_filename) {
+ if (!info->kernel_filename || info->firmware_loaded) {
if (have_dtb(info)) {
- /* If we have a device tree blob, but no kernel to supply it to,
- * copy it to the base of RAM for a bootloader to pick up.
+ /* If we have a device tree blob, but no kernel to supply it to (or
+ * the kernel is supposed to be loaded by the bootloader), copy the
+ * DTB to the base of RAM for the bootloader to pick up.
*/
if (load_dtb(info->loader_start, info, 0) < 0) {
exit(1);
}
}
- /* If no kernel specified, do nothing; we will start from address 0
- * (typically a boot ROM image) in the same way as hardware.
+ if (info->kernel_filename) {
+ FWCfgState *fw_cfg;
+ bool try_decompressing_kernel;
+
+ fw_cfg = fw_cfg_find();
+ try_decompressing_kernel = arm_feature(&cpu->env,
+ ARM_FEATURE_AARCH64);
+
+ /* Expose the kernel, the command line, and the initrd in fw_cfg.
+ * We don't process them here at all, it's all left to the
+ * firmware.
+ */
+ load_image_to_fw_cfg(fw_cfg,
+ FW_CFG_KERNEL_SIZE, FW_CFG_KERNEL_DATA,
+ info->kernel_filename,
+ try_decompressing_kernel);
+ load_image_to_fw_cfg(fw_cfg,
+ FW_CFG_INITRD_SIZE, FW_CFG_INITRD_DATA,
+ info->initrd_filename, false);
+
+ if (info->kernel_cmdline) {
+ fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE,
+ strlen(info->kernel_cmdline) + 1);
+ fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA,
+ info->kernel_cmdline);
+ }
+ }
+
+ /* We will start from address 0 (typically a boot ROM image) in the
+ * same way as hardware.
*/
return;
}
diff --git a/hw/arm/exynos4210.c b/hw/arm/exynos4210.c
index 582794c19f..97dafca49a 100644
--- a/hw/arm/exynos4210.c
+++ b/hw/arm/exynos4210.c
@@ -152,6 +152,17 @@ Exynos4210State *exynos4210_init(MemoryRegion *system_mem,
Object *cpuobj = object_new(object_class_get_name(cpu_oc));
Error *err = NULL;
+ /* By default A9 CPUs have EL3 enabled. This board does not currently
+ * support EL3 so the CPU EL3 property is disabled before realization.
+ */
+ if (object_property_find(cpuobj, "has_el3", NULL)) {
+ object_property_set_bool(cpuobj, false, "has_el3", &err);
+ if (err) {
+ error_report("%s", error_get_pretty(err));
+ exit(1);
+ }
+ }
+
s->cpu[n] = ARM_CPU(cpuobj);
object_property_set_int(cpuobj, EXYNOS4210_SMP_PRIVATE_BASE_ADDR,
"reset-cbar", &error_abort);
diff --git a/hw/arm/highbank.c b/hw/arm/highbank.c
index 30f744a1bd..f67570a7ee 100644
--- a/hw/arm/highbank.c
+++ b/hw/arm/highbank.c
@@ -241,6 +241,18 @@ static void calxeda_init(MachineState *machine, enum cxmachines machine_id)
cpuobj = object_new(object_class_get_name(oc));
cpu = ARM_CPU(cpuobj);
+ /* By default A9 and A15 CPUs have EL3 enabled. This board does not
+ * currently support EL3 so the CPU EL3 property is disabled before
+ * realization.
+ */
+ if (object_property_find(cpuobj, "has_el3", NULL)) {
+ object_property_set_bool(cpuobj, false, "has_el3", &err);
+ if (err) {
+ error_report("%s", error_get_pretty(err));
+ exit(1);
+ }
+ }
+
if (object_property_find(cpuobj, "reset-cbar", NULL)) {
object_property_set_int(cpuobj, MPCORE_PERIPHBASE,
"reset-cbar", &error_abort);
diff --git a/hw/arm/integratorcp.c b/hw/arm/integratorcp.c
index 266ec18fb3..8c48b68a34 100644
--- a/hw/arm/integratorcp.c
+++ b/hw/arm/integratorcp.c
@@ -15,6 +15,7 @@
#include "net/net.h"
#include "exec/address-spaces.h"
#include "sysemu/sysemu.h"
+#include "qemu/error-report.h"
#define TYPE_INTEGRATOR_CM "integrator_core"
#define INTEGRATOR_CM(obj) \
@@ -469,6 +470,8 @@ static void integratorcp_init(MachineState *machine)
const char *kernel_filename = machine->kernel_filename;
const char *kernel_cmdline = machine->kernel_cmdline;
const char *initrd_filename = machine->initrd_filename;
+ ObjectClass *cpu_oc;
+ Object *cpuobj;
ARMCPU *cpu;
MemoryRegion *address_space_mem = get_system_memory();
MemoryRegion *ram = g_new(MemoryRegion, 1);
@@ -476,16 +479,40 @@ static void integratorcp_init(MachineState *machine)
qemu_irq pic[32];
DeviceState *dev;
int i;
+ Error *err = NULL;
if (!cpu_model) {
cpu_model = "arm926";
}
- cpu = cpu_arm_init(cpu_model);
- if (!cpu) {
+
+ cpu_oc = cpu_class_by_name(TYPE_ARM_CPU, cpu_model);
+ if (!cpu_oc) {
fprintf(stderr, "Unable to find CPU definition\n");
exit(1);
}
+ cpuobj = object_new(object_class_get_name(cpu_oc));
+
+ /* By default ARM1176 CPUs have EL3 enabled. This board does not
+ * currently support EL3 so the CPU EL3 property is disabled before
+ * realization.
+ */
+ if (object_property_find(cpuobj, "has_el3", NULL)) {
+ object_property_set_bool(cpuobj, false, "has_el3", &err);
+ if (err) {
+ error_report("%s", error_get_pretty(err));
+ exit(1);
+ }
+ }
+
+ object_property_set_bool(cpuobj, true, "realized", &err);
+ if (err) {
+ error_report("%s", error_get_pretty(err));
+ exit(1);
+ }
+
+ cpu = ARM_CPU(cpuobj);
+
memory_region_init_ram(ram, NULL, "integrator.ram", ram_size, &error_abort);
vmstate_register_ram_global(ram);
/* ??? On a real system the first 1Mb is mapped as SSRAM or boot flash. */
diff --git a/hw/arm/realview.c b/hw/arm/realview.c
index d41ec97a23..66e51ef1ad 100644
--- a/hw/arm/realview.c
+++ b/hw/arm/realview.c
@@ -101,6 +101,18 @@ static void realview_init(MachineState *machine,
Object *cpuobj = object_new(object_class_get_name(cpu_oc));
Error *err = NULL;
+ /* By default A9,A15 and ARM1176 CPUs have EL3 enabled. This board
+ * does not currently support EL3 so the CPU EL3 property is disabled
+ * before realization.
+ */
+ if (object_property_find(cpuobj, "has_el3", NULL)) {
+ object_property_set_bool(cpuobj, false, "has_el3", &err);
+ if (err) {
+ error_report("%s", error_get_pretty(err));
+ exit(1);
+ }
+ }
+
if (is_pb && is_mpcore) {
object_property_set_int(cpuobj, periphbase, "reset-cbar", &err);
if (err) {
diff --git a/hw/arm/versatilepb.c b/hw/arm/versatilepb.c
index e6ef0a2e7e..6c4c2e780e 100644
--- a/hw/arm/versatilepb.c
+++ b/hw/arm/versatilepb.c
@@ -18,6 +18,7 @@
#include "sysemu/block-backend.h"
#include "exec/address-spaces.h"
#include "hw/block/flash.h"
+#include "qemu/error-report.h"
#define VERSATILE_FLASH_ADDR 0x34000000
#define VERSATILE_FLASH_SIZE (64 * 1024 * 1024)
@@ -175,6 +176,8 @@ static struct arm_boot_info versatile_binfo;
static void versatile_init(MachineState *machine, int board_id)
{
+ ObjectClass *cpu_oc;
+ Object *cpuobj;
ARMCPU *cpu;
MemoryRegion *sysmem = get_system_memory();
MemoryRegion *ram = g_new(MemoryRegion, 1);
@@ -189,15 +192,40 @@ static void versatile_init(MachineState *machine, int board_id)
int n;
int done_smc = 0;
DriveInfo *dinfo;
+ Error *err = NULL;
if (!machine->cpu_model) {
machine->cpu_model = "arm926";
}
- cpu = cpu_arm_init(machine->cpu_model);
- if (!cpu) {
+
+ cpu_oc = cpu_class_by_name(TYPE_ARM_CPU, machine->cpu_model);
+ if (!cpu_oc) {
fprintf(stderr, "Unable to find CPU definition\n");
exit(1);
}
+
+ cpuobj = object_new(object_class_get_name(cpu_oc));
+
+ /* By default ARM1176 CPUs have EL3 enabled. This board does not
+ * currently support EL3 so the CPU EL3 property is disabled before
+ * realization.
+ */
+ if (object_property_find(cpuobj, "has_el3", NULL)) {
+ object_property_set_bool(cpuobj, false, "has_el3", &err);
+ if (err) {
+ error_report("%s", error_get_pretty(err));
+ exit(1);
+ }
+ }
+
+ object_property_set_bool(cpuobj, true, "realized", &err);
+ if (err) {
+ error_report("%s", error_get_pretty(err));
+ exit(1);
+ }
+
+ cpu = ARM_CPU(cpuobj);
+
memory_region_init_ram(ram, NULL, "versatile.ram", machine->ram_size,
&error_abort);
vmstate_register_ram_global(ram);
diff --git a/hw/arm/vexpress.c b/hw/arm/vexpress.c
index 7cbd13f182..84415c8b0a 100644
--- a/hw/arm/vexpress.c
+++ b/hw/arm/vexpress.c
@@ -157,7 +157,27 @@ static hwaddr motherboard_aseries_map[] = {
typedef struct VEDBoardInfo VEDBoardInfo;
-typedef void DBoardInitFn(const VEDBoardInfo *daughterboard,
+typedef struct {
+ MachineClass parent;
+ VEDBoardInfo *daughterboard;
+} VexpressMachineClass;
+
+typedef struct {
+ MachineState parent;
+ bool secure;
+} VexpressMachineState;
+
+#define TYPE_VEXPRESS_MACHINE "vexpress"
+#define TYPE_VEXPRESS_A9_MACHINE "vexpress-a9"
+#define TYPE_VEXPRESS_A15_MACHINE "vexpress-a15"
+#define VEXPRESS_MACHINE(obj) \
+ OBJECT_CHECK(VexpressMachineState, (obj), TYPE_VEXPRESS_MACHINE)
+#define VEXPRESS_MACHINE_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(VexpressMachineClass, obj, TYPE_VEXPRESS_MACHINE)
+#define VEXPRESS_MACHINE_CLASS(klass) \
+ OBJECT_CLASS_CHECK(VexpressMachineClass, klass, TYPE_VEXPRESS_MACHINE)
+
+typedef void DBoardInitFn(const VexpressMachineState *machine,
ram_addr_t ram_size,
const char *cpu_model,
qemu_irq *pic);
@@ -176,7 +196,7 @@ struct VEDBoardInfo {
};
static void init_cpus(const char *cpu_model, const char *privdev,
- hwaddr periphbase, qemu_irq *pic)
+ hwaddr periphbase, qemu_irq *pic, bool secure)
{
ObjectClass *cpu_oc = cpu_class_by_name(TYPE_ARM_CPU, cpu_model);
DeviceState *dev;
@@ -193,6 +213,10 @@ static void init_cpus(const char *cpu_model, const char *privdev,
Object *cpuobj = object_new(object_class_get_name(cpu_oc));
Error *err = NULL;
+ if (!secure) {
+ object_property_set_bool(cpuobj, false, "has_el3", NULL);
+ }
+
if (object_property_find(cpuobj, "reset-cbar", NULL)) {
object_property_set_int(cpuobj, periphbase,
"reset-cbar", &error_abort);
@@ -232,7 +256,7 @@ static void init_cpus(const char *cpu_model, const char *privdev,
}
}
-static void a9_daughterboard_init(const VEDBoardInfo *daughterboard,
+static void a9_daughterboard_init(const VexpressMachineState *vms,
ram_addr_t ram_size,
const char *cpu_model,
qemu_irq *pic)
@@ -268,7 +292,7 @@ static void a9_daughterboard_init(const VEDBoardInfo *daughterboard,
memory_region_add_subregion(sysmem, 0x60000000, ram);
/* 0x1e000000 A9MPCore (SCU) private memory region */
- init_cpus(cpu_model, "a9mpcore_priv", 0x1e000000, pic);
+ init_cpus(cpu_model, "a9mpcore_priv", 0x1e000000, pic, vms->secure);
/* Daughterboard peripherals : 0x10020000 .. 0x20000000 */
@@ -322,7 +346,7 @@ static VEDBoardInfo a9_daughterboard = {
.init = a9_daughterboard_init,
};
-static void a15_daughterboard_init(const VEDBoardInfo *daughterboard,
+static void a15_daughterboard_init(const VexpressMachineState *vms,
ram_addr_t ram_size,
const char *cpu_model,
qemu_irq *pic)
@@ -354,7 +378,7 @@ static void a15_daughterboard_init(const VEDBoardInfo *daughterboard,
memory_region_add_subregion(sysmem, 0x80000000, ram);
/* 0x2c000000 A15MPCore private memory region (GIC) */
- init_cpus(cpu_model, "a15mpcore_priv", 0x2c000000, pic);
+ init_cpus(cpu_model, "a15mpcore_priv", 0x2c000000, pic, vms->secure);
/* A15 daughterboard peripherals: */
@@ -513,9 +537,11 @@ static pflash_t *ve_pflash_cfi01_register(hwaddr base, const char *name,
return OBJECT_CHECK(pflash_t, (dev), "cfi.pflash01");
}
-static void vexpress_common_init(VEDBoardInfo *daughterboard,
- MachineState *machine)
+static void vexpress_common_init(MachineState *machine)
{
+ VexpressMachineState *vms = VEXPRESS_MACHINE(machine);
+ VexpressMachineClass *vmc = VEXPRESS_MACHINE_GET_CLASS(machine);
+ VEDBoardInfo *daughterboard = vmc->daughterboard;;
DeviceState *dev, *sysctl, *pl041;
qemu_irq pic[64];
uint32_t sys_id;
@@ -530,8 +556,7 @@ static void vexpress_common_init(VEDBoardInfo *daughterboard,
const hwaddr *map = daughterboard->motherboard_map;
int i;
- daughterboard->init(daughterboard, machine->ram_size, machine->cpu_model,
- pic);
+ daughterboard->init(vms, machine->ram_size, machine->cpu_model, pic);
/*
* If a bios file was provided, attempt to map it into memory
@@ -678,39 +703,99 @@ static void vexpress_common_init(VEDBoardInfo *daughterboard,
daughterboard->bootinfo.smp_bootreg_addr = map[VE_SYSREGS] + 0x30;
daughterboard->bootinfo.gic_cpu_if_addr = daughterboard->gic_cpu_if_addr;
daughterboard->bootinfo.modify_dtb = vexpress_modify_dtb;
+ /* Indicate that when booting Linux we should be in secure state */
+ daughterboard->bootinfo.secure_boot = true;
arm_load_kernel(ARM_CPU(first_cpu), &daughterboard->bootinfo);
}
-static void vexpress_a9_init(MachineState *machine)
+static bool vexpress_get_secure(Object *obj, Error **errp)
+{
+ VexpressMachineState *vms = VEXPRESS_MACHINE(obj);
+
+ return vms->secure;
+}
+
+static void vexpress_set_secure(Object *obj, bool value, Error **errp)
{
- vexpress_common_init(&a9_daughterboard, machine);
+ VexpressMachineState *vms = VEXPRESS_MACHINE(obj);
+
+ vms->secure = value;
+}
+
+static void vexpress_instance_init(Object *obj)
+{
+ VexpressMachineState *vms = VEXPRESS_MACHINE(obj);
+
+ /* EL3 is enabled by default on vexpress */
+ vms->secure = true;
+ object_property_add_bool(obj, "secure", vexpress_get_secure,
+ vexpress_set_secure, NULL);
+ object_property_set_description(obj, "secure",
+ "Set on/off to enable/disable the ARM "
+ "Security Extensions (TrustZone)",
+ NULL);
}
-static void vexpress_a15_init(MachineState *machine)
+static void vexpress_class_init(ObjectClass *oc, void *data)
{
- vexpress_common_init(&a15_daughterboard, machine);
+ MachineClass *mc = MACHINE_CLASS(oc);
+
+ mc->name = TYPE_VEXPRESS_MACHINE;
+ mc->desc = "ARM Versatile Express";
+ mc->init = vexpress_common_init;
+ mc->block_default_type = IF_SCSI;
+ mc->max_cpus = 4;
}
-static QEMUMachine vexpress_a9_machine = {
- .name = "vexpress-a9",
- .desc = "ARM Versatile Express for Cortex-A9",
- .init = vexpress_a9_init,
- .block_default_type = IF_SCSI,
- .max_cpus = 4,
+static void vexpress_a9_class_init(ObjectClass *oc, void *data)
+{
+ MachineClass *mc = MACHINE_CLASS(oc);
+ VexpressMachineClass *vmc = VEXPRESS_MACHINE_CLASS(oc);
+
+ mc->name = TYPE_VEXPRESS_A9_MACHINE;
+ mc->desc = "ARM Versatile Express for Cortex-A9";
+
+ vmc->daughterboard = &a9_daughterboard;;
+}
+
+static void vexpress_a15_class_init(ObjectClass *oc, void *data)
+{
+ MachineClass *mc = MACHINE_CLASS(oc);
+ VexpressMachineClass *vmc = VEXPRESS_MACHINE_CLASS(oc);
+
+ mc->name = TYPE_VEXPRESS_A15_MACHINE;
+ mc->desc = "ARM Versatile Express for Cortex-A15";
+
+ vmc->daughterboard = &a15_daughterboard;
+}
+
+static const TypeInfo vexpress_info = {
+ .name = TYPE_VEXPRESS_MACHINE,
+ .parent = TYPE_MACHINE,
+ .abstract = true,
+ .instance_size = sizeof(VexpressMachineState),
+ .instance_init = vexpress_instance_init,
+ .class_size = sizeof(VexpressMachineClass),
+ .class_init = vexpress_class_init,
+};
+
+static const TypeInfo vexpress_a9_info = {
+ .name = TYPE_VEXPRESS_A9_MACHINE,
+ .parent = TYPE_VEXPRESS_MACHINE,
+ .class_init = vexpress_a9_class_init,
};
-static QEMUMachine vexpress_a15_machine = {
- .name = "vexpress-a15",
- .desc = "ARM Versatile Express for Cortex-A15",
- .init = vexpress_a15_init,
- .block_default_type = IF_SCSI,
- .max_cpus = 4,
+static const TypeInfo vexpress_a15_info = {
+ .name = TYPE_VEXPRESS_A15_MACHINE,
+ .parent = TYPE_VEXPRESS_MACHINE,
+ .class_init = vexpress_a15_class_init,
};
static void vexpress_machine_init(void)
{
- qemu_register_machine(&vexpress_a9_machine);
- qemu_register_machine(&vexpress_a15_machine);
+ type_register_static(&vexpress_info);
+ type_register_static(&vexpress_a9_info);
+ type_register_static(&vexpress_a15_info);
}
machine_init(vexpress_machine_init);
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 314e55b563..235344034d 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -68,6 +68,7 @@ enum {
VIRT_UART,
VIRT_MMIO,
VIRT_RTC,
+ VIRT_FW_CFG,
};
typedef struct MemMapEntry {
@@ -86,6 +87,24 @@ typedef struct VirtBoardInfo {
uint32_t clock_phandle;
} VirtBoardInfo;
+typedef struct {
+ MachineClass parent;
+ VirtBoardInfo *daughterboard;
+} VirtMachineClass;
+
+typedef struct {
+ MachineState parent;
+ bool secure;
+} VirtMachineState;
+
+#define TYPE_VIRT_MACHINE "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)
+
/* Addresses and sizes of our components.
* 0..128MB is space for a flash device so we can run bootrom code such as UEFI.
* 128MB..256MB is used for miscellaneous device I/O.
@@ -107,6 +126,7 @@ static const MemMapEntry a15memmap[] = {
[VIRT_GIC_CPU] = { 0x08010000, 0x00010000 },
[VIRT_UART] = { 0x09000000, 0x00001000 },
[VIRT_RTC] = { 0x09010000, 0x00001000 },
+ [VIRT_FW_CFG] = { 0x09020000, 0x0000000a },
[VIRT_MMIO] = { 0x0a000000, 0x00000200 },
/* ...repeating for a total of NUM_VIRTIO_TRANSPORTS, each of that size */
/* 0x10000000 .. 0x40000000 reserved for PCI */
@@ -519,6 +539,23 @@ static void create_flash(const VirtBoardInfo *vbi)
g_free(nodename);
}
+static void create_fw_cfg(const VirtBoardInfo *vbi)
+{
+ hwaddr base = vbi->memmap[VIRT_FW_CFG].base;
+ hwaddr size = vbi->memmap[VIRT_FW_CFG].size;
+ char *nodename;
+
+ fw_cfg_init_mem_wide(base + 8, base, 8);
+
+ nodename = g_strdup_printf("/fw-cfg@%" PRIx64, base);
+ qemu_fdt_add_subnode(vbi->fdt, nodename);
+ qemu_fdt_setprop_string(vbi->fdt, nodename,
+ "compatible", "qemu,fw-cfg-mmio");
+ qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg",
+ 2, base, 2, size);
+ g_free(nodename);
+}
+
static void *machvirt_dtb(const struct arm_boot_info *binfo, int *fdt_size)
{
const VirtBoardInfo *board = (const VirtBoardInfo *)binfo;
@@ -529,6 +566,7 @@ static void *machvirt_dtb(const struct arm_boot_info *binfo, int *fdt_size)
static void machvirt_init(MachineState *machine)
{
+ VirtMachineState *vms = VIRT_MACHINE(machine);
qemu_irq pic[NUM_IRQS];
MemoryRegion *sysmem = get_system_memory();
int n;
@@ -566,6 +604,10 @@ static void machvirt_init(MachineState *machine)
}
cpuobj = object_new(object_class_get_name(oc));
+ if (!vms->secure) {
+ object_property_set_bool(cpuobj, false, "has_el3", NULL);
+ }
+
object_property_set_int(cpuobj, QEMU_PSCI_CONDUIT_HVC, "psci-conduit",
NULL);
@@ -604,6 +646,8 @@ static void machvirt_init(MachineState *machine)
*/
create_virtio_devices(vbi, pic);
+ create_fw_cfg(vbi);
+
vbi->bootinfo.ram_size = machine->ram_size;
vbi->bootinfo.kernel_filename = machine->kernel_filename;
vbi->bootinfo.kernel_cmdline = machine->kernel_cmdline;
@@ -612,19 +656,60 @@ static void machvirt_init(MachineState *machine)
vbi->bootinfo.board_id = -1;
vbi->bootinfo.loader_start = vbi->memmap[VIRT_MEM].base;
vbi->bootinfo.get_dtb = machvirt_dtb;
+ vbi->bootinfo.firmware_loaded = bios_name || drive_get(IF_PFLASH, 0, 0);
arm_load_kernel(ARM_CPU(first_cpu), &vbi->bootinfo);
}
-static QEMUMachine machvirt_a15_machine = {
- .name = "virt",
- .desc = "ARM Virtual Machine",
- .init = machvirt_init,
- .max_cpus = 8,
+static bool virt_get_secure(Object *obj, Error **errp)
+{
+ VirtMachineState *vms = VIRT_MACHINE(obj);
+
+ return vms->secure;
+}
+
+static void virt_set_secure(Object *obj, bool value, Error **errp)
+{
+ VirtMachineState *vms = VIRT_MACHINE(obj);
+
+ vms->secure = value;
+}
+
+static void virt_instance_init(Object *obj)
+{
+ VirtMachineState *vms = VIRT_MACHINE(obj);
+
+ /* EL3 is enabled by default on virt */
+ vms->secure = true;
+ object_property_add_bool(obj, "secure", virt_get_secure,
+ virt_set_secure, NULL);
+ object_property_set_description(obj, "secure",
+ "Set on/off to enable/disable the ARM "
+ "Security Extensions (TrustZone)",
+ NULL);
+}
+
+static void virt_class_init(ObjectClass *oc, void *data)
+{
+ MachineClass *mc = MACHINE_CLASS(oc);
+
+ mc->name = TYPE_VIRT_MACHINE;
+ mc->desc = "ARM Virtual Machine",
+ mc->init = machvirt_init;
+ mc->max_cpus = 8;
+}
+
+static const TypeInfo machvirt_info = {
+ .name = TYPE_VIRT_MACHINE,
+ .parent = TYPE_MACHINE,
+ .instance_size = sizeof(VirtMachineState),
+ .instance_init = virt_instance_init,
+ .class_size = sizeof(VirtMachineClass),
+ .class_init = virt_class_init,
};
static void machvirt_machine_init(void)
{
- qemu_register_machine(&machvirt_a15_machine);
+ type_register_static(&machvirt_info);
}
machine_init(machvirt_machine_init);
diff --git a/hw/arm/xilinx_zynq.c b/hw/arm/xilinx_zynq.c
index b59039297a..06e6e24da1 100644
--- a/hw/arm/xilinx_zynq.c
+++ b/hw/arm/xilinx_zynq.c
@@ -126,6 +126,18 @@ static void zynq_init(MachineState *machine)
cpu = ARM_CPU(object_new(object_class_get_name(cpu_oc)));
+ /* By default A9 CPUs have EL3 enabled. This board does not
+ * currently support EL3 so the CPU EL3 property is disabled before
+ * realization.
+ */
+ if (object_property_find(OBJECT(cpu), "has_el3", NULL)) {
+ object_property_set_bool(OBJECT(cpu), false, "has_el3", &err);
+ if (err) {
+ error_report("%s", error_get_pretty(err));
+ exit(1);
+ }
+ }
+
object_property_set_int(OBJECT(cpu), ZYNQ_BOARD_MIDR, "midr", &err);
if (err) {
error_report("%s", error_get_pretty(err));