qemu-devel
[Top][All Lists]
Advanced

[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




reply via email to

[Prev in Thread] Current Thread [Next in Thread]