From: Tobias Röhmel <quic_troh...@quicinc.com> Signed-off-by: Tobias Röhmel <quic_troh...@quicinc.com> --- configs/devices/arm-softmmu/default.mak | 1 + hw/arm/Kconfig | 5 + hw/arm/meson.build | 1 + hw/arm/r52_machine.c | 133 +++++++++++++++ hw/arm/r52_virt.c | 217 ++++++++++++++++++++++++ include/hw/arm/r52_virt.h | 61 +++++++ 6 files changed, 418 insertions(+) create mode 100644 hw/arm/r52_machine.c create mode 100644 hw/arm/r52_virt.c create mode 100644 include/hw/arm/r52_virt.h
diff --git a/configs/devices/arm-softmmu/default.mak b/configs/devices/arm-softmmu/default.mak index 6985a25377..4df0844080 100644 --- a/configs/devices/arm-softmmu/default.mak +++ b/configs/devices/arm-softmmu/default.mak @@ -42,3 +42,4 @@ CONFIG_FSL_IMX6UL=y CONFIG_SEMIHOSTING=y CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y CONFIG_ALLWINNER_H3=y +CONFIG_CORTEX_R52_VIRT=y diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index 219262a8da..72ec0bb656 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -565,3 +565,8 @@ config ARMSSE select UNIMP select SSE_COUNTER select SSE_TIMER + +config CORTEX_R52_VIRT + bool + select ARM_GIC + select PL011 diff --git a/hw/arm/meson.build b/hw/arm/meson.build index 2d8381339c..2a0cdb9c83 100644 --- a/hw/arm/meson.build +++ b/hw/arm/meson.build @@ -43,6 +43,7 @@ arm_ss.add(when: 'CONFIG_STM32F100_SOC', if_true: files('stm32f100_soc.c')) arm_ss.add(when: 'CONFIG_STM32F205_SOC', if_true: files('stm32f205_soc.c')) arm_ss.add(when: 'CONFIG_STM32F405_SOC', if_true: files('stm32f405_soc.c')) arm_ss.add(when: 'CONFIG_XLNX_ZYNQMP_ARM', if_true: files('xlnx-zynqmp.c', 'xlnx-zcu102.c')) +arm_ss.add(when: 'CONFIG_CORTEX_R52_VIRT', if_true: files('r52_virt.c', 'r52_machine.c')) arm_ss.add(when: 'CONFIG_XLNX_VERSAL', if_true: files('xlnx-versal.c', 'xlnx-versal-virt.c')) arm_ss.add(when: 'CONFIG_FSL_IMX25', if_true: files('fsl-imx25.c', 'imx25_pdk.c')) arm_ss.add(when: 'CONFIG_FSL_IMX31', if_true: files('fsl-imx31.c', 'kzm.c')) diff --git a/hw/arm/r52_machine.c b/hw/arm/r52_machine.c new file mode 100644 index 0000000000..33e9764793 --- /dev/null +++ b/hw/arm/r52_machine.c @@ -0,0 +1,133 @@ +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "hw/arm/r52_virt.h" +#include "hw/boards.h" +#include "qemu/error-report.h" +#include "qemu/log.h" +#include "qom/object.h" + +struct r52MachineState { + MachineState parent_obj; + + ArmR52VirtState soc; + + bool secure; + bool virt; + + struct arm_boot_info binfo; +}; + +#define TYPE_R52_MACHINE MACHINE_TYPE_NAME("r52") +OBJECT_DECLARE_SIMPLE_TYPE(r52MachineState, R52_MACHINE) + + +static bool r52_get_secure(Object *obj, Error **errp) +{ + r52MachineState *s = R52_MACHINE(obj); + + return s->secure; +} + +static void r52_set_secure(Object *obj, bool value, Error **errp) +{ + r52MachineState *s = R52_MACHINE(obj); + + s->secure = value; +} + +static bool r52_get_virt(Object *obj, Error **errp) +{ + r52MachineState *s = R52_MACHINE(obj); + + return s->virt; +} + +static void r52_set_virt(Object *obj, bool value, Error **errp) +{ + r52MachineState *s = R52_MACHINE(obj); + + s->virt = value; +} + +static void r52_init(MachineState *machine) +{ + r52MachineState *s = R52_MACHINE(machine); + uint64_t ram_size = machine->ram_size; + + object_initialize_child(OBJECT(machine), "soc", &s->soc, TYPE_ARMR52VIRT); + + object_property_set_bool(OBJECT(&s->soc), "secure", s->secure, + &error_fatal); + object_property_set_bool(OBJECT(&s->soc), "virtualization", s->virt, + &error_fatal); + + qdev_realize(DEVICE(&s->soc), NULL, &error_fatal); + + s->binfo.ram_size = ram_size; + s->binfo.loader_start = 0; + s->binfo.psci_conduit = QEMU_PSCI_CONDUIT_SMC; + arm_load_kernel(s->soc.boot_cpu_ptr, machine, &s->binfo); +} + +static void r52_machine_instance_init(Object *obj) +{ + r52MachineState *s = R52_MACHINE(obj); + + /* Default to secure mode being disabled */ + s->secure = false; + /* Default to virt (EL2) being enabled */ + s->virt = true; +} + +static void r52_machine_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + + mc->desc = "Cortex-R52 platform"; + mc->init = r52_init; + mc->block_default_type = IF_IDE; + mc->units_per_default_bus = 1; + mc->ignore_memory_transaction_failures = true; + mc->max_cpus = ARMR52_VIRT_NUM_APU_CPUS; + mc->default_cpus = ARMR52_VIRT_NUM_APU_CPUS; + + object_class_property_add_bool(oc, "secure", r52_get_secure, + r52_set_secure); + object_class_property_set_description(oc, "secure", + "Set on/off to enable/disable the ARM " + "Security Extensions (TrustZone)"); + + object_class_property_add_bool(oc, "virtualization", r52_get_virt, + r52_set_virt); + object_class_property_set_description(oc, "virtualization", + "Set on/off to enable/disable emulating a " + "guest CPU which implements the ARM " + "Virtualization Extensions"); +} + +static const TypeInfo r52_machine_init_typeinfo = { + .name = TYPE_R52_MACHINE, + .parent = TYPE_MACHINE, + .class_init = r52_machine_class_init, + .instance_init = r52_machine_instance_init, + .instance_size = sizeof(r52MachineState), +}; + +static void r52_machine_init_register_types(void) +{ + type_register_static(&r52_machine_init_typeinfo); +} + +type_init(r52_machine_init_register_types) diff --git a/hw/arm/r52_virt.c b/hw/arm/r52_virt.c new file mode 100644 index 0000000000..edf3dadb0e --- /dev/null +++ b/hw/arm/r52_virt.c @@ -0,0 +1,217 @@ +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu/module.h" +#include "hw/arm/r52_virt.h" +#include "hw/intc/arm_gic_common.h" +#include "hw/misc/unimp.h" +#include "hw/boards.h" +#include "sysemu/kvm.h" +#include "sysemu/sysemu.h" +#include "kvm_arm.h" + +#define GIC_NUM_SPI_INTR 160 + +#define ARM_PHYS_TIMER_PPI 30 +#define ARM_VIRT_TIMER_PPI 27 +#define ARM_HYP_TIMER_PPI 26 +#define ARM_SEC_TIMER_PPI 29 +#define GIC_MAINTENANCE_PPI 25 + +#define GIC_BASE_ADDR 0xaf000000 +#define GIC_REDIST_ADDR 0xaf100000 + +static const uint64_t uart_addr[ARMR52_VIRT_NUM_UARTS] = { + 0x9c090000, +}; + +static const int uart_intr[ARMR52_VIRT_NUM_UARTS] = { + 5, +}; + +static inline int arm_gic_ppi_index(int cpu_nr, int ppi_index) +{ + return GIC_NUM_SPI_INTR + cpu_nr * GIC_INTERNAL + ppi_index; +} + +static void armr52_virt_init(Object *obj) +{ + MachineState *ms = MACHINE(qdev_get_machine()); + ArmR52VirtState *s = ARMR52VIRT(obj); + int i; + int num_apus = MIN(ms->smp.cpus, ARMR52_VIRT_NUM_APU_CPUS); + + object_initialize_child(obj, "apu-cluster", &s->apu_cluster, + TYPE_CPU_CLUSTER); + qdev_prop_set_uint32(DEVICE(&s->apu_cluster), "cluster-id", 0); + + for (i = 0; i < num_apus; i++) { + object_initialize_child(OBJECT(&s->apu_cluster), "apu-cpu[*]", + &s->apu_cpu[i], + ARM_CPU_TYPE_NAME("cortex-r52")); + } + + object_initialize_child(obj, "gic", &s->gic, gicv3_class_name()); + + + for (i = 0; i < ARMR52_VIRT_NUM_UARTS; i++) { + object_initialize_child(obj, "uart[*]", &s->uart[i], + TYPE_PL011); + } +} + +static void armr52_virt_realize(DeviceState *dev, Error **errp) +{ + MachineState *ms = MACHINE(qdev_get_machine()); + ArmR52VirtState *s = ARMR52VIRT(dev); + uint8_t i; + int num_apus = MIN(ms->smp.cpus, ARMR52_VIRT_NUM_APU_CPUS); + const char *boot_cpu = s->boot_cpu ? s->boot_cpu : "apu-cpu[0]"; + qemu_irq gic_spi[GIC_NUM_SPI_INTR]; + Error *err = NULL; + + memory_region_init_ram(&s->ddr_ram, NULL, "armr52virt.dram", 0x04000000, + &error_fatal); + memory_region_add_subregion(get_system_memory(), 0, &s->ddr_ram); + + qdev_prop_set_uint32(DEVICE(&s->gic), "num-irq", NUM_IRQS + 32); + qdev_prop_set_uint32(DEVICE(&s->gic), "revision", 3); + qdev_prop_set_uint32(DEVICE(&s->gic), "num-cpu", num_apus); + qdev_prop_set_bit(DEVICE(&s->gic), "has-security-extensions", false); + qdev_prop_set_uint32(DEVICE(&s->gic), "len-redist-region-count", 1); + qdev_prop_set_uint32(DEVICE(&s->gic), "redist-region-count[0]", num_apus); + + qdev_realize(DEVICE(&s->apu_cluster), NULL, &error_fatal); + + for (i = 0; i < num_apus; i++) { + const char *name; + + name = object_get_canonical_path_component(OBJECT(&s->apu_cpu[i])); + if (strcmp(name, boot_cpu)) { + /* + * Secondary CPUs start in powered-down state. + */ + object_property_set_bool(OBJECT(&s->apu_cpu[i]), + "start-powered-off", true, &error_abort); + } else { + s->boot_cpu_ptr = &s->apu_cpu[i]; + } + + object_property_set_bool(OBJECT(&s->apu_cpu[i]), "has_el3", s->secure, + NULL); + object_property_set_bool(OBJECT(&s->apu_cpu[i]), "has_el2", s->virt, + NULL); + object_property_set_int(OBJECT(&s->apu_cpu[i]), "core-count", + num_apus, &error_abort); + if (!qdev_realize(DEVICE(&s->apu_cpu[i]), NULL, errp)) { + return; + } + } + + if (!sysbus_realize(SYS_BUS_DEVICE(&s->gic), errp)) { + return; + } + + sysbus_mmio_map(SYS_BUS_DEVICE(&s->gic), 0, GIC_BASE_ADDR); + sysbus_mmio_map(SYS_BUS_DEVICE(&s->gic), 1, GIC_REDIST_ADDR); + + for (i = 0; i < num_apus; i++) { + + int ppibase = NUM_IRQS + i * GIC_INTERNAL + GIC_NR_SGIS; + int irq; + /* + * Mapping from the output timer irq lines from the CPU to the + * GIC PPI inputs we use for the virt board. + */ + const int timer_irq[] = { + [GTIMER_PHYS] = ARCH_TIMER_NS_EL1_IRQ, + [GTIMER_VIRT] = ARCH_TIMER_VIRT_IRQ, + [GTIMER_HYP] = ARCH_TIMER_NS_EL2_IRQ, + [GTIMER_SEC] = ARCH_TIMER_S_EL1_IRQ, + }; + + for (irq = 0; irq < ARRAY_SIZE(timer_irq); irq++) { + qdev_connect_gpio_out(DEVICE(&s->apu_cpu[i]), irq, + qdev_get_gpio_in(DEVICE(&s->gic), + ppibase + timer_irq[irq])); + } + + sysbus_connect_irq(SYS_BUS_DEVICE(&s->gic), i, + qdev_get_gpio_in(DEVICE(&s->apu_cpu[i]), + ARM_CPU_IRQ)); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->gic), i + num_apus, + qdev_get_gpio_in(DEVICE(&s->apu_cpu[i]), + ARM_CPU_FIQ)); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->gic), i + num_apus * 2, + qdev_get_gpio_in(DEVICE(&s->apu_cpu[i]), + ARM_CPU_VIRQ)); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->gic), i + num_apus * 3, + qdev_get_gpio_in(DEVICE(&s->apu_cpu[i]), + ARM_CPU_VFIQ)); + } + + if (err) { + error_propagate(errp, err); + return; + } + + if (!s->boot_cpu_ptr) { + error_setg(errp, "Boot cpu %s not found", boot_cpu); + return; + } + + for (i = 0; i < GIC_NUM_SPI_INTR; i++) { + gic_spi[i] = qdev_get_gpio_in(DEVICE(&s->gic), i); + } + + for (i = 0; i < ARMR52_VIRT_NUM_UARTS; i++) { + qdev_prop_set_chr(DEVICE(&s->uart[i]), "chardev", serial_hd(i)); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->uart[i]), errp)) { + return; + } + sysbus_mmio_map(SYS_BUS_DEVICE(&s->uart[i]), 0, uart_addr[i]); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->uart[i]), 0, + gic_spi[uart_intr[i]]); + } + +} + +static Property armr52_virt_props[] = { + DEFINE_PROP_STRING("boot-cpu", ArmR52VirtState, boot_cpu), + DEFINE_PROP_BOOL("secure", ArmR52VirtState, secure, false), + DEFINE_PROP_BOOL("virtualization", ArmR52VirtState, virt, false), +}; + +static void armr52_virt_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + + device_class_set_props(dc, armr52_virt_props); + dc->realize = armr52_virt_realize; +} + +static const TypeInfo armr52_virt_type_info = { + .name = TYPE_ARMR52VIRT, + .parent = TYPE_DEVICE, + .instance_size = sizeof(ArmR52VirtState), + .instance_init = armr52_virt_init, + .class_init = armr52_virt_class_init, +}; + +static void armr52_virt_register_types(void) +{ + type_register_static(&armr52_virt_type_info); +} + +type_init(armr52_virt_register_types) diff --git a/include/hw/arm/r52_virt.h b/include/hw/arm/r52_virt.h new file mode 100644 index 0000000000..0f26745535 --- /dev/null +++ b/include/hw/arm/r52_virt.h @@ -0,0 +1,61 @@ +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#ifndef ARMR52VIRT_H +#define ARMR52VIRT_H + +#include "hw/arm/boot.h" +#include "hw/intc/arm_gic.h" +#include "hw/char/pl011.h" +#include "include/exec/address-spaces.h" +#include "hw/cpu/cluster.h" +#include "target/arm/cpu.h" +#include "qom/object.h" +#include "hw/intc/arm_gicv3_common.h" + +#define TYPE_ARMR52VIRT "armr52virt" +OBJECT_DECLARE_SIMPLE_TYPE(ArmR52VirtState, ARMR52VIRT) + +#define ARMR52_VIRT_NUM_APU_CPUS 4 +#define ARMR52_VIRT_NUM_UARTS 1 +#define ARMR52_VIRT_GIC_REGIONS 6 + +#define ARCH_TIMER_VIRT_IRQ 11 +#define ARCH_TIMER_S_EL1_IRQ 13 +#define ARCH_TIMER_NS_EL1_IRQ 14 +#define ARCH_TIMER_NS_EL2_IRQ 10 +#define NUM_IRQS 256 + +struct ArmR52VirtState { + /*< private >*/ + DeviceState parent_obj; + + /*< public >*/ + CPUClusterState apu_cluster; + ARMCPU apu_cpu[ARMR52_VIRT_NUM_APU_CPUS]; + GICv3State gic; + + MemoryRegion ddr_ram; + + PL011State uart[ARMR52_VIRT_NUM_UARTS]; + + char *boot_cpu; + ARMCPU *boot_cpu_ptr; + + /* Has the ARM Security extensions? */ + bool secure; + /* Has the ARM Virtualization extensions? */ + bool virt; + +}; + +#endif -- 2.25.1