diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2014-12-23 15:05:22 +0000 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2014-12-23 15:05:22 +0000 |
commit | ab0302ee764fd702465aef6d88612cdff4302809 (patch) | |
tree | 4f7ba47706d9e60c5dc731159030280c2cd7b5a9 /hw/arm | |
parent | 03de06dde54df1f64bb099efe22edfa773b16e8e (diff) | |
parent | aa351061dbb0e3054db11c00a69395785c4186c8 (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.c | 98 | ||||
-rw-r--r-- | hw/arm/exynos4210.c | 11 | ||||
-rw-r--r-- | hw/arm/highbank.c | 12 | ||||
-rw-r--r-- | hw/arm/integratorcp.c | 31 | ||||
-rw-r--r-- | hw/arm/realview.c | 12 | ||||
-rw-r--r-- | hw/arm/versatilepb.c | 32 | ||||
-rw-r--r-- | hw/arm/vexpress.c | 141 | ||||
-rw-r--r-- | hw/arm/virt.c | 97 | ||||
-rw-r--r-- | hw/arm/xilinx_zynq.c | 12 |
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)); |