@@ -22,6 +22,7 @@
#include "hw/core/cpu.h"
#include "qom/object.h"
+#include "qapi/qapi-types-common.h"
struct arm_boot_info;
@@ -182,6 +183,9 @@ struct ARMCPUClass {
* QEMU_KVM_ARM_TARGET_NONE if the kernel doesn't support this CPU type.
*/
uint32_t kvm_target;
+
+ /* CPU has virtualization extension */
+ OnOffAuto has_el2;
};
static inline int arm_class_feature(ARMCPUClass *acc, int feature)
@@ -25,7 +25,6 @@
#include "hw/registerfields.h"
#include "cpu-qom.h"
#include "exec/cpu-defs.h"
-#include "qapi/qapi-types-common.h"
/* ARM processors have a weak memory model */
#define TCG_GUEST_DEFAULT_MO (0)
@@ -887,8 +886,6 @@ struct ArchCPU {
/* Current power state, access guarded by BQL */
ARMPSCIState power_state;
- /* CPU has virtualization extension */
- bool has_el2;
/* CPU has security extension */
bool has_el3;
/* CPU has PMU (Performance Monitor Unit) */
@@ -188,12 +188,16 @@ void allwinner_h3_bootrom_setup(AwH3State *s, BlockBackend *blk)
static void allwinner_h3_init(Object *obj)
{
AwH3State *s = AW_H3(obj);
+ const char *cpu_type = ARM_CPU_TYPE_NAME("cortex-a7");
+ ObjectClass *cpu_class = object_class_by_name(cpu_type);
s->memmap = allwinner_h3_memmap;
+ /* ??? This is the default for A7. */
+ class_property_set_bool(cpu_class, "has_el2", true, &error_abort);
+
for (int i = 0; i < AW_H3_NUM_CPUS; i++) {
- object_initialize_child(obj, "cpu[*]", &s->cpus[i],
- ARM_CPU_TYPE_NAME("cortex-a7"));
+ object_initialize_child(obj, "cpu[*]", &s->cpus[i], cpu_type);
}
object_initialize_child(obj, "gic", &s->gic, TYPE_ARM_GIC);
@@ -244,7 +248,6 @@ static void allwinner_h3_realize(DeviceState *dev, Error **errp)
/* All exception levels required */
qdev_prop_set_bit(DEVICE(&s->cpus[i]), "has_el3", true);
- qdev_prop_set_bit(DEVICE(&s->cpus[i]), "has_el2", true);
/* Mark realized */
qdev_realize(DEVICE(&s->cpus[i]), NULL, &error_fatal);
@@ -208,6 +208,11 @@ static void init_cpus(MachineState *ms, const char *cpu_type,
SysBusDevice *busdev;
int n;
unsigned int smp_cpus = ms->smp.cpus;
+ ObjectClass *cpu_class = object_class_by_name(cpu_type);
+
+ if (!virt) {
+ class_property_set_bool(cpu_class, "has_el2", false, NULL);
+ }
/* Create the actual CPUs */
for (n = 0; n < smp_cpus; n++) {
@@ -216,11 +221,6 @@ static void init_cpus(MachineState *ms, const char *cpu_type,
if (!secure) {
object_property_set_bool(cpuobj, "has_el3", false, NULL);
}
- if (!virt) {
- if (object_property_find(cpuobj, "has_el2")) {
- object_property_set_bool(cpuobj, "has_el2", false, NULL);
- }
- }
if (object_property_find(cpuobj, "reset-cbar")) {
object_property_set_int(cpuobj, "reset-cbar", periphbase,
@@ -2018,6 +2018,7 @@ static void machvirt_init(MachineState *machine)
MemoryRegion *secure_sysmem = NULL;
MemoryRegion *tag_sysmem = NULL;
MemoryRegion *secure_tag_sysmem = NULL;
+ ObjectClass *cpu_class;
int n, virt_max_cpus;
bool firmware_loaded;
bool aarch64 = true;
@@ -2032,6 +2033,16 @@ static void machvirt_init(MachineState *machine)
possible_cpus = mc->possible_cpu_arch_ids(machine);
+ assert(possible_cpus->len == max_cpus);
+ for (n = 0; n < max_cpus; n++) {
+ assert(strcmp(machine->cpu_type, possible_cpus->cpus[n].type) == 0);
+ }
+
+ cpu_class = object_class_by_name(machine->cpu_type);
+ if (!vms->virt) {
+ class_property_set_bool(cpu_class, "has_el2", false, &error_abort);
+ }
+
/*
* In accelerated mode, the memory map is computed earlier in kvm_type()
* to create a VM with the right number of IPA bits.
@@ -2046,7 +2057,7 @@ static void machvirt_init(MachineState *machine)
* we are about to deal with. Once this is done, get rid of
* the object.
*/
- cpuobj = object_new(possible_cpus->cpus[0].type);
+ cpuobj = object_new_with_class(cpu_class);
armcpu = ARM_CPU(cpuobj);
pa_bits = arm_pamax(armcpu);
@@ -2143,8 +2154,7 @@ static void machvirt_init(MachineState *machine)
create_fdt(vms);
- assert(possible_cpus->len == max_cpus);
- for (n = 0; n < possible_cpus->len; n++) {
+ for (n = 0; n < max_cpus; n++) {
Object *cpuobj;
CPUState *cs;
@@ -2152,7 +2162,7 @@ static void machvirt_init(MachineState *machine)
break;
}
- cpuobj = object_new(possible_cpus->cpus[n].type);
+ cpuobj = object_new_with_class(cpu_class);
object_property_set_int(cpuobj, "mp-affinity",
possible_cpus->cpus[n].arch_id, NULL);
@@ -2168,10 +2178,6 @@ static void machvirt_init(MachineState *machine)
object_property_set_bool(cpuobj, "has_el3", false, NULL);
}
- if (!vms->virt && object_property_find(cpuobj, "has_el2")) {
- object_property_set_bool(cpuobj, "has_el2", false, NULL);
- }
-
if (vmc->kvm_no_adjvtime &&
object_property_find(cpuobj, "kvm-no-adjvtime")) {
object_property_set_bool(cpuobj, "kvm-no-adjvtime", true, NULL);
@@ -385,6 +385,7 @@ static void xlnx_zynqmp_init(Object *obj)
cpu_type = ARM_CPU_TYPE_NAME("cortex-a53");
cpu_class = object_class_by_name(cpu_type);
class_property_set_bool(cpu_class, "reset-hivecs", true, &error_abort);
+ class_property_set_bool(cpu_class, "has_el2", s->virt, &error_abort);
for (i = 0; i < num_apus; i++) {
object_initialize_child(OBJECT(&s->apu_cluster), "apu-cpu[*]",
@@ -529,8 +530,6 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
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]), "reset-cbar",
GIC_BASE_ADDR, &error_abort);
object_property_set_int(OBJECT(&s->apu_cpu[i]), "core-count",
@@ -55,7 +55,6 @@ static void a15mp_priv_realize(DeviceState *dev, Error **errp)
int i;
bool has_el3;
bool has_el2 = false;
- Object *cpuobj;
gicdev = DEVICE(&s->gic);
qdev_prop_set_uint32(gicdev, "num-cpu", s->num_cpu);
@@ -65,13 +64,15 @@ static void a15mp_priv_realize(DeviceState *dev, Error **errp)
/* Make the GIC's TZ support match the CPUs. We assume that
* either all the CPUs have TZ, or none do.
*/
- cpuobj = OBJECT(qemu_get_cpu(0));
+ Object *cpuobj = OBJECT(qemu_get_cpu(0));
+ ObjectClass *cpucls = object_get_class(cpuobj);
+
has_el3 = object_property_find(cpuobj, "has_el3") &&
object_property_get_bool(cpuobj, "has_el3", &error_abort);
qdev_prop_set_bit(gicdev, "has-security-extensions", has_el3);
+
/* Similarly for virtualization support */
- has_el2 = object_property_find(cpuobj, "has_el2") &&
- object_property_get_bool(cpuobj, "has_el2", &error_abort);
+ has_el2 = class_property_get_bool(cpucls, "has_el2", NULL);
qdev_prop_set_bit(gicdev, "has-virtualization-extensions", has_el2);
}
@@ -1281,9 +1281,6 @@ static Property arm_cpu_reset_cbar_property =
DEFINE_PROP_UINT64("reset-cbar", ARMCPU, reset_cbar, 0);
#ifndef CONFIG_USER_ONLY
-static Property arm_cpu_has_el2_property =
- DEFINE_PROP_BOOL("has_el2", ARMCPU, has_el2, true);
-
static Property arm_cpu_has_el3_property =
DEFINE_PROP_BOOL("has_el3", ARMCPU, has_el3, true);
#endif
@@ -1391,10 +1388,6 @@ static void arm_cpu_post_init(Object *obj)
qdev_prop_allow_set_link_before_realize,
OBJ_PROP_LINK_STRONG);
}
-
- if (arm_feature(&cpu->env, ARM_FEATURE_EL2)) {
- qdev_property_add_static(DEVICE(obj), &arm_cpu_has_el2_property);
- }
#endif
if (arm_feature(&cpu->env, ARM_FEATURE_PMU)) {
@@ -1818,10 +1811,6 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
ID_AA64PFR0, EL3, 0);
}
- if (!cpu->has_el2) {
- unset_feature(env, ARM_FEATURE_EL2);
- }
-
if (!cpu->has_pmu) {
unset_feature(env, ARM_FEATURE_PMU);
}
@@ -2159,6 +2148,34 @@ static bool arm_class_prop_uint64_ofs(ObjectClass *oc, Visitor *v,
}
#ifndef CONFIG_USER_ONLY
+static bool arm_class_prop_get_auto_ofs(ObjectClass *oc, Visitor *v,
+ const char *name, void *opaque,
+ Error **errp)
+{
+ ARMCPUClass *acc = ARM_CPU_CLASS(oc);
+ uintptr_t ofs = (uintptr_t)opaque;
+ OnOffAuto *ptr = (void *)acc + ofs;
+ bool val = *ptr == ON_OFF_AUTO_ON;
+
+ return visit_type_bool(v, name, &val, errp);
+}
+
+static bool arm_class_prop_set_auto_ofs(ObjectClass *oc, Visitor *v,
+ const char *name, void *opaque,
+ Error **errp)
+{
+ ARMCPUClass *acc = ARM_CPU_CLASS(oc);
+ uintptr_t ofs = (uintptr_t)opaque;
+ OnOffAuto *ptr = (void *)acc + ofs;
+ bool val;
+
+ if (visit_type_bool(v, name, &val, errp)) {
+ *ptr = val ? ON_OFF_AUTO_ON : ON_OFF_AUTO_OFF;
+ return true;
+ }
+ return false;
+}
+
static bool arm_class_prop_set_sctlrbit(ObjectClass *oc, Visitor *v,
const char *name, void *opaque,
Error **errp)
@@ -2334,6 +2351,19 @@ static void arm_cpu_leaf_class_init(ObjectClass *oc, void *data)
arm_class_prop_set_sctlrbit,
(void *)((uintptr_t)1 << 13));
}
+
+ /*
+ * With v8, we cannot yet tell if EL[23] are available, because
+ * we do not yet know if we're using tcg or host acceleration.
+ * We will reject incorrect settings during class_late_init.
+ */
+ if (arm_class_feature(acc, ARM_FEATURE_EL2) ||
+ arm_class_feature(acc, ARM_FEATURE_V8)) {
+ class_property_add(oc, "has_el2", "bool", NULL,
+ arm_class_prop_get_auto_ofs,
+ arm_class_prop_set_auto_ofs,
+ (void *)(uintptr_t)offsetof(ARMCPUClass, has_el2));
+ }
#endif /* !CONFIG_USER_ONLY */
}
@@ -2353,6 +2383,28 @@ static bool arm_cpu_class_late_init(ObjectClass *oc, Error **errp)
error_setg(errp, "Invalid CNTFRQ: %"PRId64"Hz", acc->gt_cntfrq_hz);
return false;
}
+
+ switch (acc->has_el2) {
+ case ON_OFF_AUTO_AUTO:
+ acc->has_el2 = (arm_class_feature(acc, ARM_FEATURE_EL2)
+ ? ON_OFF_AUTO_ON : ON_OFF_AUTO_OFF);
+ break;
+ case ON_OFF_AUTO_OFF:
+ unset_class_feature(acc, ARM_FEATURE_EL2);
+ acc->isar.id_pfr1 = FIELD_DP32(acc->isar.id_pfr1, ID_PFR1,
+ VIRTUALIZATION, 0);
+ acc->isar.id_aa64pfr0 = FIELD_DP64(acc->isar.id_aa64pfr0,
+ ID_AA64PFR0, EL2, 0);
+ break;
+ case ON_OFF_AUTO_ON:
+ if (!arm_class_feature(acc, ARM_FEATURE_EL2)) {
+ error_setg(errp, "CPU does not support EL2");
+ return false;
+ }
+ break;
+ default:
+ g_assert_not_reached();
+ }
#endif /* !CONFIG_USER_ONLY */
/* Run some consistency checks for TCG. */
With the movement of the property, we can remove the field from the cpu entirely, using only the class. However, late initialization of the "max" cpu, due to its interaction with "host", means that we cannot leave the class property undefined when EL2 is not supported. Adjust the class field to OnOffAuto and generate an error if enabled when not supported. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- target/arm/cpu-qom.h | 4 +++ target/arm/cpu.h | 3 -- hw/arm/allwinner-h3.c | 9 ++++-- hw/arm/vexpress.c | 10 +++--- hw/arm/virt.c | 22 ++++++++----- hw/arm/xlnx-zynqmp.c | 3 +- hw/cpu/a15mpcore.c | 9 +++--- target/arm/cpu.c | 74 ++++++++++++++++++++++++++++++++++++------- 8 files changed, 98 insertions(+), 36 deletions(-)