This patch allows to boot AA64 linux kernel in SMP mode with DTB generated from 'arch/arm64/boot/dts/rtsm_ve-aemv8a.dts' of Linux kernel source code.
CPU and GIC creation parts are adaptation of code from "hw/arm/virt.c". Signed-off-by: Sergey Fedorov <serge.f...@gmail.com> --- hw/arm/vexpress.c | 137 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 137 insertions(+) diff --git a/hw/arm/vexpress.c b/hw/arm/vexpress.c index 97ccf15..8ab4e8a 100644 --- a/hw/arm/vexpress.c +++ b/hw/arm/vexpress.c @@ -170,6 +170,7 @@ typedef struct { #define TYPE_VEXPRESS_MACHINE "vexpress" #define TYPE_VEXPRESS_A9_MACHINE "vexpress-a9" #define TYPE_VEXPRESS_A15_MACHINE "vexpress-a15" +#define TYPE_FVP_VE_MACHINE "fvp_ve" #define VEXPRESS_MACHINE(obj) \ OBJECT_CHECK(VexpressMachineState, (obj), TYPE_VEXPRESS_MACHINE) #define VEXPRESS_MACHINE_GET_CLASS(obj) \ @@ -430,6 +431,124 @@ static VEDBoardInfo a15_daughterboard = { .init = a15_daughterboard_init, }; +static void fvp_ve_create_gic(const VexpressMachineState *vms, + hwaddr periphbase, qemu_irq *pic) +{ + /* We create a standalone GIC v2 */ + DeviceState *gicdev; + SysBusDevice *gicbusdev; + int i; + + gicdev = qdev_create(NULL, "arm_gic"); + qdev_prop_set_uint32(gicdev, "revision", 2); + qdev_prop_set_uint32(gicdev, "num-cpu", smp_cpus); + qdev_prop_set_uint32(gicdev, "num-irq", 96); + qdev_init_nofail(gicdev); + gicbusdev = SYS_BUS_DEVICE(gicdev); + sysbus_mmio_map(gicbusdev, 0, periphbase + 0x1000); + sysbus_mmio_map(gicbusdev, 1, periphbase + 0x2000); + + /* Wire the outputs from each CPU's generic timer to the + * appropriate GIC PPI inputs, and the GIC's IRQ output to + * the CPU's IRQ input. + */ + for (i = 0; i < smp_cpus; i++) { + DeviceState *cpudev = DEVICE(qemu_get_cpu(i)); + int ppibase = 64 + i * 32; + /* physical timer; we wire it up to the non-secure timer's ID, + * since QEMU doesn't have TrustZone support so far. + */ + qdev_connect_gpio_out(cpudev, 0, + qdev_get_gpio_in(gicdev, ppibase + 30)); + /* virtual timer */ + qdev_connect_gpio_out(cpudev, 1, + qdev_get_gpio_in(gicdev, ppibase + 27)); + + sysbus_connect_irq(gicbusdev, i, qdev_get_gpio_in(cpudev, ARM_CPU_IRQ)); + } + + for (i = 0; i < 64; i++) { + pic[i] = qdev_get_gpio_in(gicdev, i); + } +} + +static void fvp_ve_daughterboard_init(const VexpressMachineState *vms, + ram_addr_t ram_size, + const char *cpu_model, + qemu_irq *pic) +{ + MemoryRegion *sysmem = get_system_memory(); + MemoryRegion *ram = g_new(MemoryRegion, 1); + MemoryRegion *sram = g_new(MemoryRegion, 1); + const hwaddr periphbase = 0x2c000000; + int n; + + if (!cpu_model) { + cpu_model = "cortex-a57"; + } + + { + /* We have to use a separate 64 bit variable here to avoid the gcc + * "comparison is always false due to limited range of data type" + * warning if we are on a host where ram_addr_t is 32 bits. + */ + uint64_t rsz = ram_size; + if (rsz > (30ULL * 1024 * 1024 * 1024)) { + fprintf(stderr, "fvp_ve: cannot model more than 30GB RAM\n"); + exit(1); + } + } + + memory_region_init_ram(ram, NULL, "fvp.highmem", ram_size, &error_abort); + vmstate_register_ram_global(ram); + memory_region_add_subregion(sysmem, 0x80000000, ram); + + for (n = 0; n < smp_cpus; n++) { + ObjectClass *oc = cpu_class_by_name(TYPE_ARM_CPU, cpu_model); + Object *cpuobj; + + if (!oc) { + fprintf(stderr, "Unable to find CPU definition\n"); + exit(1); + } + cpuobj = object_new(object_class_get_name(oc)); + + if (!vms->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); + } + + object_property_set_bool(cpuobj, true, "realized", NULL); + } + + fvp_ve_create_gic(vms, periphbase, pic); + + memory_region_init_ram(sram, NULL, "fvp.sram", 0x10000, &error_abort); + vmstate_register_ram_global(sram); + memory_region_add_subregion(sysmem, 0x2e000000, sram); +} + +static const uint32_t fvp_ve_clocks[] = { + 32000, /* refclk */ + 1000000, /* timclk */ + 24000000, /* apb_pclk */ +}; + +static VEDBoardInfo fvp_ve_daughterboard = { + .motherboard_map = motherboard_aseries_map, + .loader_start = 0x80000000, + .smp_bootreg_addr = 0x8000fff8, + .gic_cpu_if_addr = 0x2c002000, + .num_voltage_sensors = 0, + .num_clocks = ARRAY_SIZE(fvp_ve_clocks), + .clocks = fvp_ve_clocks, + .init = fvp_ve_daughterboard_init, +}; + static int add_virtio_mmio_node(void *fdt, uint32_t acells, uint32_t scells, hwaddr addr, hwaddr size, uint32_t intc, int irq) @@ -772,6 +891,17 @@ static void vexpress_a15_class_init(ObjectClass *oc, void *data) vmc->daughterboard = &a15_daughterboard; } +static void fvp_ve_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + VexpressMachineClass *vmc = VEXPRESS_MACHINE_CLASS(oc); + + mc->name = TYPE_FVP_VE_MACHINE; + mc->desc = "ARM Versatile Express for Cortex-A15"; + + vmc->daughterboard = &fvp_ve_daughterboard; +} + static const TypeInfo vexpress_info = { .name = TYPE_VEXPRESS_MACHINE, .parent = TYPE_MACHINE, @@ -794,11 +924,18 @@ static const TypeInfo vexpress_a15_info = { .class_init = vexpress_a15_class_init, }; +static const TypeInfo fvp_ve_info = { + .name = TYPE_FVP_VE_MACHINE, + .parent = TYPE_VEXPRESS_MACHINE, + .class_init = fvp_ve_class_init, +}; + static void vexpress_machine_init(void) { type_register_static(&vexpress_info); type_register_static(&vexpress_a9_info); type_register_static(&vexpress_a15_info); + type_register_static(&fvp_ve_info); } machine_init(vexpress_machine_init); -- 2.3.4