[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH 11/11] hw/arm: Add R52 machine
From: |
Tobias Roehmel |
Subject: |
[PATCH 11/11] hw/arm: Add R52 machine |
Date: |
Thu, 14 Jul 2022 16:53:55 +0200 |
From: Tobias Röhmel <quic_trohmel@quicinc.com>
Signed-off-by: Tobias Röhmel <quic_trohmel@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
- [PATCH 05/11] target/arm: Make stage_2_format for cache attributes optional, (continued)
- [PATCH 05/11] target/arm: Make stage_2_format for cache attributes optional, Tobias Roehmel, 2022/07/14
- [PATCH 03/11] target/arm: Add v8R MIDR register, Tobias Roehmel, 2022/07/14
- [PATCH 07/11] target/arm: Enable TTBCR_EAE for ARM_FEATURE_V8_R, Tobias Roehmel, 2022/07/14
- [PATCH 10/11] target/arm: Make SPSR_hyp accessible for Cortex-R52, Tobias Roehmel, 2022/07/14
- [PATCH 02/11] target/arm: Add ARM Cortex-R52 cpu, Tobias Roehmel, 2022/07/14
- [PATCH 11/11] hw/arm: Add R52 machine,
Tobias Roehmel <=