All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC PATCH 00/40] Toward class init of cpu features
@ 2023-01-03 18:16 Richard Henderson
  2023-01-03 18:16 ` [RFC PATCH 01/40] qdev: Don't always force the global property array non-null Richard Henderson
                   ` (41 more replies)
  0 siblings, 42 replies; 77+ messages in thread
From: Richard Henderson @ 2023-01-03 18:16 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, berrange, eduardo, armbru, ajones, alex.bennee

The specific problem I'm trying to solve is the location and
representation of the coprocessor register hash table for ARM cpus,
but in the process affects how cpu initialization might be done for
all targets.

At present, each cpu (for all targets) is initialized separately.
For some, like ARM, we apply QOM properties and then build a hash
table of all coprocessor regs that are valid for the cpu.  For others,
like m68k and ppc, we build tables of all valid instructions
(ppc is slowly moving away from constructed tables to decodetree,
but the migration is not complete).

Importantly, this happens N times for smp system emulation, for each
cpu instance, meaning we do N times the work on startup as necessary.
For system emulation this isn't so bad, as N is generally small-ish,
but it certainly could be improved.

More importantly, this happens for each thread in user-only emulation.
This is much more significant because threads can be short-lived, and
there can be many hundreds of them, each one performing what amounts
to redundant initialization.

The "obvious" solution is to make better use of the cpu class object.
Construct data structures once to be shared with all instances.

The immediate problem encountered here is that of QOM properties,
which are used to control how each object is configured.

The first couple of patches here create a new QOM "class property",
which is sufficient to allow command-line parameters to find their
way to the correct bit of code to interpret them.  (Pardon the
roughness in these patches, RFC and all.)  The restriction I add 
here is that all class properties must be applied before the first
object is created, which gives for a definite point at which the
properties must have be applied and we can construct data structures
based on those values.

However, I wind up banging my head against the wall later, when it
comes to the first qmp_query_cpu_model_expansion properties.  This
wants to create an object, apply properties, and see what stuck.
Adding a query of the class properties is fine, but I can't set any
of them because of the object creation.  And if I tweak the location
of the class property set vs the object create, that only allows the
first such probe to succeed, because the second will still have had
an object created.

I can imagine a way out of this, e.g. by keeping a ref count of the
number of instantiated objects, and allowing class properties to change 
when that count is zero.  But it feels like I really should know what
QMP is attempting to do here, rather than work around it blindly.


r~


Richard Henderson (40):
  qdev: Don't always force the global property array non-null
  qom: Introduce class_late_init
  qom: Create class properties
  target/arm: Remove aarch64_cpu_finalizefn
  target/arm: Create arm_cpu_register_parent
  target/arm: Remove AArch64CPUClass
  target/arm: Create TYPE_ARM_V7M_CPU
  target/arm: Pass ARMCPUClass to ARMCPUInfo.class_init
  target/arm: Utilize arm-cpu instance_post_init hook
  target/arm: Copy dtb_compatible from ARMCPUClass
  target/arm: Copy features from ARMCPUClass
  target/arm: Copy isar and friends from ARMCPUClass
  hw/arm/bcm2836: Set mp-affinity property in realize
  target/arm: Rename arm_cpu_mp_affinity
  target/arm: Create arm_cpu_mp_affinity
  target/arm: Represent the entire MPIDR_EL1
  target/arm: Copy cp_regs from ARMCPUClass
  target/arm: Create cpreg definition functions with GHashTable arg
  target/arm: Move most cpu initialization to the class
  target/arm: Merge kvm64.c with kvm.c
  target/arm: Remove aarch64 check from aarch64_host_object_init
  target/arm: Hoist feature and dtb_compatible from KVM, HVF
  target/arm: Probe KVM host into ARMCPUClass
  target/arm/hvf: Probe host into ARMCPUClass
  target/arm/hvf: Use offsetof in hvf_arm_get_host_cpu_features
  target/arm: Rename 'cpu' to 'acc' in class init functions
  target/arm: Split out strongarm_class_init
  target/arm: Split out xscale*_class_init
  target/arm: Remove m-profile has_vfp and has_dsp properties
  target/arm: Move feature bit propagation to class init
  target/arm: Get and set class properties in the monitor
  target/arm: Move "midr" to class property
  target/arm: Move "cntfrq" to class property
  target/arm: Move "reset-hivecs" to class property
  target/arm: Move "has_el2" to class property
  target/arm: Move "has_el3" to class property
  target/arm: Move "cfgend" to class property
  target/arm: Move "vfp" and "neon" to class properties
  target/arm: Move "has-mpu" and "pmsav7-dregion" to class properties
  target/arm: Move "pmu" to class property

 hw/core/qdev-prop-internal.h |    2 +
 include/hw/arm/armsse.h      |    3 +-
 include/hw/arm/armv7m.h      |    2 -
 include/qom/object.h         |   67 ++
 include/qom/qom-qobject.h    |   28 +
 target/arm/cpregs.h          |   33 +-
 target/arm/cpu-qom.h         |  171 ++-
 target/arm/cpu.h             |   89 +-
 target/arm/hvf_arm.h         |    2 +-
 target/arm/internals.h       |    6 +-
 target/arm/kvm_arm.h         |  217 +---
 hw/arm/allwinner-h3.c        |   14 +-
 hw/arm/armsse.c              |   53 +-
 hw/arm/armv7m.c              |   12 -
 hw/arm/aspeed_ast2600.c      |    9 +-
 hw/arm/bcm2836.c             |    7 +-
 hw/arm/digic.c               |   11 +-
 hw/arm/exynos4210.c          |   18 +-
 hw/arm/integratorcp.c        |   12 +-
 hw/arm/musca.c               |   14 +-
 hw/arm/npcm7xx.c             |   16 +-
 hw/arm/realview.c            |   20 +-
 hw/arm/sbsa-ref.c            |    2 +-
 hw/arm/versatilepb.c         |   12 +-
 hw/arm/vexpress.c            |   19 +-
 hw/arm/virt-acpi-build.c     |    2 +-
 hw/arm/virt.c                |   47 +-
 hw/arm/xilinx_zynq.c         |   15 +-
 hw/arm/xlnx-versal-virt.c    |    3 +-
 hw/arm/xlnx-zynqmp.c         |   17 +-
 hw/core/cpu-common.c         |   61 +-
 hw/core/qdev-properties.c    |   79 +-
 hw/core/qdev.c               |    2 +
 hw/cpu/a15mpcore.c           |   14 +-
 hw/cpu/a9mpcore.c            |    6 +-
 hw/intc/armv7m_nvic.c        |    2 +-
 hw/misc/xlnx-versal-crl.c    |    4 +-
 qom/object.c                 |  249 ++++-
 qom/object_interfaces.c      |   13 +
 qom/qom-qmp-cmds.c           |   37 +
 target/arm/arm-powerctl.c    |    2 +-
 target/arm/cpu.c             | 1195 +++++++++++---------
 target/arm/cpu64.c           | 1014 +++++++++--------
 target/arm/cpu_tcg.c         | 1486 +++++++++++++------------
 target/arm/helper.c          |   96 +-
 target/arm/hvf/hvf.c         |   94 +-
 target/arm/kvm.c             | 2006 +++++++++++++++++++++++++++++++---
 target/arm/kvm64.c           | 1632 ---------------------------
 target/arm/monitor.c         |   21 +-
 target/arm/psci.c            |    2 +-
 target/arm/meson.build       |    2 +-
 51 files changed, 4765 insertions(+), 4175 deletions(-)
 delete mode 100644 target/arm/kvm64.c

-- 
2.34.1



^ permalink raw reply	[flat|nested] 77+ messages in thread

* [RFC PATCH 01/40] qdev: Don't always force the global property array non-null
  2023-01-03 18:16 [RFC PATCH 00/40] Toward class init of cpu features Richard Henderson
@ 2023-01-03 18:16 ` Richard Henderson
  2023-01-05 21:56   ` Philippe Mathieu-Daudé
  2023-01-03 18:16 ` [RFC PATCH 02/40] qom: Introduce class_late_init Richard Henderson
                   ` (40 subsequent siblings)
  41 siblings, 1 reply; 77+ messages in thread
From: Richard Henderson @ 2023-01-03 18:16 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, berrange, eduardo, armbru, ajones, alex.bennee

Only qdev_prop_register_global requires a non-null array.
The other instances can simply exit early.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 hw/core/qdev-properties.c | 43 ++++++++++++++++++++++++---------------
 1 file changed, 27 insertions(+), 16 deletions(-)

diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c
index 357b8761b5..f7775d0ea4 100644
--- a/hw/core/qdev-properties.c
+++ b/hw/core/qdev-properties.c
@@ -739,29 +739,31 @@ void qdev_prop_set_enum(DeviceState *dev, const char *name, int value)
                             &error_abort);
 }
 
-static GPtrArray *global_props(void)
-{
-    static GPtrArray *gp;
-
-    if (!gp) {
-        gp = g_ptr_array_new();
-    }
-
-    return gp;
-}
+static GPtrArray *global_properties;
 
 void qdev_prop_register_global(GlobalProperty *prop)
 {
-    g_ptr_array_add(global_props(), prop);
+    GPtrArray *props = global_properties;
+
+    if (!props) {
+        props = g_ptr_array_new();
+        global_properties = props;
+    }
+
+    g_ptr_array_add(props, prop);
 }
 
 const GlobalProperty *qdev_find_global_prop(Object *obj,
                                             const char *name)
 {
-    GPtrArray *props = global_props();
+    GPtrArray *props = global_properties;
     const GlobalProperty *p;
     int i;
 
+    if (!props) {
+        return NULL;
+    }
+
     for (i = 0; i < props->len; i++) {
         p = g_ptr_array_index(props, i);
         if (object_dynamic_cast(obj, p->driver)
@@ -774,14 +776,19 @@ const GlobalProperty *qdev_find_global_prop(Object *obj,
 
 int qdev_prop_check_globals(void)
 {
+    GPtrArray *props = global_properties;
     int i, ret = 0;
 
-    for (i = 0; i < global_props()->len; i++) {
+    if (!props) {
+        return 0;
+    }
+
+    for (i = 0; i < props->len; i++) {
         GlobalProperty *prop;
         ObjectClass *oc;
         DeviceClass *dc;
 
-        prop = g_ptr_array_index(global_props(), i);
+        prop = g_ptr_array_index(props, i);
         if (prop->used) {
             continue;
         }
@@ -806,8 +813,12 @@ int qdev_prop_check_globals(void)
 
 void qdev_prop_set_globals(DeviceState *dev)
 {
-    object_apply_global_props(OBJECT(dev), global_props(),
-                              dev->hotplugged ? NULL : &error_fatal);
+    GPtrArray *props = global_properties;
+
+    if (props) {
+        object_apply_global_props(OBJECT(dev), props,
+                                  dev->hotplugged ? NULL : &error_fatal);
+    }
 }
 
 /* --- 64bit unsigned int 'size' type --- */
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* [RFC PATCH 02/40] qom: Introduce class_late_init
  2023-01-03 18:16 [RFC PATCH 00/40] Toward class init of cpu features Richard Henderson
  2023-01-03 18:16 ` [RFC PATCH 01/40] qdev: Don't always force the global property array non-null Richard Henderson
@ 2023-01-03 18:16 ` Richard Henderson
  2023-01-03 18:16 ` [RFC PATCH 03/40] qom: Create class properties Richard Henderson
                   ` (39 subsequent siblings)
  41 siblings, 0 replies; 77+ messages in thread
From: Richard Henderson @ 2023-01-03 18:16 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, berrange, eduardo, armbru, ajones, alex.bennee

Create a new class initialization hook, to be called immediately
before creation of the first instance.  Most class initialization
happens quite early, which makes interaction between classes
difficult.  E.g. cpu objects often depend on the accellerator,
or the global properties coming from the command-line.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 include/qom/object.h |  4 ++++
 qom/object.c         | 55 +++++++++++++++++++++++++++++++++++++-------
 2 files changed, 51 insertions(+), 8 deletions(-)

diff --git a/include/qom/object.h b/include/qom/object.h
index ef7258a5e1..86958abe15 100644
--- a/include/qom/object.h
+++ b/include/qom/object.h
@@ -402,6 +402,9 @@ struct Object
  *   parent class initialization has occurred, but before the class itself
  *   is initialized.  This is the function to use to undo the effects of
  *   memcpy from the parent class to the descendants.
+ * @class_late_init: This function is called for all base classes just
+ *   before the first object is created.  This is the function to use to
+ *   apply properties (which are interpreted quite late).
  * @class_data: Data to pass to the @class_init,
  *   @class_base_init. This can be useful when building dynamic
  *   classes.
@@ -425,6 +428,7 @@ struct TypeInfo
 
     void (*class_init)(ObjectClass *klass, void *data);
     void (*class_base_init)(ObjectClass *klass, void *data);
+    bool (*class_late_init)(ObjectClass *klass, Error **errp);
     void *class_data;
 
     InterfaceInfo *interfaces;
diff --git a/qom/object.c b/qom/object.c
index e25f1e96db..82a5c7d36e 100644
--- a/qom/object.c
+++ b/qom/object.c
@@ -56,6 +56,7 @@ struct TypeImpl
 
     void (*class_init)(ObjectClass *klass, void *data);
     void (*class_base_init)(ObjectClass *klass, void *data);
+    bool (*class_late_init)(ObjectClass *klass, Error **errp);
 
     void *class_data;
 
@@ -64,6 +65,7 @@ struct TypeImpl
     void (*instance_finalize)(Object *obj);
 
     bool abstract;
+    bool object_created;
 
     const char *parent;
     TypeImpl *parent_type;
@@ -121,6 +123,7 @@ static TypeImpl *type_new(const TypeInfo *info)
 
     ti->class_init = info->class_init;
     ti->class_base_init = info->class_base_init;
+    ti->class_late_init = info->class_late_init;
     ti->class_data = info->class_data;
 
     ti->instance_init = info->instance_init;
@@ -367,6 +370,26 @@ static void type_initialize(TypeImpl *ti)
     }
 }
 
+static bool type_late_initialize(TypeImpl *ti, ObjectClass *cls, Error **errp)
+{
+    TypeImpl *pi = type_get_parent(ti);
+    if (pi && !type_late_initialize(pi, cls, errp)) {
+        return false;
+    }
+
+    for (GSList *e = ti->class->interfaces; e ; e = e->next) {
+        InterfaceClass *ic = e->data;
+        if (!type_late_initialize(ic->interface_type, cls, errp)) {
+            return false;
+        }
+    }
+
+    if (ti->class_late_init) {
+        return ti->class_late_init(cls, errp);
+    }
+    return true;
+}
+
 static void object_init_with_type(Object *obj, TypeImpl *ti)
 {
     if (type_has_parent(ti)) {
@@ -502,7 +525,8 @@ static void object_class_property_init_all(Object *obj)
     }
 }
 
-static void object_initialize_with_type(Object *obj, size_t size, TypeImpl *type)
+static bool object_initialize_with_type(Object *obj, size_t size,
+                                        TypeImpl *type, Error **errp)
 {
     type_initialize(type);
 
@@ -510,6 +534,13 @@ static void object_initialize_with_type(Object *obj, size_t size, TypeImpl *type
     g_assert(type->abstract == false);
     g_assert(size >= type->instance_size);
 
+    if (!type->object_created) {
+        type->object_created = true;
+        if (!type_late_initialize(type, type->class, errp)) {
+            return false;
+        }
+    }
+
     memset(obj, 0, type->instance_size);
     obj->class = type->class;
     object_ref(obj);
@@ -518,6 +549,7 @@ static void object_initialize_with_type(Object *obj, size_t size, TypeImpl *type
                                             NULL, object_property_free);
     object_init_with_type(obj, type);
     object_post_init_with_type(obj, type);
+    return true;
 }
 
 void object_initialize(void *data, size_t size, const char *typename)
@@ -540,7 +572,7 @@ void object_initialize(void *data, size_t size, const char *typename)
         abort();
     }
 
-    object_initialize_with_type(data, size, type);
+    object_initialize_with_type(data, size, type, &error_fatal);
 }
 
 bool object_initialize_child_with_props(Object *parentobj,
@@ -712,7 +744,7 @@ typedef union {
 } qemu_max_align_t;
 #endif
 
-static Object *object_new_with_type(Type type)
+static Object *object_new_with_type(Type type, Error **errp)
 {
     Object *obj;
     size_t size, align;
@@ -736,22 +768,25 @@ static Object *object_new_with_type(Type type)
         obj_free = qemu_vfree;
     }
 
-    object_initialize_with_type(obj, size, type);
-    obj->free = obj_free;
+    if (!object_initialize_with_type(obj, size, type, errp)) {
+        obj_free(obj);
+        return NULL;
+    }
 
+    obj->free = obj_free;
     return obj;
 }
 
 Object *object_new_with_class(ObjectClass *klass)
 {
-    return object_new_with_type(klass->type);
+    return object_new_with_type(klass->type, &error_fatal);
 }
 
 Object *object_new(const char *typename)
 {
     TypeImpl *ti = type_get_by_name(typename);
 
-    return object_new_with_type(ti);
+    return object_new_with_type(ti, &error_fatal);
 }
 
 
@@ -792,7 +827,11 @@ Object *object_new_with_propv(const char *typename,
         error_setg(errp, "object type '%s' is abstract", typename);
         return NULL;
     }
-    obj = object_new_with_type(klass->type);
+
+    obj = object_new_with_type(klass->type, errp);
+    if (!obj) {
+        return NULL;
+    }
 
     if (!object_set_propv(obj, errp, vargs)) {
         goto error;
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* [RFC PATCH 03/40] qom: Create class properties
  2023-01-03 18:16 [RFC PATCH 00/40] Toward class init of cpu features Richard Henderson
  2023-01-03 18:16 ` [RFC PATCH 01/40] qdev: Don't always force the global property array non-null Richard Henderson
  2023-01-03 18:16 ` [RFC PATCH 02/40] qom: Introduce class_late_init Richard Henderson
@ 2023-01-03 18:16 ` Richard Henderson
  2023-01-03 18:16 ` [RFC PATCH 04/40] target/arm: Remove aarch64_cpu_finalizefn Richard Henderson
                   ` (38 subsequent siblings)
  41 siblings, 0 replies; 77+ messages in thread
From: Richard Henderson @ 2023-01-03 18:16 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, berrange, eduardo, armbru, ajones, alex.bennee

These properties apply to the class itself, as opposed to
object_class_property_* in which the property is attached
to the class but applies to each object instance.

Apply global properties via a class_late_init on DeviceClass.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 hw/core/qdev-prop-internal.h |   2 +
 include/qom/object.h         |  63 ++++++++++++
 include/qom/qom-qobject.h    |  28 +++++
 hw/core/cpu-common.c         |  61 ++++++++---
 hw/core/qdev-properties.c    |  36 +++++++
 hw/core/qdev.c               |   2 +
 qom/object.c                 | 194 +++++++++++++++++++++++++++++++++++
 qom/object_interfaces.c      |  13 +++
 qom/qom-qmp-cmds.c           |  37 +++++++
 9 files changed, 419 insertions(+), 17 deletions(-)

diff --git a/hw/core/qdev-prop-internal.h b/hw/core/qdev-prop-internal.h
index d7b77844fe..21cd3bca27 100644
--- a/hw/core/qdev-prop-internal.h
+++ b/hw/core/qdev-prop-internal.h
@@ -25,4 +25,6 @@ void qdev_propinfo_get_int32(Object *obj, Visitor *v, const char *name,
 void qdev_propinfo_get_size32(Object *obj, Visitor *v, const char *name,
                               void *opaque, Error **errp);
 
+bool device_class_late_init(ObjectClass *class, Error **errp);
+
 #endif
diff --git a/include/qom/object.h b/include/qom/object.h
index 86958abe15..caa4774f80 100644
--- a/include/qom/object.h
+++ b/include/qom/object.h
@@ -27,8 +27,25 @@ typedef struct InterfaceInfo InterfaceInfo;
 
 #define TYPE_OBJECT "object"
 
+typedef struct ClassProperty ClassProperty;
 typedef struct ObjectProperty ObjectProperty;
 
+/**
+ * typedef ClassPropertyAccessor:
+ * @klass: the class that owns the property
+ * @v: the visitor that contains the property data
+ * @name: the name of the property
+ * @opaque: the class property opaque
+ * @errp: a pointer to an Error that is filled if getting/setting fails.
+ *
+ * Called when trying to get/set a property.
+ */
+typedef bool (ClassPropertyAccessor)(ObjectClass *klass,
+                                     Visitor *v,
+                                     const char *name,
+                                     void *opaque,
+                                     Error **errp);
+
 /**
  * typedef ObjectPropertyAccessor:
  * @obj: the object that owns the property
@@ -85,6 +102,16 @@ typedef void (ObjectPropertyRelease)(Object *obj,
  */
 typedef void (ObjectPropertyInit)(Object *obj, ObjectProperty *prop);
 
+struct ClassProperty
+{
+    char *name;
+    char *type;
+    char *description;
+    ClassPropertyAccessor *get;
+    ClassPropertyAccessor *set;
+    void *opaque;
+};
+
 struct ObjectProperty
 {
     char *name;
@@ -135,6 +162,7 @@ struct ObjectClass
 
     ObjectUnparent *unparent;
 
+    GHashTable *class_properties;
     GHashTable *properties;
 };
 
@@ -1072,6 +1100,11 @@ ObjectProperty *object_property_add(Object *obj, const char *name,
 
 void object_property_del(Object *obj, const char *name);
 
+/**
+ * object_class_property_add:
+ *
+ * Add a property to the class, as if added to each object instance.
+ */
 ObjectProperty *object_class_property_add(ObjectClass *klass, const char *name,
                                           const char *type,
                                           ObjectPropertyAccessor *get,
@@ -1079,6 +1112,33 @@ ObjectProperty *object_class_property_add(ObjectClass *klass, const char *name,
                                           ObjectPropertyRelease *release,
                                           void *opaque);
 
+/**
+ * class_property_add:
+ *
+ * Add a property to the class, affecting the class as a whole
+ * rather than each instance.  All such properties are resolved
+ * before the first object instance is created.
+ */
+void class_property_add(ObjectClass *klass, const char *name,
+                        const char *type, const char *desc,
+                        ClassPropertyAccessor *get,
+                        ClassPropertyAccessor *set,
+                        void *opaque);
+
+ClassProperty *class_property_find(ObjectClass *klass, const char *name);
+
+bool class_property_set(ObjectClass *klass, ClassProperty *cp,
+                        Visitor *v, Error **errp);
+bool class_property_set_bool(ObjectClass *klass, const char *name,
+                             bool value, Error **errp);
+bool class_property_set_uint(ObjectClass *klass, const char *name,
+                             uint64_t value, Error **errp);
+
+bool class_property_get(ObjectClass *klass, ClassProperty *cp,
+                        Visitor *v, Error **errp);
+bool class_property_get_bool(ObjectClass *klass, const char *name,
+                             Error **errp);
+
 /**
  * object_property_set_default_bool:
  * @prop: the property to set
@@ -1229,6 +1289,9 @@ void object_class_property_iter_init(ObjectPropertyIterator *iter,
  */
 ObjectProperty *object_property_iter_next(ObjectPropertyIterator *iter);
 
+void class_property_iter_init(ObjectPropertyIterator *iter, ObjectClass *klass);
+ClassProperty *class_property_iter_next(ObjectPropertyIterator *iter);
+
 void object_unparent(Object *obj);
 
 /**
diff --git a/include/qom/qom-qobject.h b/include/qom/qom-qobject.h
index 73e4e0e474..4026fe6964 100644
--- a/include/qom/qom-qobject.h
+++ b/include/qom/qom-qobject.h
@@ -40,4 +40,32 @@ bool object_property_set_qobject(Object *obj,
                                  const char *name, struct QObject *value,
                                  struct Error **errp);
 
+/*
+ * class_property_get_qobject:
+ * @cls: the class object
+ * @name: the name of the property
+ * @errp: returns an error if this function fails
+ *
+ * Returns: the value of the property, converted to QObject, or NULL if
+ * an error occurs.
+ */
+struct QObject *class_property_get_qobject(ObjectClass *cls,
+                                           const char *name,
+                                           struct Error **errp);
+
+/**
+ * class_property_set_qobject:
+ * @cls: the class object
+ * @name: the name of the property
+ * @value: The value that will be written to the property.
+ * @errp: returns an error if this function fails
+ *
+ * Writes a property to a class object.
+ *
+ * Returns: %true on success, %false on failure.
+ */
+bool class_property_set_qobject(ObjectClass *cls,
+                                const char *name, struct QObject *value,
+                                struct Error **errp);
+
 #endif
diff --git a/hw/core/cpu-common.c b/hw/core/cpu-common.c
index 78b5f350a0..34cab4ef31 100644
--- a/hw/core/cpu-common.c
+++ b/hw/core/cpu-common.c
@@ -34,6 +34,7 @@
 #include "hw/qdev-properties.h"
 #include "trace/trace-root.h"
 #include "qemu/plugin.h"
+#include "qapi/string-input-visitor.h"
 
 CPUState *cpu_by_arch_id(int64_t id)
 {
@@ -158,31 +159,57 @@ ObjectClass *cpu_class_by_name(const char *typename, const char *cpu_model)
 static void cpu_common_parse_features(const char *typename, char *features,
                                       Error **errp)
 {
-    char *val;
     static bool cpu_globals_initialized;
-    /* Single "key=value" string being parsed */
-    char *featurestr = features ? strtok(features, ",") : NULL;
+    ObjectClass *klass;
+    char *f;
 
     /* should be called only once, catch invalid users */
     assert(!cpu_globals_initialized);
     cpu_globals_initialized = true;
 
-    while (featurestr) {
-        val = strchr(featurestr, '=');
-        if (val) {
-            GlobalProperty *prop = g_new0(typeof(*prop), 1);
-            *val = 0;
-            val++;
-            prop->driver = typename;
-            prop->property = g_strdup(featurestr);
-            prop->value = g_strdup(val);
-            qdev_prop_register_global(prop);
-        } else {
-            error_setg(errp, "Expected key=value format, found %s.",
-                       featurestr);
+    if (!features) {
+        return;
+    }
+
+    /*
+     * If typename is invalid, we'll register the global properties anyway
+     * and report a warning in qdev_prop_check_globals.
+     * TODO: Report an error early if -cpu typename is invalid; all classes
+     * will have been registered by now, whether or not the target is using
+     * class properties or object properties.
+     */
+    klass = object_class_by_name(typename);
+
+    /* Single "key=value" string being parsed */
+    for (f = strtok(features, ","); f != NULL; f = strtok(NULL, ",")) {
+        char *val = strchr(f, '=');
+        GlobalProperty *prop;
+
+        if (!val) {
+            error_setg(errp, "Expected key=value format, found %s.", f);
             return;
         }
-        featurestr = strtok(NULL, ",");
+        *val++ = 0;
+
+        if (klass) {
+            ClassProperty *cp = class_property_find(klass, f);
+            if (cp) {
+                Visitor *v = string_input_visitor_new(val);
+                bool ok = class_property_set(klass, cp, v, errp);
+
+                visit_free(v);
+                if (!ok) {
+                    return;
+                }
+                continue;
+            }
+        }
+
+        prop = g_new0(typeof(*prop), 1);
+        prop->driver = typename;
+        prop->property = g_strdup(f);
+        prop->value = g_strdup(val);
+        qdev_prop_register_global(prop);
     }
 }
 
diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c
index f7775d0ea4..30037ddfb2 100644
--- a/hw/core/qdev-properties.c
+++ b/hw/core/qdev-properties.c
@@ -6,6 +6,7 @@
 #include "qemu/ctype.h"
 #include "qemu/error-report.h"
 #include "qapi/visitor.h"
+#include "qapi/string-input-visitor.h"
 #include "qemu/units.h"
 #include "qemu/cutils.h"
 #include "qdev-prop-internal.h"
@@ -821,6 +822,41 @@ void qdev_prop_set_globals(DeviceState *dev)
     }
 }
 
+bool device_class_late_init(ObjectClass *class, Error **errp)
+{
+    GPtrArray *props = global_properties;
+    int i, len = props ? props->len : 0;
+
+    for (i = 0; i < len; i++) {
+        GlobalProperty *p = g_ptr_array_index(props, i);
+        ClassProperty *cp;
+        Visitor *v;
+        bool ok;
+
+        if (object_class_dynamic_cast(class, p->driver) == NULL) {
+            continue;
+        }
+
+        cp = class_property_find(class, p->property);
+        if (!cp) {
+            /* The property may be on the object. */
+            continue;
+        }
+        p->used = true;
+
+        v = string_input_visitor_new(p->value);
+        ok = class_property_set(class, cp, v, errp);
+        visit_free(v);
+
+        if (!ok) {
+            error_prepend(errp, "can't apply global %s.%s=%s: ",
+                          p->driver, p->property, p->value);
+            return false;
+        }
+    }
+    return true;
+}
+
 /* --- 64bit unsigned int 'size' type --- */
 
 static void get_size(Object *obj, Visitor *v, const char *name, void *opaque,
diff --git a/hw/core/qdev.c b/hw/core/qdev.c
index d759c4602c..772aedc914 100644
--- a/hw/core/qdev.c
+++ b/hw/core/qdev.c
@@ -40,6 +40,7 @@
 #include "hw/qdev-clock.h"
 #include "migration/vmstate.h"
 #include "trace.h"
+#include "qdev-prop-internal.h"
 
 static bool qdev_hot_added = false;
 bool qdev_hot_removed = false;
@@ -901,6 +902,7 @@ static const TypeInfo device_type_info = {
     .instance_finalize = device_finalize,
     .class_base_init = device_class_base_init,
     .class_init = device_class_init,
+    .class_late_init = device_class_late_init,
     .abstract = true,
     .class_size = sizeof(DeviceClass),
     .interfaces = (InterfaceInfo[]) {
diff --git a/qom/object.c b/qom/object.c
index 82a5c7d36e..344ca03877 100644
--- a/qom/object.c
+++ b/qom/object.c
@@ -21,6 +21,7 @@
 #include "qapi/string-input-visitor.h"
 #include "qapi/string-output-visitor.h"
 #include "qapi/qobject-input-visitor.h"
+#include "qapi/qobject-output-visitor.h"
 #include "qapi/forward-visitor.h"
 #include "qapi/qapi-builtin-visit.h"
 #include "qapi/qmp/qerror.h"
@@ -34,6 +35,7 @@
 #include "qapi/qmp/qnum.h"
 #include "qapi/qmp/qstring.h"
 #include "qemu/error-report.h"
+#include "sysemu/qtest.h"
 
 #define MAX_INTERFACES 32
 
@@ -76,6 +78,190 @@ struct TypeImpl
     InterfaceImpl interfaces[MAX_INTERFACES];
 };
 
+ClassProperty *class_property_find(ObjectClass *klass, const char *name)
+{
+    ObjectClass *parent_klass;
+
+    if (klass->class_properties) {
+        ClassProperty *p = g_hash_table_lookup(klass->class_properties, name);
+        if (p) {
+            return p;
+        }
+    }
+
+    parent_klass = object_class_get_parent(klass);
+    if (parent_klass) {
+        return class_property_find(parent_klass, name);
+    }
+    return NULL;
+}
+
+static ClassProperty *class_property_find_err(ObjectClass *klass,
+                                              const char *name,
+                                              Error **errp)
+{
+    ClassProperty *cp = class_property_find(klass, name);
+    if (!cp) {
+        error_setg(errp, "Property '%s.%s' not found",
+                   klass->type->name, name);
+    }
+    return cp;
+}
+
+void class_property_add(ObjectClass *klass, const char *name,
+                        const char *type, const char *desc,
+                        ClassPropertyAccessor *get,
+                        ClassPropertyAccessor *set,
+                        void *opaque)
+{
+    ClassProperty *prop;
+
+    assert(!class_property_find(klass, name));
+
+    prop = g_new0(ClassProperty, 1);
+
+    prop->name = g_strdup(name);
+    prop->type = g_strdup(type);
+    prop->description = g_strdup(desc);
+
+    prop->get = get;
+    prop->set = set;
+    prop->opaque = opaque;
+
+    if (!klass->class_properties) {
+        klass->class_properties = g_hash_table_new(g_str_hash, g_str_equal);
+    }
+    g_hash_table_insert(klass->class_properties, prop->name, prop);
+}
+
+bool class_property_set(ObjectClass *klass, ClassProperty *cp,
+                        Visitor *v, Error **errp)
+{
+    /*
+     * FIXME: qtest/device-introspect-test creates one of each board,
+     * inside the same qemu instance.  The class properties for the
+     * cpus may well be adjusted for each board.  This cannot happen
+     * during normal usage.
+     */
+    if (!qtest_enabled() && klass->type->object_created) {
+        error_setg(errp, "Property '%s.%s' set after object creation",
+                   klass->type->name, cp->name);
+        return false;
+    }
+    return cp->set(klass, v, cp->name, cp->opaque, errp);
+}
+
+static bool class_property_set_lookup(ObjectClass *klass, const char *name,
+                                      Visitor *v, Error **errp)
+{
+    ClassProperty *cp = class_property_find_err(klass, name, errp);
+    if (!cp) {
+        return false;
+    }
+    return class_property_set(klass, cp, v, errp);
+}
+
+bool class_property_set_qobject(ObjectClass *klass, const char *name,
+                                QObject *value, Error **errp)
+{
+    Visitor *v = qobject_input_visitor_new(value);
+    bool ok;
+
+    ok = class_property_set_lookup(klass, name, v, errp);
+    visit_free(v);
+    return ok;
+}
+
+bool class_property_set_bool(ObjectClass *klass, const char *name,
+                             bool value, Error **errp)
+{
+    QBool *qbool = qbool_from_bool(value);
+    bool ok;
+
+    ok = class_property_set_qobject(klass, name, QOBJECT(qbool), errp);
+    qobject_unref(qbool);
+    return ok;
+}
+
+bool class_property_set_uint(ObjectClass *klass, const char *name,
+                             uint64_t value, Error **errp)
+{
+    QNum *qnum = qnum_from_uint(value);
+    bool ok;
+
+    ok = class_property_set_qobject(klass, name, QOBJECT(qnum), errp);
+    qobject_unref(qnum);
+    return ok;
+}
+
+bool class_property_get(ObjectClass *klass, ClassProperty *cp,
+                        Visitor *v, Error **errp)
+{
+    return cp->get(klass, v, cp->name, cp->opaque, errp);
+}
+
+static bool class_property_get_lookup(ObjectClass *klass, const char *name,
+                                      Visitor *v, Error **errp)
+{
+    ClassProperty *cp = class_property_find_err(klass, name, errp);
+    if (!cp) {
+        return false;
+    }
+    return class_property_get(klass, cp, v, errp);
+}
+
+
+QObject *class_property_get_qobject(ObjectClass *klass, const char *name,
+                                    Error **errp)
+{
+    QObject *ret = NULL;
+    Visitor *v = qobject_output_visitor_new(&ret);
+
+    if (class_property_get_lookup(klass, name, v, errp)) {
+        visit_complete(v, &ret);
+    }
+    visit_free(v);
+    return ret;
+}
+
+bool class_property_get_bool(ObjectClass *klass, const char *name,
+                             Error **errp)
+{
+    QObject *qobj = class_property_get_qobject(klass, name, errp);
+    bool ret = false;
+
+    if (qobj) {
+        QBool *qbool = qobject_to(QBool, qobj);
+        if (!qbool) {
+            error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name, "boolean");
+        } else {
+            ret = qbool_get_bool(qbool);
+        }
+        qobject_unref(qobj);
+    }
+    return ret;
+}
+
+void class_property_iter_init(ObjectPropertyIterator *iter,
+                              ObjectClass *klass)
+{
+    g_hash_table_iter_init(&iter->iter, klass->class_properties);
+    iter->nextclass = object_class_get_parent(klass);
+}
+
+ClassProperty *class_property_iter_next(ObjectPropertyIterator *iter)
+{
+    gpointer key, val;
+    while (!g_hash_table_iter_next(&iter->iter, &key, &val)) {
+        if (!iter->nextclass) {
+            return NULL;
+        }
+        g_hash_table_iter_init(&iter->iter, iter->nextclass->class_properties);
+        iter->nextclass = object_class_get_parent(iter->nextclass);
+    }
+    return val;
+}
+
 static Type type_interface;
 
 static GHashTable *type_table_get(void)
@@ -322,6 +508,7 @@ static void type_initialize(TypeImpl *ti)
         g_assert(parent->instance_size <= ti->instance_size);
         memcpy(ti->class, parent->class, parent->class_size);
         ti->class->interfaces = NULL;
+        ti->class->class_properties = NULL;
 
         for (e = parent->class->interfaces; e; e = e->next) {
             InterfaceClass *iface = e->data;
@@ -415,12 +602,15 @@ static void object_post_init_with_type(Object *obj, TypeImpl *ti)
 bool object_apply_global_props(Object *obj, const GPtrArray *props,
                                Error **errp)
 {
+    ObjectClass *klass;
     int i;
 
     if (!props) {
         return true;
     }
 
+    klass = object_get_class(obj);
+
     for (i = 0; i < props->len; i++) {
         GlobalProperty *p = g_ptr_array_index(props, i);
         Error *err = NULL;
@@ -428,6 +618,10 @@ bool object_apply_global_props(Object *obj, const GPtrArray *props,
         if (object_dynamic_cast(obj, p->driver) == NULL) {
             continue;
         }
+        if (class_property_find(klass, p->property)) {
+            /* This was handled in device_class_late_init. */
+            continue;
+        }
         if (p->optional && !object_property_find(obj, p->property)) {
             continue;
         }
diff --git a/qom/object_interfaces.c b/qom/object_interfaces.c
index f94b6c3193..aee86eb708 100644
--- a/qom/object_interfaces.c
+++ b/qom/object_interfaces.c
@@ -203,6 +203,7 @@ bool type_print_class_properties(const char *type)
     ObjectClass *klass;
     ObjectPropertyIterator iter;
     ObjectProperty *prop;
+    ClassProperty *cprop;
     GPtrArray *array;
     int i;
 
@@ -212,6 +213,7 @@ bool type_print_class_properties(const char *type)
     }
 
     array = g_ptr_array_new();
+
     object_class_property_iter_init(&iter, klass);
     while ((prop = object_property_iter_next(&iter))) {
         if (!prop->set) {
@@ -222,6 +224,17 @@ bool type_print_class_properties(const char *type)
                         object_property_help(prop->name, prop->type,
                                              prop->defval, prop->description));
     }
+
+    class_property_iter_init(&iter, klass);
+    while ((cprop = class_property_iter_next(&iter))) {
+        if (!cprop->set) {
+            continue;
+        }
+        g_ptr_array_add(array,
+                        object_property_help(cprop->name, cprop->type,
+                                             NULL, cprop->description));
+    }
+
     g_ptr_array_sort(array, (GCompareFunc)qemu_pstrcmp0);
     if (array->len > 0) {
         qemu_printf("%s options:\n", type);
diff --git a/qom/qom-qmp-cmds.c b/qom/qom-qmp-cmds.c
index 7c087299de..ea3f542a1d 100644
--- a/qom/qom-qmp-cmds.c
+++ b/qom/qom-qmp-cmds.c
@@ -34,6 +34,7 @@ ObjectPropertyInfoList *qmp_qom_list(const char *path, Error **errp)
     bool ambiguous = false;
     ObjectPropertyInfoList *props = NULL;
     ObjectProperty *prop;
+    ClassProperty *cprop;
     ObjectPropertyIterator iter;
 
     obj = object_resolve_path(path, &ambiguous);
@@ -57,6 +58,16 @@ ObjectPropertyInfoList *qmp_qom_list(const char *path, Error **errp)
         value->type = g_strdup(prop->type);
     }
 
+    class_property_iter_init(&iter, object_get_class(obj));
+    while ((cprop = class_property_iter_next(&iter))) {
+        ObjectPropertyInfo *value = g_new0(ObjectPropertyInfo, 1);
+
+        QAPI_LIST_PREPEND(props, value);
+
+        value->name = g_strdup(cprop->name);
+        value->type = g_strdup(cprop->type);
+    }
+
     return props;
 }
 
@@ -124,6 +135,7 @@ ObjectPropertyInfoList *qmp_device_list_properties(const char *typename,
     ObjectClass *klass;
     Object *obj;
     ObjectProperty *prop;
+    ClassProperty *cprop;
     ObjectPropertyIterator iter;
     ObjectPropertyInfoList *prop_list = NULL;
 
@@ -172,6 +184,18 @@ ObjectPropertyInfoList *qmp_device_list_properties(const char *typename,
         QAPI_LIST_PREPEND(prop_list, info);
     }
 
+    class_property_iter_init(&iter, klass);
+    while ((cprop = class_property_iter_next(&iter))) {
+        ObjectPropertyInfo *info;
+
+        info = g_new0(ObjectPropertyInfo, 1);
+        info->name = g_strdup(cprop->name);
+        info->type = g_strdup(cprop->type);
+        info->description = g_strdup(cprop->description);
+
+        QAPI_LIST_PREPEND(prop_list, info);
+    }
+
     object_unref(obj);
 
     return prop_list;
@@ -183,6 +207,7 @@ ObjectPropertyInfoList *qmp_qom_list_properties(const char *typename,
     ObjectClass *klass;
     Object *obj = NULL;
     ObjectProperty *prop;
+    ClassProperty *cprop;
     ObjectPropertyIterator iter;
     ObjectPropertyInfoList *prop_list = NULL;
 
@@ -216,6 +241,18 @@ ObjectPropertyInfoList *qmp_qom_list_properties(const char *typename,
         QAPI_LIST_PREPEND(prop_list, info);
     }
 
+    class_property_iter_init(&iter, klass);
+    while ((cprop = class_property_iter_next(&iter))) {
+        ObjectPropertyInfo *info;
+
+        info = g_malloc0(sizeof(*info));
+        info->name = g_strdup(cprop->name);
+        info->type = g_strdup(cprop->type);
+        info->description = g_strdup(cprop->description);
+
+        QAPI_LIST_PREPEND(prop_list, info);
+    }
+
     object_unref(obj);
 
     return prop_list;
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* [RFC PATCH 04/40] target/arm: Remove aarch64_cpu_finalizefn
  2023-01-03 18:16 [RFC PATCH 00/40] Toward class init of cpu features Richard Henderson
                   ` (2 preceding siblings ...)
  2023-01-03 18:16 ` [RFC PATCH 03/40] qom: Create class properties Richard Henderson
@ 2023-01-03 18:16 ` Richard Henderson
  2023-01-05 21:51   ` Philippe Mathieu-Daudé
  2023-01-03 18:16 ` [RFC PATCH 05/40] target/arm: Create arm_cpu_register_parent Richard Henderson
                   ` (37 subsequent siblings)
  41 siblings, 1 reply; 77+ messages in thread
From: Richard Henderson @ 2023-01-03 18:16 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, berrange, eduardo, armbru, ajones, alex.bennee

If the instance_finalize hook is NULL, the hook is not called.
There is no need to install an empty function.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/cpu64.c | 5 -----
 1 file changed, 5 deletions(-)

diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
index 2cf2ca4ce5..611b233d23 100644
--- a/target/arm/cpu64.c
+++ b/target/arm/cpu64.c
@@ -1351,10 +1351,6 @@ static void aarch64_cpu_set_aarch64(Object *obj, bool value, Error **errp)
     }
 }
 
-static void aarch64_cpu_finalizefn(Object *obj)
-{
-}
-
 static gchar *aarch64_gdb_arch_name(CPUState *cs)
 {
     return g_strdup("aarch64");
@@ -1412,7 +1408,6 @@ static const TypeInfo aarch64_cpu_type_info = {
     .name = TYPE_AARCH64_CPU,
     .parent = TYPE_ARM_CPU,
     .instance_size = sizeof(ARMCPU),
-    .instance_finalize = aarch64_cpu_finalizefn,
     .abstract = true,
     .class_size = sizeof(AArch64CPUClass),
     .class_init = aarch64_cpu_class_init,
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* [RFC PATCH 05/40] target/arm: Create arm_cpu_register_parent
  2023-01-03 18:16 [RFC PATCH 00/40] Toward class init of cpu features Richard Henderson
                   ` (3 preceding siblings ...)
  2023-01-03 18:16 ` [RFC PATCH 04/40] target/arm: Remove aarch64_cpu_finalizefn Richard Henderson
@ 2023-01-03 18:16 ` Richard Henderson
  2023-01-05 21:57   ` Philippe Mathieu-Daudé
  2023-01-03 18:16 ` [RFC PATCH 06/40] target/arm: Remove AArch64CPUClass Richard Henderson
                   ` (36 subsequent siblings)
  41 siblings, 1 reply; 77+ messages in thread
From: Richard Henderson @ 2023-01-03 18:16 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, berrange, eduardo, armbru, ajones, alex.bennee

Create an arm cpu class with a specific abstract parent class.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/cpu-qom.h | 7 ++++++-
 target/arm/cpu.c     | 4 ++--
 2 files changed, 8 insertions(+), 3 deletions(-)

diff --git a/target/arm/cpu-qom.h b/target/arm/cpu-qom.h
index 514c22ced9..95f7805076 100644
--- a/target/arm/cpu-qom.h
+++ b/target/arm/cpu-qom.h
@@ -37,9 +37,14 @@ typedef struct ARMCPUInfo {
     void (*class_init)(ObjectClass *oc, void *data);
 } ARMCPUInfo;
 
-void arm_cpu_register(const ARMCPUInfo *info);
+void arm_cpu_register_parent(const ARMCPUInfo *info, const char *parent);
 void aarch64_cpu_register(const ARMCPUInfo *info);
 
+static inline void arm_cpu_register(const ARMCPUInfo *info)
+{
+    arm_cpu_register_parent(info, TYPE_ARM_CPU);
+}
+
 /**
  * ARMCPUClass:
  * @parent_realize: The parent class' realize handler.
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index 2fa022f62b..c97461e164 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -2260,10 +2260,10 @@ static void cpu_register_class_init(ObjectClass *oc, void *data)
     acc->info = data;
 }
 
-void arm_cpu_register(const ARMCPUInfo *info)
+void arm_cpu_register_parent(const ARMCPUInfo *info, const char *parent)
 {
     TypeInfo type_info = {
-        .parent = TYPE_ARM_CPU,
+        .parent = parent,
         .instance_size = sizeof(ARMCPU),
         .instance_align = __alignof__(ARMCPU),
         .instance_init = arm_cpu_instance_init,
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* [RFC PATCH 06/40] target/arm: Remove AArch64CPUClass
  2023-01-03 18:16 [RFC PATCH 00/40] Toward class init of cpu features Richard Henderson
                   ` (4 preceding siblings ...)
  2023-01-03 18:16 ` [RFC PATCH 05/40] target/arm: Create arm_cpu_register_parent Richard Henderson
@ 2023-01-03 18:16 ` Richard Henderson
  2023-01-05 21:50   ` Philippe Mathieu-Daudé
  2023-01-03 18:16 ` [RFC PATCH 07/40] target/arm: Create TYPE_ARM_V7M_CPU Richard Henderson
                   ` (35 subsequent siblings)
  41 siblings, 1 reply; 77+ messages in thread
From: Richard Henderson @ 2023-01-03 18:16 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, berrange, eduardo, armbru, ajones, alex.bennee

The class structure is a plain wrapper around ARMCPUClass.  We really
only need the QOM class, TYPE_AARCH64_CPU.  The instance init and
fallback class init functions are identical to the same ones over
in cpu.c.  Make arm_cpu_post_init static.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/cpu-qom.h | 19 ++++++-------------
 target/arm/cpu.h     |  2 --
 target/arm/cpu.c     |  2 +-
 target/arm/cpu64.c   | 33 +--------------------------------
 4 files changed, 8 insertions(+), 48 deletions(-)

diff --git a/target/arm/cpu-qom.h b/target/arm/cpu-qom.h
index 95f7805076..184b3e3726 100644
--- a/target/arm/cpu-qom.h
+++ b/target/arm/cpu-qom.h
@@ -26,6 +26,7 @@
 struct arm_boot_info;
 
 #define TYPE_ARM_CPU "arm-cpu"
+#define TYPE_AARCH64_CPU "aarch64-cpu"
 
 OBJECT_DECLARE_CPU_TYPE(ARMCPU, ARMCPUClass, ARM_CPU)
 
@@ -38,13 +39,17 @@ typedef struct ARMCPUInfo {
 } ARMCPUInfo;
 
 void arm_cpu_register_parent(const ARMCPUInfo *info, const char *parent);
-void aarch64_cpu_register(const ARMCPUInfo *info);
 
 static inline void arm_cpu_register(const ARMCPUInfo *info)
 {
     arm_cpu_register_parent(info, TYPE_ARM_CPU);
 }
 
+static inline void aarch64_cpu_register(const ARMCPUInfo *info)
+{
+    arm_cpu_register_parent(info, TYPE_AARCH64_CPU);
+}
+
 /**
  * ARMCPUClass:
  * @parent_realize: The parent class' realize handler.
@@ -62,18 +67,6 @@ struct ARMCPUClass {
     ResettablePhases parent_phases;
 };
 
-
-#define TYPE_AARCH64_CPU "aarch64-cpu"
-typedef struct AArch64CPUClass AArch64CPUClass;
-DECLARE_CLASS_CHECKERS(AArch64CPUClass, AARCH64_CPU,
-                       TYPE_AARCH64_CPU)
-
-struct AArch64CPUClass {
-    /*< private >*/
-    ARMCPUClass parent_class;
-    /*< public >*/
-};
-
 void register_cp_regs_for_features(ARMCPU *cpu);
 void init_cpreg_list(ARMCPU *cpu);
 
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index 2b4bd20f9d..3ac650092f 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -1076,8 +1076,6 @@ struct ArchCPU {
 
 unsigned int gt_cntfrq_period_ns(ARMCPU *cpu);
 
-void arm_cpu_post_init(Object *obj);
-
 uint64_t arm_cpu_mp_affinity(int idx, uint8_t clustersz);
 
 #ifndef CONFIG_USER_ONLY
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index c97461e164..a2f59ac378 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -1324,7 +1324,7 @@ unsigned int gt_cntfrq_period_ns(ARMCPU *cpu)
       NANOSECONDS_PER_SECOND / cpu->gt_cntfrq_hz : 1;
 }
 
-void arm_cpu_post_init(Object *obj)
+static void arm_cpu_post_init(Object *obj)
 {
     ARMCPU *cpu = ARM_CPU(obj);
 
diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
index 611b233d23..1d3aff868d 100644
--- a/target/arm/cpu64.c
+++ b/target/arm/cpu64.c
@@ -1373,43 +1373,12 @@ static void aarch64_cpu_class_init(ObjectClass *oc, void *data)
                                           "execution state ");
 }
 
-static void aarch64_cpu_instance_init(Object *obj)
-{
-    ARMCPUClass *acc = ARM_CPU_GET_CLASS(obj);
-
-    acc->info->initfn(obj);
-    arm_cpu_post_init(obj);
-}
-
-static void cpu_register_class_init(ObjectClass *oc, void *data)
-{
-    ARMCPUClass *acc = ARM_CPU_CLASS(oc);
-
-    acc->info = data;
-}
-
-void aarch64_cpu_register(const ARMCPUInfo *info)
-{
-    TypeInfo type_info = {
-        .parent = TYPE_AARCH64_CPU,
-        .instance_size = sizeof(ARMCPU),
-        .instance_init = aarch64_cpu_instance_init,
-        .class_size = sizeof(ARMCPUClass),
-        .class_init = info->class_init ?: cpu_register_class_init,
-        .class_data = (void *)info,
-    };
-
-    type_info.name = g_strdup_printf("%s-" TYPE_ARM_CPU, info->name);
-    type_register(&type_info);
-    g_free((void *)type_info.name);
-}
-
 static const TypeInfo aarch64_cpu_type_info = {
     .name = TYPE_AARCH64_CPU,
     .parent = TYPE_ARM_CPU,
     .instance_size = sizeof(ARMCPU),
     .abstract = true,
-    .class_size = sizeof(AArch64CPUClass),
+    .class_size = sizeof(ARMCPUClass),
     .class_init = aarch64_cpu_class_init,
 };
 
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* [RFC PATCH 07/40] target/arm: Create TYPE_ARM_V7M_CPU
  2023-01-03 18:16 [RFC PATCH 00/40] Toward class init of cpu features Richard Henderson
                   ` (5 preceding siblings ...)
  2023-01-03 18:16 ` [RFC PATCH 06/40] target/arm: Remove AArch64CPUClass Richard Henderson
@ 2023-01-03 18:16 ` Richard Henderson
  2023-01-05 21:58   ` Philippe Mathieu-Daudé
  2023-01-03 18:16 ` [RFC PATCH 08/40] target/arm: Pass ARMCPUClass to ARMCPUInfo.class_init Richard Henderson
                   ` (34 subsequent siblings)
  41 siblings, 1 reply; 77+ messages in thread
From: Richard Henderson @ 2023-01-03 18:16 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, berrange, eduardo, armbru, ajones, alex.bennee

Create a new intermediate abstract class for v7m, like we do for
aarch64. The initialization of ARMCPUClass.info follows the
concrete class, so remove that init from arm_v7m_class_init.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/cpu-qom.h |  6 ++++++
 target/arm/cpu_tcg.c | 36 ++++++++++++++++++++++--------------
 2 files changed, 28 insertions(+), 14 deletions(-)

diff --git a/target/arm/cpu-qom.h b/target/arm/cpu-qom.h
index 184b3e3726..ae31289582 100644
--- a/target/arm/cpu-qom.h
+++ b/target/arm/cpu-qom.h
@@ -26,6 +26,7 @@
 struct arm_boot_info;
 
 #define TYPE_ARM_CPU "arm-cpu"
+#define TYPE_ARM_V7M_CPU "arm-v7m-cpu"
 #define TYPE_AARCH64_CPU "aarch64-cpu"
 
 OBJECT_DECLARE_CPU_TYPE(ARMCPU, ARMCPUClass, ARM_CPU)
@@ -45,6 +46,11 @@ static inline void arm_cpu_register(const ARMCPUInfo *info)
     arm_cpu_register_parent(info, TYPE_ARM_CPU);
 }
 
+static inline void arm_v7m_cpu_register(const ARMCPUInfo *info)
+{
+    arm_cpu_register_parent(info, TYPE_ARM_V7M_CPU);
+}
+
 static inline void aarch64_cpu_register(const ARMCPUInfo *info)
 {
     arm_cpu_register_parent(info, TYPE_AARCH64_CPU);
diff --git a/target/arm/cpu_tcg.c b/target/arm/cpu_tcg.c
index 568cbcfc52..d566a815d3 100644
--- a/target/arm/cpu_tcg.c
+++ b/target/arm/cpu_tcg.c
@@ -1056,10 +1056,8 @@ static const struct TCGCPUOps arm_v7m_tcg_ops = {
 
 static void arm_v7m_class_init(ObjectClass *oc, void *data)
 {
-    ARMCPUClass *acc = ARM_CPU_CLASS(oc);
     CPUClass *cc = CPU_CLASS(oc);
 
-    acc->info = data;
 #ifdef CONFIG_TCG
     cc->tcg_ops = &arm_v7m_tcg_ops;
 #endif /* CONFIG_TCG */
@@ -1149,18 +1147,6 @@ static const ARMCPUInfo arm_tcg_cpus[] = {
     { .name = "cortex-a8",   .initfn = cortex_a8_initfn },
     { .name = "cortex-a9",   .initfn = cortex_a9_initfn },
     { .name = "cortex-a15",  .initfn = cortex_a15_initfn },
-    { .name = "cortex-m0",   .initfn = cortex_m0_initfn,
-                             .class_init = arm_v7m_class_init },
-    { .name = "cortex-m3",   .initfn = cortex_m3_initfn,
-                             .class_init = arm_v7m_class_init },
-    { .name = "cortex-m4",   .initfn = cortex_m4_initfn,
-                             .class_init = arm_v7m_class_init },
-    { .name = "cortex-m7",   .initfn = cortex_m7_initfn,
-                             .class_init = arm_v7m_class_init },
-    { .name = "cortex-m33",  .initfn = cortex_m33_initfn,
-                             .class_init = arm_v7m_class_init },
-    { .name = "cortex-m55",  .initfn = cortex_m55_initfn,
-                             .class_init = arm_v7m_class_init },
     { .name = "cortex-r5",   .initfn = cortex_r5_initfn },
     { .name = "cortex-r5f",  .initfn = cortex_r5f_initfn },
     { .name = "ti925t",      .initfn = ti925t_initfn },
@@ -1187,6 +1173,24 @@ static const ARMCPUInfo arm_tcg_cpus[] = {
 #endif
 };
 
+static const ARMCPUInfo arm_v7m_tcg_cpus[] = {
+    { .name = "cortex-m0",   .initfn = cortex_m0_initfn },
+    { .name = "cortex-m3",   .initfn = cortex_m3_initfn },
+    { .name = "cortex-m4",   .initfn = cortex_m4_initfn },
+    { .name = "cortex-m7",   .initfn = cortex_m7_initfn },
+    { .name = "cortex-m33",  .initfn = cortex_m33_initfn },
+    { .name = "cortex-m55",  .initfn = cortex_m55_initfn },
+};
+
+static const TypeInfo arm_v7m_cpu_type_info = {
+    .name = TYPE_ARM_V7M_CPU,
+    .parent = TYPE_ARM_CPU,
+    .instance_size = sizeof(ARMCPU),
+    .abstract = true,
+    .class_size = sizeof(ARMCPUClass),
+    .class_init = arm_v7m_class_init,
+};
+
 static const TypeInfo idau_interface_type_info = {
     .name = TYPE_IDAU_INTERFACE,
     .parent = TYPE_INTERFACE,
@@ -1197,10 +1201,14 @@ static void arm_tcg_cpu_register_types(void)
 {
     size_t i;
 
+    type_register_static(&arm_v7m_cpu_type_info);
     type_register_static(&idau_interface_type_info);
     for (i = 0; i < ARRAY_SIZE(arm_tcg_cpus); ++i) {
         arm_cpu_register(&arm_tcg_cpus[i]);
     }
+    for (i = 0; i < ARRAY_SIZE(arm_v7m_tcg_cpus); ++i) {
+        arm_v7m_cpu_register(&arm_v7m_tcg_cpus[i]);
+    }
 }
 
 type_init(arm_tcg_cpu_register_types)
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* [RFC PATCH 08/40] target/arm: Pass ARMCPUClass to ARMCPUInfo.class_init
  2023-01-03 18:16 [RFC PATCH 00/40] Toward class init of cpu features Richard Henderson
                   ` (6 preceding siblings ...)
  2023-01-03 18:16 ` [RFC PATCH 07/40] target/arm: Create TYPE_ARM_V7M_CPU Richard Henderson
@ 2023-01-03 18:16 ` Richard Henderson
  2023-01-05 22:00   ` Philippe Mathieu-Daudé
  2023-01-03 18:16 ` [RFC PATCH 09/40] target/arm: Utilize arm-cpu instance_post_init hook Richard Henderson
                   ` (33 subsequent siblings)
  41 siblings, 1 reply; 77+ messages in thread
From: Richard Henderson @ 2023-01-03 18:16 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, berrange, eduardo, armbru, ajones, alex.bennee

Streamline new instances of this hook, so that we always go
through arm_cpu_leaf_class_init first, performing common tasks,
and have resolved the ARMCPUClass.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/cpu-qom.h |  2 +-
 target/arm/cpu.c     | 10 +++++++---
 2 files changed, 8 insertions(+), 4 deletions(-)

diff --git a/target/arm/cpu-qom.h b/target/arm/cpu-qom.h
index ae31289582..057978b9db 100644
--- a/target/arm/cpu-qom.h
+++ b/target/arm/cpu-qom.h
@@ -36,7 +36,7 @@ OBJECT_DECLARE_CPU_TYPE(ARMCPU, ARMCPUClass, ARM_CPU)
 typedef struct ARMCPUInfo {
     const char *name;
     void (*initfn)(Object *obj);
-    void (*class_init)(ObjectClass *oc, void *data);
+    void (*class_init)(ARMCPUClass *acc);
 } ARMCPUInfo;
 
 void arm_cpu_register_parent(const ARMCPUInfo *info, const char *parent);
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index a2f59ac378..b16d9bbe47 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -2253,11 +2253,15 @@ static void arm_cpu_instance_init(Object *obj)
     arm_cpu_post_init(obj);
 }
 
-static void cpu_register_class_init(ObjectClass *oc, void *data)
+static void arm_cpu_leaf_class_init(ObjectClass *oc, void *data)
 {
     ARMCPUClass *acc = ARM_CPU_CLASS(oc);
+    const ARMCPUInfo *info = data;
 
-    acc->info = data;
+    acc->info = info;
+    if (info->class_init) {
+        info->class_init(acc);
+    }
 }
 
 void arm_cpu_register_parent(const ARMCPUInfo *info, const char *parent)
@@ -2268,7 +2272,7 @@ void arm_cpu_register_parent(const ARMCPUInfo *info, const char *parent)
         .instance_align = __alignof__(ARMCPU),
         .instance_init = arm_cpu_instance_init,
         .class_size = sizeof(ARMCPUClass),
-        .class_init = info->class_init ?: cpu_register_class_init,
+        .class_init = arm_cpu_leaf_class_init,
         .class_data = (void *)info,
     };
 
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* [RFC PATCH 09/40] target/arm: Utilize arm-cpu instance_post_init hook
  2023-01-03 18:16 [RFC PATCH 00/40] Toward class init of cpu features Richard Henderson
                   ` (7 preceding siblings ...)
  2023-01-03 18:16 ` [RFC PATCH 08/40] target/arm: Pass ARMCPUClass to ARMCPUInfo.class_init Richard Henderson
@ 2023-01-03 18:16 ` Richard Henderson
  2023-01-03 18:16 ` [RFC PATCH 10/40] target/arm: Copy dtb_compatible from ARMCPUClass Richard Henderson
                   ` (32 subsequent siblings)
  41 siblings, 0 replies; 77+ messages in thread
From: Richard Henderson @ 2023-01-03 18:16 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, berrange, eduardo, armbru, ajones, alex.bennee

Rather than call arm_cpu_post_init ourselves from the
object instance_init, let QOM handle this.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/cpu.c | 11 ++---------
 1 file changed, 2 insertions(+), 9 deletions(-)

diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index b16d9bbe47..a6c6916f36 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -2245,14 +2245,6 @@ static void arm_cpu_class_init(ObjectClass *oc, void *data)
 #endif /* CONFIG_TCG */
 }
 
-static void arm_cpu_instance_init(Object *obj)
-{
-    ARMCPUClass *acc = ARM_CPU_GET_CLASS(obj);
-
-    acc->info->initfn(obj);
-    arm_cpu_post_init(obj);
-}
-
 static void arm_cpu_leaf_class_init(ObjectClass *oc, void *data)
 {
     ARMCPUClass *acc = ARM_CPU_CLASS(oc);
@@ -2270,7 +2262,7 @@ void arm_cpu_register_parent(const ARMCPUInfo *info, const char *parent)
         .parent = parent,
         .instance_size = sizeof(ARMCPU),
         .instance_align = __alignof__(ARMCPU),
-        .instance_init = arm_cpu_instance_init,
+        .instance_init = info->initfn,
         .class_size = sizeof(ARMCPUClass),
         .class_init = arm_cpu_leaf_class_init,
         .class_data = (void *)info,
@@ -2287,6 +2279,7 @@ static const TypeInfo arm_cpu_type_info = {
     .instance_size = sizeof(ARMCPU),
     .instance_align = __alignof__(ARMCPU),
     .instance_init = arm_cpu_initfn,
+    .instance_post_init = arm_cpu_post_init,
     .instance_finalize = arm_cpu_finalizefn,
     .abstract = true,
     .class_size = sizeof(ARMCPUClass),
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* [RFC PATCH 10/40] target/arm: Copy dtb_compatible from ARMCPUClass
  2023-01-03 18:16 [RFC PATCH 00/40] Toward class init of cpu features Richard Henderson
                   ` (8 preceding siblings ...)
  2023-01-03 18:16 ` [RFC PATCH 09/40] target/arm: Utilize arm-cpu instance_post_init hook Richard Henderson
@ 2023-01-03 18:16 ` Richard Henderson
  2023-01-03 18:16 ` [RFC PATCH 11/40] target/arm: Copy features " Richard Henderson
                   ` (31 subsequent siblings)
  41 siblings, 0 replies; 77+ messages in thread
From: Richard Henderson @ 2023-01-03 18:16 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, berrange, eduardo, armbru, ajones, alex.bennee

Move the default initialization of dtb_compatible to arm_cpu_class_init,
and copy back to the instance in arm_cpu_init.  Further class overrides
will come in a future patch.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/cpu-qom.h |  3 +++
 target/arm/cpu.c     | 15 ++++++++++-----
 2 files changed, 13 insertions(+), 5 deletions(-)

diff --git a/target/arm/cpu-qom.h b/target/arm/cpu-qom.h
index 057978b9db..5509ef9d85 100644
--- a/target/arm/cpu-qom.h
+++ b/target/arm/cpu-qom.h
@@ -71,6 +71,9 @@ struct ARMCPUClass {
     const ARMCPUInfo *info;
     DeviceRealize parent_realize;
     ResettablePhases parent_phases;
+
+    /* 'compatible' string for this CPU for Linux device trees */
+    const char *dtb_compatible;
 };
 
 void register_cp_regs_for_features(ARMCPU *cpu);
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index a6c6916f36..1bc45b2b25 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -1181,6 +1181,7 @@ uint64_t arm_cpu_mp_affinity(int idx, uint8_t clustersz)
 static void arm_cpu_initfn(Object *obj)
 {
     ARMCPU *cpu = ARM_CPU(obj);
+    ARMCPUClass *acc = ARM_CPU_GET_CLASS(cpu);
 
     cpu_set_cpustate_pointers(cpu);
     cpu->cp_regs = g_hash_table_new_full(g_direct_hash, g_direct_equal,
@@ -1189,6 +1190,8 @@ static void arm_cpu_initfn(Object *obj)
     QLIST_INIT(&cpu->pre_el_change_hooks);
     QLIST_INIT(&cpu->el_change_hooks);
 
+    cpu->dtb_compatible = acc->dtb_compatible;
+
 #ifdef CONFIG_USER_ONLY
 # ifdef TARGET_AARCH64
     /*
@@ -1220,11 +1223,6 @@ static void arm_cpu_initfn(Object *obj)
                              "pmu-interrupt", 1);
 #endif
 
-    /* DTB consumers generally don't in fact care what the 'compatible'
-     * string is, so always provide some string and trust that a hypothetical
-     * picky DTB consumer will also provide a helpful error message.
-     */
-    cpu->dtb_compatible = "qemu,unknown";
     cpu->psci_version = QEMU_PSCI_VERSION_0_1; /* By default assume PSCI v0.1 */
     cpu->kvm_target = QEMU_KVM_ARM_TARGET_NONE;
 
@@ -2243,6 +2241,13 @@ static void arm_cpu_class_init(ObjectClass *oc, void *data)
 #ifdef CONFIG_TCG
     cc->tcg_ops = &arm_tcg_ops;
 #endif /* CONFIG_TCG */
+
+    /*
+     * DTB consumers generally don't in fact care what the 'compatible'
+     * string is, so always provide some string and trust that a hypothetical
+     * picky DTB consumer will also provide a helpful error message.
+     */
+    acc->dtb_compatible = "qemu,unknown";
 }
 
 static void arm_cpu_leaf_class_init(ObjectClass *oc, void *data)
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* [RFC PATCH 11/40] target/arm: Copy features from ARMCPUClass
  2023-01-03 18:16 [RFC PATCH 00/40] Toward class init of cpu features Richard Henderson
                   ` (9 preceding siblings ...)
  2023-01-03 18:16 ` [RFC PATCH 10/40] target/arm: Copy dtb_compatible from ARMCPUClass Richard Henderson
@ 2023-01-03 18:16 ` Richard Henderson
  2023-01-05 22:04   ` Philippe Mathieu-Daudé
  2023-01-03 18:16 ` [RFC PATCH 12/40] target/arm: Copy isar and friends " Richard Henderson
                   ` (30 subsequent siblings)
  41 siblings, 1 reply; 77+ messages in thread
From: Richard Henderson @ 2023-01-03 18:16 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, berrange, eduardo, armbru, ajones, alex.bennee

Create a features member in ARMCPUClass and copy to the instance in
arm_cpu_init.  Settings of this value will come in a future patch.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/cpu-qom.h | 18 ++++++++++++++++++
 target/arm/cpu.c     |  1 +
 2 files changed, 19 insertions(+)

diff --git a/target/arm/cpu-qom.h b/target/arm/cpu-qom.h
index 5509ef9d85..ac58cc3a87 100644
--- a/target/arm/cpu-qom.h
+++ b/target/arm/cpu-qom.h
@@ -74,8 +74,26 @@ struct ARMCPUClass {
 
     /* 'compatible' string for this CPU for Linux device trees */
     const char *dtb_compatible;
+
+    /* Internal CPU feature flags.  */
+    uint64_t features;
 };
 
+static inline int arm_class_feature(ARMCPUClass *acc, int feature)
+{
+    return (acc->features & (1ULL << feature)) != 0;
+}
+
+static inline void set_class_feature(ARMCPUClass *acc, int feature)
+{
+    acc->features |= 1ULL << feature;
+}
+
+static inline void unset_class_feature(ARMCPUClass *acc, int feature)
+{
+    acc->features &= ~(1ULL << feature);
+}
+
 void register_cp_regs_for_features(ARMCPU *cpu);
 void init_cpreg_list(ARMCPU *cpu);
 
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index 1bc45b2b25..d64b86b6a5 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -1191,6 +1191,7 @@ static void arm_cpu_initfn(Object *obj)
     QLIST_INIT(&cpu->el_change_hooks);
 
     cpu->dtb_compatible = acc->dtb_compatible;
+    cpu->env.features = acc->features;
 
 #ifdef CONFIG_USER_ONLY
 # ifdef TARGET_AARCH64
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* [RFC PATCH 12/40] target/arm: Copy isar and friends from ARMCPUClass
  2023-01-03 18:16 [RFC PATCH 00/40] Toward class init of cpu features Richard Henderson
                   ` (10 preceding siblings ...)
  2023-01-03 18:16 ` [RFC PATCH 11/40] target/arm: Copy features " Richard Henderson
@ 2023-01-03 18:16 ` Richard Henderson
  2023-01-03 18:16 ` [RFC PATCH 13/40] hw/arm/bcm2836: Set mp-affinity property in realize Richard Henderson
                   ` (29 subsequent siblings)
  41 siblings, 0 replies; 77+ messages in thread
From: Richard Henderson @ 2023-01-03 18:16 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, berrange, eduardo, armbru, ajones, alex.bennee

Create a block of cpregs in ARMCPUClass and copy to the instance in
arm_cpu_init.  Settings of these values will come in a future patch.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/cpu-qom.h | 98 ++++++++++++++++++++++++++++++++++++++++++++
 target/arm/cpu.h     | 43 ++-----------------
 target/arm/cpu.c     | 28 ++++++++++++-
 3 files changed, 128 insertions(+), 41 deletions(-)

diff --git a/target/arm/cpu-qom.h b/target/arm/cpu-qom.h
index ac58cc3a87..832b2cccf9 100644
--- a/target/arm/cpu-qom.h
+++ b/target/arm/cpu-qom.h
@@ -56,6 +56,45 @@ static inline void aarch64_cpu_register(const ARMCPUInfo *info)
     arm_cpu_register_parent(info, TYPE_AARCH64_CPU);
 }
 
+typedef struct ARMISARegisters {
+    uint32_t id_isar0;
+    uint32_t id_isar1;
+    uint32_t id_isar2;
+    uint32_t id_isar3;
+    uint32_t id_isar4;
+    uint32_t id_isar5;
+    uint32_t id_isar6;
+    uint32_t id_mmfr0;
+    uint32_t id_mmfr1;
+    uint32_t id_mmfr2;
+    uint32_t id_mmfr3;
+    uint32_t id_mmfr4;
+    uint32_t id_mmfr5;
+    uint32_t id_pfr0;
+    uint32_t id_pfr1;
+    uint32_t id_pfr2;
+    uint32_t mvfr0;
+    uint32_t mvfr1;
+    uint32_t mvfr2;
+    uint32_t id_dfr0;
+    uint32_t id_dfr1;
+    uint32_t dbgdidr;
+    uint32_t dbgdevid;
+    uint32_t dbgdevid1;
+    uint64_t id_aa64isar0;
+    uint64_t id_aa64isar1;
+    uint64_t id_aa64pfr0;
+    uint64_t id_aa64pfr1;
+    uint64_t id_aa64mmfr0;
+    uint64_t id_aa64mmfr1;
+    uint64_t id_aa64mmfr2;
+    uint64_t id_aa64dfr0;
+    uint64_t id_aa64dfr1;
+    uint64_t id_aa64zfr0;
+    uint64_t id_aa64smfr0;
+    uint64_t reset_pmcr_el0;
+} ARMISARegisters;
+
 /**
  * ARMCPUClass:
  * @parent_realize: The parent class' realize handler.
@@ -77,6 +116,65 @@ struct ARMCPUClass {
 
     /* Internal CPU feature flags.  */
     uint64_t features;
+
+    /*
+     * The instance init functions for implementation-specific subclasses
+     * set these fields to specify the implementation-dependent values of
+     * various constant registers and reset values of non-constant
+     * registers.
+     * Some of these might become QOM properties eventually.
+     * Field names match the official register names as defined in the
+     * ARMv7AR ARM Architecture Reference Manual. A reset_ prefix
+     * is used for reset values of non-constant registers; no reset_
+     * prefix means a constant register.
+     * Some of these registers are split out into a substructure that
+     * is shared with the translators to control the ISA.
+     *
+     * Note that if you add an ID register to the ARMISARegisters struct
+     * you need to also update the 32-bit and 64-bit versions of the
+     * kvm_arm_get_host_cpu_features() function to correctly populate the
+     * field by reading the value from the KVM vCPU.
+     */
+    ARMISARegisters isar;
+
+    uint64_t midr;
+    uint64_t ctr;
+    uint64_t pmceid0;
+    uint64_t pmceid1;
+    uint64_t id_aa64afr0;
+    uint64_t id_aa64afr1;
+    uint64_t clidr;
+    /*
+     * The elements of this array are the CCSIDR values for each cache,
+     * in the order L1DCache, L1ICache, L2DCache, L2ICache, etc.
+     */
+    uint64_t ccsidr[16];
+
+    uint32_t revidr;
+    uint32_t id_afr0;
+    uint32_t reset_fpsid;
+    uint32_t reset_sctlr;
+    uint32_t reset_auxcr;
+
+    /* PMSAv7 MPU number of supported regions */
+    uint32_t pmsav7_dregion;
+    /* v8M SAU number of supported regions */
+    uint32_t sau_sregion;
+
+    /* DCZ blocksize, in log_2(words), ie low 4 bits of DCZID_EL0 */
+    uint32_t dcz_blocksize;
+
+    /* Configurable aspects of GIC cpu interface (which is part of the CPU) */
+    int gic_num_lrs; /* number of list registers */
+    int gic_vpribits; /* number of virtual priority bits */
+    int gic_vprebits; /* number of virtual preemption bits */
+    int gic_pribits; /* number of physical priority bits */
+
+    /*
+     * [QEMU_]KVM_ARM_TARGET_* constant for this CPU, or
+     * QEMU_KVM_ARM_TARGET_NONE if the kernel doesn't support this CPU type.
+     */
+    uint32_t kvm_target;
 };
 
 static inline int arm_class_feature(ARMCPUClass *acc, int feature)
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index 3ac650092f..2d9bddf197 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -799,8 +799,6 @@ typedef enum ARMPSCIState {
     PSCI_ON_PENDING = 2
 } ARMPSCIState;
 
-typedef struct ARMISARegisters ARMISARegisters;
-
 /*
  * In map, each set bit is a supported vector length of (bit-number + 1) * 16
  * bytes, i.e. each bit number + 1 is the vector length in quadwords.
@@ -967,44 +965,7 @@ struct ArchCPU {
      * kvm_arm_get_host_cpu_features() function to correctly populate the
      * field by reading the value from the KVM vCPU.
      */
-    struct ARMISARegisters {
-        uint32_t id_isar0;
-        uint32_t id_isar1;
-        uint32_t id_isar2;
-        uint32_t id_isar3;
-        uint32_t id_isar4;
-        uint32_t id_isar5;
-        uint32_t id_isar6;
-        uint32_t id_mmfr0;
-        uint32_t id_mmfr1;
-        uint32_t id_mmfr2;
-        uint32_t id_mmfr3;
-        uint32_t id_mmfr4;
-        uint32_t id_mmfr5;
-        uint32_t id_pfr0;
-        uint32_t id_pfr1;
-        uint32_t id_pfr2;
-        uint32_t mvfr0;
-        uint32_t mvfr1;
-        uint32_t mvfr2;
-        uint32_t id_dfr0;
-        uint32_t id_dfr1;
-        uint32_t dbgdidr;
-        uint32_t dbgdevid;
-        uint32_t dbgdevid1;
-        uint64_t id_aa64isar0;
-        uint64_t id_aa64isar1;
-        uint64_t id_aa64pfr0;
-        uint64_t id_aa64pfr1;
-        uint64_t id_aa64mmfr0;
-        uint64_t id_aa64mmfr1;
-        uint64_t id_aa64mmfr2;
-        uint64_t id_aa64dfr0;
-        uint64_t id_aa64dfr1;
-        uint64_t id_aa64zfr0;
-        uint64_t id_aa64smfr0;
-        uint64_t reset_pmcr_el0;
-    } isar;
+    ARMISARegisters isar;
     uint64_t midr;
     uint32_t revidr;
     uint32_t reset_fpsid;
@@ -4346,5 +4307,7 @@ static inline bool isar_feature_any_evt(const ARMISARegisters *id)
  */
 #define cpu_isar_feature(name, cpu) \
     ({ ARMCPU *cpu_ = (cpu); isar_feature_##name(&cpu_->isar); })
+#define class_isar_feature(name, acc) \
+    ({ ARMCPUClass *acc_ = (acc); isar_feature_##name(&acc_->isar); })
 
 #endif
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index d64b86b6a5..8463c45d87 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -1192,6 +1192,32 @@ static void arm_cpu_initfn(Object *obj)
 
     cpu->dtb_compatible = acc->dtb_compatible;
     cpu->env.features = acc->features;
+    cpu->isar = acc->isar;
+
+    cpu->midr = acc->midr;
+    cpu->ctr = acc->ctr;
+    cpu->pmceid0 = acc->pmceid0;
+    cpu->pmceid1 = acc->pmceid1;
+    cpu->id_aa64afr0 = acc->id_aa64afr0;
+    cpu->id_aa64afr1 = acc->id_aa64afr1;
+    cpu->clidr = acc->clidr;
+
+    QEMU_BUILD_BUG_ON(sizeof(cpu->ccsidr) != sizeof(acc->ccsidr));
+    memcpy(cpu->ccsidr, acc->ccsidr, sizeof(acc->ccsidr));
+
+    cpu->revidr = acc->revidr;
+    cpu->id_afr0 = acc->id_afr0;
+    cpu->reset_fpsid = acc->reset_fpsid;
+    cpu->reset_sctlr = acc->reset_sctlr;
+    cpu->reset_auxcr = acc->reset_auxcr;
+    cpu->pmsav7_dregion = acc->pmsav7_dregion;
+    cpu->sau_sregion = acc->sau_sregion;
+    cpu->dcz_blocksize = acc->dcz_blocksize;
+    cpu->gic_num_lrs = acc->gic_num_lrs;
+    cpu->gic_vpribits = acc->gic_vpribits;
+    cpu->gic_vprebits = acc->gic_vprebits;
+    cpu->gic_pribits = acc->gic_pribits;
+    cpu->kvm_target = acc->kvm_target;
 
 #ifdef CONFIG_USER_ONLY
 # ifdef TARGET_AARCH64
@@ -1225,7 +1251,6 @@ static void arm_cpu_initfn(Object *obj)
 #endif
 
     cpu->psci_version = QEMU_PSCI_VERSION_0_1; /* By default assume PSCI v0.1 */
-    cpu->kvm_target = QEMU_KVM_ARM_TARGET_NONE;
 
     if (tcg_enabled() || hvf_enabled()) {
         /* TCG and HVF implement PSCI 1.1 */
@@ -2249,6 +2274,7 @@ static void arm_cpu_class_init(ObjectClass *oc, void *data)
      * picky DTB consumer will also provide a helpful error message.
      */
     acc->dtb_compatible = "qemu,unknown";
+    acc->kvm_target = QEMU_KVM_ARM_TARGET_NONE;
 }
 
 static void arm_cpu_leaf_class_init(ObjectClass *oc, void *data)
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* [RFC PATCH 13/40] hw/arm/bcm2836: Set mp-affinity property in realize
  2023-01-03 18:16 [RFC PATCH 00/40] Toward class init of cpu features Richard Henderson
                   ` (11 preceding siblings ...)
  2023-01-03 18:16 ` [RFC PATCH 12/40] target/arm: Copy isar and friends " Richard Henderson
@ 2023-01-03 18:16 ` Richard Henderson
  2023-01-05 21:48   ` Philippe Mathieu-Daudé
  2023-01-03 18:16 ` [RFC PATCH 14/40] target/arm: Rename arm_cpu_mp_affinity Richard Henderson
                   ` (28 subsequent siblings)
  41 siblings, 1 reply; 77+ messages in thread
From: Richard Henderson @ 2023-01-03 18:16 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, berrange, eduardo, armbru, ajones, alex.bennee

There was even a TODO comment that we ought to be using a cpu
property, but we failed to update when the property was added.
Use ARM_AFF1_SHIFT instead of the bare constant 8.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 hw/arm/bcm2836.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/hw/arm/bcm2836.c b/hw/arm/bcm2836.c
index 24354338ca..abbb3689d0 100644
--- a/hw/arm/bcm2836.c
+++ b/hw/arm/bcm2836.c
@@ -130,8 +130,11 @@ static void bcm2836_realize(DeviceState *dev, Error **errp)
         qdev_get_gpio_in_named(DEVICE(&s->control), "gpu-fiq", 0));
 
     for (n = 0; n < BCM283X_NCPUS; n++) {
-        /* TODO: this should be converted to a property of ARM_CPU */
-        s->cpu[n].core.mp_affinity = (bc->clusterid << 8) | n;
+        if (!object_property_set_int(OBJECT(&s->cpu[n].core), "mp-affinity",
+                                     (bc->clusterid << ARM_AFF1_SHIFT) | n,
+                                     errp)) {
+            return;
+        }
 
         /* set periphbase/CBAR value for CPU-local registers */
         if (!object_property_set_int(OBJECT(&s->cpu[n].core), "reset-cbar",
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* [RFC PATCH 14/40] target/arm: Rename arm_cpu_mp_affinity
  2023-01-03 18:16 [RFC PATCH 00/40] Toward class init of cpu features Richard Henderson
                   ` (12 preceding siblings ...)
  2023-01-03 18:16 ` [RFC PATCH 13/40] hw/arm/bcm2836: Set mp-affinity property in realize Richard Henderson
@ 2023-01-03 18:16 ` Richard Henderson
  2023-01-05 21:55   ` Philippe Mathieu-Daudé
  2023-01-03 18:16 ` [RFC PATCH 15/40] target/arm: Create arm_cpu_mp_affinity Richard Henderson
                   ` (27 subsequent siblings)
  41 siblings, 1 reply; 77+ messages in thread
From: Richard Henderson @ 2023-01-03 18:16 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, berrange, eduardo, armbru, ajones, alex.bennee

Rename to arm_build_mp_affinity.  This frees up the name for
other usage, and emphasizes that the cpu object is not involved.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/cpu.h  | 2 +-
 hw/arm/npcm7xx.c  | 2 +-
 hw/arm/sbsa-ref.c | 2 +-
 hw/arm/virt.c     | 2 +-
 target/arm/cpu.c  | 6 +++---
 5 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index 2d9bddf197..dd72519fda 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -1037,7 +1037,7 @@ struct ArchCPU {
 
 unsigned int gt_cntfrq_period_ns(ARMCPU *cpu);
 
-uint64_t arm_cpu_mp_affinity(int idx, uint8_t clustersz);
+uint64_t arm_build_mp_affinity(int idx, uint8_t clustersz);
 
 #ifndef CONFIG_USER_ONLY
 extern const VMStateDescription vmstate_arm_cpu;
diff --git a/hw/arm/npcm7xx.c b/hw/arm/npcm7xx.c
index d85cc02765..41124b7444 100644
--- a/hw/arm/npcm7xx.c
+++ b/hw/arm/npcm7xx.c
@@ -462,7 +462,7 @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
     /* CPUs */
     for (i = 0; i < nc->num_cpus; i++) {
         object_property_set_int(OBJECT(&s->cpu[i]), "mp-affinity",
-                                arm_cpu_mp_affinity(i, NPCM7XX_MAX_NUM_CPUS),
+                                arm_build_mp_affinity(i, NPCM7XX_MAX_NUM_CPUS),
                                 &error_abort);
         object_property_set_int(OBJECT(&s->cpu[i]), "reset-cbar",
                                 NPCM7XX_GIC_CPU_IF_ADDR, &error_abort);
diff --git a/hw/arm/sbsa-ref.c b/hw/arm/sbsa-ref.c
index 4bb444684f..06fd4b6fb0 100644
--- a/hw/arm/sbsa-ref.c
+++ b/hw/arm/sbsa-ref.c
@@ -165,7 +165,7 @@ static bool cpu_type_valid(const char *cpu)
 static uint64_t sbsa_ref_cpu_mp_affinity(SBSAMachineState *sms, int idx)
 {
     uint8_t clustersz = ARM_DEFAULT_CPUS_PER_CLUSTER;
-    return arm_cpu_mp_affinity(idx, clustersz);
+    return arm_build_mp_affinity(idx, clustersz);
 }
 
 /*
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index ea2413a0ba..3642604dea 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -1700,7 +1700,7 @@ static uint64_t virt_cpu_mp_affinity(VirtMachineState *vms, int idx)
             clustersz = GICV3_TARGETLIST_BITS;
         }
     }
-    return arm_cpu_mp_affinity(idx, clustersz);
+    return arm_build_mp_affinity(idx, clustersz);
 }
 
 static inline bool *virt_get_high_memmap_enabled(VirtMachineState *vms,
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index 8463c45d87..a104a77165 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -1171,7 +1171,7 @@ static void arm_cpu_dump_state(CPUState *cs, FILE *f, int flags)
     }
 }
 
-uint64_t arm_cpu_mp_affinity(int idx, uint8_t clustersz)
+uint64_t arm_build_mp_affinity(int idx, uint8_t clustersz)
 {
     uint32_t Aff1 = idx / clustersz;
     uint32_t Aff0 = idx % clustersz;
@@ -1927,8 +1927,8 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
      * so these bits always RAZ.
      */
     if (cpu->mp_affinity == ARM64_AFFINITY_INVALID) {
-        cpu->mp_affinity = arm_cpu_mp_affinity(cs->cpu_index,
-                                               ARM_DEFAULT_CPUS_PER_CLUSTER);
+        cpu->mp_affinity = arm_build_mp_affinity(cs->cpu_index,
+                                                 ARM_DEFAULT_CPUS_PER_CLUSTER);
     }
 
     if (cpu->reset_hivecs) {
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* [RFC PATCH 15/40] target/arm: Create arm_cpu_mp_affinity
  2023-01-03 18:16 [RFC PATCH 00/40] Toward class init of cpu features Richard Henderson
                   ` (13 preceding siblings ...)
  2023-01-03 18:16 ` [RFC PATCH 14/40] target/arm: Rename arm_cpu_mp_affinity Richard Henderson
@ 2023-01-03 18:16 ` Richard Henderson
  2023-01-05 21:53   ` Philippe Mathieu-Daudé
  2023-01-03 18:16 ` [RFC PATCH 16/40] target/arm: Represent the entire MPIDR_EL1 Richard Henderson
                   ` (26 subsequent siblings)
  41 siblings, 1 reply; 77+ messages in thread
From: Richard Henderson @ 2023-01-03 18:16 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, berrange, eduardo, armbru, ajones, alex.bennee

Wrapper to return the mp affinity bits from the cpu.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/cpu.h          | 5 +++++
 hw/arm/virt-acpi-build.c  | 2 +-
 hw/arm/virt.c             | 6 +++---
 hw/arm/xlnx-versal-virt.c | 3 ++-
 hw/misc/xlnx-versal-crl.c | 4 ++--
 target/arm/arm-powerctl.c | 2 +-
 target/arm/hvf/hvf.c      | 4 ++--
 target/arm/psci.c         | 2 +-
 8 files changed, 17 insertions(+), 11 deletions(-)

diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index dd72519fda..499d2a6028 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -1039,6 +1039,11 @@ unsigned int gt_cntfrq_period_ns(ARMCPU *cpu);
 
 uint64_t arm_build_mp_affinity(int idx, uint8_t clustersz);
 
+static inline uint64_t arm_cpu_mp_affinity(ARMCPU *cpu)
+{
+    return cpu->mp_affinity;
+}
+
 #ifndef CONFIG_USER_ONLY
 extern const VMStateDescription vmstate_arm_cpu;
 
diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
index 4156111d49..40fa3faf47 100644
--- a/hw/arm/virt-acpi-build.c
+++ b/hw/arm/virt-acpi-build.c
@@ -759,7 +759,7 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
         build_append_int_noprefix(table_data, vgic_interrupt, 4);
         build_append_int_noprefix(table_data, 0, 8);    /* GICR Base Address*/
         /* MPIDR */
-        build_append_int_noprefix(table_data, armcpu->mp_affinity, 8);
+        build_append_int_noprefix(table_data, arm_cpu_mp_affinity(armcpu), 8);
         /* Processor Power Efficiency Class */
         build_append_int_noprefix(table_data, 0, 1);
         /* Reserved */
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 3642604dea..aed86997c0 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -391,7 +391,7 @@ static void fdt_add_cpu_nodes(const VirtMachineState *vms)
     for (cpu = 0; cpu < smp_cpus; cpu++) {
         ARMCPU *armcpu = ARM_CPU(qemu_get_cpu(cpu));
 
-        if (armcpu->mp_affinity & ARM_AFF3_MASK) {
+        if (arm_cpu_mp_affinity(armcpu) & ARM_AFF3_MASK) {
             addr_cells = 2;
             break;
         }
@@ -418,10 +418,10 @@ static void fdt_add_cpu_nodes(const VirtMachineState *vms)
 
         if (addr_cells == 2) {
             qemu_fdt_setprop_u64(ms->fdt, nodename, "reg",
-                                 armcpu->mp_affinity);
+                                 arm_cpu_mp_affinity(armcpu));
         } else {
             qemu_fdt_setprop_cell(ms->fdt, nodename, "reg",
-                                  armcpu->mp_affinity);
+                                  arm_cpu_mp_affinity(armcpu));
         }
 
         if (ms->possible_cpus->cpus[cs->cpu_index].props.has_node_id) {
diff --git a/hw/arm/xlnx-versal-virt.c b/hw/arm/xlnx-versal-virt.c
index 37fc9b919c..50d983c239 100644
--- a/hw/arm/xlnx-versal-virt.c
+++ b/hw/arm/xlnx-versal-virt.c
@@ -104,7 +104,8 @@ static void fdt_add_cpu_nodes(VersalVirt *s, uint32_t psci_conduit)
         ARMCPU *armcpu = ARM_CPU(qemu_get_cpu(i));
 
         qemu_fdt_add_subnode(s->fdt, name);
-        qemu_fdt_setprop_cell(s->fdt, name, "reg", armcpu->mp_affinity);
+        qemu_fdt_setprop_cell(s->fdt, name, "reg",
+                              arm_cpu_mp_affinity(armcpu));
         if (psci_conduit != QEMU_PSCI_CONDUIT_DISABLED) {
             qemu_fdt_setprop_string(s->fdt, name, "enable-method", "psci");
         }
diff --git a/hw/misc/xlnx-versal-crl.c b/hw/misc/xlnx-versal-crl.c
index 767106b7a3..267aa55106 100644
--- a/hw/misc/xlnx-versal-crl.c
+++ b/hw/misc/xlnx-versal-crl.c
@@ -67,9 +67,9 @@ static void crl_reset_cpu(XlnxVersalCRL *s, ARMCPU *armcpu,
                           bool rst_old, bool rst_new)
 {
     if (rst_new) {
-        arm_set_cpu_off(armcpu->mp_affinity);
+        arm_set_cpu_off(arm_cpu_mp_affinity(armcpu));
     } else {
-        arm_set_cpu_on_and_reset(armcpu->mp_affinity);
+        arm_set_cpu_on_and_reset(arm_cpu_mp_affinity(armcpu));
     }
 }
 
diff --git a/target/arm/arm-powerctl.c b/target/arm/arm-powerctl.c
index b75f813b40..5a6dfdfb83 100644
--- a/target/arm/arm-powerctl.c
+++ b/target/arm/arm-powerctl.c
@@ -36,7 +36,7 @@ CPUState *arm_get_cpu_by_id(uint64_t id)
     CPU_FOREACH(cpu) {
         ARMCPU *armcpu = ARM_CPU(cpu);
 
-        if (armcpu->mp_affinity == id) {
+        if (arm_cpu_mp_affinity(armcpu) == id) {
             return cpu;
         }
     }
diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c
index 060aa0ccf4..e0ba91f5c6 100644
--- a/target/arm/hvf/hvf.c
+++ b/target/arm/hvf/hvf.c
@@ -645,7 +645,7 @@ static void hvf_raise_exception(CPUState *cpu, uint32_t excp,
 
 static void hvf_psci_cpu_off(ARMCPU *arm_cpu)
 {
-    int32_t ret = arm_set_cpu_off(arm_cpu->mp_affinity);
+    int32_t ret = arm_set_cpu_off(arm_cpu_mp_affinity(arm_cpu));
     assert(ret == QEMU_ARM_POWERCTL_RET_SUCCESS);
 }
 
@@ -674,7 +674,7 @@ static bool hvf_handle_psci_call(CPUState *cpu)
     int32_t ret = 0;
 
     trace_hvf_psci_call(param[0], param[1], param[2], param[3],
-                        arm_cpu->mp_affinity);
+                        arm_cpu_mp_affinity(arm_cpu));
 
     switch (param[0]) {
     case QEMU_PSCI_0_2_FN_PSCI_VERSION:
diff --git a/target/arm/psci.c b/target/arm/psci.c
index 6c1239bb96..b49d406e39 100644
--- a/target/arm/psci.c
+++ b/target/arm/psci.c
@@ -215,7 +215,7 @@ err:
     return;
 
 cpu_off:
-    ret = arm_set_cpu_off(cpu->mp_affinity);
+    ret = arm_set_cpu_off(arm_cpu_mp_affinity(cpu));
     /* notreached */
     /* sanity check in case something failed */
     assert(ret == QEMU_ARM_POWERCTL_RET_SUCCESS);
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* [RFC PATCH 16/40] target/arm: Represent the entire MPIDR_EL1
  2023-01-03 18:16 [RFC PATCH 00/40] Toward class init of cpu features Richard Henderson
                   ` (14 preceding siblings ...)
  2023-01-03 18:16 ` [RFC PATCH 15/40] target/arm: Create arm_cpu_mp_affinity Richard Henderson
@ 2023-01-03 18:16 ` Richard Henderson
  2023-01-06 19:16   ` Peter Maydell
  2023-01-03 18:16 ` [RFC PATCH 17/40] target/arm: Copy cp_regs from ARMCPUClass Richard Henderson
                   ` (25 subsequent siblings)
  41 siblings, 1 reply; 77+ messages in thread
From: Richard Henderson @ 2023-01-03 18:16 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, berrange, eduardo, armbru, ajones, alex.bennee

Replace ARMCPU.mp_affinity with CPUARMState.cp15.mpidr_el1,
setting the additional bits as required.  In particular,
always set the U bit when there is only one cpu in the system.
Remove the mp_is_up bit which attempted to do the same thing.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/cpu.h     |  7 ++--
 target/arm/cpu.c     | 80 +++++++++++++++++++++++++++++++++++++-------
 target/arm/cpu_tcg.c |  1 -
 target/arm/helper.c  | 25 ++------------
 target/arm/hvf/hvf.c |  2 +-
 target/arm/kvm64.c   |  4 +--
 6 files changed, 75 insertions(+), 44 deletions(-)

diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index 499d2a6028..0c5b942ed0 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -935,9 +935,6 @@ struct ArchCPU {
     /* KVM steal time */
     OnOffAuto kvm_steal_time;
 
-    /* Uniprocessor system with MP extensions */
-    bool mp_is_up;
-
     /* True if we tried kvm_arm_host_cpu_features() during CPU instance_init
      * and the probe failed (so we need to report the error in realize)
      */
@@ -977,7 +974,7 @@ struct ArchCPU {
     uint64_t id_aa64afr0;
     uint64_t id_aa64afr1;
     uint64_t clidr;
-    uint64_t mp_affinity; /* MP ID without feature bits */
+    uint64_t mpidr_el1;
     /* The elements of this array are the CCSIDR values for each cache,
      * in the order L1DCache, L1ICache, L2DCache, L2ICache, etc.
      */
@@ -1041,7 +1038,7 @@ uint64_t arm_build_mp_affinity(int idx, uint8_t clustersz);
 
 static inline uint64_t arm_cpu_mp_affinity(ARMCPU *cpu)
 {
-    return cpu->mp_affinity;
+    return cpu->mpidr_el1 & ARM64_AFFINITY_MASK;
 }
 
 #ifndef CONFIG_USER_ONLY
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index a104a77165..a46fa424d3 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -1231,6 +1231,9 @@ static void arm_cpu_initfn(Object *obj)
     cpu->sme_default_vq = 2;
 # endif
 #else
+    /* To be set properly by either the board or by realize. */
+    cpu->mpidr_el1 = ARM64_AFFINITY_INVALID;
+
     /* Our inbound IRQ and FIQ lines */
     if (kvm_enabled()) {
         /* VIRQ and VFIQ are unused with KVM but we add them to maintain
@@ -1921,16 +1924,6 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
         return;
     }
 
-    /* This cpu-id-to-MPIDR affinity is used only for TCG; KVM will override it.
-     * We don't support setting cluster ID ([16..23]) (known as Aff2
-     * in later ARM ARM versions), or any of the higher affinity level fields,
-     * so these bits always RAZ.
-     */
-    if (cpu->mp_affinity == ARM64_AFFINITY_INVALID) {
-        cpu->mp_affinity = arm_build_mp_affinity(cs->cpu_index,
-                                                 ARM_DEFAULT_CPUS_PER_CLUSTER);
-    }
-
     if (cpu->reset_hivecs) {
             cpu->reset_sctlr |= (1 << 13);
     }
@@ -2116,7 +2109,27 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
     if (cpu->core_count == -1) {
         cpu->core_count = smp_cpus;
     }
-#endif
+
+    /*
+     * Provide a default cpu-id-to-MPIDR affinity; we don't support setting
+     * Aff2 or Aff3.  This has already set by KVM and by some board models,
+     * which will have cleared our internal invalid bit.
+     */
+    if (cpu->mpidr_el1 == ARM64_AFFINITY_INVALID) {
+        assert(!kvm_enabled());
+        assert(cs->cpu_index < 256 * ARM_DEFAULT_CPUS_PER_CLUSTER);
+        cpu->mpidr_el1 = arm_build_mp_affinity(cs->cpu_index,
+                                               ARM_DEFAULT_CPUS_PER_CLUSTER);
+    }
+#endif /* !CONFIG_USER_ONLY */
+
+    /* Linux exposes M to userland, so still need to set it for user-only. */
+    if (arm_feature(env, ARM_FEATURE_V7MP)) {
+        cpu->mpidr_el1 |= (1u << 31);   /* M */
+        if (cpu->core_count == 1) {
+            cpu->mpidr_el1 |= 1 << 30;  /* U */
+        }
+    }
 
     if (tcg_enabled()) {
         int dcz_blocklen = 4 << cpu->dcz_blocksize;
@@ -2176,10 +2189,47 @@ static ObjectClass *arm_cpu_class_by_name(const char *cpu_model)
     return oc;
 }
 
+static void cpu_arm_set_mp_affinity(Object *obj, Visitor *v, const char *name,
+                                    void *opaque, Error **errp)
+{
+    ARMCPU *cpu = ARM_CPU(obj);
+    CPUARMState *env = &cpu->env;
+    uint64_t value;
+
+    if (!visit_type_uint64(v, name, &value, errp)) {
+        return;
+    }
+
+    if (arm_feature(env, ARM_FEATURE_AARCH64)) {
+        value &= ARM64_AFFINITY_MASK;
+    } else {
+        value &= ARM32_AFFINITY_MASK;
+    }
+    if (cpu->mpidr_el1 == ARM64_AFFINITY_INVALID) {
+        cpu->mpidr_el1 = value;
+    } else {
+        cpu->mpidr_el1 &= ~ARM64_AFFINITY_MASK;
+        cpu->mpidr_el1 |= value;
+    }
+}
+
+static void cpu_arm_get_mp_affinity(Object *obj, Visitor *v, const char *name,
+                                    void *opaque, Error **errp)
+{
+    ARMCPU *cpu = ARM_CPU(obj);
+    uint64_t value;
+
+    /*
+     * Note that the arm64 mask is a superset of the arm32 mask,
+     * and we will have limited the value upon setting.
+     * Here we simply want to return the Aff[0-3] fields.
+     */
+    value = cpu->mpidr_el1 & ARM64_AFFINITY_MASK;
+    visit_type_uint64(v, name, &value, errp);
+}
+
 static Property arm_cpu_properties[] = {
     DEFINE_PROP_UINT64("midr", ARMCPU, midr, 0),
-    DEFINE_PROP_UINT64("mp-affinity", ARMCPU,
-                        mp_affinity, ARM64_AFFINITY_INVALID),
     DEFINE_PROP_INT32("node-id", ARMCPU, node_id, CPU_UNSET_NUMA_NODE_ID),
     DEFINE_PROP_INT32("core-count", ARMCPU, core_count, -1),
     DEFINE_PROP_END_OF_LIST()
@@ -2244,6 +2294,10 @@ static void arm_cpu_class_init(ObjectClass *oc, void *data)
 
     device_class_set_props(dc, arm_cpu_properties);
 
+    object_class_property_add(oc, "mp-affinity", "uint64",
+                              cpu_arm_get_mp_affinity,
+                              cpu_arm_set_mp_affinity, NULL, NULL);
+
     resettable_class_set_parent_phases(rc, NULL, arm_cpu_reset_hold, NULL,
                                        &acc->parent_phases);
 
diff --git a/target/arm/cpu_tcg.c b/target/arm/cpu_tcg.c
index d566a815d3..7514065d5b 100644
--- a/target/arm/cpu_tcg.c
+++ b/target/arm/cpu_tcg.c
@@ -848,7 +848,6 @@ static void cortex_r5_initfn(Object *obj)
     cpu->isar.id_isar4 = 0x0010142;
     cpu->isar.id_isar5 = 0x0;
     cpu->isar.id_isar6 = 0x0;
-    cpu->mp_is_up = true;
     cpu->pmsav7_dregion = 16;
     cpu->isar.reset_pmcr_el0 = 0x41151800;
     define_arm_cp_regs(cpu, cortexr5_cp_reginfo);
diff --git a/target/arm/helper.c b/target/arm/helper.c
index bac2ea62c4..8f5097f995 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -4087,24 +4087,6 @@ static uint64_t midr_read(CPUARMState *env, const ARMCPRegInfo *ri)
     return raw_read(env, ri);
 }
 
-static uint64_t mpidr_read_val(CPUARMState *env)
-{
-    ARMCPU *cpu = env_archcpu(env);
-    uint64_t mpidr = cpu->mp_affinity;
-
-    if (arm_feature(env, ARM_FEATURE_V7MP)) {
-        mpidr |= (1U << 31);
-        /* Cores which are uniprocessor (non-coherent)
-         * but still implement the MP extensions set
-         * bit 30. (For instance, Cortex-R5).
-         */
-        if (cpu->mp_is_up) {
-            mpidr |= (1u << 30);
-        }
-    }
-    return mpidr;
-}
-
 static uint64_t mpidr_read(CPUARMState *env, const ARMCPRegInfo *ri)
 {
     unsigned int cur_el = arm_current_el(env);
@@ -4112,7 +4094,7 @@ static uint64_t mpidr_read(CPUARMState *env, const ARMCPRegInfo *ri)
     if (arm_is_el2_enabled(env) && cur_el == 1) {
         return env->cp15.vmpidr_el2;
     }
-    return mpidr_read_val(env);
+    return env_archcpu(env)->mpidr_el1;
 }
 
 static const ARMCPRegInfo lpae_cp_reginfo[] = {
@@ -7940,7 +7922,6 @@ void register_cp_regs_for_features(ARMCPU *cpu)
     if (arm_feature(env, ARM_FEATURE_EL2)
         || (arm_feature(env, ARM_FEATURE_EL3)
             && arm_feature(env, ARM_FEATURE_V8))) {
-        uint64_t vmpidr_def = mpidr_read_val(env);
         ARMCPRegInfo vpidr_regs[] = {
             { .name = "VPIDR", .state = ARM_CP_STATE_AA32,
               .cp = 15, .opc1 = 4, .crn = 0, .crm = 0, .opc2 = 0,
@@ -7956,12 +7937,12 @@ void register_cp_regs_for_features(ARMCPU *cpu)
             { .name = "VMPIDR", .state = ARM_CP_STATE_AA32,
               .cp = 15, .opc1 = 4, .crn = 0, .crm = 0, .opc2 = 5,
               .access = PL2_RW, .accessfn = access_el3_aa32ns,
-              .resetvalue = vmpidr_def,
+              .resetvalue = cpu->mpidr_el1,
               .type = ARM_CP_ALIAS | ARM_CP_EL3_NO_EL2_C_NZ,
               .fieldoffset = offsetoflow32(CPUARMState, cp15.vmpidr_el2) },
             { .name = "VMPIDR_EL2", .state = ARM_CP_STATE_AA64,
               .opc0 = 3, .opc1 = 4, .crn = 0, .crm = 0, .opc2 = 5,
-              .access = PL2_RW, .resetvalue = vmpidr_def,
+              .access = PL2_RW, .resetvalue = cpu->mpidr_el1,
               .type = ARM_CP_EL3_NO_EL2_C_NZ,
               .fieldoffset = offsetof(CPUARMState, cp15.vmpidr_el2) },
         };
diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c
index e0ba91f5c6..278a4b2ede 100644
--- a/target/arm/hvf/hvf.c
+++ b/target/arm/hvf/hvf.c
@@ -607,7 +607,7 @@ int hvf_arch_init_vcpu(CPUState *cpu)
     assert_hvf_ok(ret);
 
     ret = hv_vcpu_set_sys_reg(cpu->hvf->fd, HV_SYS_REG_MPIDR_EL1,
-                              arm_cpu->mp_affinity);
+                              arm_cpu->mpidr_el1);
     assert_hvf_ok(ret);
 
     ret = hv_vcpu_get_sys_reg(cpu->hvf->fd, HV_SYS_REG_ID_AA64PFR0_EL1, &pfr);
diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c
index 1197253d12..2cdd7517b8 100644
--- a/target/arm/kvm64.c
+++ b/target/arm/kvm64.c
@@ -914,11 +914,11 @@ int kvm_arch_init_vcpu(CPUState *cs)
      * Currently KVM has its own idea about MPIDR assignment, so we
      * override our defaults with what we get from KVM.
      */
-    ret = kvm_get_one_reg(cs, ARM64_SYS_REG(ARM_CPU_ID_MPIDR), &mpidr);
+    ret = kvm_get_one_reg(cs, ARM64_SYS_REG(ARM_CPU_ID_MPIDR),
+                          &cpu->mpidr_el1);
     if (ret) {
         return ret;
     }
-    cpu->mp_affinity = mpidr & ARM64_AFFINITY_MASK;
 
     kvm_arm_init_debug(cs);
 
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* [RFC PATCH 17/40] target/arm: Copy cp_regs from ARMCPUClass
  2023-01-03 18:16 [RFC PATCH 00/40] Toward class init of cpu features Richard Henderson
                   ` (15 preceding siblings ...)
  2023-01-03 18:16 ` [RFC PATCH 16/40] target/arm: Represent the entire MPIDR_EL1 Richard Henderson
@ 2023-01-03 18:16 ` Richard Henderson
  2023-01-03 18:16 ` [RFC PATCH 18/40] target/arm: Create cpreg definition functions with GHashTable arg Richard Henderson
                   ` (24 subsequent siblings)
  41 siblings, 0 replies; 77+ messages in thread
From: Richard Henderson @ 2023-01-03 18:16 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, berrange, eduardo, armbru, ajones, alex.bennee

Create a hash table of cpregs in ARMCPUClass and copy to the
instance in arm_cpu_init.  Population of this new table will
come in a future patch.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/cpu-qom.h |  3 +++
 target/arm/cpu.c     | 23 +++++++++++++++++++++--
 2 files changed, 24 insertions(+), 2 deletions(-)

diff --git a/target/arm/cpu-qom.h b/target/arm/cpu-qom.h
index 832b2cccf9..36d7fa9779 100644
--- a/target/arm/cpu-qom.h
+++ b/target/arm/cpu-qom.h
@@ -111,6 +111,9 @@ struct ARMCPUClass {
     DeviceRealize parent_realize;
     ResettablePhases parent_phases;
 
+    /* Coprocessor information */
+    GHashTable *cp_regs;
+
     /* 'compatible' string for this CPU for Linux device trees */
     const char *dtb_compatible;
 
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index a46fa424d3..da58f1fae7 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -1178,14 +1178,29 @@ uint64_t arm_build_mp_affinity(int idx, uint8_t clustersz)
     return (Aff1 << ARM_AFF1_SHIFT) | Aff0;
 }
 
+static void copy_cp_regs_1(gpointer key, gpointer value, gpointer user)
+{
+    GHashTable *new_table = user;
+    ARMCPRegInfo *new_reg = g_memdup(value, sizeof(ARMCPRegInfo));
+    bool ok = g_hash_table_insert(new_table, key, new_reg);
+    g_assert(ok);
+}
+
+static GHashTable *copy_cp_regs(GHashTable *cp_regs)
+{
+    GHashTable *ret = g_hash_table_new_full(g_direct_hash, g_direct_equal,
+                                            NULL, g_free);
+
+    g_hash_table_foreach(cp_regs, copy_cp_regs_1, ret);
+    return ret;
+}
+
 static void arm_cpu_initfn(Object *obj)
 {
     ARMCPU *cpu = ARM_CPU(obj);
     ARMCPUClass *acc = ARM_CPU_GET_CLASS(cpu);
 
     cpu_set_cpustate_pointers(cpu);
-    cpu->cp_regs = g_hash_table_new_full(g_direct_hash, g_direct_equal,
-                                         NULL, g_free);
 
     QLIST_INIT(&cpu->pre_el_change_hooks);
     QLIST_INIT(&cpu->el_change_hooks);
@@ -1219,6 +1234,8 @@ static void arm_cpu_initfn(Object *obj)
     cpu->gic_pribits = acc->gic_pribits;
     cpu->kvm_target = acc->kvm_target;
 
+    cpu->cp_regs = copy_cp_regs(acc->cp_regs);
+
 #ifdef CONFIG_USER_ONLY
 # ifdef TARGET_AARCH64
     /*
@@ -2337,6 +2354,8 @@ static void arm_cpu_leaf_class_init(ObjectClass *oc, void *data)
     const ARMCPUInfo *info = data;
 
     acc->info = info;
+    acc->cp_regs = g_hash_table_new_full(g_direct_hash, g_direct_equal,
+                                         NULL, g_free);
     if (info->class_init) {
         info->class_init(acc);
     }
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* [RFC PATCH 18/40] target/arm: Create cpreg definition functions with GHashTable arg
  2023-01-03 18:16 [RFC PATCH 00/40] Toward class init of cpu features Richard Henderson
                   ` (16 preceding siblings ...)
  2023-01-03 18:16 ` [RFC PATCH 17/40] target/arm: Copy cp_regs from ARMCPUClass Richard Henderson
@ 2023-01-03 18:16 ` Richard Henderson
  2023-01-03 18:16 ` [RFC PATCH 19/40] target/arm: Move most cpu initialization to the class Richard Henderson
                   ` (23 subsequent siblings)
  41 siblings, 0 replies; 77+ messages in thread
From: Richard Henderson @ 2023-01-03 18:16 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, berrange, eduardo, armbru, ajones, alex.bennee

This will allow registration of cpregs at the class level.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/cpregs.h | 33 +++++++++++++++++++++++++++----
 target/arm/helper.c | 47 +++++++++++++++++++++++++--------------------
 2 files changed, 55 insertions(+), 25 deletions(-)

diff --git a/target/arm/cpregs.h b/target/arm/cpregs.h
index 7e78c2c05c..11926c643e 100644
--- a/target/arm/cpregs.h
+++ b/target/arm/cpregs.h
@@ -381,16 +381,33 @@ struct ARMCPRegInfo {
 #define CPREG_FIELD64(env, ri) \
     (*(uint64_t *)((char *)(env) + (ri)->fieldoffset))
 
-void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu, const ARMCPRegInfo *reg,
-                                       void *opaque);
+void define_one_arm_cp_reg_with_table(GHashTable *cp_regs, uint64_t features,
+                                      const ARMCPRegInfo *reg, void *opaque);
+
+void define_arm_cp_regs_with_table(GHashTable *cp_regs, uint64_t features,
+                                   const ARMCPRegInfo *regs,
+                                   void *opaque, size_t len);
+
+static inline void
+define_one_arm_cp_reg_with_opaque(ARMCPU *cpu, const ARMCPRegInfo *reg,
+                                  void *opaque)
+{
+    define_one_arm_cp_reg_with_table(cpu->cp_regs, cpu->env.features,
+                                     reg, opaque);
+}
 
 static inline void define_one_arm_cp_reg(ARMCPU *cpu, const ARMCPRegInfo *regs)
 {
     define_one_arm_cp_reg_with_opaque(cpu, regs, NULL);
 }
 
-void define_arm_cp_regs_with_opaque_len(ARMCPU *cpu, const ARMCPRegInfo *regs,
-                                        void *opaque, size_t len);
+static inline void
+define_arm_cp_regs_with_opaque_len(ARMCPU *cpu, const ARMCPRegInfo *regs,
+                                   void *opaque, size_t len)
+{
+    define_arm_cp_regs_with_table(cpu->cp_regs, cpu->env.features,
+                                  regs, opaque, len);
+}
 
 #define define_arm_cp_regs_with_opaque(CPU, REGS, OPAQUE)               \
     do {                                                                \
@@ -402,6 +419,14 @@ void define_arm_cp_regs_with_opaque_len(ARMCPU *cpu, const ARMCPRegInfo *regs,
 #define define_arm_cp_regs(CPU, REGS) \
     define_arm_cp_regs_with_opaque(CPU, REGS, NULL)
 
+#define define_arm_cp_regs_with_class(ACC, REGS, OPAQUE)                \
+    do {                                                                \
+        QEMU_BUILD_BUG_ON(ARRAY_SIZE(REGS) == 0);                       \
+        ARMCPUClass *acc_ = (ACC);                                      \
+        define_arm_cp_regs_with_table(acc_->cp_regs, acc_->features,    \
+                                      REGS, OPAQUE, ARRAY_SIZE(REGS));  \
+    } while (0)
+
 const ARMCPRegInfo *get_arm_cp_reginfo(GHashTable *cpregs, uint32_t encoded_cp);
 
 /*
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 8f5097f995..43756e130a 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -8527,13 +8527,13 @@ CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
  * Private utility function for define_one_arm_cp_reg_with_opaque():
  * add a single reginfo struct to the hash table.
  */
-static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
+static void add_cpreg_to_hashtable(GHashTable *cp_regs, uint64_t features,
+                                   const ARMCPRegInfo *r,
                                    void *opaque, CPState state,
                                    CPSecureState secstate,
                                    int crm, int opc1, int opc2,
                                    const char *name)
 {
-    CPUARMState *env = &cpu->env;
     uint32_t key;
     ARMCPRegInfo *r2;
     bool is64 = r->type & ARM_CP_64BIT;
@@ -8541,6 +8541,7 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
     int cp = r->cp;
     size_t name_len;
     bool make_const;
+    bool have_el2;
 
     switch (state) {
     case ARM_CP_STATE_AA32:
@@ -8569,7 +8570,7 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
 
     /* Overriding of an existing definition must be explicitly requested. */
     if (!(r->type & ARM_CP_OVERRIDE)) {
-        const ARMCPRegInfo *oldreg = get_arm_cp_reginfo(cpu->cp_regs, key);
+        const ARMCPRegInfo *oldreg = get_arm_cp_reginfo(cp_regs, key);
         if (oldreg) {
             assert(oldreg->type & ARM_CP_OVERRIDE);
         }
@@ -8581,21 +8582,21 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
      * feature into the same ARMCPRegInfo array and define them all at once.
      */
     make_const = false;
-    if (arm_feature(env, ARM_FEATURE_EL3)) {
+    have_el2 = features & (1ull << ARM_FEATURE_EL2);
+    if (features & (1ull << ARM_FEATURE_EL3)) {
         /*
          * An EL2 register without EL2 but with EL3 is (usually) RES0.
          * See rule RJFFP in section D1.1.3 of DDI0487H.a.
          */
         int min_el = ctz32(r->access) / 2;
-        if (min_el == 2 && !arm_feature(env, ARM_FEATURE_EL2)) {
+        if (min_el == 2 && !have_el2) {
             if (r->type & ARM_CP_EL3_NO_EL2_UNDEF) {
                 return;
             }
             make_const = !(r->type & ARM_CP_EL3_NO_EL2_KEEP);
         }
     } else {
-        CPAccessRights max_el = (arm_feature(env, ARM_FEATURE_EL2)
-                                 ? PL2_RW : PL1_RW);
+        CPAccessRights max_el = have_el2 ? PL2_RW : PL1_RW;
         if ((r->access & max_el) == 0) {
             return;
         }
@@ -8677,7 +8678,7 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
                  *    that separate 32 and 64-bit definitions are provided.
                  */
                 if ((r->state == ARM_CP_STATE_BOTH && ns) ||
-                    (arm_feature(env, ARM_FEATURE_V8) && !ns)) {
+                    ((features & (1ull << ARM_FEATURE_V8)) && !ns)) {
                     r2->type |= ARM_CP_ALIAS;
                 }
             } else if ((secstate != r->secure) && !ns) {
@@ -8720,12 +8721,11 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
         assert(!raw_accessors_invalid(r2));
     }
 
-    g_hash_table_insert(cpu->cp_regs, (gpointer)(uintptr_t)key, r2);
+    g_hash_table_insert(cp_regs, (gpointer)(uintptr_t)key, r2);
 }
 
-
-void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu,
-                                       const ARMCPRegInfo *r, void *opaque)
+void define_one_arm_cp_reg_with_table(GHashTable *cp_regs, uint64_t features,
+                                      const ARMCPRegInfo *r, void *opaque)
 {
     /* Define implementations of coprocessor registers.
      * We store these in a hashtable because typically
@@ -8781,8 +8781,8 @@ void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu,
         }
         /* fall through */
     case ARM_CP_STATE_AA32:
-        if (arm_feature(&cpu->env, ARM_FEATURE_V8) &&
-            !arm_feature(&cpu->env, ARM_FEATURE_M)) {
+        if ((features & (1ull << ARM_FEATURE_V8)) &&
+            !(features & (1ull << ARM_FEATURE_M))) {
             assert(r->cp >= 14 && r->cp <= 15);
         } else {
             assert(r->cp < 8 || (r->cp >= 14 && r->cp <= 15));
@@ -8869,17 +8869,20 @@ void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu,
                         switch (r->secure) {
                         case ARM_CP_SECSTATE_S:
                         case ARM_CP_SECSTATE_NS:
-                            add_cpreg_to_hashtable(cpu, r, opaque, state,
+                            add_cpreg_to_hashtable(cp_regs, features, r,
+                                                   opaque, state,
                                                    r->secure, crm, opc1, opc2,
                                                    r->name);
                             break;
                         case ARM_CP_SECSTATE_BOTH:
                             name = g_strdup_printf("%s_S", r->name);
-                            add_cpreg_to_hashtable(cpu, r, opaque, state,
+                            add_cpreg_to_hashtable(cp_regs, features, r,
+                                                   opaque, state,
                                                    ARM_CP_SECSTATE_S,
                                                    crm, opc1, opc2, name);
                             g_free(name);
-                            add_cpreg_to_hashtable(cpu, r, opaque, state,
+                            add_cpreg_to_hashtable(cp_regs, features, r,
+                                                   opaque, state,
                                                    ARM_CP_SECSTATE_NS,
                                                    crm, opc1, opc2, r->name);
                             break;
@@ -8889,7 +8892,8 @@ void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu,
                     } else {
                         /* AArch64 registers get mapped to non-secure instance
                          * of AArch32 */
-                        add_cpreg_to_hashtable(cpu, r, opaque, state,
+                        add_cpreg_to_hashtable(cp_regs, features, r,
+                                               opaque, state,
                                                ARM_CP_SECSTATE_NS,
                                                crm, opc1, opc2, r->name);
                     }
@@ -8900,12 +8904,13 @@ void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu,
 }
 
 /* Define a whole list of registers */
-void define_arm_cp_regs_with_opaque_len(ARMCPU *cpu, const ARMCPRegInfo *regs,
-                                        void *opaque, size_t len)
+void define_arm_cp_regs_with_table(GHashTable *cp_regs, uint64_t features,
+                                   const ARMCPRegInfo *regs,
+                                   void *opaque, size_t len)
 {
     size_t i;
     for (i = 0; i < len; ++i) {
-        define_one_arm_cp_reg_with_opaque(cpu, regs + i, opaque);
+        define_one_arm_cp_reg_with_table(cp_regs, features, regs + i, opaque);
     }
 }
 
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* [RFC PATCH 19/40] target/arm: Move most cpu initialization to the class
  2023-01-03 18:16 [RFC PATCH 00/40] Toward class init of cpu features Richard Henderson
                   ` (17 preceding siblings ...)
  2023-01-03 18:16 ` [RFC PATCH 18/40] target/arm: Create cpreg definition functions with GHashTable arg Richard Henderson
@ 2023-01-03 18:16 ` Richard Henderson
  2023-01-03 18:16 ` [RFC PATCH 20/40] target/arm: Merge kvm64.c with kvm.c Richard Henderson
                   ` (22 subsequent siblings)
  41 siblings, 0 replies; 77+ messages in thread
From: Richard Henderson @ 2023-01-03 18:16 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, berrange, eduardo, armbru, ajones, alex.bennee

Quite a lot of the cpu definition is constant, and can be initialized
once with the type, rather than for each object instance.  For now,
leave the "host" cpu with the object init.

Note that the "max" class (and even a converted "host") must be delayed
until accellerator init, which itself is delayed until after board init,
which already creates all of the types.  Thus we invent our own hook.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/cpu-qom.h   |   3 +-
 target/arm/internals.h |   6 +-
 target/arm/cpu.c       |  23 +-
 target/arm/cpu64.c     | 227 +++++++++----------
 target/arm/cpu_tcg.c   | 496 ++++++++++++++++++-----------------------
 5 files changed, 355 insertions(+), 400 deletions(-)

diff --git a/target/arm/cpu-qom.h b/target/arm/cpu-qom.h
index 36d7fa9779..6b113d7fe6 100644
--- a/target/arm/cpu-qom.h
+++ b/target/arm/cpu-qom.h
@@ -35,8 +35,9 @@ OBJECT_DECLARE_CPU_TYPE(ARMCPU, ARMCPUClass, ARM_CPU)
 
 typedef struct ARMCPUInfo {
     const char *name;
-    void (*initfn)(Object *obj);
+    void (*object_init)(Object *obj);
     void (*class_init)(ARMCPUClass *acc);
+    bool (*class_late_init)(ARMCPUClass *acc, Error **errp);
 } ARMCPUInfo;
 
 void arm_cpu_register_parent(const ARMCPUInfo *info, const char *parent);
diff --git a/target/arm/internals.h b/target/arm/internals.h
index 161e42d50f..3feed370e7 100644
--- a/target/arm/internals.h
+++ b/target/arm/internals.h
@@ -1347,14 +1347,14 @@ void arm_cpu_lpa2_finalize(ARMCPU *cpu, Error **errp);
 #endif
 
 #ifdef CONFIG_USER_ONLY
-static inline void define_cortex_a72_a57_a53_cp_reginfo(ARMCPU *cpu) { }
+static inline void define_cortex_a72_a57_a53_cp_reginfo(ARMCPUClass *acc) { }
 #else
-void define_cortex_a72_a57_a53_cp_reginfo(ARMCPU *cpu);
+void define_cortex_a72_a57_a53_cp_reginfo(ARMCPUClass *acc);
 #endif
 
 bool el_is_in_host(CPUARMState *env, int el);
 
-void aa32_max_features(ARMCPU *cpu);
+void aa32_max_features(ARMCPUClass *acc);
 int exception_target_el(CPUARMState *env);
 bool arm_singlestep_active(CPUARMState *env);
 bool arm_generate_debug_exceptions(CPUARMState *env);
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index da58f1fae7..c58029fb4a 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -2351,23 +2351,35 @@ static void arm_cpu_class_init(ObjectClass *oc, void *data)
 static void arm_cpu_leaf_class_init(ObjectClass *oc, void *data)
 {
     ARMCPUClass *acc = ARM_CPU_CLASS(oc);
-    const ARMCPUInfo *info = data;
 
-    acc->info = info;
     acc->cp_regs = g_hash_table_new_full(g_direct_hash, g_direct_equal,
                                          NULL, g_free);
-    if (info->class_init) {
-        info->class_init(acc);
+
+    acc->info = data;
+    if (acc->info->class_init) {
+        acc->info->class_init(acc);
     }
 }
 
+static bool arm_cpu_class_late_init(ObjectClass *oc, Error **errp)
+{
+    ARMCPUClass *acc = ARM_CPU_CLASS(oc);
+
+    if (acc->info->class_late_init) {
+        if (!acc->info->class_late_init(acc, errp)) {
+            return false;
+        }
+    }
+    return true;
+}
+
 void arm_cpu_register_parent(const ARMCPUInfo *info, const char *parent)
 {
     TypeInfo type_info = {
         .parent = parent,
         .instance_size = sizeof(ARMCPU),
         .instance_align = __alignof__(ARMCPU),
-        .instance_init = info->initfn,
+        .instance_init = info->object_init,
         .class_size = sizeof(ARMCPUClass),
         .class_init = arm_cpu_leaf_class_init,
         .class_data = (void *)info,
@@ -2389,6 +2401,7 @@ static const TypeInfo arm_cpu_type_info = {
     .abstract = true,
     .class_size = sizeof(ARMCPUClass),
     .class_init = arm_cpu_class_init,
+    .class_late_init = arm_cpu_class_late_init,
 };
 
 static void arm_cpu_register_types(void)
diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
index 1d3aff868d..28b5a07244 100644
--- a/target/arm/cpu64.c
+++ b/target/arm/cpu64.c
@@ -36,19 +36,17 @@
 #include "hw/qdev-properties.h"
 #include "internals.h"
 
-static void aarch64_a35_initfn(Object *obj)
+static void aarch64_a35_class_init(ARMCPUClass *cpu)
 {
-    ARMCPU *cpu = ARM_CPU(obj);
-
     cpu->dtb_compatible = "arm,cortex-a35";
-    set_feature(&cpu->env, ARM_FEATURE_V8);
-    set_feature(&cpu->env, ARM_FEATURE_NEON);
-    set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER);
-    set_feature(&cpu->env, ARM_FEATURE_AARCH64);
-    set_feature(&cpu->env, ARM_FEATURE_CBAR_RO);
-    set_feature(&cpu->env, ARM_FEATURE_EL2);
-    set_feature(&cpu->env, ARM_FEATURE_EL3);
-    set_feature(&cpu->env, ARM_FEATURE_PMU);
+    set_class_feature(cpu, ARM_FEATURE_V8);
+    set_class_feature(cpu, ARM_FEATURE_NEON);
+    set_class_feature(cpu, ARM_FEATURE_GENERIC_TIMER);
+    set_class_feature(cpu, ARM_FEATURE_AARCH64);
+    set_class_feature(cpu, ARM_FEATURE_CBAR_RO);
+    set_class_feature(cpu, ARM_FEATURE_EL2);
+    set_class_feature(cpu, ARM_FEATURE_EL3);
+    set_class_feature(cpu, ARM_FEATURE_PMU);
 
     /* From B2.2 AArch64 identification registers. */
     cpu->midr = 0x411fd040;
@@ -678,19 +676,17 @@ void arm_cpu_lpa2_finalize(ARMCPU *cpu, Error **errp)
     cpu->isar.id_aa64mmfr0 = t;
 }
 
-static void aarch64_a57_initfn(Object *obj)
+static void aarch64_a57_class_init(ARMCPUClass *cpu)
 {
-    ARMCPU *cpu = ARM_CPU(obj);
-
     cpu->dtb_compatible = "arm,cortex-a57";
-    set_feature(&cpu->env, ARM_FEATURE_V8);
-    set_feature(&cpu->env, ARM_FEATURE_NEON);
-    set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER);
-    set_feature(&cpu->env, ARM_FEATURE_AARCH64);
-    set_feature(&cpu->env, ARM_FEATURE_CBAR_RO);
-    set_feature(&cpu->env, ARM_FEATURE_EL2);
-    set_feature(&cpu->env, ARM_FEATURE_EL3);
-    set_feature(&cpu->env, ARM_FEATURE_PMU);
+    set_class_feature(cpu, ARM_FEATURE_V8);
+    set_class_feature(cpu, ARM_FEATURE_NEON);
+    set_class_feature(cpu, ARM_FEATURE_GENERIC_TIMER);
+    set_class_feature(cpu, ARM_FEATURE_AARCH64);
+    set_class_feature(cpu, ARM_FEATURE_CBAR_RO);
+    set_class_feature(cpu, ARM_FEATURE_EL2);
+    set_class_feature(cpu, ARM_FEATURE_EL3);
+    set_class_feature(cpu, ARM_FEATURE_PMU);
     cpu->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A57;
     cpu->midr = 0x411fd070;
     cpu->revidr = 0x00000000;
@@ -735,19 +731,17 @@ static void aarch64_a57_initfn(Object *obj)
     define_cortex_a72_a57_a53_cp_reginfo(cpu);
 }
 
-static void aarch64_a53_initfn(Object *obj)
+static void aarch64_a53_class_init(ARMCPUClass *cpu)
 {
-    ARMCPU *cpu = ARM_CPU(obj);
-
     cpu->dtb_compatible = "arm,cortex-a53";
-    set_feature(&cpu->env, ARM_FEATURE_V8);
-    set_feature(&cpu->env, ARM_FEATURE_NEON);
-    set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER);
-    set_feature(&cpu->env, ARM_FEATURE_AARCH64);
-    set_feature(&cpu->env, ARM_FEATURE_CBAR_RO);
-    set_feature(&cpu->env, ARM_FEATURE_EL2);
-    set_feature(&cpu->env, ARM_FEATURE_EL3);
-    set_feature(&cpu->env, ARM_FEATURE_PMU);
+    set_class_feature(cpu, ARM_FEATURE_V8);
+    set_class_feature(cpu, ARM_FEATURE_NEON);
+    set_class_feature(cpu, ARM_FEATURE_GENERIC_TIMER);
+    set_class_feature(cpu, ARM_FEATURE_AARCH64);
+    set_class_feature(cpu, ARM_FEATURE_CBAR_RO);
+    set_class_feature(cpu, ARM_FEATURE_EL2);
+    set_class_feature(cpu, ARM_FEATURE_EL3);
+    set_class_feature(cpu, ARM_FEATURE_PMU);
     cpu->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A53;
     cpu->midr = 0x410fd034;
     cpu->revidr = 0x00000000;
@@ -792,19 +786,17 @@ static void aarch64_a53_initfn(Object *obj)
     define_cortex_a72_a57_a53_cp_reginfo(cpu);
 }
 
-static void aarch64_a55_initfn(Object *obj)
+static void aarch64_a55_class_init(ARMCPUClass *cpu)
 {
-    ARMCPU *cpu = ARM_CPU(obj);
-
     cpu->dtb_compatible = "arm,cortex-a55";
-    set_feature(&cpu->env, ARM_FEATURE_V8);
-    set_feature(&cpu->env, ARM_FEATURE_NEON);
-    set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER);
-    set_feature(&cpu->env, ARM_FEATURE_AARCH64);
-    set_feature(&cpu->env, ARM_FEATURE_CBAR_RO);
-    set_feature(&cpu->env, ARM_FEATURE_EL2);
-    set_feature(&cpu->env, ARM_FEATURE_EL3);
-    set_feature(&cpu->env, ARM_FEATURE_PMU);
+    set_class_feature(cpu, ARM_FEATURE_V8);
+    set_class_feature(cpu, ARM_FEATURE_NEON);
+    set_class_feature(cpu, ARM_FEATURE_GENERIC_TIMER);
+    set_class_feature(cpu, ARM_FEATURE_AARCH64);
+    set_class_feature(cpu, ARM_FEATURE_CBAR_RO);
+    set_class_feature(cpu, ARM_FEATURE_EL2);
+    set_class_feature(cpu, ARM_FEATURE_EL3);
+    set_class_feature(cpu, ARM_FEATURE_PMU);
 
     /* Ordered by B2.4 AArch64 registers by functional group */
     cpu->clidr = 0x82000023;
@@ -860,19 +852,17 @@ static void aarch64_a55_initfn(Object *obj)
     cpu->isar.reset_pmcr_el0 = 0x410b3000;
 }
 
-static void aarch64_a72_initfn(Object *obj)
+static void aarch64_a72_class_init(ARMCPUClass *cpu)
 {
-    ARMCPU *cpu = ARM_CPU(obj);
-
     cpu->dtb_compatible = "arm,cortex-a72";
-    set_feature(&cpu->env, ARM_FEATURE_V8);
-    set_feature(&cpu->env, ARM_FEATURE_NEON);
-    set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER);
-    set_feature(&cpu->env, ARM_FEATURE_AARCH64);
-    set_feature(&cpu->env, ARM_FEATURE_CBAR_RO);
-    set_feature(&cpu->env, ARM_FEATURE_EL2);
-    set_feature(&cpu->env, ARM_FEATURE_EL3);
-    set_feature(&cpu->env, ARM_FEATURE_PMU);
+    set_class_feature(cpu, ARM_FEATURE_V8);
+    set_class_feature(cpu, ARM_FEATURE_NEON);
+    set_class_feature(cpu, ARM_FEATURE_GENERIC_TIMER);
+    set_class_feature(cpu, ARM_FEATURE_AARCH64);
+    set_class_feature(cpu, ARM_FEATURE_CBAR_RO);
+    set_class_feature(cpu, ARM_FEATURE_EL2);
+    set_class_feature(cpu, ARM_FEATURE_EL3);
+    set_class_feature(cpu, ARM_FEATURE_PMU);
     cpu->midr = 0x410fd083;
     cpu->revidr = 0x00000000;
     cpu->reset_fpsid = 0x41034080;
@@ -915,19 +905,17 @@ static void aarch64_a72_initfn(Object *obj)
     define_cortex_a72_a57_a53_cp_reginfo(cpu);
 }
 
-static void aarch64_a76_initfn(Object *obj)
+static void aarch64_a76_class_init(ARMCPUClass *cpu)
 {
-    ARMCPU *cpu = ARM_CPU(obj);
-
     cpu->dtb_compatible = "arm,cortex-a76";
-    set_feature(&cpu->env, ARM_FEATURE_V8);
-    set_feature(&cpu->env, ARM_FEATURE_NEON);
-    set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER);
-    set_feature(&cpu->env, ARM_FEATURE_AARCH64);
-    set_feature(&cpu->env, ARM_FEATURE_CBAR_RO);
-    set_feature(&cpu->env, ARM_FEATURE_EL2);
-    set_feature(&cpu->env, ARM_FEATURE_EL3);
-    set_feature(&cpu->env, ARM_FEATURE_PMU);
+    set_class_feature(cpu, ARM_FEATURE_V8);
+    set_class_feature(cpu, ARM_FEATURE_NEON);
+    set_class_feature(cpu, ARM_FEATURE_GENERIC_TIMER);
+    set_class_feature(cpu, ARM_FEATURE_AARCH64);
+    set_class_feature(cpu, ARM_FEATURE_CBAR_RO);
+    set_class_feature(cpu, ARM_FEATURE_EL2);
+    set_class_feature(cpu, ARM_FEATURE_EL3);
+    set_class_feature(cpu, ARM_FEATURE_PMU);
 
     /* Ordered by B2.4 AArch64 registers by functional group */
     cpu->clidr = 0x82000023;
@@ -984,18 +972,16 @@ static void aarch64_a76_initfn(Object *obj)
     cpu->isar.reset_pmcr_el0 = 0x410b3000;
 }
 
-static void aarch64_a64fx_initfn(Object *obj)
+static void aarch64_a64fx_class_init(ARMCPUClass *cpu)
 {
-    ARMCPU *cpu = ARM_CPU(obj);
-
     cpu->dtb_compatible = "arm,a64fx";
-    set_feature(&cpu->env, ARM_FEATURE_V8);
-    set_feature(&cpu->env, ARM_FEATURE_NEON);
-    set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER);
-    set_feature(&cpu->env, ARM_FEATURE_AARCH64);
-    set_feature(&cpu->env, ARM_FEATURE_EL2);
-    set_feature(&cpu->env, ARM_FEATURE_EL3);
-    set_feature(&cpu->env, ARM_FEATURE_PMU);
+    set_class_feature(cpu, ARM_FEATURE_V8);
+    set_class_feature(cpu, ARM_FEATURE_NEON);
+    set_class_feature(cpu, ARM_FEATURE_GENERIC_TIMER);
+    set_class_feature(cpu, ARM_FEATURE_AARCH64);
+    set_class_feature(cpu, ARM_FEATURE_EL2);
+    set_class_feature(cpu, ARM_FEATURE_EL3);
+    set_class_feature(cpu, ARM_FEATURE_PMU);
     cpu->midr = 0x461f0010;
     cpu->revidr = 0x00000000;
     cpu->ctr = 0x86668006;
@@ -1021,31 +1007,33 @@ static void aarch64_a64fx_initfn(Object *obj)
     cpu->gic_vpribits = 5;
     cpu->gic_vprebits = 5;
     cpu->gic_pribits = 5;
+    cpu->isar.reset_pmcr_el0 = 0x46014040;
+
+    /* TODO:  Add A64FX specific HPC extension registers */
+}
+
+static void aarch64_a64fx_object_init(Object *obj)
+{
+    ARMCPU *cpu = ARM_CPU(obj);
 
     /* The A64FX supports only 128, 256 and 512 bit vector lengths */
     aarch64_add_sve_properties(obj);
     cpu->sve_vq.supported = (1 << 0)  /* 128bit */
                           | (1 << 1)  /* 256bit */
                           | (1 << 3); /* 512bit */
-
-    cpu->isar.reset_pmcr_el0 = 0x46014040;
-
-    /* TODO:  Add A64FX specific HPC extension registers */
 }
 
-static void aarch64_neoverse_n1_initfn(Object *obj)
+static void aarch64_neoverse_n1_class_init(ARMCPUClass *cpu)
 {
-    ARMCPU *cpu = ARM_CPU(obj);
-
     cpu->dtb_compatible = "arm,neoverse-n1";
-    set_feature(&cpu->env, ARM_FEATURE_V8);
-    set_feature(&cpu->env, ARM_FEATURE_NEON);
-    set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER);
-    set_feature(&cpu->env, ARM_FEATURE_AARCH64);
-    set_feature(&cpu->env, ARM_FEATURE_CBAR_RO);
-    set_feature(&cpu->env, ARM_FEATURE_EL2);
-    set_feature(&cpu->env, ARM_FEATURE_EL3);
-    set_feature(&cpu->env, ARM_FEATURE_PMU);
+    set_class_feature(cpu, ARM_FEATURE_V8);
+    set_class_feature(cpu, ARM_FEATURE_NEON);
+    set_class_feature(cpu, ARM_FEATURE_GENERIC_TIMER);
+    set_class_feature(cpu, ARM_FEATURE_AARCH64);
+    set_class_feature(cpu, ARM_FEATURE_CBAR_RO);
+    set_class_feature(cpu, ARM_FEATURE_EL2);
+    set_class_feature(cpu, ARM_FEATURE_EL3);
+    set_class_feature(cpu, ARM_FEATURE_PMU);
 
     /* Ordered by B2.4 AArch64 registers by functional group */
     cpu->clidr = 0x82000023;
@@ -1102,7 +1090,7 @@ static void aarch64_neoverse_n1_initfn(Object *obj)
     cpu->isar.reset_pmcr_el0 = 0x410c3000;
 }
 
-static void aarch64_host_initfn(Object *obj)
+static void aarch64_host_object_init(Object *obj)
 {
 #if defined(CONFIG_KVM)
     ARMCPU *cpu = ARM_CPU(obj);
@@ -1120,26 +1108,24 @@ static void aarch64_host_initfn(Object *obj)
 #endif
 }
 
-/* -cpu max: if KVM is enabled, like -cpu host (best possible with this host);
- * otherwise, a CPU with as many features enabled as our emulation supports.
+/*
+ * -cpu max: if hardware acceleration is enabled, like -cpu host
+ * (best possible with this host); otherwise, a CPU with as many
+ * features enabled as TCG supports.
  * The version of '-cpu max' for qemu-system-arm is defined in cpu.c;
- * this only needs to handle 64 bits.
+ * this version only needs to handle 64 bits.
  */
-static void aarch64_max_initfn(Object *obj)
+static bool aarch64_max_class_late_init(ARMCPUClass *cpu, Error **errp)
 {
-    ARMCPU *cpu = ARM_CPU(obj);
     uint64_t t;
     uint32_t u;
 
     if (kvm_enabled() || hvf_enabled()) {
-        /* With KVM or HVF, '-cpu max' is identical to '-cpu host' */
-        aarch64_host_initfn(obj);
-        return;
+        return true;
     }
 
     /* '-cpu max' for TCG: we currently do this as "A57 with extra things" */
-
-    aarch64_a57_initfn(obj);
+    aarch64_a57_class_init(cpu);
 
     /*
      * Reset MIDR so the guest doesn't mistake our 'max' CPU type for a real
@@ -1296,6 +1282,18 @@ static void aarch64_max_initfn(Object *obj)
     cpu->ctr = 0x80038003; /* 32 byte I and D cacheline size, VIPT icache */
     cpu->dcz_blocksize = 7; /*  512 bytes */
 #endif
+    return true;
+}
+
+static void aarch64_max_object_init(Object *obj)
+{
+    ARMCPU *cpu = ARM_CPU(obj);
+
+    if (kvm_enabled() || hvf_enabled()) {
+        /* With KVM or HVF, '-cpu max' is identical to '-cpu host' */
+        aarch64_host_object_init(obj);
+        return;
+    }
 
     cpu->sve_vq.supported = MAKE_64BIT_MASK(0, ARM_MAX_VQ);
     cpu->sme_vq.supported = SVE_VQ_POW2_MAP;
@@ -1309,17 +1307,22 @@ static void aarch64_max_initfn(Object *obj)
 }
 
 static const ARMCPUInfo aarch64_cpus[] = {
-    { .name = "cortex-a35",         .initfn = aarch64_a35_initfn },
-    { .name = "cortex-a57",         .initfn = aarch64_a57_initfn },
-    { .name = "cortex-a53",         .initfn = aarch64_a53_initfn },
-    { .name = "cortex-a55",         .initfn = aarch64_a55_initfn },
-    { .name = "cortex-a72",         .initfn = aarch64_a72_initfn },
-    { .name = "cortex-a76",         .initfn = aarch64_a76_initfn },
-    { .name = "a64fx",              .initfn = aarch64_a64fx_initfn },
-    { .name = "neoverse-n1",        .initfn = aarch64_neoverse_n1_initfn },
-    { .name = "max",                .initfn = aarch64_max_initfn },
+    { .name = "cortex-a35", .class_init = aarch64_a35_class_init },
+    { .name = "cortex-a57", .class_init = aarch64_a57_class_init },
+    { .name = "cortex-a53", .class_init = aarch64_a53_class_init },
+    { .name = "cortex-a55", .class_init = aarch64_a55_class_init },
+    { .name = "cortex-a72", .class_init = aarch64_a72_class_init },
+    { .name = "cortex-a76", .class_init = aarch64_a76_class_init },
+    { .name = "neoverse-n1", .class_init = aarch64_neoverse_n1_class_init },
+    { .name = "a64fx",
+      .class_init = aarch64_a64fx_class_init,
+      .object_init = aarch64_a64fx_object_init },
+    { .name = "max",
+      .class_late_init = aarch64_max_class_late_init,
+      .object_init = aarch64_max_object_init },
 #if defined(CONFIG_KVM) || defined(CONFIG_HVF)
-    { .name = "host",               .initfn = aarch64_host_initfn },
+    { .name = "host",
+      .object_init = aarch64_host_object_init },
 #endif
 };
 
diff --git a/target/arm/cpu_tcg.c b/target/arm/cpu_tcg.c
index 7514065d5b..f35b4a52b0 100644
--- a/target/arm/cpu_tcg.c
+++ b/target/arm/cpu_tcg.c
@@ -22,7 +22,7 @@
 
 
 /* Share AArch32 -cpu max features with AArch64. */
-void aa32_max_features(ARMCPU *cpu)
+void aa32_max_features(ARMCPUClass *cpu)
 {
     uint32_t t;
 
@@ -143,9 +143,9 @@ static const ARMCPRegInfo cortex_a72_a57_a53_cp_reginfo[] = {
       .access = PL1_RW, .type = ARM_CP_CONST | ARM_CP_64BIT, .resetvalue = 0 },
 };
 
-void define_cortex_a72_a57_a53_cp_reginfo(ARMCPU *cpu)
+void define_cortex_a72_a57_a53_cp_reginfo(ARMCPUClass *acc)
 {
-    define_arm_cp_regs(cpu, cortex_a72_a57_a53_cp_reginfo);
+    define_arm_cp_regs_with_class(acc, cortex_a72_a57_a53_cp_reginfo, NULL);
 }
 #endif /* !CONFIG_USER_ONLY */
 
@@ -178,14 +178,12 @@ static bool arm_v7m_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
 }
 #endif /* !CONFIG_USER_ONLY && CONFIG_TCG */
 
-static void arm926_initfn(Object *obj)
+static void arm926_class_init(ARMCPUClass *cpu)
 {
-    ARMCPU *cpu = ARM_CPU(obj);
-
     cpu->dtb_compatible = "arm,arm926";
-    set_feature(&cpu->env, ARM_FEATURE_V5);
-    set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS);
-    set_feature(&cpu->env, ARM_FEATURE_CACHE_TEST_CLEAN);
+    set_class_feature(cpu, ARM_FEATURE_V5);
+    set_class_feature(cpu, ARM_FEATURE_DUMMY_C15_REGS);
+    set_class_feature(cpu, ARM_FEATURE_CACHE_TEST_CLEAN);
     cpu->midr = 0x41069265;
     cpu->reset_fpsid = 0x41011090;
     cpu->ctr = 0x1dd20d2;
@@ -205,28 +203,32 @@ static void arm926_initfn(Object *obj)
     cpu->isar.mvfr0 = FIELD_DP32(cpu->isar.mvfr0, MVFR0, FPDP, 1);
 }
 
-static void arm946_initfn(Object *obj)
+static void arm946_class_init(ARMCPUClass *cpu)
 {
-    ARMCPU *cpu = ARM_CPU(obj);
-
     cpu->dtb_compatible = "arm,arm946";
-    set_feature(&cpu->env, ARM_FEATURE_V5);
-    set_feature(&cpu->env, ARM_FEATURE_PMSA);
-    set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS);
+    set_class_feature(cpu, ARM_FEATURE_V5);
+    set_class_feature(cpu, ARM_FEATURE_PMSA);
+    set_class_feature(cpu, ARM_FEATURE_DUMMY_C15_REGS);
     cpu->midr = 0x41059461;
     cpu->ctr = 0x0f004006;
     cpu->reset_sctlr = 0x00000078;
 }
 
-static void arm1026_initfn(Object *obj)
+static void arm1026_class_init(ARMCPUClass *cpu)
 {
-    ARMCPU *cpu = ARM_CPU(obj);
+    /* The 1026 had an IFAR at c6,c0,0,1 rather than the ARMv6 c6,c0,0,2 */
+    static const ARMCPRegInfo ifar[1] = {
+        { .name = "IFAR", .cp = 15, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 1,
+          .access = PL1_RW,
+          .fieldoffset = offsetof(CPUARMState, cp15.ifar_ns),
+          .resetvalue = 0 }
+    };
 
     cpu->dtb_compatible = "arm,arm1026";
-    set_feature(&cpu->env, ARM_FEATURE_V5);
-    set_feature(&cpu->env, ARM_FEATURE_AUXCR);
-    set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS);
-    set_feature(&cpu->env, ARM_FEATURE_CACHE_TEST_CLEAN);
+    set_class_feature(cpu, ARM_FEATURE_V5);
+    set_class_feature(cpu, ARM_FEATURE_AUXCR);
+    set_class_feature(cpu, ARM_FEATURE_DUMMY_C15_REGS);
+    set_class_feature(cpu, ARM_FEATURE_CACHE_TEST_CLEAN);
     cpu->midr = 0x4106a262;
     cpu->reset_fpsid = 0x410110a0;
     cpu->ctr = 0x1dd20d2;
@@ -246,21 +248,11 @@ static void arm1026_initfn(Object *obj)
     cpu->isar.mvfr0 = FIELD_DP32(cpu->isar.mvfr0, MVFR0, FPSP, 1);
     cpu->isar.mvfr0 = FIELD_DP32(cpu->isar.mvfr0, MVFR0, FPDP, 1);
 
-    {
-        /* The 1026 had an IFAR at c6,c0,0,1 rather than the ARMv6 c6,c0,0,2 */
-        ARMCPRegInfo ifar = {
-            .name = "IFAR", .cp = 15, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 1,
-            .access = PL1_RW,
-            .fieldoffset = offsetof(CPUARMState, cp15.ifar_ns),
-            .resetvalue = 0
-        };
-        define_one_arm_cp_reg(cpu, &ifar);
-    }
+    define_arm_cp_regs_with_class(cpu, ifar, NULL);
 }
 
-static void arm1136_r2_initfn(Object *obj)
+static void arm1136_r2_class_init(ARMCPUClass *cpu)
 {
-    ARMCPU *cpu = ARM_CPU(obj);
     /*
      * What qemu calls "arm1136_r2" is actually the 1136 r0p2, ie an
      * older core than plain "arm1136". In particular this does not
@@ -271,10 +263,10 @@ static void arm1136_r2_initfn(Object *obj)
      */
 
     cpu->dtb_compatible = "arm,arm1136";
-    set_feature(&cpu->env, ARM_FEATURE_V6);
-    set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS);
-    set_feature(&cpu->env, ARM_FEATURE_CACHE_DIRTY_REG);
-    set_feature(&cpu->env, ARM_FEATURE_CACHE_BLOCK_OPS);
+    set_class_feature(cpu, ARM_FEATURE_V6);
+    set_class_feature(cpu, ARM_FEATURE_DUMMY_C15_REGS);
+    set_class_feature(cpu, ARM_FEATURE_CACHE_DIRTY_REG);
+    set_class_feature(cpu, ARM_FEATURE_CACHE_BLOCK_OPS);
     cpu->midr = 0x4107b362;
     cpu->reset_fpsid = 0x410120b4;
     cpu->isar.mvfr0 = 0x11111111;
@@ -296,16 +288,14 @@ static void arm1136_r2_initfn(Object *obj)
     cpu->reset_auxcr = 7;
 }
 
-static void arm1136_initfn(Object *obj)
+static void arm1136_class_init(ARMCPUClass *cpu)
 {
-    ARMCPU *cpu = ARM_CPU(obj);
-
     cpu->dtb_compatible = "arm,arm1136";
-    set_feature(&cpu->env, ARM_FEATURE_V6K);
-    set_feature(&cpu->env, ARM_FEATURE_V6);
-    set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS);
-    set_feature(&cpu->env, ARM_FEATURE_CACHE_DIRTY_REG);
-    set_feature(&cpu->env, ARM_FEATURE_CACHE_BLOCK_OPS);
+    set_class_feature(cpu, ARM_FEATURE_V6K);
+    set_class_feature(cpu, ARM_FEATURE_V6);
+    set_class_feature(cpu, ARM_FEATURE_DUMMY_C15_REGS);
+    set_class_feature(cpu, ARM_FEATURE_CACHE_DIRTY_REG);
+    set_class_feature(cpu, ARM_FEATURE_CACHE_BLOCK_OPS);
     cpu->midr = 0x4117b363;
     cpu->reset_fpsid = 0x410120b4;
     cpu->isar.mvfr0 = 0x11111111;
@@ -327,17 +317,15 @@ static void arm1136_initfn(Object *obj)
     cpu->reset_auxcr = 7;
 }
 
-static void arm1176_initfn(Object *obj)
+static void arm1176_class_init(ARMCPUClass *cpu)
 {
-    ARMCPU *cpu = ARM_CPU(obj);
-
     cpu->dtb_compatible = "arm,arm1176";
-    set_feature(&cpu->env, ARM_FEATURE_V6K);
-    set_feature(&cpu->env, ARM_FEATURE_VAPA);
-    set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS);
-    set_feature(&cpu->env, ARM_FEATURE_CACHE_DIRTY_REG);
-    set_feature(&cpu->env, ARM_FEATURE_CACHE_BLOCK_OPS);
-    set_feature(&cpu->env, ARM_FEATURE_EL3);
+    set_class_feature(cpu, ARM_FEATURE_V6K);
+    set_class_feature(cpu, ARM_FEATURE_VAPA);
+    set_class_feature(cpu, ARM_FEATURE_DUMMY_C15_REGS);
+    set_class_feature(cpu, ARM_FEATURE_CACHE_DIRTY_REG);
+    set_class_feature(cpu, ARM_FEATURE_CACHE_BLOCK_OPS);
+    set_class_feature(cpu, ARM_FEATURE_EL3);
     cpu->midr = 0x410fb767;
     cpu->reset_fpsid = 0x410120b5;
     cpu->isar.mvfr0 = 0x11111111;
@@ -359,15 +347,13 @@ static void arm1176_initfn(Object *obj)
     cpu->reset_auxcr = 7;
 }
 
-static void arm11mpcore_initfn(Object *obj)
+static void arm11mpcore_class_init(ARMCPUClass *cpu)
 {
-    ARMCPU *cpu = ARM_CPU(obj);
-
     cpu->dtb_compatible = "arm,arm11mpcore";
-    set_feature(&cpu->env, ARM_FEATURE_V6K);
-    set_feature(&cpu->env, ARM_FEATURE_VAPA);
-    set_feature(&cpu->env, ARM_FEATURE_MPIDR);
-    set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS);
+    set_class_feature(cpu, ARM_FEATURE_V6K);
+    set_class_feature(cpu, ARM_FEATURE_VAPA);
+    set_class_feature(cpu, ARM_FEATURE_MPIDR);
+    set_class_feature(cpu, ARM_FEATURE_DUMMY_C15_REGS);
     cpu->midr = 0x410fb022;
     cpu->reset_fpsid = 0x410120b4;
     cpu->isar.mvfr0 = 0x11111111;
@@ -395,16 +381,14 @@ static const ARMCPRegInfo cortexa8_cp_reginfo[] = {
       .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
 };
 
-static void cortex_a8_initfn(Object *obj)
+static void cortex_a8_class_init(ARMCPUClass *cpu)
 {
-    ARMCPU *cpu = ARM_CPU(obj);
-
     cpu->dtb_compatible = "arm,cortex-a8";
-    set_feature(&cpu->env, ARM_FEATURE_V7);
-    set_feature(&cpu->env, ARM_FEATURE_NEON);
-    set_feature(&cpu->env, ARM_FEATURE_THUMB2EE);
-    set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS);
-    set_feature(&cpu->env, ARM_FEATURE_EL3);
+    set_class_feature(cpu, ARM_FEATURE_V7);
+    set_class_feature(cpu, ARM_FEATURE_NEON);
+    set_class_feature(cpu, ARM_FEATURE_THUMB2EE);
+    set_class_feature(cpu, ARM_FEATURE_DUMMY_C15_REGS);
+    set_class_feature(cpu, ARM_FEATURE_EL3);
     cpu->midr = 0x410fc080;
     cpu->reset_fpsid = 0x410330c0;
     cpu->isar.mvfr0 = 0x11110222;
@@ -431,7 +415,7 @@ static void cortex_a8_initfn(Object *obj)
     cpu->ccsidr[2] = 0xf0000000; /* No L2 icache. */
     cpu->reset_auxcr = 2;
     cpu->isar.reset_pmcr_el0 = 0x41002000;
-    define_arm_cp_regs(cpu, cortexa8_cp_reginfo);
+    define_arm_cp_regs_with_class(cpu, cortexa8_cp_reginfo, NULL);
 }
 
 static const ARMCPRegInfo cortexa9_cp_reginfo[] = {
@@ -463,22 +447,20 @@ static const ARMCPRegInfo cortexa9_cp_reginfo[] = {
       .access = PL1_RW, .resetvalue = 0, .type = ARM_CP_CONST },
 };
 
-static void cortex_a9_initfn(Object *obj)
+static void cortex_a9_class_init(ARMCPUClass *cpu)
 {
-    ARMCPU *cpu = ARM_CPU(obj);
-
     cpu->dtb_compatible = "arm,cortex-a9";
-    set_feature(&cpu->env, ARM_FEATURE_V7);
-    set_feature(&cpu->env, ARM_FEATURE_NEON);
-    set_feature(&cpu->env, ARM_FEATURE_THUMB2EE);
-    set_feature(&cpu->env, ARM_FEATURE_EL3);
+    set_class_feature(cpu, ARM_FEATURE_V7);
+    set_class_feature(cpu, ARM_FEATURE_NEON);
+    set_class_feature(cpu, ARM_FEATURE_THUMB2EE);
+    set_class_feature(cpu, ARM_FEATURE_EL3);
     /*
      * Note that A9 supports the MP extensions even for
      * A9UP and single-core A9MP (which are both different
      * and valid configurations; we don't model A9UP).
      */
-    set_feature(&cpu->env, ARM_FEATURE_V7MP);
-    set_feature(&cpu->env, ARM_FEATURE_CBAR);
+    set_class_feature(cpu, ARM_FEATURE_V7MP);
+    set_class_feature(cpu, ARM_FEATURE_CBAR);
     cpu->midr = 0x410fc090;
     cpu->reset_fpsid = 0x41033090;
     cpu->isar.mvfr0 = 0x11110222;
@@ -503,7 +485,7 @@ static void cortex_a9_initfn(Object *obj)
     cpu->ccsidr[0] = 0xe00fe019; /* 16k L1 dcache. */
     cpu->ccsidr[1] = 0x200fe019; /* 16k L1 icache. */
     cpu->isar.reset_pmcr_el0 = 0x41093000;
-    define_arm_cp_regs(cpu, cortexa9_cp_reginfo);
+    define_arm_cp_regs_with_class(cpu, cortexa9_cp_reginfo, NULL);
 }
 
 #ifndef CONFIG_USER_ONLY
@@ -529,20 +511,18 @@ static const ARMCPRegInfo cortexa15_cp_reginfo[] = {
       .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
 };
 
-static void cortex_a7_initfn(Object *obj)
+static void cortex_a7_class_init(ARMCPUClass *cpu)
 {
-    ARMCPU *cpu = ARM_CPU(obj);
-
     cpu->dtb_compatible = "arm,cortex-a7";
-    set_feature(&cpu->env, ARM_FEATURE_V7VE);
-    set_feature(&cpu->env, ARM_FEATURE_NEON);
-    set_feature(&cpu->env, ARM_FEATURE_THUMB2EE);
-    set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER);
-    set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS);
-    set_feature(&cpu->env, ARM_FEATURE_CBAR_RO);
-    set_feature(&cpu->env, ARM_FEATURE_EL2);
-    set_feature(&cpu->env, ARM_FEATURE_EL3);
-    set_feature(&cpu->env, ARM_FEATURE_PMU);
+    set_class_feature(cpu, ARM_FEATURE_V7VE);
+    set_class_feature(cpu, ARM_FEATURE_NEON);
+    set_class_feature(cpu, ARM_FEATURE_THUMB2EE);
+    set_class_feature(cpu, ARM_FEATURE_GENERIC_TIMER);
+    set_class_feature(cpu, ARM_FEATURE_DUMMY_C15_REGS);
+    set_class_feature(cpu, ARM_FEATURE_CBAR_RO);
+    set_class_feature(cpu, ARM_FEATURE_EL2);
+    set_class_feature(cpu, ARM_FEATURE_EL3);
+    set_class_feature(cpu, ARM_FEATURE_PMU);
     cpu->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A7;
     cpu->midr = 0x410fc075;
     cpu->reset_fpsid = 0x41023075;
@@ -575,23 +555,23 @@ static void cortex_a7_initfn(Object *obj)
     cpu->ccsidr[1] = 0x201fe00a; /* 32K L1 icache */
     cpu->ccsidr[2] = 0x711fe07a; /* 4096K L2 unified cache */
     cpu->isar.reset_pmcr_el0 = 0x41072000;
-    define_arm_cp_regs(cpu, cortexa15_cp_reginfo); /* Same as A15 */
+
+    /* Same as A15 */
+    define_arm_cp_regs_with_class(cpu, cortexa15_cp_reginfo, NULL);
 }
 
-static void cortex_a15_initfn(Object *obj)
+static void cortex_a15_class_init(ARMCPUClass *cpu)
 {
-    ARMCPU *cpu = ARM_CPU(obj);
-
     cpu->dtb_compatible = "arm,cortex-a15";
-    set_feature(&cpu->env, ARM_FEATURE_V7VE);
-    set_feature(&cpu->env, ARM_FEATURE_NEON);
-    set_feature(&cpu->env, ARM_FEATURE_THUMB2EE);
-    set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER);
-    set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS);
-    set_feature(&cpu->env, ARM_FEATURE_CBAR_RO);
-    set_feature(&cpu->env, ARM_FEATURE_EL2);
-    set_feature(&cpu->env, ARM_FEATURE_EL3);
-    set_feature(&cpu->env, ARM_FEATURE_PMU);
+    set_class_feature(cpu, ARM_FEATURE_V7VE);
+    set_class_feature(cpu, ARM_FEATURE_NEON);
+    set_class_feature(cpu, ARM_FEATURE_THUMB2EE);
+    set_class_feature(cpu, ARM_FEATURE_GENERIC_TIMER);
+    set_class_feature(cpu, ARM_FEATURE_DUMMY_C15_REGS);
+    set_class_feature(cpu, ARM_FEATURE_CBAR_RO);
+    set_class_feature(cpu, ARM_FEATURE_EL2);
+    set_class_feature(cpu, ARM_FEATURE_EL3);
+    set_class_feature(cpu, ARM_FEATURE_PMU);
     cpu->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A15;
     /* r4p0 cpu, not requiring expensive tlb flush errata */
     cpu->midr = 0x414fc0f0;
@@ -622,14 +602,13 @@ static void cortex_a15_initfn(Object *obj)
     cpu->ccsidr[1] = 0x201fe00a; /* 32K L1 icache */
     cpu->ccsidr[2] = 0x711fe07a; /* 4096K L2 unified cache */
     cpu->isar.reset_pmcr_el0 = 0x410F3000;
-    define_arm_cp_regs(cpu, cortexa15_cp_reginfo);
+    define_arm_cp_regs_with_class(cpu, cortexa15_cp_reginfo, NULL);
 }
 
-static void cortex_m0_initfn(Object *obj)
+static void cortex_m0_class_init(ARMCPUClass *cpu)
 {
-    ARMCPU *cpu = ARM_CPU(obj);
-    set_feature(&cpu->env, ARM_FEATURE_V6);
-    set_feature(&cpu->env, ARM_FEATURE_M);
+    set_class_feature(cpu, ARM_FEATURE_V6);
+    set_class_feature(cpu, ARM_FEATURE_M);
 
     cpu->midr = 0x410cc200;
 
@@ -658,12 +637,11 @@ static void cortex_m0_initfn(Object *obj)
     cpu->isar.id_isar6 = 0x00000000;
 }
 
-static void cortex_m3_initfn(Object *obj)
+static void cortex_m3_class_init(ARMCPUClass *cpu)
 {
-    ARMCPU *cpu = ARM_CPU(obj);
-    set_feature(&cpu->env, ARM_FEATURE_V7);
-    set_feature(&cpu->env, ARM_FEATURE_M);
-    set_feature(&cpu->env, ARM_FEATURE_M_MAIN);
+    set_class_feature(cpu, ARM_FEATURE_V7);
+    set_class_feature(cpu, ARM_FEATURE_M);
+    set_class_feature(cpu, ARM_FEATURE_M_MAIN);
     cpu->midr = 0x410fc231;
     cpu->pmsav7_dregion = 8;
     cpu->isar.id_pfr0 = 0x00000030;
@@ -683,14 +661,12 @@ static void cortex_m3_initfn(Object *obj)
     cpu->isar.id_isar6 = 0x00000000;
 }
 
-static void cortex_m4_initfn(Object *obj)
+static void cortex_m4_class_init(ARMCPUClass *cpu)
 {
-    ARMCPU *cpu = ARM_CPU(obj);
-
-    set_feature(&cpu->env, ARM_FEATURE_V7);
-    set_feature(&cpu->env, ARM_FEATURE_M);
-    set_feature(&cpu->env, ARM_FEATURE_M_MAIN);
-    set_feature(&cpu->env, ARM_FEATURE_THUMB_DSP);
+    set_class_feature(cpu, ARM_FEATURE_V7);
+    set_class_feature(cpu, ARM_FEATURE_M);
+    set_class_feature(cpu, ARM_FEATURE_M_MAIN);
+    set_class_feature(cpu, ARM_FEATURE_THUMB_DSP);
     cpu->midr = 0x410fc240; /* r0p0 */
     cpu->pmsav7_dregion = 8;
     cpu->isar.mvfr0 = 0x10110021;
@@ -713,14 +689,12 @@ static void cortex_m4_initfn(Object *obj)
     cpu->isar.id_isar6 = 0x00000000;
 }
 
-static void cortex_m7_initfn(Object *obj)
+static void cortex_m7_class_init(ARMCPUClass *cpu)
 {
-    ARMCPU *cpu = ARM_CPU(obj);
-
-    set_feature(&cpu->env, ARM_FEATURE_V7);
-    set_feature(&cpu->env, ARM_FEATURE_M);
-    set_feature(&cpu->env, ARM_FEATURE_M_MAIN);
-    set_feature(&cpu->env, ARM_FEATURE_THUMB_DSP);
+    set_class_feature(cpu, ARM_FEATURE_V7);
+    set_class_feature(cpu, ARM_FEATURE_M);
+    set_class_feature(cpu, ARM_FEATURE_M_MAIN);
+    set_class_feature(cpu, ARM_FEATURE_THUMB_DSP);
     cpu->midr = 0x411fc272; /* r1p2 */
     cpu->pmsav7_dregion = 8;
     cpu->isar.mvfr0 = 0x10110221;
@@ -743,15 +717,13 @@ static void cortex_m7_initfn(Object *obj)
     cpu->isar.id_isar6 = 0x00000000;
 }
 
-static void cortex_m33_initfn(Object *obj)
+static void cortex_m33_class_init(ARMCPUClass *cpu)
 {
-    ARMCPU *cpu = ARM_CPU(obj);
-
-    set_feature(&cpu->env, ARM_FEATURE_V8);
-    set_feature(&cpu->env, ARM_FEATURE_M);
-    set_feature(&cpu->env, ARM_FEATURE_M_MAIN);
-    set_feature(&cpu->env, ARM_FEATURE_M_SECURITY);
-    set_feature(&cpu->env, ARM_FEATURE_THUMB_DSP);
+    set_class_feature(cpu, ARM_FEATURE_V8);
+    set_class_feature(cpu, ARM_FEATURE_M);
+    set_class_feature(cpu, ARM_FEATURE_M_MAIN);
+    set_class_feature(cpu, ARM_FEATURE_M_SECURITY);
+    set_class_feature(cpu, ARM_FEATURE_THUMB_DSP);
     cpu->midr = 0x410fd213; /* r0p3 */
     cpu->pmsav7_dregion = 16;
     cpu->sau_sregion = 8;
@@ -777,16 +749,14 @@ static void cortex_m33_initfn(Object *obj)
     cpu->ctr = 0x8000c000;
 }
 
-static void cortex_m55_initfn(Object *obj)
+static void cortex_m55_class_init(ARMCPUClass *cpu)
 {
-    ARMCPU *cpu = ARM_CPU(obj);
-
-    set_feature(&cpu->env, ARM_FEATURE_V8);
-    set_feature(&cpu->env, ARM_FEATURE_V8_1M);
-    set_feature(&cpu->env, ARM_FEATURE_M);
-    set_feature(&cpu->env, ARM_FEATURE_M_MAIN);
-    set_feature(&cpu->env, ARM_FEATURE_M_SECURITY);
-    set_feature(&cpu->env, ARM_FEATURE_THUMB_DSP);
+    set_class_feature(cpu, ARM_FEATURE_V8);
+    set_class_feature(cpu, ARM_FEATURE_V8_1M);
+    set_class_feature(cpu, ARM_FEATURE_M);
+    set_class_feature(cpu, ARM_FEATURE_M_MAIN);
+    set_class_feature(cpu, ARM_FEATURE_M_SECURITY);
+    set_class_feature(cpu, ARM_FEATURE_THUMB_DSP);
     cpu->midr = 0x410fd221; /* r0p1 */
     cpu->revidr = 0;
     cpu->pmsav7_dregion = 16;
@@ -824,14 +794,12 @@ static const ARMCPRegInfo cortexr5_cp_reginfo[] = {
       .opc2 = 0, .access = PL1_W, .type = ARM_CP_NOP },
 };
 
-static void cortex_r5_initfn(Object *obj)
+static void cortex_r5_class_init(ARMCPUClass *cpu)
 {
-    ARMCPU *cpu = ARM_CPU(obj);
-
-    set_feature(&cpu->env, ARM_FEATURE_V7);
-    set_feature(&cpu->env, ARM_FEATURE_V7MP);
-    set_feature(&cpu->env, ARM_FEATURE_PMSA);
-    set_feature(&cpu->env, ARM_FEATURE_PMU);
+    set_class_feature(cpu, ARM_FEATURE_V7);
+    set_class_feature(cpu, ARM_FEATURE_V7MP);
+    set_class_feature(cpu, ARM_FEATURE_PMSA);
+    set_class_feature(cpu, ARM_FEATURE_PMU);
     cpu->midr = 0x411fc153; /* r1p3 */
     cpu->isar.id_pfr0 = 0x0131;
     cpu->isar.id_pfr1 = 0x001;
@@ -850,181 +818,153 @@ static void cortex_r5_initfn(Object *obj)
     cpu->isar.id_isar6 = 0x0;
     cpu->pmsav7_dregion = 16;
     cpu->isar.reset_pmcr_el0 = 0x41151800;
-    define_arm_cp_regs(cpu, cortexr5_cp_reginfo);
+    define_arm_cp_regs_with_class(cpu, cortexr5_cp_reginfo, NULL);
 }
 
-static void cortex_r5f_initfn(Object *obj)
+static void cortex_r5f_class_init(ARMCPUClass *cpu)
 {
-    ARMCPU *cpu = ARM_CPU(obj);
-
-    cortex_r5_initfn(obj);
+    cortex_r5_class_init(cpu);
     cpu->isar.mvfr0 = 0x10110221;
     cpu->isar.mvfr1 = 0x00000011;
 }
 
-static void ti925t_initfn(Object *obj)
+static void ti925t_class_init(ARMCPUClass *cpu)
 {
-    ARMCPU *cpu = ARM_CPU(obj);
-    set_feature(&cpu->env, ARM_FEATURE_V4T);
-    set_feature(&cpu->env, ARM_FEATURE_OMAPCP);
+    set_class_feature(cpu, ARM_FEATURE_V4T);
+    set_class_feature(cpu, ARM_FEATURE_OMAPCP);
     cpu->midr = ARM_CPUID_TI925T;
     cpu->ctr = 0x5109149;
     cpu->reset_sctlr = 0x00000070;
 }
 
-static void sa1100_initfn(Object *obj)
+static void sa1100_class_init(ARMCPUClass *cpu)
 {
-    ARMCPU *cpu = ARM_CPU(obj);
-
     cpu->dtb_compatible = "intel,sa1100";
-    set_feature(&cpu->env, ARM_FEATURE_STRONGARM);
-    set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS);
+    set_class_feature(cpu, ARM_FEATURE_STRONGARM);
+    set_class_feature(cpu, ARM_FEATURE_DUMMY_C15_REGS);
     cpu->midr = 0x4401A11B;
     cpu->reset_sctlr = 0x00000070;
 }
 
-static void sa1110_initfn(Object *obj)
+static void sa1110_class_init(ARMCPUClass *cpu)
 {
-    ARMCPU *cpu = ARM_CPU(obj);
-    set_feature(&cpu->env, ARM_FEATURE_STRONGARM);
-    set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS);
+    set_class_feature(cpu, ARM_FEATURE_STRONGARM);
+    set_class_feature(cpu, ARM_FEATURE_DUMMY_C15_REGS);
     cpu->midr = 0x6901B119;
     cpu->reset_sctlr = 0x00000070;
 }
 
-static void pxa250_initfn(Object *obj)
+static void pxa250_class_init(ARMCPUClass *cpu)
 {
-    ARMCPU *cpu = ARM_CPU(obj);
-
     cpu->dtb_compatible = "marvell,xscale";
-    set_feature(&cpu->env, ARM_FEATURE_V5);
-    set_feature(&cpu->env, ARM_FEATURE_XSCALE);
+    set_class_feature(cpu, ARM_FEATURE_V5);
+    set_class_feature(cpu, ARM_FEATURE_XSCALE);
     cpu->midr = 0x69052100;
     cpu->ctr = 0xd172172;
     cpu->reset_sctlr = 0x00000078;
 }
 
-static void pxa255_initfn(Object *obj)
+static void pxa255_class_init(ARMCPUClass *cpu)
 {
-    ARMCPU *cpu = ARM_CPU(obj);
-
     cpu->dtb_compatible = "marvell,xscale";
-    set_feature(&cpu->env, ARM_FEATURE_V5);
-    set_feature(&cpu->env, ARM_FEATURE_XSCALE);
+    set_class_feature(cpu, ARM_FEATURE_V5);
+    set_class_feature(cpu, ARM_FEATURE_XSCALE);
     cpu->midr = 0x69052d00;
     cpu->ctr = 0xd172172;
     cpu->reset_sctlr = 0x00000078;
 }
 
-static void pxa260_initfn(Object *obj)
+static void pxa260_class_init(ARMCPUClass *cpu)
 {
-    ARMCPU *cpu = ARM_CPU(obj);
-
     cpu->dtb_compatible = "marvell,xscale";
-    set_feature(&cpu->env, ARM_FEATURE_V5);
-    set_feature(&cpu->env, ARM_FEATURE_XSCALE);
+    set_class_feature(cpu, ARM_FEATURE_V5);
+    set_class_feature(cpu, ARM_FEATURE_XSCALE);
     cpu->midr = 0x69052903;
     cpu->ctr = 0xd172172;
     cpu->reset_sctlr = 0x00000078;
 }
 
-static void pxa261_initfn(Object *obj)
+static void pxa261_class_init(ARMCPUClass *cpu)
 {
-    ARMCPU *cpu = ARM_CPU(obj);
-
     cpu->dtb_compatible = "marvell,xscale";
-    set_feature(&cpu->env, ARM_FEATURE_V5);
-    set_feature(&cpu->env, ARM_FEATURE_XSCALE);
+    set_class_feature(cpu, ARM_FEATURE_V5);
+    set_class_feature(cpu, ARM_FEATURE_XSCALE);
     cpu->midr = 0x69052d05;
     cpu->ctr = 0xd172172;
     cpu->reset_sctlr = 0x00000078;
 }
 
-static void pxa262_initfn(Object *obj)
+static void pxa262_class_init(ARMCPUClass *cpu)
 {
-    ARMCPU *cpu = ARM_CPU(obj);
-
     cpu->dtb_compatible = "marvell,xscale";
-    set_feature(&cpu->env, ARM_FEATURE_V5);
-    set_feature(&cpu->env, ARM_FEATURE_XSCALE);
+    set_class_feature(cpu, ARM_FEATURE_V5);
+    set_class_feature(cpu, ARM_FEATURE_XSCALE);
     cpu->midr = 0x69052d06;
     cpu->ctr = 0xd172172;
     cpu->reset_sctlr = 0x00000078;
 }
 
-static void pxa270a0_initfn(Object *obj)
+static void pxa270a0_class_init(ARMCPUClass *cpu)
 {
-    ARMCPU *cpu = ARM_CPU(obj);
-
     cpu->dtb_compatible = "marvell,xscale";
-    set_feature(&cpu->env, ARM_FEATURE_V5);
-    set_feature(&cpu->env, ARM_FEATURE_XSCALE);
-    set_feature(&cpu->env, ARM_FEATURE_IWMMXT);
+    set_class_feature(cpu, ARM_FEATURE_V5);
+    set_class_feature(cpu, ARM_FEATURE_XSCALE);
+    set_class_feature(cpu, ARM_FEATURE_IWMMXT);
     cpu->midr = 0x69054110;
     cpu->ctr = 0xd172172;
     cpu->reset_sctlr = 0x00000078;
 }
 
-static void pxa270a1_initfn(Object *obj)
+static void pxa270a1_class_init(ARMCPUClass *cpu)
 {
-    ARMCPU *cpu = ARM_CPU(obj);
-
     cpu->dtb_compatible = "marvell,xscale";
-    set_feature(&cpu->env, ARM_FEATURE_V5);
-    set_feature(&cpu->env, ARM_FEATURE_XSCALE);
-    set_feature(&cpu->env, ARM_FEATURE_IWMMXT);
+    set_class_feature(cpu, ARM_FEATURE_V5);
+    set_class_feature(cpu, ARM_FEATURE_XSCALE);
+    set_class_feature(cpu, ARM_FEATURE_IWMMXT);
     cpu->midr = 0x69054111;
     cpu->ctr = 0xd172172;
     cpu->reset_sctlr = 0x00000078;
 }
 
-static void pxa270b0_initfn(Object *obj)
+static void pxa270b0_class_init(ARMCPUClass *cpu)
 {
-    ARMCPU *cpu = ARM_CPU(obj);
-
     cpu->dtb_compatible = "marvell,xscale";
-    set_feature(&cpu->env, ARM_FEATURE_V5);
-    set_feature(&cpu->env, ARM_FEATURE_XSCALE);
-    set_feature(&cpu->env, ARM_FEATURE_IWMMXT);
+    set_class_feature(cpu, ARM_FEATURE_V5);
+    set_class_feature(cpu, ARM_FEATURE_XSCALE);
+    set_class_feature(cpu, ARM_FEATURE_IWMMXT);
     cpu->midr = 0x69054112;
     cpu->ctr = 0xd172172;
     cpu->reset_sctlr = 0x00000078;
 }
 
-static void pxa270b1_initfn(Object *obj)
+static void pxa270b1_class_init(ARMCPUClass *cpu)
 {
-    ARMCPU *cpu = ARM_CPU(obj);
-
     cpu->dtb_compatible = "marvell,xscale";
-    set_feature(&cpu->env, ARM_FEATURE_V5);
-    set_feature(&cpu->env, ARM_FEATURE_XSCALE);
-    set_feature(&cpu->env, ARM_FEATURE_IWMMXT);
+    set_class_feature(cpu, ARM_FEATURE_V5);
+    set_class_feature(cpu, ARM_FEATURE_XSCALE);
+    set_class_feature(cpu, ARM_FEATURE_IWMMXT);
     cpu->midr = 0x69054113;
     cpu->ctr = 0xd172172;
     cpu->reset_sctlr = 0x00000078;
 }
 
-static void pxa270c0_initfn(Object *obj)
+static void pxa270c0_class_init(ARMCPUClass *cpu)
 {
-    ARMCPU *cpu = ARM_CPU(obj);
-
     cpu->dtb_compatible = "marvell,xscale";
-    set_feature(&cpu->env, ARM_FEATURE_V5);
-    set_feature(&cpu->env, ARM_FEATURE_XSCALE);
-    set_feature(&cpu->env, ARM_FEATURE_IWMMXT);
+    set_class_feature(cpu, ARM_FEATURE_V5);
+    set_class_feature(cpu, ARM_FEATURE_XSCALE);
+    set_class_feature(cpu, ARM_FEATURE_IWMMXT);
     cpu->midr = 0x69054114;
     cpu->ctr = 0xd172172;
     cpu->reset_sctlr = 0x00000078;
 }
 
-static void pxa270c5_initfn(Object *obj)
+static void pxa270c5_class_init(ARMCPUClass *cpu)
 {
-    ARMCPU *cpu = ARM_CPU(obj);
-
     cpu->dtb_compatible = "marvell,xscale";
-    set_feature(&cpu->env, ARM_FEATURE_V5);
-    set_feature(&cpu->env, ARM_FEATURE_XSCALE);
-    set_feature(&cpu->env, ARM_FEATURE_IWMMXT);
+    set_class_feature(cpu, ARM_FEATURE_V5);
+    set_class_feature(cpu, ARM_FEATURE_XSCALE);
+    set_class_feature(cpu, ARM_FEATURE_IWMMXT);
     cpu->midr = 0x69054117;
     cpu->ctr = 0xd172172;
     cpu->reset_sctlr = 0x00000078;
@@ -1070,19 +1010,17 @@ static void arm_v7m_class_init(ObjectClass *oc, void *data)
  * The version of '-cpu max' for qemu-system-aarch64 is defined in cpu64.c;
  * this only needs to handle 32 bits, and need not care about KVM.
  */
-static void arm_max_initfn(Object *obj)
+static void arm_max_class_init(ARMCPUClass *cpu)
 {
-    ARMCPU *cpu = ARM_CPU(obj);
-
-    /* aarch64_a57_initfn, advertising none of the aarch64 features */
+    /* aarch64_a57_class_init, advertising none of the aarch64 features */
     cpu->dtb_compatible = "arm,cortex-a57";
-    set_feature(&cpu->env, ARM_FEATURE_V8);
-    set_feature(&cpu->env, ARM_FEATURE_NEON);
-    set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER);
-    set_feature(&cpu->env, ARM_FEATURE_CBAR_RO);
-    set_feature(&cpu->env, ARM_FEATURE_EL2);
-    set_feature(&cpu->env, ARM_FEATURE_EL3);
-    set_feature(&cpu->env, ARM_FEATURE_PMU);
+    set_class_feature(cpu, ARM_FEATURE_V8);
+    set_class_feature(cpu, ARM_FEATURE_NEON);
+    set_class_feature(cpu, ARM_FEATURE_GENERIC_TIMER);
+    set_class_feature(cpu, ARM_FEATURE_CBAR_RO);
+    set_class_feature(cpu, ARM_FEATURE_EL2);
+    set_class_feature(cpu, ARM_FEATURE_EL3);
+    set_class_feature(cpu, ARM_FEATURE_PMU);
     cpu->midr = 0x411fd070;
     cpu->revidr = 0x00000000;
     cpu->reset_fpsid = 0x41034070;
@@ -1130,55 +1068,55 @@ static void arm_max_initfn(Object *obj)
 #endif /* !TARGET_AARCH64 */
 
 static const ARMCPUInfo arm_tcg_cpus[] = {
-    { .name = "arm926",      .initfn = arm926_initfn },
-    { .name = "arm946",      .initfn = arm946_initfn },
-    { .name = "arm1026",     .initfn = arm1026_initfn },
+    { .name = "arm926",      .class_init = arm926_class_init },
+    { .name = "arm946",      .class_init = arm946_class_init },
+    { .name = "arm1026",     .class_init = arm1026_class_init },
     /*
      * What QEMU calls "arm1136-r2" is actually the 1136 r0p2, i.e. an
      * older core than plain "arm1136". In particular this does not
      * have the v6K features.
      */
-    { .name = "arm1136-r2",  .initfn = arm1136_r2_initfn },
-    { .name = "arm1136",     .initfn = arm1136_initfn },
-    { .name = "arm1176",     .initfn = arm1176_initfn },
-    { .name = "arm11mpcore", .initfn = arm11mpcore_initfn },
-    { .name = "cortex-a7",   .initfn = cortex_a7_initfn },
-    { .name = "cortex-a8",   .initfn = cortex_a8_initfn },
-    { .name = "cortex-a9",   .initfn = cortex_a9_initfn },
-    { .name = "cortex-a15",  .initfn = cortex_a15_initfn },
-    { .name = "cortex-r5",   .initfn = cortex_r5_initfn },
-    { .name = "cortex-r5f",  .initfn = cortex_r5f_initfn },
-    { .name = "ti925t",      .initfn = ti925t_initfn },
-    { .name = "sa1100",      .initfn = sa1100_initfn },
-    { .name = "sa1110",      .initfn = sa1110_initfn },
-    { .name = "pxa250",      .initfn = pxa250_initfn },
-    { .name = "pxa255",      .initfn = pxa255_initfn },
-    { .name = "pxa260",      .initfn = pxa260_initfn },
-    { .name = "pxa261",      .initfn = pxa261_initfn },
-    { .name = "pxa262",      .initfn = pxa262_initfn },
+    { .name = "arm1136-r2",  .class_init = arm1136_r2_class_init },
+    { .name = "arm1136",     .class_init = arm1136_class_init },
+    { .name = "arm1176",     .class_init = arm1176_class_init },
+    { .name = "arm11mpcore", .class_init = arm11mpcore_class_init },
+    { .name = "cortex-a7",   .class_init = cortex_a7_class_init },
+    { .name = "cortex-a8",   .class_init = cortex_a8_class_init },
+    { .name = "cortex-a9",   .class_init = cortex_a9_class_init },
+    { .name = "cortex-a15",  .class_init = cortex_a15_class_init },
+    { .name = "cortex-r5",   .class_init = cortex_r5_class_init },
+    { .name = "cortex-r5f",  .class_init = cortex_r5f_class_init },
+    { .name = "ti925t",      .class_init = ti925t_class_init },
+    { .name = "sa1100",      .class_init = sa1100_class_init },
+    { .name = "sa1110",      .class_init = sa1110_class_init },
+    { .name = "pxa250",      .class_init = pxa250_class_init },
+    { .name = "pxa255",      .class_init = pxa255_class_init },
+    { .name = "pxa260",      .class_init = pxa260_class_init },
+    { .name = "pxa261",      .class_init = pxa261_class_init },
+    { .name = "pxa262",      .class_init = pxa262_class_init },
     /* "pxa270" is an alias for "pxa270-a0" */
-    { .name = "pxa270",      .initfn = pxa270a0_initfn },
-    { .name = "pxa270-a0",   .initfn = pxa270a0_initfn },
-    { .name = "pxa270-a1",   .initfn = pxa270a1_initfn },
-    { .name = "pxa270-b0",   .initfn = pxa270b0_initfn },
-    { .name = "pxa270-b1",   .initfn = pxa270b1_initfn },
-    { .name = "pxa270-c0",   .initfn = pxa270c0_initfn },
-    { .name = "pxa270-c5",   .initfn = pxa270c5_initfn },
+    { .name = "pxa270",      .class_init = pxa270a0_class_init },
+    { .name = "pxa270-a0",   .class_init = pxa270a0_class_init },
+    { .name = "pxa270-a1",   .class_init = pxa270a1_class_init },
+    { .name = "pxa270-b0",   .class_init = pxa270b0_class_init },
+    { .name = "pxa270-b1",   .class_init = pxa270b1_class_init },
+    { .name = "pxa270-c0",   .class_init = pxa270c0_class_init },
+    { .name = "pxa270-c5",   .class_init = pxa270c5_class_init },
 #ifndef TARGET_AARCH64
-    { .name = "max",         .initfn = arm_max_initfn },
+    { .name = "max",         .class_init = arm_max_class_init },
 #endif
 #ifdef CONFIG_USER_ONLY
-    { .name = "any",         .initfn = arm_max_initfn },
+    { .name = "any",         .class_init = arm_max_class_init },
 #endif
 };
 
 static const ARMCPUInfo arm_v7m_tcg_cpus[] = {
-    { .name = "cortex-m0",   .initfn = cortex_m0_initfn },
-    { .name = "cortex-m3",   .initfn = cortex_m3_initfn },
-    { .name = "cortex-m4",   .initfn = cortex_m4_initfn },
-    { .name = "cortex-m7",   .initfn = cortex_m7_initfn },
-    { .name = "cortex-m33",  .initfn = cortex_m33_initfn },
-    { .name = "cortex-m55",  .initfn = cortex_m55_initfn },
+    { .name = "cortex-m0",   .class_init = cortex_m0_class_init },
+    { .name = "cortex-m3",   .class_init = cortex_m3_class_init },
+    { .name = "cortex-m4",   .class_init = cortex_m4_class_init },
+    { .name = "cortex-m7",   .class_init = cortex_m7_class_init },
+    { .name = "cortex-m33",  .class_init = cortex_m33_class_init },
+    { .name = "cortex-m55",  .class_init = cortex_m55_class_init },
 };
 
 static const TypeInfo arm_v7m_cpu_type_info = {
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* [RFC PATCH 20/40] target/arm: Merge kvm64.c with kvm.c
  2023-01-03 18:16 [RFC PATCH 00/40] Toward class init of cpu features Richard Henderson
                   ` (18 preceding siblings ...)
  2023-01-03 18:16 ` [RFC PATCH 19/40] target/arm: Move most cpu initialization to the class Richard Henderson
@ 2023-01-03 18:16 ` Richard Henderson
  2023-01-03 18:16 ` [RFC PATCH 21/40] target/arm: Remove aarch64 check from aarch64_host_object_init Richard Henderson
                   ` (21 subsequent siblings)
  41 siblings, 0 replies; 77+ messages in thread
From: Richard Henderson @ 2023-01-03 18:16 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, berrange, eduardo, armbru, ajones, alex.bennee

With appropriate sorting of functions, this allows quite a
number of prototypes to be removed from kvm_arm.h, and the
corresponding functions made static.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/kvm_arm.h   |  190 ----
 target/arm/kvm.c       | 2048 +++++++++++++++++++++++++++++++++++++---
 target/arm/kvm64.c     | 1632 --------------------------------
 target/arm/meson.build |    2 +-
 4 files changed, 1896 insertions(+), 1976 deletions(-)
 delete mode 100644 target/arm/kvm64.c

diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h
index 99017b635c..8efbe0cc4b 100644
--- a/target/arm/kvm_arm.h
+++ b/target/arm/kvm_arm.h
@@ -18,32 +18,6 @@
 #define KVM_ARM_VGIC_V2   (1 << 0)
 #define KVM_ARM_VGIC_V3   (1 << 1)
 
-/**
- * kvm_arm_vcpu_init:
- * @cs: CPUState
- *
- * Initialize (or reinitialize) the VCPU by invoking the
- * KVM_ARM_VCPU_INIT ioctl with the CPU type and feature
- * bitmask specified in the CPUState.
- *
- * Returns: 0 if success else < 0 error code
- */
-int kvm_arm_vcpu_init(CPUState *cs);
-
-/**
- * kvm_arm_vcpu_finalize:
- * @cs: CPUState
- * @feature: feature to finalize
- *
- * Finalizes the configuration of the specified VCPU feature by
- * invoking the KVM_ARM_VCPU_FINALIZE ioctl. Features requiring
- * this are documented in the "KVM_ARM_VCPU_FINALIZE" section of
- * KVM's API documentation.
- *
- * Returns: 0 if success else < 0 error code
- */
-int kvm_arm_vcpu_finalize(CPUState *cs, int feature);
-
 /**
  * kvm_arm_register_device:
  * @mr: memory region for this device
@@ -65,37 +39,6 @@ int kvm_arm_vcpu_finalize(CPUState *cs, int feature);
 void kvm_arm_register_device(MemoryRegion *mr, uint64_t devid, uint64_t group,
                              uint64_t attr, int dev_fd, uint64_t addr_ormask);
 
-/**
- * kvm_arm_init_cpreg_list:
- * @cpu: ARMCPU
- *
- * Initialize the ARMCPU cpreg list according to the kernel's
- * definition of what CPU registers it knows about (and throw away
- * the previous TCG-created cpreg list).
- *
- * Returns: 0 if success, else < 0 error code
- */
-int kvm_arm_init_cpreg_list(ARMCPU *cpu);
-
-/**
- * kvm_arm_reg_syncs_via_cpreg_list:
- * @regidx: KVM register index
- *
- * Return true if this KVM register should be synchronized via the
- * cpreg list of arbitrary system registers, false if it is synchronized
- * by hand using code in kvm_arch_get/put_registers().
- */
-bool kvm_arm_reg_syncs_via_cpreg_list(uint64_t regidx);
-
-/**
- * kvm_arm_cpreg_level:
- * @regidx: KVM register index
- *
- * Return the level of this coprocessor/system register.  Return value is
- * either KVM_PUT_RUNTIME_STATE, KVM_PUT_RESET_STATE, or KVM_PUT_FULL_STATE.
- */
-int kvm_arm_cpreg_level(uint64_t regidx);
-
 /**
  * write_list_to_kvmstate:
  * @cpu: ARMCPU
@@ -155,34 +98,6 @@ void kvm_arm_cpu_post_load(ARMCPU *cpu);
  */
 void kvm_arm_reset_vcpu(ARMCPU *cpu);
 
-/**
- * kvm_arm_init_serror_injection:
- * @cs: CPUState
- *
- * Check whether KVM can set guest SError syndrome.
- */
-void kvm_arm_init_serror_injection(CPUState *cs);
-
-/**
- * kvm_get_vcpu_events:
- * @cpu: ARMCPU
- *
- * Get VCPU related state from kvm.
- *
- * Returns: 0 if success else < 0 error code
- */
-int kvm_get_vcpu_events(ARMCPU *cpu);
-
-/**
- * kvm_put_vcpu_events:
- * @cpu: ARMCPU
- *
- * Put VCPU related state to kvm.
- *
- * Returns: 0 if success else < 0 error code
- */
-int kvm_put_vcpu_events(ARMCPU *cpu);
-
 #ifdef CONFIG_KVM
 /**
  * kvm_arm_create_scratch_host_vcpu:
@@ -214,28 +129,6 @@ bool kvm_arm_create_scratch_host_vcpu(const uint32_t *cpus_to_try,
  */
 void kvm_arm_destroy_scratch_host_vcpu(int *fdarray);
 
-/**
- * ARMHostCPUFeatures: information about the host CPU (identified
- * by asking the host kernel)
- */
-typedef struct ARMHostCPUFeatures {
-    ARMISARegisters isar;
-    uint64_t features;
-    uint32_t target;
-    const char *dtb_compatible;
-} ARMHostCPUFeatures;
-
-/**
- * kvm_arm_get_host_cpu_features:
- * @ahcf: ARMHostCPUClass to fill in
- *
- * Probe the capabilities of the host kernel's preferred CPU and fill
- * in the ARMHostCPUClass struct accordingly.
- *
- * Returns true on success and false otherwise.
- */
-bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf);
-
 /**
  * kvm_arm_sve_get_vls:
  * @cs: CPUState
@@ -274,14 +167,6 @@ void kvm_arm_add_vcpu_properties(Object *obj);
  */
 void kvm_arm_steal_time_finalize(ARMCPU *cpu, Error **errp);
 
-/**
- * kvm_arm_steal_time_supported:
- *
- * Returns: true if KVM can enable steal time reporting
- * and false otherwise.
- */
-bool kvm_arm_steal_time_supported(void);
-
 /**
  * kvm_arm_aarch32_supported:
  *
@@ -315,44 +200,6 @@ bool kvm_arm_sve_supported(void);
  */
 int kvm_arm_get_max_vm_ipa_size(MachineState *ms, bool *fixed_ipa);
 
-/**
- * kvm_arm_sync_mpstate_to_kvm:
- * @cpu: ARMCPU
- *
- * If supported set the KVM MP_STATE based on QEMU's model.
- *
- * Returns 0 on success and -1 on failure.
- */
-int kvm_arm_sync_mpstate_to_kvm(ARMCPU *cpu);
-
-/**
- * kvm_arm_sync_mpstate_to_qemu:
- * @cpu: ARMCPU
- *
- * If supported get the MP_STATE from KVM and store in QEMU's model.
- *
- * Returns 0 on success and aborts on failure.
- */
-int kvm_arm_sync_mpstate_to_qemu(ARMCPU *cpu);
-
-/**
- * kvm_arm_get_virtual_time:
- * @cs: CPUState
- *
- * Gets the VCPU's virtual counter and stores it in the KVM CPU state.
- */
-void kvm_arm_get_virtual_time(CPUState *cs);
-
-/**
- * kvm_arm_put_virtual_time:
- * @cs: CPUState
- *
- * Sets the VCPU's virtual counter to the value stored in the KVM CPU state.
- */
-void kvm_arm_put_virtual_time(CPUState *cs);
-
-void kvm_arm_vm_state_change(void *opaque, bool running, RunState state);
-
 int kvm_arm_vgic_probe(void);
 
 void kvm_arm_pmu_set_irq(CPUState *cs, int irq);
@@ -471,43 +318,6 @@ static inline const char *gicv3_class_name(void)
     }
 }
 
-/**
- * kvm_arm_handle_debug:
- * @cs: CPUState
- * @debug_exit: debug part of the KVM exit structure
- *
- * Returns: TRUE if the debug exception was handled.
- */
-bool kvm_arm_handle_debug(CPUState *cs, struct kvm_debug_exit_arch *debug_exit);
-
-/**
- * kvm_arm_hw_debug_active:
- * @cs: CPU State
- *
- * Return: TRUE if any hardware breakpoints in use.
- */
-bool kvm_arm_hw_debug_active(CPUState *cs);
-
-/**
- * kvm_arm_copy_hw_debug_data:
- * @ptr: kvm_guest_debug_arch structure
- *
- * Copy the architecture specific debug registers into the
- * kvm_guest_debug ioctl structure.
- */
-struct kvm_guest_debug_arch;
-void kvm_arm_copy_hw_debug_data(struct kvm_guest_debug_arch *ptr);
-
-/**
- * kvm_arm_verify_ext_dabt_pending:
- * @cs: CPUState
- *
- * Verify the fault status code wrt the Ext DABT injection
- *
- * Returns: true if the fault status code is as expected, false otherwise
- */
-bool kvm_arm_verify_ext_dabt_pending(CPUState *cs);
-
 /**
  * its_class_name:
  *
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index f022c644d2..02a15c6013 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -19,6 +19,7 @@
 #include "qom/object.h"
 #include "qapi/error.h"
 #include "sysemu/sysemu.h"
+#include "sysemu/runstate.h"
 #include "sysemu/kvm.h"
 #include "sysemu/kvm_int.h"
 #include "kvm_arm.h"
@@ -28,8 +29,11 @@
 #include "hw/pci/pci.h"
 #include "exec/memattrs.h"
 #include "exec/address-spaces.h"
+#include "exec/gdbstub.h"
 #include "hw/boards.h"
 #include "hw/irq.h"
+#include "hw/acpi/acpi.h"
+#include "hw/acpi/ghes.h"
 #include "qemu/log.h"
 
 const KVMCapabilityInfo kvm_arch_required_capabilities[] = {
@@ -40,9 +44,30 @@ static bool cap_has_mp_state;
 static bool cap_has_inject_serror_esr;
 static bool cap_has_inject_ext_dabt;
 
+/**
+ * ARMHostCPUFeatures: information about the host CPU (identified
+ * by asking the host kernel)
+ */
+typedef struct ARMHostCPUFeatures {
+    ARMISARegisters isar;
+    uint64_t features;
+    uint32_t target;
+    const char *dtb_compatible;
+} ARMHostCPUFeatures;
+
 static ARMHostCPUFeatures arm_host_cpu_features;
 
-int kvm_arm_vcpu_init(CPUState *cs)
+/**
+ * kvm_arm_vcpu_init:
+ * @cs: CPUState
+ *
+ * Initialize (or reinitialize) the VCPU by invoking the
+ * KVM_ARM_VCPU_INIT ioctl with the CPU type and feature
+ * bitmask specified in the CPUState.
+ *
+ * Returns: 0 if success else < 0 error code
+ */
+static int kvm_arm_vcpu_init(CPUState *cs)
 {
     ARMCPU *cpu = ARM_CPU(cs);
     struct kvm_vcpu_init init;
@@ -53,12 +78,30 @@ int kvm_arm_vcpu_init(CPUState *cs)
     return kvm_vcpu_ioctl(cs, KVM_ARM_VCPU_INIT, &init);
 }
 
-int kvm_arm_vcpu_finalize(CPUState *cs, int feature)
+/**
+ * kvm_arm_vcpu_finalize:
+ * @cs: CPUState
+ * @feature: feature to finalize
+ *
+ * Finalizes the configuration of the specified VCPU feature by
+ * invoking the KVM_ARM_VCPU_FINALIZE ioctl. Features requiring
+ * this are documented in the "KVM_ARM_VCPU_FINALIZE" section of
+ * KVM's API documentation.
+ *
+ * Returns: 0 if success else < 0 error code
+ */
+static int kvm_arm_vcpu_finalize(CPUState *cs, int feature)
 {
     return kvm_vcpu_ioctl(cs, KVM_ARM_VCPU_FINALIZE, &feature);
 }
 
-void kvm_arm_init_serror_injection(CPUState *cs)
+/**
+ * kvm_arm_init_serror_injection:
+ * @cs: CPUState
+ *
+ * Check whether KVM can set guest SError syndrome.
+ */
+static void kvm_arm_init_serror_injection(CPUState *cs)
 {
     cap_has_inject_serror_esr = kvm_check_extension(cs->kvm_state,
                                     KVM_CAP_ARM_INJECT_SERROR_ESR);
@@ -166,28 +209,6 @@ void kvm_arm_destroy_scratch_host_vcpu(int *fdarray)
     }
 }
 
-void kvm_arm_set_cpu_features_from_host(ARMCPU *cpu)
-{
-    CPUARMState *env = &cpu->env;
-
-    if (!arm_host_cpu_features.dtb_compatible) {
-        if (!kvm_enabled() ||
-            !kvm_arm_get_host_cpu_features(&arm_host_cpu_features)) {
-            /* We can't report this error yet, so flag that we need to
-             * in arm_cpu_realizefn().
-             */
-            cpu->kvm_target = QEMU_KVM_ARM_TARGET_NONE;
-            cpu->host_cpu_probe_failed = true;
-            return;
-        }
-    }
-
-    cpu->kvm_target = arm_host_cpu_features.target;
-    cpu->dtb_compatible = arm_host_cpu_features.dtb_compatible;
-    cpu->isar = arm_host_cpu_features.isar;
-    env->features = arm_host_cpu_features.features;
-}
-
 static bool kvm_no_adjvtime_get(Object *obj, Error **errp)
 {
     return !ARM_CPU(obj)->kvm_adjvtime;
@@ -438,11 +459,40 @@ static uint64_t *kvm_arm_get_cpreg_ptr(ARMCPU *cpu, uint64_t regidx)
     return &cpu->cpreg_values[res - cpu->cpreg_indexes];
 }
 
-/* Initialize the ARMCPU cpreg list according to the kernel's
+/**
+ * kvm_arm_reg_syncs_via_cpreg_list:
+ * @regidx: KVM register index
+ *
+ * Return true if this KVM register should be synchronized via the
+ * cpreg list of arbitrary system registers, false if it is synchronized
+ * by hand using code in kvm_arch_get/put_registers().
+ */
+static bool kvm_arm_reg_syncs_via_cpreg_list(uint64_t regidx)
+{
+    /* Return true if the regidx is a register we should synchronize
+     * via the cpreg_tuples array (ie is not a core or sve reg that
+     * we sync by hand in kvm_arch_get/put_registers())
+     */
+    switch (regidx & KVM_REG_ARM_COPROC_MASK) {
+    case KVM_REG_ARM_CORE:
+    case KVM_REG_ARM64_SVE:
+        return false;
+    default:
+        return true;
+    }
+}
+
+/**
+ * kvm_arm_init_cpreg_list:
+ * @cpu: ARMCPU
+ *
+ * Initialize the ARMCPU cpreg list according to the kernel's
  * definition of what CPU registers it knows about (and throw away
  * the previous TCG-created cpreg list).
+ *
+ * Returns: 0 if success, else < 0 error code
  */
-int kvm_arm_init_cpreg_list(ARMCPU *cpu)
+static int kvm_arm_init_cpreg_list(ARMCPU *cpu)
 {
     struct kvm_reg_list rl;
     struct kvm_reg_list *rlp;
@@ -551,6 +601,41 @@ bool write_kvmstate_to_list(ARMCPU *cpu)
     return ok;
 }
 
+typedef struct CPRegStateLevel {
+    uint64_t regidx;
+    int level;
+} CPRegStateLevel;
+
+/* All system registers not listed in the following table are assumed to be
+ * of the level KVM_PUT_RUNTIME_STATE. If a register should be written less
+ * often, you must add it to this table with a state of either
+ * KVM_PUT_RESET_STATE or KVM_PUT_FULL_STATE.
+ */
+static const CPRegStateLevel non_runtime_cpregs[] = {
+    { KVM_REG_ARM_TIMER_CNT, KVM_PUT_FULL_STATE },
+};
+
+/**
+ * kvm_arm_cpreg_level:
+ * @regidx: KVM register index
+ *
+ * Return the level of this coprocessor/system register.  Return value is
+ * either KVM_PUT_RUNTIME_STATE, KVM_PUT_RESET_STATE, or KVM_PUT_FULL_STATE.
+ */
+static int kvm_arm_cpreg_level(uint64_t regidx)
+{
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(non_runtime_cpregs); i++) {
+        const CPRegStateLevel *l = &non_runtime_cpregs[i];
+        if (l->regidx == regidx) {
+            return l->level;
+        }
+    }
+
+    return KVM_PUT_RUNTIME_STATE;
+}
+
 bool write_list_to_kvmstate(ARMCPU *cpu, int level)
 {
     CPUState *cs = CPU(cpu);
@@ -634,10 +719,15 @@ void kvm_arm_reset_vcpu(ARMCPU *cpu)
     write_list_to_cpustate(cpu);
 }
 
-/*
- * Update KVM's MP_STATE based on what QEMU thinks it is
+/**
+ * kvm_arm_sync_mpstate_to_kvm:
+ * @cpu: ARMCPU
+ *
+ * If supported set the KVM MP_STATE based on QEMU's model.
+ *
+ * Returns 0 on success and -1 on failure.
  */
-int kvm_arm_sync_mpstate_to_kvm(ARMCPU *cpu)
+static int kvm_arm_sync_mpstate_to_kvm(ARMCPU *cpu)
 {
     if (cap_has_mp_state) {
         struct kvm_mp_state mp_state = {
@@ -655,10 +745,15 @@ int kvm_arm_sync_mpstate_to_kvm(ARMCPU *cpu)
     return 0;
 }
 
-/*
- * Sync the KVM MP_STATE into QEMU
+/**
+ * kvm_arm_sync_mpstate_to_qemu:
+ * @cpu: ARMCPU
+ *
+ * If supported get the MP_STATE from KVM and store in QEMU's model.
+ *
+ * Returns 0 on success and aborts on failure.
  */
-int kvm_arm_sync_mpstate_to_qemu(ARMCPU *cpu)
+static int kvm_arm_sync_mpstate_to_qemu(ARMCPU *cpu)
 {
     if (cap_has_mp_state) {
         struct kvm_mp_state mp_state;
@@ -675,7 +770,13 @@ int kvm_arm_sync_mpstate_to_qemu(ARMCPU *cpu)
     return 0;
 }
 
-void kvm_arm_get_virtual_time(CPUState *cs)
+/**
+ * kvm_arm_get_virtual_time:
+ * @cs: CPUState
+ *
+ * Gets the VCPU's virtual counter and stores it in the KVM CPU state.
+ */
+static void kvm_arm_get_virtual_time(CPUState *cs)
 {
     ARMCPU *cpu = ARM_CPU(cs);
     struct kvm_one_reg reg = {
@@ -697,7 +798,13 @@ void kvm_arm_get_virtual_time(CPUState *cs)
     cpu->kvm_vtime_dirty = true;
 }
 
-void kvm_arm_put_virtual_time(CPUState *cs)
+/**
+ * kvm_arm_put_virtual_time:
+ * @cs: CPUState
+ *
+ * Sets the VCPU's virtual counter to the value stored in the KVM CPU state.
+ */
+static void kvm_arm_put_virtual_time(CPUState *cs)
 {
     ARMCPU *cpu = ARM_CPU(cs);
     struct kvm_one_reg reg = {
@@ -719,7 +826,15 @@ void kvm_arm_put_virtual_time(CPUState *cs)
     cpu->kvm_vtime_dirty = false;
 }
 
-int kvm_put_vcpu_events(ARMCPU *cpu)
+/**
+ * kvm_put_vcpu_events:
+ * @cpu: ARMCPU
+ *
+ * Put VCPU related state to kvm.
+ *
+ * Returns: 0 if success else < 0 error code
+ */
+static int kvm_put_vcpu_events(ARMCPU *cpu)
 {
     CPUARMState *env = &cpu->env;
     struct kvm_vcpu_events events;
@@ -748,7 +863,15 @@ int kvm_put_vcpu_events(ARMCPU *cpu)
     return ret;
 }
 
-int kvm_get_vcpu_events(ARMCPU *cpu)
+/**
+ * kvm_get_vcpu_events:
+ * @cpu: ARMCPU
+ *
+ * Get VCPU related state from kvm.
+ *
+ * Returns: 0 if success else < 0 error code
+ */
+static int kvm_get_vcpu_events(ARMCPU *cpu)
 {
     CPUARMState *env = &cpu->env;
     struct kvm_vcpu_events events;
@@ -772,88 +895,7 @@ int kvm_get_vcpu_events(ARMCPU *cpu)
     return 0;
 }
 
-void kvm_arch_pre_run(CPUState *cs, struct kvm_run *run)
-{
-    ARMCPU *cpu = ARM_CPU(cs);
-    CPUARMState *env = &cpu->env;
-
-    if (unlikely(env->ext_dabt_raised)) {
-        /*
-         * Verifying that the ext DABT has been properly injected,
-         * otherwise risking indefinitely re-running the faulting instruction
-         * Covering a very narrow case for kernels 5.5..5.5.4
-         * when injected abort was misconfigured to be
-         * an IMPLEMENTATION DEFINED exception (for 32-bit EL1)
-         */
-        if (!arm_feature(env, ARM_FEATURE_AARCH64) &&
-            unlikely(!kvm_arm_verify_ext_dabt_pending(cs))) {
-
-            error_report("Data abort exception with no valid ISS generated by "
-                   "guest memory access. KVM unable to emulate faulting "
-                   "instruction. Failed to inject an external data abort "
-                   "into the guest.");
-            abort();
-       }
-       /* Clear the status */
-       env->ext_dabt_raised = 0;
-    }
-}
-
-MemTxAttrs kvm_arch_post_run(CPUState *cs, struct kvm_run *run)
-{
-    ARMCPU *cpu;
-    uint32_t switched_level;
-
-    if (kvm_irqchip_in_kernel()) {
-        /*
-         * We only need to sync timer states with user-space interrupt
-         * controllers, so return early and save cycles if we don't.
-         */
-        return MEMTXATTRS_UNSPECIFIED;
-    }
-
-    cpu = ARM_CPU(cs);
-
-    /* Synchronize our shadowed in-kernel device irq lines with the kvm ones */
-    if (run->s.regs.device_irq_level != cpu->device_irq_level) {
-        switched_level = cpu->device_irq_level ^ run->s.regs.device_irq_level;
-
-        qemu_mutex_lock_iothread();
-
-        if (switched_level & KVM_ARM_DEV_EL1_VTIMER) {
-            qemu_set_irq(cpu->gt_timer_outputs[GTIMER_VIRT],
-                         !!(run->s.regs.device_irq_level &
-                            KVM_ARM_DEV_EL1_VTIMER));
-            switched_level &= ~KVM_ARM_DEV_EL1_VTIMER;
-        }
-
-        if (switched_level & KVM_ARM_DEV_EL1_PTIMER) {
-            qemu_set_irq(cpu->gt_timer_outputs[GTIMER_PHYS],
-                         !!(run->s.regs.device_irq_level &
-                            KVM_ARM_DEV_EL1_PTIMER));
-            switched_level &= ~KVM_ARM_DEV_EL1_PTIMER;
-        }
-
-        if (switched_level & KVM_ARM_DEV_PMU) {
-            qemu_set_irq(cpu->pmu_interrupt,
-                         !!(run->s.regs.device_irq_level & KVM_ARM_DEV_PMU));
-            switched_level &= ~KVM_ARM_DEV_PMU;
-        }
-
-        if (switched_level) {
-            qemu_log_mask(LOG_UNIMP, "%s: unhandled in-kernel device IRQ %x\n",
-                          __func__, switched_level);
-        }
-
-        /* We also mark unknown levels as processed to not waste cycles */
-        cpu->device_irq_level = run->s.regs.device_irq_level;
-        qemu_mutex_unlock_iothread();
-    }
-
-    return MEMTXATTRS_UNSPECIFIED;
-}
-
-void kvm_arm_vm_state_change(void *opaque, bool running, RunState state)
+static void kvm_arm_vm_state_change(void *opaque, bool running, RunState state)
 {
     CPUState *cs = opaque;
     ARMCPU *cpu = ARM_CPU(cs);
@@ -910,29 +952,6 @@ static int kvm_arm_handle_dabt_nisv(CPUState *cs, uint64_t esr_iss,
     return -1;
 }
 
-int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
-{
-    int ret = 0;
-
-    switch (run->exit_reason) {
-    case KVM_EXIT_DEBUG:
-        if (kvm_arm_handle_debug(cs, &run->debug.arch)) {
-            ret = EXCP_DEBUG;
-        } /* otherwise return to guest */
-        break;
-    case KVM_EXIT_ARM_NISV:
-        /* External DABT with no valid iss to decode */
-        ret = kvm_arm_handle_dabt_nisv(cs, run->arm_nisv.esr_iss,
-                                       run->arm_nisv.fault_ipa);
-        break;
-    default:
-        qemu_log_mask(LOG_UNIMP, "%s: un-handled exit reason %d\n",
-                      __func__, run->exit_reason);
-        break;
-    }
-    return ret;
-}
-
 bool kvm_arch_stop_on_emulation_error(CPUState *cs)
 {
     return true;
@@ -943,17 +962,6 @@ int kvm_arch_process_async_events(CPUState *cs)
     return 0;
 }
 
-void kvm_arch_update_guest_debug(CPUState *cs, struct kvm_guest_debug *dbg)
-{
-    if (kvm_sw_breakpoints_active(cs)) {
-        dbg->control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_SW_BP;
-    }
-    if (kvm_arm_hw_debug_active(cs)) {
-        dbg->control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_HW;
-        kvm_arm_copy_hw_debug_data(&dbg->arch);
-    }
-}
-
 void kvm_arch_init_irq_routing(KVMState *s)
 {
 }
@@ -1062,3 +1070,1737 @@ bool kvm_arch_cpu_check_are_resettable(void)
 void kvm_arch_accel_class_init(ObjectClass *oc)
 {
 }
+
+static bool have_guest_debug;
+
+/*
+ * Although the ARM implementation of hardware assisted debugging
+ * allows for different breakpoints per-core, the current GDB
+ * interface treats them as a global pool of registers (which seems to
+ * be the case for x86, ppc and s390). As a result we store one copy
+ * of registers which is used for all active cores.
+ *
+ * Write access is serialised by virtue of the GDB protocol which
+ * updates things. Read access (i.e. when the values are copied to the
+ * vCPU) is also gated by GDB's run control.
+ *
+ * This is not unreasonable as most of the time debugging kernels you
+ * never know which core will eventually execute your function.
+ */
+
+typedef struct {
+    uint64_t bcr;
+    uint64_t bvr;
+} HWBreakpoint;
+
+/* The watchpoint registers can cover more area than the requested
+ * watchpoint so we need to store the additional information
+ * somewhere. We also need to supply a CPUWatchpoint to the GDB stub
+ * when the watchpoint is hit.
+ */
+typedef struct {
+    uint64_t wcr;
+    uint64_t wvr;
+    CPUWatchpoint details;
+} HWWatchpoint;
+
+/* Maximum and current break/watch point counts */
+int max_hw_bps, max_hw_wps;
+GArray *hw_breakpoints, *hw_watchpoints;
+
+#define cur_hw_wps      (hw_watchpoints->len)
+#define cur_hw_bps      (hw_breakpoints->len)
+#define get_hw_bp(i)    (&g_array_index(hw_breakpoints, HWBreakpoint, i))
+#define get_hw_wp(i)    (&g_array_index(hw_watchpoints, HWWatchpoint, i))
+
+/**
+ * kvm_arm_init_debug() - check for guest debug capabilities
+ * @cs: CPUState
+ *
+ * kvm_check_extension returns the number of debug registers we have
+ * or 0 if we have none.
+ *
+ */
+static void kvm_arm_init_debug(CPUState *cs)
+{
+    have_guest_debug = kvm_check_extension(cs->kvm_state,
+                                           KVM_CAP_SET_GUEST_DEBUG);
+
+    max_hw_wps = kvm_check_extension(cs->kvm_state, KVM_CAP_GUEST_DEBUG_HW_WPS);
+    hw_watchpoints = g_array_sized_new(true, true,
+                                       sizeof(HWWatchpoint), max_hw_wps);
+
+    max_hw_bps = kvm_check_extension(cs->kvm_state, KVM_CAP_GUEST_DEBUG_HW_BPS);
+    hw_breakpoints = g_array_sized_new(true, true,
+                                       sizeof(HWBreakpoint), max_hw_bps);
+    return;
+}
+
+/**
+ * insert_hw_breakpoint()
+ * @addr: address of breakpoint
+ *
+ * See ARM ARM D2.9.1 for details but here we are only going to create
+ * simple un-linked breakpoints (i.e. we don't chain breakpoints
+ * together to match address and context or vmid). The hardware is
+ * capable of fancier matching but that will require exposing that
+ * fanciness to GDB's interface
+ *
+ * DBGBCR<n>_EL1, Debug Breakpoint Control Registers
+ *
+ *  31  24 23  20 19   16 15 14  13  12   9 8   5 4    3 2   1  0
+ * +------+------+-------+-----+----+------+-----+------+-----+---+
+ * | RES0 |  BT  |  LBN  | SSC | HMC| RES0 | BAS | RES0 | PMC | E |
+ * +------+------+-------+-----+----+------+-----+------+-----+---+
+ *
+ * BT: Breakpoint type (0 = unlinked address match)
+ * LBN: Linked BP number (0 = unused)
+ * SSC/HMC/PMC: Security, Higher and Priv access control (Table D-12)
+ * BAS: Byte Address Select (RES1 for AArch64)
+ * E: Enable bit
+ *
+ * DBGBVR<n>_EL1, Debug Breakpoint Value Registers
+ *
+ *  63  53 52       49 48       2  1 0
+ * +------+-----------+----------+-----+
+ * | RESS | VA[52:49] | VA[48:2] | 0 0 |
+ * +------+-----------+----------+-----+
+ *
+ * Depending on the addressing mode bits the top bits of the register
+ * are a sign extension of the highest applicable VA bit. Some
+ * versions of GDB don't do it correctly so we ensure they are correct
+ * here so future PC comparisons will work properly.
+ */
+
+static int insert_hw_breakpoint(target_ulong addr)
+{
+    HWBreakpoint brk = {
+        .bcr = 0x1,                             /* BCR E=1, enable */
+        .bvr = sextract64(addr, 0, 53)
+    };
+
+    if (cur_hw_bps >= max_hw_bps) {
+        return -ENOBUFS;
+    }
+
+    brk.bcr = deposit32(brk.bcr, 1, 2, 0x3);   /* PMC = 11 */
+    brk.bcr = deposit32(brk.bcr, 5, 4, 0xf);   /* BAS = RES1 */
+
+    g_array_append_val(hw_breakpoints, brk);
+
+    return 0;
+}
+
+/**
+ * delete_hw_breakpoint()
+ * @pc: address of breakpoint
+ *
+ * Delete a breakpoint and shuffle any above down
+ */
+
+static int delete_hw_breakpoint(target_ulong pc)
+{
+    int i;
+    for (i = 0; i < hw_breakpoints->len; i++) {
+        HWBreakpoint *brk = get_hw_bp(i);
+        if (brk->bvr == pc) {
+            g_array_remove_index(hw_breakpoints, i);
+            return 0;
+        }
+    }
+    return -ENOENT;
+}
+
+/**
+ * insert_hw_watchpoint()
+ * @addr: address of watch point
+ * @len: size of area
+ * @type: type of watch point
+ *
+ * See ARM ARM D2.10. As with the breakpoints we can do some advanced
+ * stuff if we want to. The watch points can be linked with the break
+ * points above to make them context aware. However for simplicity
+ * currently we only deal with simple read/write watch points.
+ *
+ * D7.3.11 DBGWCR<n>_EL1, Debug Watchpoint Control Registers
+ *
+ *  31  29 28   24 23  21  20  19 16 15 14  13   12  5 4   3 2   1  0
+ * +------+-------+------+----+-----+-----+-----+-----+-----+-----+---+
+ * | RES0 |  MASK | RES0 | WT | LBN | SSC | HMC | BAS | LSC | PAC | E |
+ * +------+-------+------+----+-----+-----+-----+-----+-----+-----+---+
+ *
+ * MASK: num bits addr mask (0=none,01/10=res,11=3 bits (8 bytes))
+ * WT: 0 - unlinked, 1 - linked (not currently used)
+ * LBN: Linked BP number (not currently used)
+ * SSC/HMC/PAC: Security, Higher and Priv access control (Table D2-11)
+ * BAS: Byte Address Select
+ * LSC: Load/Store control (01: load, 10: store, 11: both)
+ * E: Enable
+ *
+ * The bottom 2 bits of the value register are masked. Therefore to
+ * break on any sizes smaller than an unaligned word you need to set
+ * MASK=0, BAS=bit per byte in question. For larger regions (^2) you
+ * need to ensure you mask the address as required and set BAS=0xff
+ */
+
+static int insert_hw_watchpoint(target_ulong addr,
+                                target_ulong len, int type)
+{
+    HWWatchpoint wp = {
+        .wcr = R_DBGWCR_E_MASK, /* E=1, enable */
+        .wvr = addr & (~0x7ULL),
+        .details = { .vaddr = addr, .len = len }
+    };
+
+    if (cur_hw_wps >= max_hw_wps) {
+        return -ENOBUFS;
+    }
+
+    /*
+     * HMC=0 SSC=0 PAC=3 will hit EL0 or EL1, any security state,
+     * valid whether EL3 is implemented or not
+     */
+    wp.wcr = FIELD_DP64(wp.wcr, DBGWCR, PAC, 3);
+
+    switch (type) {
+    case GDB_WATCHPOINT_READ:
+        wp.wcr = FIELD_DP64(wp.wcr, DBGWCR, LSC, 1);
+        wp.details.flags = BP_MEM_READ;
+        break;
+    case GDB_WATCHPOINT_WRITE:
+        wp.wcr = FIELD_DP64(wp.wcr, DBGWCR, LSC, 2);
+        wp.details.flags = BP_MEM_WRITE;
+        break;
+    case GDB_WATCHPOINT_ACCESS:
+        wp.wcr = FIELD_DP64(wp.wcr, DBGWCR, LSC, 3);
+        wp.details.flags = BP_MEM_ACCESS;
+        break;
+    default:
+        g_assert_not_reached();
+        break;
+    }
+    if (len <= 8) {
+        /* we align the address and set the bits in BAS */
+        int off = addr & 0x7;
+        int bas = (1 << len) - 1;
+
+        wp.wcr = deposit32(wp.wcr, 5 + off, 8 - off, bas);
+    } else {
+        /* For ranges above 8 bytes we need to be a power of 2 */
+        if (is_power_of_2(len)) {
+            int bits = ctz64(len);
+
+            wp.wvr &= ~((1 << bits) - 1);
+            wp.wcr = FIELD_DP64(wp.wcr, DBGWCR, MASK, bits);
+            wp.wcr = FIELD_DP64(wp.wcr, DBGWCR, BAS, 0xff);
+        } else {
+            return -ENOBUFS;
+        }
+    }
+
+    g_array_append_val(hw_watchpoints, wp);
+    return 0;
+}
+
+
+static bool check_watchpoint_in_range(int i, target_ulong addr)
+{
+    HWWatchpoint *wp = get_hw_wp(i);
+    uint64_t addr_top, addr_bottom = wp->wvr;
+    int bas = extract32(wp->wcr, 5, 8);
+    int mask = extract32(wp->wcr, 24, 4);
+
+    if (mask) {
+        addr_top = addr_bottom + (1 << mask);
+    } else {
+        /* BAS must be contiguous but can offset against the base
+         * address in DBGWVR */
+        addr_bottom = addr_bottom + ctz32(bas);
+        addr_top = addr_bottom + clo32(bas);
+    }
+
+    if (addr >= addr_bottom && addr <= addr_top) {
+        return true;
+    }
+
+    return false;
+}
+
+/**
+ * delete_hw_watchpoint()
+ * @addr: address of breakpoint
+ *
+ * Delete a breakpoint and shuffle any above down
+ */
+
+static int delete_hw_watchpoint(target_ulong addr,
+                                target_ulong len, int type)
+{
+    int i;
+    for (i = 0; i < cur_hw_wps; i++) {
+        if (check_watchpoint_in_range(i, addr)) {
+            g_array_remove_index(hw_watchpoints, i);
+            return 0;
+        }
+    }
+    return -ENOENT;
+}
+
+
+int kvm_arch_insert_hw_breakpoint(target_ulong addr,
+                                  target_ulong len, int type)
+{
+    switch (type) {
+    case GDB_BREAKPOINT_HW:
+        return insert_hw_breakpoint(addr);
+        break;
+    case GDB_WATCHPOINT_READ:
+    case GDB_WATCHPOINT_WRITE:
+    case GDB_WATCHPOINT_ACCESS:
+        return insert_hw_watchpoint(addr, len, type);
+    default:
+        return -ENOSYS;
+    }
+}
+
+int kvm_arch_remove_hw_breakpoint(target_ulong addr,
+                                  target_ulong len, int type)
+{
+    switch (type) {
+    case GDB_BREAKPOINT_HW:
+        return delete_hw_breakpoint(addr);
+    case GDB_WATCHPOINT_READ:
+    case GDB_WATCHPOINT_WRITE:
+    case GDB_WATCHPOINT_ACCESS:
+        return delete_hw_watchpoint(addr, len, type);
+    default:
+        return -ENOSYS;
+    }
+}
+
+
+void kvm_arch_remove_all_hw_breakpoints(void)
+{
+    if (cur_hw_wps > 0) {
+        g_array_remove_range(hw_watchpoints, 0, cur_hw_wps);
+    }
+    if (cur_hw_bps > 0) {
+        g_array_remove_range(hw_breakpoints, 0, cur_hw_bps);
+    }
+}
+
+/**
+ * kvm_arm_copy_hw_debug_data:
+ * @ptr: kvm_guest_debug_arch structure
+ *
+ * Copy the architecture specific debug registers into the
+ * kvm_guest_debug ioctl structure.
+ */
+static void kvm_arm_copy_hw_debug_data(struct kvm_guest_debug_arch *ptr)
+{
+    int i;
+    memset(ptr, 0, sizeof(struct kvm_guest_debug_arch));
+
+    for (i = 0; i < max_hw_wps; i++) {
+        HWWatchpoint *wp = get_hw_wp(i);
+        ptr->dbg_wcr[i] = wp->wcr;
+        ptr->dbg_wvr[i] = wp->wvr;
+    }
+    for (i = 0; i < max_hw_bps; i++) {
+        HWBreakpoint *bp = get_hw_bp(i);
+        ptr->dbg_bcr[i] = bp->bcr;
+        ptr->dbg_bvr[i] = bp->bvr;
+    }
+}
+
+/**
+ * kvm_arm_hw_debug_active:
+ * @cs: CPU State
+ *
+ * Return: TRUE if any hardware breakpoints in use.
+ */
+static bool kvm_arm_hw_debug_active(CPUState *cs)
+{
+    return ((cur_hw_wps > 0) || (cur_hw_bps > 0));
+}
+
+static bool find_hw_breakpoint(CPUState *cpu, target_ulong pc)
+{
+    int i;
+
+    for (i = 0; i < cur_hw_bps; i++) {
+        HWBreakpoint *bp = get_hw_bp(i);
+        if (bp->bvr == pc) {
+            return true;
+        }
+    }
+    return false;
+}
+
+static CPUWatchpoint *find_hw_watchpoint(CPUState *cpu, target_ulong addr)
+{
+    int i;
+
+    for (i = 0; i < cur_hw_wps; i++) {
+        if (check_watchpoint_in_range(i, addr)) {
+            return &get_hw_wp(i)->details;
+        }
+    }
+    return NULL;
+}
+
+static bool kvm_arm_set_device_attr(CPUState *cs, struct kvm_device_attr *attr,
+                                    const char *name)
+{
+    int err;
+
+    err = kvm_vcpu_ioctl(cs, KVM_HAS_DEVICE_ATTR, attr);
+    if (err != 0) {
+        error_report("%s: KVM_HAS_DEVICE_ATTR: %s", name, strerror(-err));
+        return false;
+    }
+
+    err = kvm_vcpu_ioctl(cs, KVM_SET_DEVICE_ATTR, attr);
+    if (err != 0) {
+        error_report("%s: KVM_SET_DEVICE_ATTR: %s", name, strerror(-err));
+        return false;
+    }
+
+    return true;
+}
+
+void kvm_arm_pmu_init(CPUState *cs)
+{
+    struct kvm_device_attr attr = {
+        .group = KVM_ARM_VCPU_PMU_V3_CTRL,
+        .attr = KVM_ARM_VCPU_PMU_V3_INIT,
+    };
+
+    if (!ARM_CPU(cs)->has_pmu) {
+        return;
+    }
+    if (!kvm_arm_set_device_attr(cs, &attr, "PMU")) {
+        error_report("failed to init PMU");
+        abort();
+    }
+}
+
+void kvm_arm_pmu_set_irq(CPUState *cs, int irq)
+{
+    struct kvm_device_attr attr = {
+        .group = KVM_ARM_VCPU_PMU_V3_CTRL,
+        .addr = (intptr_t)&irq,
+        .attr = KVM_ARM_VCPU_PMU_V3_IRQ,
+    };
+
+    if (!ARM_CPU(cs)->has_pmu) {
+        return;
+    }
+    if (!kvm_arm_set_device_attr(cs, &attr, "PMU")) {
+        error_report("failed to set irq for PMU");
+        abort();
+    }
+}
+
+void kvm_arm_pvtime_init(CPUState *cs, uint64_t ipa)
+{
+    struct kvm_device_attr attr = {
+        .group = KVM_ARM_VCPU_PVTIME_CTRL,
+        .attr = KVM_ARM_VCPU_PVTIME_IPA,
+        .addr = (uint64_t)&ipa,
+    };
+
+    if (ARM_CPU(cs)->kvm_steal_time == ON_OFF_AUTO_OFF) {
+        return;
+    }
+    if (!kvm_arm_set_device_attr(cs, &attr, "PVTIME IPA")) {
+        error_report("failed to init PVTIME IPA");
+        abort();
+    }
+}
+
+static int read_sys_reg32(int fd, uint32_t *pret, uint64_t id)
+{
+    uint64_t ret;
+    struct kvm_one_reg idreg = { .id = id, .addr = (uintptr_t)&ret };
+    int err;
+
+    assert((id & KVM_REG_SIZE_MASK) == KVM_REG_SIZE_U64);
+    err = ioctl(fd, KVM_GET_ONE_REG, &idreg);
+    if (err < 0) {
+        return -1;
+    }
+    *pret = ret;
+    return 0;
+}
+
+static int read_sys_reg64(int fd, uint64_t *pret, uint64_t id)
+{
+    struct kvm_one_reg idreg = { .id = id, .addr = (uintptr_t)pret };
+
+    assert((id & KVM_REG_SIZE_MASK) == KVM_REG_SIZE_U64);
+    return ioctl(fd, KVM_GET_ONE_REG, &idreg);
+}
+
+static bool kvm_arm_pauth_supported(void)
+{
+    return (kvm_check_extension(kvm_state, KVM_CAP_ARM_PTRAUTH_ADDRESS) &&
+            kvm_check_extension(kvm_state, KVM_CAP_ARM_PTRAUTH_GENERIC));
+}
+
+/**
+ * kvm_arm_get_host_cpu_features:
+ * @ahcf: ARMHostCPUClass to fill in
+ *
+ * Probe the capabilities of the host kernel's preferred CPU and fill
+ * in the ARMHostCPUClass struct accordingly.
+ *
+ * Returns true on success and false otherwise.
+ */
+static bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
+{
+    /* Identify the feature bits corresponding to the host CPU, and
+     * fill out the ARMHostCPUClass fields accordingly. To do this
+     * we have to create a scratch VM, create a single CPU inside it,
+     * and then query that CPU for the relevant ID registers.
+     */
+    int fdarray[3];
+    bool sve_supported;
+    bool pmu_supported = false;
+    uint64_t features = 0;
+    int err;
+
+    /* Old kernels may not know about the PREFERRED_TARGET ioctl: however
+     * we know these will only support creating one kind of guest CPU,
+     * which is its preferred CPU type. Fortunately these old kernels
+     * support only a very limited number of CPUs.
+     */
+    static const uint32_t cpus_to_try[] = {
+        KVM_ARM_TARGET_AEM_V8,
+        KVM_ARM_TARGET_FOUNDATION_V8,
+        KVM_ARM_TARGET_CORTEX_A57,
+        QEMU_KVM_ARM_TARGET_NONE
+    };
+    /*
+     * target = -1 informs kvm_arm_create_scratch_host_vcpu()
+     * to use the preferred target
+     */
+    struct kvm_vcpu_init init = { .target = -1, };
+
+    /*
+     * Ask for SVE if supported, so that we can query ID_AA64ZFR0,
+     * which is otherwise RAZ.
+     */
+    sve_supported = kvm_arm_sve_supported();
+    if (sve_supported) {
+        init.features[0] |= 1 << KVM_ARM_VCPU_SVE;
+    }
+
+    /*
+     * Ask for Pointer Authentication if supported, so that we get
+     * the unsanitized field values for AA64ISAR1_EL1.
+     */
+    if (kvm_arm_pauth_supported()) {
+        init.features[0] |= (1 << KVM_ARM_VCPU_PTRAUTH_ADDRESS |
+                             1 << KVM_ARM_VCPU_PTRAUTH_GENERIC);
+    }
+
+    if (kvm_arm_pmu_supported()) {
+        init.features[0] |= 1 << KVM_ARM_VCPU_PMU_V3;
+        pmu_supported = true;
+    }
+
+    if (!kvm_arm_create_scratch_host_vcpu(cpus_to_try, fdarray, &init)) {
+        return false;
+    }
+
+    ahcf->target = init.target;
+    ahcf->dtb_compatible = "arm,arm-v8";
+
+    err = read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64pfr0,
+                         ARM64_SYS_REG(3, 0, 0, 4, 0));
+    if (unlikely(err < 0)) {
+        /*
+         * Before v4.15, the kernel only exposed a limited number of system
+         * registers, not including any of the interesting AArch64 ID regs.
+         * For the most part we could leave these fields as zero with minimal
+         * effect, since this does not affect the values seen by the guest.
+         *
+         * However, it could cause problems down the line for QEMU,
+         * so provide a minimal v8.0 default.
+         *
+         * ??? Could read MIDR and use knowledge from cpu64.c.
+         * ??? Could map a page of memory into our temp guest and
+         *     run the tiniest of hand-crafted kernels to extract
+         *     the values seen by the guest.
+         * ??? Either of these sounds like too much effort just
+         *     to work around running a modern host kernel.
+         */
+        ahcf->isar.id_aa64pfr0 = 0x00000011; /* EL1&0, AArch64 only */
+        err = 0;
+    } else {
+        err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64pfr1,
+                              ARM64_SYS_REG(3, 0, 0, 4, 1));
+        err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64smfr0,
+                              ARM64_SYS_REG(3, 0, 0, 4, 5));
+        err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64dfr0,
+                              ARM64_SYS_REG(3, 0, 0, 5, 0));
+        err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64dfr1,
+                              ARM64_SYS_REG(3, 0, 0, 5, 1));
+        err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64isar0,
+                              ARM64_SYS_REG(3, 0, 0, 6, 0));
+        err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64isar1,
+                              ARM64_SYS_REG(3, 0, 0, 6, 1));
+        err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64mmfr0,
+                              ARM64_SYS_REG(3, 0, 0, 7, 0));
+        err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64mmfr1,
+                              ARM64_SYS_REG(3, 0, 0, 7, 1));
+        err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64mmfr2,
+                              ARM64_SYS_REG(3, 0, 0, 7, 2));
+
+        /*
+         * Note that if AArch32 support is not present in the host,
+         * the AArch32 sysregs are present to be read, but will
+         * return UNKNOWN values.  This is neither better nor worse
+         * than skipping the reads and leaving 0, as we must avoid
+         * considering the values in every case.
+         */
+        err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_pfr0,
+                              ARM64_SYS_REG(3, 0, 0, 1, 0));
+        err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_pfr1,
+                              ARM64_SYS_REG(3, 0, 0, 1, 1));
+        err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_dfr0,
+                              ARM64_SYS_REG(3, 0, 0, 1, 2));
+        err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_mmfr0,
+                              ARM64_SYS_REG(3, 0, 0, 1, 4));
+        err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_mmfr1,
+                              ARM64_SYS_REG(3, 0, 0, 1, 5));
+        err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_mmfr2,
+                              ARM64_SYS_REG(3, 0, 0, 1, 6));
+        err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_mmfr3,
+                              ARM64_SYS_REG(3, 0, 0, 1, 7));
+        err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_isar0,
+                              ARM64_SYS_REG(3, 0, 0, 2, 0));
+        err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_isar1,
+                              ARM64_SYS_REG(3, 0, 0, 2, 1));
+        err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_isar2,
+                              ARM64_SYS_REG(3, 0, 0, 2, 2));
+        err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_isar3,
+                              ARM64_SYS_REG(3, 0, 0, 2, 3));
+        err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_isar4,
+                              ARM64_SYS_REG(3, 0, 0, 2, 4));
+        err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_isar5,
+                              ARM64_SYS_REG(3, 0, 0, 2, 5));
+        err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_mmfr4,
+                              ARM64_SYS_REG(3, 0, 0, 2, 6));
+        err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_isar6,
+                              ARM64_SYS_REG(3, 0, 0, 2, 7));
+
+        err |= read_sys_reg32(fdarray[2], &ahcf->isar.mvfr0,
+                              ARM64_SYS_REG(3, 0, 0, 3, 0));
+        err |= read_sys_reg32(fdarray[2], &ahcf->isar.mvfr1,
+                              ARM64_SYS_REG(3, 0, 0, 3, 1));
+        err |= read_sys_reg32(fdarray[2], &ahcf->isar.mvfr2,
+                              ARM64_SYS_REG(3, 0, 0, 3, 2));
+        err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_pfr2,
+                              ARM64_SYS_REG(3, 0, 0, 3, 4));
+        err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_dfr1,
+                              ARM64_SYS_REG(3, 0, 0, 3, 5));
+        err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_mmfr5,
+                              ARM64_SYS_REG(3, 0, 0, 3, 6));
+
+        /*
+         * DBGDIDR is a bit complicated because the kernel doesn't
+         * provide an accessor for it in 64-bit mode, which is what this
+         * scratch VM is in, and there's no architected "64-bit sysreg
+         * which reads the same as the 32-bit register" the way there is
+         * for other ID registers. Instead we synthesize a value from the
+         * AArch64 ID_AA64DFR0, the same way the kernel code in
+         * arch/arm64/kvm/sys_regs.c:trap_dbgidr() does.
+         * We only do this if the CPU supports AArch32 at EL1.
+         */
+        if (FIELD_EX32(ahcf->isar.id_aa64pfr0, ID_AA64PFR0, EL1) >= 2) {
+            int wrps = FIELD_EX64(ahcf->isar.id_aa64dfr0, ID_AA64DFR0, WRPS);
+            int brps = FIELD_EX64(ahcf->isar.id_aa64dfr0, ID_AA64DFR0, BRPS);
+            int ctx_cmps =
+                FIELD_EX64(ahcf->isar.id_aa64dfr0, ID_AA64DFR0, CTX_CMPS);
+            int version = 6; /* ARMv8 debug architecture */
+            bool has_el3 =
+                !!FIELD_EX32(ahcf->isar.id_aa64pfr0, ID_AA64PFR0, EL3);
+            uint32_t dbgdidr = 0;
+
+            dbgdidr = FIELD_DP32(dbgdidr, DBGDIDR, WRPS, wrps);
+            dbgdidr = FIELD_DP32(dbgdidr, DBGDIDR, BRPS, brps);
+            dbgdidr = FIELD_DP32(dbgdidr, DBGDIDR, CTX_CMPS, ctx_cmps);
+            dbgdidr = FIELD_DP32(dbgdidr, DBGDIDR, VERSION, version);
+            dbgdidr = FIELD_DP32(dbgdidr, DBGDIDR, NSUHD_IMP, has_el3);
+            dbgdidr = FIELD_DP32(dbgdidr, DBGDIDR, SE_IMP, has_el3);
+            dbgdidr |= (1 << 15); /* RES1 bit */
+            ahcf->isar.dbgdidr = dbgdidr;
+        }
+
+        if (pmu_supported) {
+            /* PMCR_EL0 is only accessible if the vCPU has feature PMU_V3 */
+            err |= read_sys_reg64(fdarray[2], &ahcf->isar.reset_pmcr_el0,
+                                  ARM64_SYS_REG(3, 3, 9, 12, 0));
+        }
+
+        if (sve_supported) {
+            /*
+             * There is a range of kernels between kernel commit 73433762fcae
+             * and f81cb2c3ad41 which have a bug where the kernel doesn't
+             * expose SYS_ID_AA64ZFR0_EL1 via the ONE_REG API unless the VM has
+             * enabled SVE support, which resulted in an error rather than RAZ.
+             * So only read the register if we set KVM_ARM_VCPU_SVE above.
+             */
+            err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64zfr0,
+                                  ARM64_SYS_REG(3, 0, 0, 4, 4));
+        }
+    }
+
+    kvm_arm_destroy_scratch_host_vcpu(fdarray);
+
+    if (err < 0) {
+        return false;
+    }
+
+    /*
+     * We can assume any KVM supporting CPU is at least a v8
+     * with VFPv4+Neon; this in turn implies most of the other
+     * feature bits.
+     */
+    features |= 1ULL << ARM_FEATURE_V8;
+    features |= 1ULL << ARM_FEATURE_NEON;
+    features |= 1ULL << ARM_FEATURE_AARCH64;
+    features |= 1ULL << ARM_FEATURE_PMU;
+    features |= 1ULL << ARM_FEATURE_GENERIC_TIMER;
+
+    ahcf->features = features;
+
+    return true;
+}
+
+void kvm_arm_set_cpu_features_from_host(ARMCPU *cpu)
+{
+    CPUARMState *env = &cpu->env;
+
+    if (!arm_host_cpu_features.dtb_compatible) {
+        if (!kvm_enabled() ||
+            !kvm_arm_get_host_cpu_features(&arm_host_cpu_features)) {
+            /* We can't report this error yet, so flag that we need to
+             * in arm_cpu_realizefn().
+             */
+            cpu->kvm_target = QEMU_KVM_ARM_TARGET_NONE;
+            cpu->host_cpu_probe_failed = true;
+            return;
+        }
+    }
+
+    cpu->kvm_target = arm_host_cpu_features.target;
+    cpu->dtb_compatible = arm_host_cpu_features.dtb_compatible;
+    cpu->isar = arm_host_cpu_features.isar;
+    env->features = arm_host_cpu_features.features;
+}
+
+/**
+ * kvm_arm_steal_time_supported:
+ *
+ * Returns: true if KVM can enable steal time reporting
+ * and false otherwise.
+ */
+static bool kvm_arm_steal_time_supported(void)
+{
+    return kvm_check_extension(kvm_state, KVM_CAP_STEAL_TIME);
+}
+
+void kvm_arm_steal_time_finalize(ARMCPU *cpu, Error **errp)
+{
+    bool has_steal_time = kvm_arm_steal_time_supported();
+
+    if (cpu->kvm_steal_time == ON_OFF_AUTO_AUTO) {
+        if (!has_steal_time || !arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) {
+            cpu->kvm_steal_time = ON_OFF_AUTO_OFF;
+        } else {
+            cpu->kvm_steal_time = ON_OFF_AUTO_ON;
+        }
+    } else if (cpu->kvm_steal_time == ON_OFF_AUTO_ON) {
+        if (!has_steal_time) {
+            error_setg(errp, "'kvm-steal-time' cannot be enabled "
+                             "on this host");
+            return;
+        } else if (!arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) {
+            /*
+             * DEN0057A chapter 2 says "This specification only covers
+             * systems in which the Execution state of the hypervisor
+             * as well as EL1 of virtual machines is AArch64.". And,
+             * to ensure that, the smc/hvc calls are only specified as
+             * smc64/hvc64.
+             */
+            error_setg(errp, "'kvm-steal-time' cannot be enabled "
+                             "for AArch32 guests");
+            return;
+        }
+    }
+}
+
+bool kvm_arm_aarch32_supported(void)
+{
+    return kvm_check_extension(kvm_state, KVM_CAP_ARM_EL1_32BIT);
+}
+
+bool kvm_arm_sve_supported(void)
+{
+    return kvm_check_extension(kvm_state, KVM_CAP_ARM_SVE);
+}
+
+QEMU_BUILD_BUG_ON(KVM_ARM64_SVE_VQ_MIN != 1);
+
+uint32_t kvm_arm_sve_get_vls(CPUState *cs)
+{
+    /* Only call this function if kvm_arm_sve_supported() returns true. */
+    static uint64_t vls[KVM_ARM64_SVE_VLS_WORDS];
+    static bool probed;
+    uint32_t vq = 0;
+    int i;
+
+    /*
+     * KVM ensures all host CPUs support the same set of vector lengths.
+     * So we only need to create the scratch VCPUs once and then cache
+     * the results.
+     */
+    if (!probed) {
+        struct kvm_vcpu_init init = {
+            .target = -1,
+            .features[0] = (1 << KVM_ARM_VCPU_SVE),
+        };
+        struct kvm_one_reg reg = {
+            .id = KVM_REG_ARM64_SVE_VLS,
+            .addr = (uint64_t)&vls[0],
+        };
+        int fdarray[3], ret;
+
+        probed = true;
+
+        if (!kvm_arm_create_scratch_host_vcpu(NULL, fdarray, &init)) {
+            error_report("failed to create scratch VCPU with SVE enabled");
+            abort();
+        }
+        ret = ioctl(fdarray[2], KVM_GET_ONE_REG, &reg);
+        kvm_arm_destroy_scratch_host_vcpu(fdarray);
+        if (ret) {
+            error_report("failed to get KVM_REG_ARM64_SVE_VLS: %s",
+                         strerror(errno));
+            abort();
+        }
+
+        for (i = KVM_ARM64_SVE_VLS_WORDS - 1; i >= 0; --i) {
+            if (vls[i]) {
+                vq = 64 - clz64(vls[i]) + i * 64;
+                break;
+            }
+        }
+        if (vq > ARM_MAX_VQ) {
+            warn_report("KVM supports vector lengths larger than "
+                        "QEMU can enable");
+            vls[0] &= MAKE_64BIT_MASK(0, ARM_MAX_VQ);
+        }
+    }
+
+    return vls[0];
+}
+
+static int kvm_arm_sve_set_vls(CPUState *cs)
+{
+    ARMCPU *cpu = ARM_CPU(cs);
+    uint64_t vls[KVM_ARM64_SVE_VLS_WORDS] = { cpu->sve_vq.map };
+    struct kvm_one_reg reg = {
+        .id = KVM_REG_ARM64_SVE_VLS,
+        .addr = (uint64_t)&vls[0],
+    };
+
+    assert(cpu->sve_max_vq <= KVM_ARM64_SVE_VQ_MAX);
+
+    return kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
+}
+
+#define ARM_CPU_ID_MPIDR       3, 0, 0, 0, 5
+
+int kvm_arch_init_vcpu(CPUState *cs)
+{
+    int ret;
+    ARMCPU *cpu = ARM_CPU(cs);
+    CPUARMState *env = &cpu->env;
+    uint64_t psciver;
+
+    if (cpu->kvm_target == QEMU_KVM_ARM_TARGET_NONE ||
+        !object_dynamic_cast(OBJECT(cpu), TYPE_AARCH64_CPU)) {
+        error_report("KVM is not supported for this guest CPU type");
+        return -EINVAL;
+    }
+
+    qemu_add_vm_change_state_handler(kvm_arm_vm_state_change, cs);
+
+    /* Determine init features for this CPU */
+    memset(cpu->kvm_init_features, 0, sizeof(cpu->kvm_init_features));
+    if (cs->start_powered_off) {
+        cpu->kvm_init_features[0] |= 1 << KVM_ARM_VCPU_POWER_OFF;
+    }
+    if (kvm_check_extension(cs->kvm_state, KVM_CAP_ARM_PSCI_0_2)) {
+        cpu->psci_version = QEMU_PSCI_VERSION_0_2;
+        cpu->kvm_init_features[0] |= 1 << KVM_ARM_VCPU_PSCI_0_2;
+    }
+    if (!arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) {
+        cpu->kvm_init_features[0] |= 1 << KVM_ARM_VCPU_EL1_32BIT;
+    }
+    if (!kvm_check_extension(cs->kvm_state, KVM_CAP_ARM_PMU_V3)) {
+        cpu->has_pmu = false;
+    }
+    if (cpu->has_pmu) {
+        cpu->kvm_init_features[0] |= 1 << KVM_ARM_VCPU_PMU_V3;
+    } else {
+        env->features &= ~(1ULL << ARM_FEATURE_PMU);
+    }
+    if (cpu_isar_feature(aa64_sve, cpu)) {
+        assert(kvm_arm_sve_supported());
+        cpu->kvm_init_features[0] |= 1 << KVM_ARM_VCPU_SVE;
+    }
+    if (cpu_isar_feature(aa64_pauth, cpu)) {
+        cpu->kvm_init_features[0] |= (1 << KVM_ARM_VCPU_PTRAUTH_ADDRESS |
+                                      1 << KVM_ARM_VCPU_PTRAUTH_GENERIC);
+    }
+
+    /* Do KVM_ARM_VCPU_INIT ioctl */
+    ret = kvm_arm_vcpu_init(cs);
+    if (ret) {
+        return ret;
+    }
+
+    if (cpu_isar_feature(aa64_sve, cpu)) {
+        ret = kvm_arm_sve_set_vls(cs);
+        if (ret) {
+            return ret;
+        }
+        ret = kvm_arm_vcpu_finalize(cs, KVM_ARM_VCPU_SVE);
+        if (ret) {
+            return ret;
+        }
+    }
+
+    /*
+     * KVM reports the exact PSCI version it is implementing via a
+     * special sysreg. If it is present, use its contents to determine
+     * what to report to the guest in the dtb (it is the PSCI version,
+     * in the same 15-bits major 16-bits minor format that PSCI_VERSION
+     * returns).
+     */
+    if (!kvm_get_one_reg(cs, KVM_REG_ARM_PSCI_VERSION, &psciver)) {
+        cpu->psci_version = psciver;
+    }
+
+    /*
+     * When KVM is in use, PSCI is emulated in-kernel and not by qemu.
+     * Currently KVM has its own idea about MPIDR assignment, so we
+     * override our defaults with what we get from KVM.
+     */
+    ret = kvm_get_one_reg(cs, ARM64_SYS_REG(ARM_CPU_ID_MPIDR),
+                          &cpu->mpidr_el1);
+    if (ret) {
+        return ret;
+    }
+
+    kvm_arm_init_debug(cs);
+
+    /* Check whether user space can specify guest syndrome value */
+    kvm_arm_init_serror_injection(cs);
+
+    return kvm_arm_init_cpreg_list(cpu);
+}
+
+int kvm_arch_destroy_vcpu(CPUState *cs)
+{
+    return 0;
+}
+
+/* Callers must hold the iothread mutex lock */
+static void kvm_inject_arm_sea(CPUState *c)
+{
+    ARMCPU *cpu = ARM_CPU(c);
+    CPUARMState *env = &cpu->env;
+    uint32_t esr;
+    bool same_el;
+
+    c->exception_index = EXCP_DATA_ABORT;
+    env->exception.target_el = 1;
+
+    /*
+     * Set the DFSC to synchronous external abort and set FnV to not valid,
+     * this will tell guest the FAR_ELx is UNKNOWN for this abort.
+     */
+    same_el = arm_current_el(env) == env->exception.target_el;
+    esr = syn_data_abort_no_iss(same_el, 1, 0, 0, 0, 0, 0x10);
+
+    env->exception.syndrome = esr;
+
+    arm_cpu_do_interrupt(c);
+}
+
+#define AARCH64_CORE_REG(x)   (KVM_REG_ARM64 | KVM_REG_SIZE_U64 | \
+                 KVM_REG_ARM_CORE | KVM_REG_ARM_CORE_REG(x))
+
+#define AARCH64_SIMD_CORE_REG(x)   (KVM_REG_ARM64 | KVM_REG_SIZE_U128 | \
+                 KVM_REG_ARM_CORE | KVM_REG_ARM_CORE_REG(x))
+
+#define AARCH64_SIMD_CTRL_REG(x)   (KVM_REG_ARM64 | KVM_REG_SIZE_U32 | \
+                 KVM_REG_ARM_CORE | KVM_REG_ARM_CORE_REG(x))
+
+static int kvm_arch_put_fpsimd(CPUState *cs)
+{
+    CPUARMState *env = &ARM_CPU(cs)->env;
+    struct kvm_one_reg reg;
+    int i, ret;
+
+    for (i = 0; i < 32; i++) {
+        uint64_t *q = aa64_vfp_qreg(env, i);
+#if HOST_BIG_ENDIAN
+        uint64_t fp_val[2] = { q[1], q[0] };
+        reg.addr = (uintptr_t)fp_val;
+#else
+        reg.addr = (uintptr_t)q;
+#endif
+        reg.id = AARCH64_SIMD_CORE_REG(fp_regs.vregs[i]);
+        ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
+        if (ret) {
+            return ret;
+        }
+    }
+
+    return 0;
+}
+
+/*
+ * KVM SVE registers come in slices where ZREGs have a slice size of 2048 bits
+ * and PREGS and the FFR have a slice size of 256 bits. However we simply hard
+ * code the slice index to zero for now as it's unlikely we'll need more than
+ * one slice for quite some time.
+ */
+static int kvm_arch_put_sve(CPUState *cs)
+{
+    ARMCPU *cpu = ARM_CPU(cs);
+    CPUARMState *env = &cpu->env;
+    uint64_t tmp[ARM_MAX_VQ * 2];
+    uint64_t *r;
+    struct kvm_one_reg reg;
+    int n, ret;
+
+    for (n = 0; n < KVM_ARM64_SVE_NUM_ZREGS; ++n) {
+        r = sve_bswap64(tmp, &env->vfp.zregs[n].d[0], cpu->sve_max_vq * 2);
+        reg.addr = (uintptr_t)r;
+        reg.id = KVM_REG_ARM64_SVE_ZREG(n, 0);
+        ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
+        if (ret) {
+            return ret;
+        }
+    }
+
+    for (n = 0; n < KVM_ARM64_SVE_NUM_PREGS; ++n) {
+        r = sve_bswap64(tmp, r = &env->vfp.pregs[n].p[0],
+                        DIV_ROUND_UP(cpu->sve_max_vq * 2, 8));
+        reg.addr = (uintptr_t)r;
+        reg.id = KVM_REG_ARM64_SVE_PREG(n, 0);
+        ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
+        if (ret) {
+            return ret;
+        }
+    }
+
+    r = sve_bswap64(tmp, &env->vfp.pregs[FFR_PRED_NUM].p[0],
+                    DIV_ROUND_UP(cpu->sve_max_vq * 2, 8));
+    reg.addr = (uintptr_t)r;
+    reg.id = KVM_REG_ARM64_SVE_FFR(0);
+    ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
+    if (ret) {
+        return ret;
+    }
+
+    return 0;
+}
+
+int kvm_arch_put_registers(CPUState *cs, int level)
+{
+    struct kvm_one_reg reg;
+    uint64_t val;
+    uint32_t fpr;
+    int i, ret;
+    unsigned int el;
+
+    ARMCPU *cpu = ARM_CPU(cs);
+    CPUARMState *env = &cpu->env;
+
+    /* If we are in AArch32 mode then we need to copy the AArch32 regs to the
+     * AArch64 registers before pushing them out to 64-bit KVM.
+     */
+    if (!is_a64(env)) {
+        aarch64_sync_32_to_64(env);
+    }
+
+    for (i = 0; i < 31; i++) {
+        reg.id = AARCH64_CORE_REG(regs.regs[i]);
+        reg.addr = (uintptr_t) &env->xregs[i];
+        ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
+        if (ret) {
+            return ret;
+        }
+    }
+
+    /* KVM puts SP_EL0 in regs.sp and SP_EL1 in regs.sp_el1. On the
+     * QEMU side we keep the current SP in xregs[31] as well.
+     */
+    aarch64_save_sp(env, 1);
+
+    reg.id = AARCH64_CORE_REG(regs.sp);
+    reg.addr = (uintptr_t) &env->sp_el[0];
+    ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
+    if (ret) {
+        return ret;
+    }
+
+    reg.id = AARCH64_CORE_REG(sp_el1);
+    reg.addr = (uintptr_t) &env->sp_el[1];
+    ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
+    if (ret) {
+        return ret;
+    }
+
+    /* Note that KVM thinks pstate is 64 bit but we use a uint32_t */
+    if (is_a64(env)) {
+        val = pstate_read(env);
+    } else {
+        val = cpsr_read(env);
+    }
+    reg.id = AARCH64_CORE_REG(regs.pstate);
+    reg.addr = (uintptr_t) &val;
+    ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
+    if (ret) {
+        return ret;
+    }
+
+    reg.id = AARCH64_CORE_REG(regs.pc);
+    reg.addr = (uintptr_t) &env->pc;
+    ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
+    if (ret) {
+        return ret;
+    }
+
+    reg.id = AARCH64_CORE_REG(elr_el1);
+    reg.addr = (uintptr_t) &env->elr_el[1];
+    ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
+    if (ret) {
+        return ret;
+    }
+
+    /* Saved Program State Registers
+     *
+     * Before we restore from the banked_spsr[] array we need to
+     * ensure that any modifications to env->spsr are correctly
+     * reflected in the banks.
+     */
+    el = arm_current_el(env);
+    if (el > 0 && !is_a64(env)) {
+        i = bank_number(env->uncached_cpsr & CPSR_M);
+        env->banked_spsr[i] = env->spsr;
+    }
+
+    /* KVM 0-4 map to QEMU banks 1-5 */
+    for (i = 0; i < KVM_NR_SPSR; i++) {
+        reg.id = AARCH64_CORE_REG(spsr[i]);
+        reg.addr = (uintptr_t) &env->banked_spsr[i + 1];
+        ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
+        if (ret) {
+            return ret;
+        }
+    }
+
+    if (cpu_isar_feature(aa64_sve, cpu)) {
+        ret = kvm_arch_put_sve(cs);
+    } else {
+        ret = kvm_arch_put_fpsimd(cs);
+    }
+    if (ret) {
+        return ret;
+    }
+
+    reg.addr = (uintptr_t)(&fpr);
+    fpr = vfp_get_fpsr(env);
+    reg.id = AARCH64_SIMD_CTRL_REG(fp_regs.fpsr);
+    ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
+    if (ret) {
+        return ret;
+    }
+
+    reg.addr = (uintptr_t)(&fpr);
+    fpr = vfp_get_fpcr(env);
+    reg.id = AARCH64_SIMD_CTRL_REG(fp_regs.fpcr);
+    ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
+    if (ret) {
+        return ret;
+    }
+
+    write_cpustate_to_list(cpu, true);
+
+    if (!write_list_to_kvmstate(cpu, level)) {
+        return -EINVAL;
+    }
+
+   /*
+    * Setting VCPU events should be triggered after syncing the registers
+    * to avoid overwriting potential changes made by KVM upon calling
+    * KVM_SET_VCPU_EVENTS ioctl
+    */
+    ret = kvm_put_vcpu_events(cpu);
+    if (ret) {
+        return ret;
+    }
+
+    kvm_arm_sync_mpstate_to_kvm(cpu);
+
+    return ret;
+}
+
+static int kvm_arch_get_fpsimd(CPUState *cs)
+{
+    CPUARMState *env = &ARM_CPU(cs)->env;
+    struct kvm_one_reg reg;
+    int i, ret;
+
+    for (i = 0; i < 32; i++) {
+        uint64_t *q = aa64_vfp_qreg(env, i);
+        reg.id = AARCH64_SIMD_CORE_REG(fp_regs.vregs[i]);
+        reg.addr = (uintptr_t)q;
+        ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
+        if (ret) {
+            return ret;
+        } else {
+#if HOST_BIG_ENDIAN
+            uint64_t t;
+            t = q[0], q[0] = q[1], q[1] = t;
+#endif
+        }
+    }
+
+    return 0;
+}
+
+/*
+ * KVM SVE registers come in slices where ZREGs have a slice size of 2048 bits
+ * and PREGS and the FFR have a slice size of 256 bits. However we simply hard
+ * code the slice index to zero for now as it's unlikely we'll need more than
+ * one slice for quite some time.
+ */
+static int kvm_arch_get_sve(CPUState *cs)
+{
+    ARMCPU *cpu = ARM_CPU(cs);
+    CPUARMState *env = &cpu->env;
+    struct kvm_one_reg reg;
+    uint64_t *r;
+    int n, ret;
+
+    for (n = 0; n < KVM_ARM64_SVE_NUM_ZREGS; ++n) {
+        r = &env->vfp.zregs[n].d[0];
+        reg.addr = (uintptr_t)r;
+        reg.id = KVM_REG_ARM64_SVE_ZREG(n, 0);
+        ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
+        if (ret) {
+            return ret;
+        }
+        sve_bswap64(r, r, cpu->sve_max_vq * 2);
+    }
+
+    for (n = 0; n < KVM_ARM64_SVE_NUM_PREGS; ++n) {
+        r = &env->vfp.pregs[n].p[0];
+        reg.addr = (uintptr_t)r;
+        reg.id = KVM_REG_ARM64_SVE_PREG(n, 0);
+        ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
+        if (ret) {
+            return ret;
+        }
+        sve_bswap64(r, r, DIV_ROUND_UP(cpu->sve_max_vq * 2, 8));
+    }
+
+    r = &env->vfp.pregs[FFR_PRED_NUM].p[0];
+    reg.addr = (uintptr_t)r;
+    reg.id = KVM_REG_ARM64_SVE_FFR(0);
+    ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
+    if (ret) {
+        return ret;
+    }
+    sve_bswap64(r, r, DIV_ROUND_UP(cpu->sve_max_vq * 2, 8));
+
+    return 0;
+}
+
+int kvm_arch_get_registers(CPUState *cs)
+{
+    struct kvm_one_reg reg;
+    uint64_t val;
+    unsigned int el;
+    uint32_t fpr;
+    int i, ret;
+
+    ARMCPU *cpu = ARM_CPU(cs);
+    CPUARMState *env = &cpu->env;
+
+    for (i = 0; i < 31; i++) {
+        reg.id = AARCH64_CORE_REG(regs.regs[i]);
+        reg.addr = (uintptr_t) &env->xregs[i];
+        ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
+        if (ret) {
+            return ret;
+        }
+    }
+
+    reg.id = AARCH64_CORE_REG(regs.sp);
+    reg.addr = (uintptr_t) &env->sp_el[0];
+    ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
+    if (ret) {
+        return ret;
+    }
+
+    reg.id = AARCH64_CORE_REG(sp_el1);
+    reg.addr = (uintptr_t) &env->sp_el[1];
+    ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
+    if (ret) {
+        return ret;
+    }
+
+    reg.id = AARCH64_CORE_REG(regs.pstate);
+    reg.addr = (uintptr_t) &val;
+    ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
+    if (ret) {
+        return ret;
+    }
+
+    env->aarch64 = ((val & PSTATE_nRW) == 0);
+    if (is_a64(env)) {
+        pstate_write(env, val);
+    } else {
+        cpsr_write(env, val, 0xffffffff, CPSRWriteRaw);
+    }
+
+    /* KVM puts SP_EL0 in regs.sp and SP_EL1 in regs.sp_el1. On the
+     * QEMU side we keep the current SP in xregs[31] as well.
+     */
+    aarch64_restore_sp(env, 1);
+
+    reg.id = AARCH64_CORE_REG(regs.pc);
+    reg.addr = (uintptr_t) &env->pc;
+    ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
+    if (ret) {
+        return ret;
+    }
+
+    /* If we are in AArch32 mode then we need to sync the AArch32 regs with the
+     * incoming AArch64 regs received from 64-bit KVM.
+     * We must perform this after all of the registers have been acquired from
+     * the kernel.
+     */
+    if (!is_a64(env)) {
+        aarch64_sync_64_to_32(env);
+    }
+
+    reg.id = AARCH64_CORE_REG(elr_el1);
+    reg.addr = (uintptr_t) &env->elr_el[1];
+    ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
+    if (ret) {
+        return ret;
+    }
+
+    /* Fetch the SPSR registers
+     *
+     * KVM SPSRs 0-4 map to QEMU banks 1-5
+     */
+    for (i = 0; i < KVM_NR_SPSR; i++) {
+        reg.id = AARCH64_CORE_REG(spsr[i]);
+        reg.addr = (uintptr_t) &env->banked_spsr[i + 1];
+        ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
+        if (ret) {
+            return ret;
+        }
+    }
+
+    el = arm_current_el(env);
+    if (el > 0 && !is_a64(env)) {
+        i = bank_number(env->uncached_cpsr & CPSR_M);
+        env->spsr = env->banked_spsr[i];
+    }
+
+    if (cpu_isar_feature(aa64_sve, cpu)) {
+        ret = kvm_arch_get_sve(cs);
+    } else {
+        ret = kvm_arch_get_fpsimd(cs);
+    }
+    if (ret) {
+        return ret;
+    }
+
+    reg.addr = (uintptr_t)(&fpr);
+    reg.id = AARCH64_SIMD_CTRL_REG(fp_regs.fpsr);
+    ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
+    if (ret) {
+        return ret;
+    }
+    vfp_set_fpsr(env, fpr);
+
+    reg.addr = (uintptr_t)(&fpr);
+    reg.id = AARCH64_SIMD_CTRL_REG(fp_regs.fpcr);
+    ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
+    if (ret) {
+        return ret;
+    }
+    vfp_set_fpcr(env, fpr);
+
+    ret = kvm_get_vcpu_events(cpu);
+    if (ret) {
+        return ret;
+    }
+
+    if (!write_kvmstate_to_list(cpu)) {
+        return -EINVAL;
+    }
+    /* Note that it's OK to have registers which aren't in CPUState,
+     * so we can ignore a failure return here.
+     */
+    write_list_to_cpustate(cpu);
+
+    kvm_arm_sync_mpstate_to_qemu(cpu);
+
+    /* TODO: other registers */
+    return ret;
+}
+
+void kvm_arch_on_sigbus_vcpu(CPUState *c, int code, void *addr)
+{
+    ram_addr_t ram_addr;
+    hwaddr paddr;
+
+    assert(code == BUS_MCEERR_AR || code == BUS_MCEERR_AO);
+
+    if (acpi_ghes_present() && addr) {
+        ram_addr = qemu_ram_addr_from_host(addr);
+        if (ram_addr != RAM_ADDR_INVALID &&
+            kvm_physical_memory_addr_from_host(c->kvm_state, addr, &paddr)) {
+            kvm_hwpoison_page_add(ram_addr);
+            /*
+             * If this is a BUS_MCEERR_AR, we know we have been called
+             * synchronously from the vCPU thread, so we can easily
+             * synchronize the state and inject an error.
+             *
+             * TODO: we currently don't tell the guest at all about
+             * BUS_MCEERR_AO. In that case we might either be being
+             * called synchronously from the vCPU thread, or a bit
+             * later from the main thread, so doing the injection of
+             * the error would be more complicated.
+             */
+            if (code == BUS_MCEERR_AR) {
+                kvm_cpu_synchronize_state(c);
+                if (!acpi_ghes_record_errors(ACPI_HEST_SRC_ID_SEA, paddr)) {
+                    kvm_inject_arm_sea(c);
+                } else {
+                    error_report("failed to record the error");
+                    abort();
+                }
+            }
+            return;
+        }
+        if (code == BUS_MCEERR_AO) {
+            error_report("Hardware memory error at addr %p for memory used by "
+                "QEMU itself instead of guest system!", addr);
+        }
+    }
+
+    if (code == BUS_MCEERR_AR) {
+        error_report("Hardware memory error!");
+        exit(1);
+    }
+}
+
+/* C6.6.29 BRK instruction */
+static const uint32_t brk_insn = 0xd4200000;
+
+int kvm_arch_insert_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp)
+{
+    if (have_guest_debug) {
+        if (cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&bp->saved_insn, 4, 0) ||
+            cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&brk_insn, 4, 1)) {
+            return -EINVAL;
+        }
+        return 0;
+    } else {
+        error_report("guest debug not supported on this kernel");
+        return -EINVAL;
+    }
+}
+
+int kvm_arch_remove_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp)
+{
+    static uint32_t brk;
+
+    if (have_guest_debug) {
+        if (cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&brk, 4, 0) ||
+            brk != brk_insn ||
+            cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&bp->saved_insn, 4, 1)) {
+            return -EINVAL;
+        }
+        return 0;
+    } else {
+        error_report("guest debug not supported on this kernel");
+        return -EINVAL;
+    }
+}
+
+/**
+ * kvm_arm_handle_debug:
+ * @cs: CPUState
+ * @debug_exit: debug part of the KVM exit structure
+ *
+ * Returns: TRUE if the debug exception was handled.
+ *
+ * See v8 ARM ARM D7.2.27 ESR_ELx, Exception Syndrome Register
+ * To minimise translating between kernel and user-space the kernel
+ * ABI just provides user-space with the full exception syndrome
+ * register value to be decoded in QEMU.
+ */
+static bool kvm_arm_handle_debug(CPUState *cs,
+                                 struct kvm_debug_exit_arch *debug_exit)
+{
+    int hsr_ec = syn_get_ec(debug_exit->hsr);
+    ARMCPU *cpu = ARM_CPU(cs);
+    CPUARMState *env = &cpu->env;
+
+    /* Ensure PC is synchronised */
+    kvm_cpu_synchronize_state(cs);
+
+    switch (hsr_ec) {
+    case EC_SOFTWARESTEP:
+        if (cs->singlestep_enabled) {
+            return true;
+        } else {
+            /*
+             * The kernel should have suppressed the guest's ability to
+             * single step at this point so something has gone wrong.
+             */
+            error_report("%s: guest single-step while debugging unsupported"
+                         " (%"PRIx64", %"PRIx32")",
+                         __func__, env->pc, debug_exit->hsr);
+            return false;
+        }
+        break;
+    case EC_AA64_BKPT:
+        if (kvm_find_sw_breakpoint(cs, env->pc)) {
+            return true;
+        }
+        break;
+    case EC_BREAKPOINT:
+        if (find_hw_breakpoint(cs, env->pc)) {
+            return true;
+        }
+        break;
+    case EC_WATCHPOINT:
+    {
+        CPUWatchpoint *wp = find_hw_watchpoint(cs, debug_exit->far);
+        if (wp) {
+            cs->watchpoint_hit = wp;
+            return true;
+        }
+        break;
+    }
+    default:
+        error_report("%s: unhandled debug exit (%"PRIx32", %"PRIx64")",
+                     __func__, debug_exit->hsr, env->pc);
+    }
+
+    /* If we are not handling the debug exception it must belong to
+     * the guest. Let's re-use the existing TCG interrupt code to set
+     * everything up properly.
+     */
+    cs->exception_index = EXCP_BKPT;
+    env->exception.syndrome = debug_exit->hsr;
+    env->exception.vaddress = debug_exit->far;
+    env->exception.target_el = 1;
+    qemu_mutex_lock_iothread();
+    arm_cpu_do_interrupt(cs);
+    qemu_mutex_unlock_iothread();
+
+    return false;
+}
+
+#define ARM64_REG_ESR_EL1 ARM64_SYS_REG(3, 0, 5, 2, 0)
+#define ARM64_REG_TCR_EL1 ARM64_SYS_REG(3, 0, 2, 0, 2)
+
+/*
+ * ESR_EL1
+ * ISS encoding
+ * AARCH64: DFSC,   bits [5:0]
+ * AARCH32:
+ *      TTBCR.EAE == 0
+ *          FS[4]   - DFSR[10]
+ *          FS[3:0] - DFSR[3:0]
+ *      TTBCR.EAE == 1
+ *          FS, bits [5:0]
+ */
+#define ESR_DFSC(aarch64, lpae, v)        \
+    ((aarch64 || (lpae)) ? ((v) & 0x3F)   \
+               : (((v) >> 6) | ((v) & 0x1F)))
+
+#define ESR_DFSC_EXTABT(aarch64, lpae) \
+    ((aarch64) ? 0x10 : (lpae) ? 0x10 : 0x8)
+
+/**
+ * kvm_arm_verify_ext_dabt_pending:
+ * @cs: CPUState
+ *
+ * Verify the fault status code wrt the Ext DABT injection
+ *
+ * Returns: true if the fault status code is as expected, false otherwise
+ */
+static bool kvm_arm_verify_ext_dabt_pending(CPUState *cs)
+{
+    uint64_t dfsr_val;
+
+    if (!kvm_get_one_reg(cs, ARM64_REG_ESR_EL1, &dfsr_val)) {
+        ARMCPU *cpu = ARM_CPU(cs);
+        CPUARMState *env = &cpu->env;
+        int aarch64_mode = arm_feature(env, ARM_FEATURE_AARCH64);
+        int lpae = 0;
+
+        if (!aarch64_mode) {
+            uint64_t ttbcr;
+
+            if (!kvm_get_one_reg(cs, ARM64_REG_TCR_EL1, &ttbcr)) {
+                lpae = arm_feature(env, ARM_FEATURE_LPAE)
+                        && (ttbcr & TTBCR_EAE);
+            }
+        }
+        /*
+         * The verification here is based on the DFSC bits
+         * of the ESR_EL1 reg only
+         */
+         return (ESR_DFSC(aarch64_mode, lpae, dfsr_val) ==
+                ESR_DFSC_EXTABT(aarch64_mode, lpae));
+    }
+    return false;
+}
+
+int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
+{
+    int ret = 0;
+
+    switch (run->exit_reason) {
+    case KVM_EXIT_DEBUG:
+        if (kvm_arm_handle_debug(cs, &run->debug.arch)) {
+            ret = EXCP_DEBUG;
+        } /* otherwise return to guest */
+        break;
+    case KVM_EXIT_ARM_NISV:
+        /* External DABT with no valid iss to decode */
+        ret = kvm_arm_handle_dabt_nisv(cs, run->arm_nisv.esr_iss,
+                                       run->arm_nisv.fault_ipa);
+        break;
+    default:
+        qemu_log_mask(LOG_UNIMP, "%s: un-handled exit reason %d\n",
+                      __func__, run->exit_reason);
+        break;
+    }
+    return ret;
+}
+
+void kvm_arch_update_guest_debug(CPUState *cs, struct kvm_guest_debug *dbg)
+{
+    if (kvm_sw_breakpoints_active(cs)) {
+        dbg->control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_SW_BP;
+    }
+    if (kvm_arm_hw_debug_active(cs)) {
+        dbg->control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_HW;
+        kvm_arm_copy_hw_debug_data(&dbg->arch);
+    }
+}
+
+void kvm_arch_pre_run(CPUState *cs, struct kvm_run *run)
+{
+    ARMCPU *cpu = ARM_CPU(cs);
+    CPUARMState *env = &cpu->env;
+
+    if (unlikely(env->ext_dabt_raised)) {
+        /*
+         * Verifying that the ext DABT has been properly injected,
+         * otherwise risking indefinitely re-running the faulting instruction
+         * Covering a very narrow case for kernels 5.5..5.5.4
+         * when injected abort was misconfigured to be
+         * an IMPLEMENTATION DEFINED exception (for 32-bit EL1)
+         */
+        if (!arm_feature(env, ARM_FEATURE_AARCH64) &&
+            unlikely(!kvm_arm_verify_ext_dabt_pending(cs))) {
+
+            error_report("Data abort exception with no valid ISS generated by "
+                   "guest memory access. KVM unable to emulate faulting "
+                   "instruction. Failed to inject an external data abort "
+                   "into the guest.");
+            abort();
+       }
+       /* Clear the status */
+       env->ext_dabt_raised = 0;
+    }
+}
+
+MemTxAttrs kvm_arch_post_run(CPUState *cs, struct kvm_run *run)
+{
+    ARMCPU *cpu;
+    uint32_t switched_level;
+
+    if (kvm_irqchip_in_kernel()) {
+        /*
+         * We only need to sync timer states with user-space interrupt
+         * controllers, so return early and save cycles if we don't.
+         */
+        return MEMTXATTRS_UNSPECIFIED;
+    }
+
+    cpu = ARM_CPU(cs);
+
+    /* Synchronize our shadowed in-kernel device irq lines with the kvm ones */
+    if (run->s.regs.device_irq_level != cpu->device_irq_level) {
+        switched_level = cpu->device_irq_level ^ run->s.regs.device_irq_level;
+
+        qemu_mutex_lock_iothread();
+
+        if (switched_level & KVM_ARM_DEV_EL1_VTIMER) {
+            qemu_set_irq(cpu->gt_timer_outputs[GTIMER_VIRT],
+                         !!(run->s.regs.device_irq_level &
+                            KVM_ARM_DEV_EL1_VTIMER));
+            switched_level &= ~KVM_ARM_DEV_EL1_VTIMER;
+        }
+
+        if (switched_level & KVM_ARM_DEV_EL1_PTIMER) {
+            qemu_set_irq(cpu->gt_timer_outputs[GTIMER_PHYS],
+                         !!(run->s.regs.device_irq_level &
+                            KVM_ARM_DEV_EL1_PTIMER));
+            switched_level &= ~KVM_ARM_DEV_EL1_PTIMER;
+        }
+
+        if (switched_level & KVM_ARM_DEV_PMU) {
+            qemu_set_irq(cpu->pmu_interrupt,
+                         !!(run->s.regs.device_irq_level & KVM_ARM_DEV_PMU));
+            switched_level &= ~KVM_ARM_DEV_PMU;
+        }
+
+        if (switched_level) {
+            qemu_log_mask(LOG_UNIMP, "%s: unhandled in-kernel device IRQ %x\n",
+                          __func__, switched_level);
+        }
+
+        /* We also mark unknown levels as processed to not waste cycles */
+        cpu->device_irq_level = run->s.regs.device_irq_level;
+        qemu_mutex_unlock_iothread();
+    }
+
+    return MEMTXATTRS_UNSPECIFIED;
+}
diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c
deleted file mode 100644
index 2cdd7517b8..0000000000
--- a/target/arm/kvm64.c
+++ /dev/null
@@ -1,1632 +0,0 @@
-/*
- * ARM implementation of KVM hooks, 64 bit specific code
- *
- * Copyright Mian-M. Hamayun 2013, Virtual Open Systems
- * Copyright Alex Bennée 2014, Linaro
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- *
- */
-
-#include "qemu/osdep.h"
-#include <sys/ioctl.h>
-#include <sys/ptrace.h>
-
-#include <linux/elf.h>
-#include <linux/kvm.h>
-
-#include "qapi/error.h"
-#include "cpu.h"
-#include "qemu/timer.h"
-#include "qemu/error-report.h"
-#include "qemu/host-utils.h"
-#include "qemu/main-loop.h"
-#include "exec/gdbstub.h"
-#include "sysemu/runstate.h"
-#include "sysemu/kvm.h"
-#include "sysemu/kvm_int.h"
-#include "kvm_arm.h"
-#include "internals.h"
-#include "hw/acpi/acpi.h"
-#include "hw/acpi/ghes.h"
-#include "hw/arm/virt.h"
-
-static bool have_guest_debug;
-
-/*
- * Although the ARM implementation of hardware assisted debugging
- * allows for different breakpoints per-core, the current GDB
- * interface treats them as a global pool of registers (which seems to
- * be the case for x86, ppc and s390). As a result we store one copy
- * of registers which is used for all active cores.
- *
- * Write access is serialised by virtue of the GDB protocol which
- * updates things. Read access (i.e. when the values are copied to the
- * vCPU) is also gated by GDB's run control.
- *
- * This is not unreasonable as most of the time debugging kernels you
- * never know which core will eventually execute your function.
- */
-
-typedef struct {
-    uint64_t bcr;
-    uint64_t bvr;
-} HWBreakpoint;
-
-/* The watchpoint registers can cover more area than the requested
- * watchpoint so we need to store the additional information
- * somewhere. We also need to supply a CPUWatchpoint to the GDB stub
- * when the watchpoint is hit.
- */
-typedef struct {
-    uint64_t wcr;
-    uint64_t wvr;
-    CPUWatchpoint details;
-} HWWatchpoint;
-
-/* Maximum and current break/watch point counts */
-int max_hw_bps, max_hw_wps;
-GArray *hw_breakpoints, *hw_watchpoints;
-
-#define cur_hw_wps      (hw_watchpoints->len)
-#define cur_hw_bps      (hw_breakpoints->len)
-#define get_hw_bp(i)    (&g_array_index(hw_breakpoints, HWBreakpoint, i))
-#define get_hw_wp(i)    (&g_array_index(hw_watchpoints, HWWatchpoint, i))
-
-/**
- * kvm_arm_init_debug() - check for guest debug capabilities
- * @cs: CPUState
- *
- * kvm_check_extension returns the number of debug registers we have
- * or 0 if we have none.
- *
- */
-static void kvm_arm_init_debug(CPUState *cs)
-{
-    have_guest_debug = kvm_check_extension(cs->kvm_state,
-                                           KVM_CAP_SET_GUEST_DEBUG);
-
-    max_hw_wps = kvm_check_extension(cs->kvm_state, KVM_CAP_GUEST_DEBUG_HW_WPS);
-    hw_watchpoints = g_array_sized_new(true, true,
-                                       sizeof(HWWatchpoint), max_hw_wps);
-
-    max_hw_bps = kvm_check_extension(cs->kvm_state, KVM_CAP_GUEST_DEBUG_HW_BPS);
-    hw_breakpoints = g_array_sized_new(true, true,
-                                       sizeof(HWBreakpoint), max_hw_bps);
-    return;
-}
-
-/**
- * insert_hw_breakpoint()
- * @addr: address of breakpoint
- *
- * See ARM ARM D2.9.1 for details but here we are only going to create
- * simple un-linked breakpoints (i.e. we don't chain breakpoints
- * together to match address and context or vmid). The hardware is
- * capable of fancier matching but that will require exposing that
- * fanciness to GDB's interface
- *
- * DBGBCR<n>_EL1, Debug Breakpoint Control Registers
- *
- *  31  24 23  20 19   16 15 14  13  12   9 8   5 4    3 2   1  0
- * +------+------+-------+-----+----+------+-----+------+-----+---+
- * | RES0 |  BT  |  LBN  | SSC | HMC| RES0 | BAS | RES0 | PMC | E |
- * +------+------+-------+-----+----+------+-----+------+-----+---+
- *
- * BT: Breakpoint type (0 = unlinked address match)
- * LBN: Linked BP number (0 = unused)
- * SSC/HMC/PMC: Security, Higher and Priv access control (Table D-12)
- * BAS: Byte Address Select (RES1 for AArch64)
- * E: Enable bit
- *
- * DBGBVR<n>_EL1, Debug Breakpoint Value Registers
- *
- *  63  53 52       49 48       2  1 0
- * +------+-----------+----------+-----+
- * | RESS | VA[52:49] | VA[48:2] | 0 0 |
- * +------+-----------+----------+-----+
- *
- * Depending on the addressing mode bits the top bits of the register
- * are a sign extension of the highest applicable VA bit. Some
- * versions of GDB don't do it correctly so we ensure they are correct
- * here so future PC comparisons will work properly.
- */
-
-static int insert_hw_breakpoint(target_ulong addr)
-{
-    HWBreakpoint brk = {
-        .bcr = 0x1,                             /* BCR E=1, enable */
-        .bvr = sextract64(addr, 0, 53)
-    };
-
-    if (cur_hw_bps >= max_hw_bps) {
-        return -ENOBUFS;
-    }
-
-    brk.bcr = deposit32(brk.bcr, 1, 2, 0x3);   /* PMC = 11 */
-    brk.bcr = deposit32(brk.bcr, 5, 4, 0xf);   /* BAS = RES1 */
-
-    g_array_append_val(hw_breakpoints, brk);
-
-    return 0;
-}
-
-/**
- * delete_hw_breakpoint()
- * @pc: address of breakpoint
- *
- * Delete a breakpoint and shuffle any above down
- */
-
-static int delete_hw_breakpoint(target_ulong pc)
-{
-    int i;
-    for (i = 0; i < hw_breakpoints->len; i++) {
-        HWBreakpoint *brk = get_hw_bp(i);
-        if (brk->bvr == pc) {
-            g_array_remove_index(hw_breakpoints, i);
-            return 0;
-        }
-    }
-    return -ENOENT;
-}
-
-/**
- * insert_hw_watchpoint()
- * @addr: address of watch point
- * @len: size of area
- * @type: type of watch point
- *
- * See ARM ARM D2.10. As with the breakpoints we can do some advanced
- * stuff if we want to. The watch points can be linked with the break
- * points above to make them context aware. However for simplicity
- * currently we only deal with simple read/write watch points.
- *
- * D7.3.11 DBGWCR<n>_EL1, Debug Watchpoint Control Registers
- *
- *  31  29 28   24 23  21  20  19 16 15 14  13   12  5 4   3 2   1  0
- * +------+-------+------+----+-----+-----+-----+-----+-----+-----+---+
- * | RES0 |  MASK | RES0 | WT | LBN | SSC | HMC | BAS | LSC | PAC | E |
- * +------+-------+------+----+-----+-----+-----+-----+-----+-----+---+
- *
- * MASK: num bits addr mask (0=none,01/10=res,11=3 bits (8 bytes))
- * WT: 0 - unlinked, 1 - linked (not currently used)
- * LBN: Linked BP number (not currently used)
- * SSC/HMC/PAC: Security, Higher and Priv access control (Table D2-11)
- * BAS: Byte Address Select
- * LSC: Load/Store control (01: load, 10: store, 11: both)
- * E: Enable
- *
- * The bottom 2 bits of the value register are masked. Therefore to
- * break on any sizes smaller than an unaligned word you need to set
- * MASK=0, BAS=bit per byte in question. For larger regions (^2) you
- * need to ensure you mask the address as required and set BAS=0xff
- */
-
-static int insert_hw_watchpoint(target_ulong addr,
-                                target_ulong len, int type)
-{
-    HWWatchpoint wp = {
-        .wcr = R_DBGWCR_E_MASK, /* E=1, enable */
-        .wvr = addr & (~0x7ULL),
-        .details = { .vaddr = addr, .len = len }
-    };
-
-    if (cur_hw_wps >= max_hw_wps) {
-        return -ENOBUFS;
-    }
-
-    /*
-     * HMC=0 SSC=0 PAC=3 will hit EL0 or EL1, any security state,
-     * valid whether EL3 is implemented or not
-     */
-    wp.wcr = FIELD_DP64(wp.wcr, DBGWCR, PAC, 3);
-
-    switch (type) {
-    case GDB_WATCHPOINT_READ:
-        wp.wcr = FIELD_DP64(wp.wcr, DBGWCR, LSC, 1);
-        wp.details.flags = BP_MEM_READ;
-        break;
-    case GDB_WATCHPOINT_WRITE:
-        wp.wcr = FIELD_DP64(wp.wcr, DBGWCR, LSC, 2);
-        wp.details.flags = BP_MEM_WRITE;
-        break;
-    case GDB_WATCHPOINT_ACCESS:
-        wp.wcr = FIELD_DP64(wp.wcr, DBGWCR, LSC, 3);
-        wp.details.flags = BP_MEM_ACCESS;
-        break;
-    default:
-        g_assert_not_reached();
-        break;
-    }
-    if (len <= 8) {
-        /* we align the address and set the bits in BAS */
-        int off = addr & 0x7;
-        int bas = (1 << len) - 1;
-
-        wp.wcr = deposit32(wp.wcr, 5 + off, 8 - off, bas);
-    } else {
-        /* For ranges above 8 bytes we need to be a power of 2 */
-        if (is_power_of_2(len)) {
-            int bits = ctz64(len);
-
-            wp.wvr &= ~((1 << bits) - 1);
-            wp.wcr = FIELD_DP64(wp.wcr, DBGWCR, MASK, bits);
-            wp.wcr = FIELD_DP64(wp.wcr, DBGWCR, BAS, 0xff);
-        } else {
-            return -ENOBUFS;
-        }
-    }
-
-    g_array_append_val(hw_watchpoints, wp);
-    return 0;
-}
-
-
-static bool check_watchpoint_in_range(int i, target_ulong addr)
-{
-    HWWatchpoint *wp = get_hw_wp(i);
-    uint64_t addr_top, addr_bottom = wp->wvr;
-    int bas = extract32(wp->wcr, 5, 8);
-    int mask = extract32(wp->wcr, 24, 4);
-
-    if (mask) {
-        addr_top = addr_bottom + (1 << mask);
-    } else {
-        /* BAS must be contiguous but can offset against the base
-         * address in DBGWVR */
-        addr_bottom = addr_bottom + ctz32(bas);
-        addr_top = addr_bottom + clo32(bas);
-    }
-
-    if (addr >= addr_bottom && addr <= addr_top) {
-        return true;
-    }
-
-    return false;
-}
-
-/**
- * delete_hw_watchpoint()
- * @addr: address of breakpoint
- *
- * Delete a breakpoint and shuffle any above down
- */
-
-static int delete_hw_watchpoint(target_ulong addr,
-                                target_ulong len, int type)
-{
-    int i;
-    for (i = 0; i < cur_hw_wps; i++) {
-        if (check_watchpoint_in_range(i, addr)) {
-            g_array_remove_index(hw_watchpoints, i);
-            return 0;
-        }
-    }
-    return -ENOENT;
-}
-
-
-int kvm_arch_insert_hw_breakpoint(target_ulong addr,
-                                  target_ulong len, int type)
-{
-    switch (type) {
-    case GDB_BREAKPOINT_HW:
-        return insert_hw_breakpoint(addr);
-        break;
-    case GDB_WATCHPOINT_READ:
-    case GDB_WATCHPOINT_WRITE:
-    case GDB_WATCHPOINT_ACCESS:
-        return insert_hw_watchpoint(addr, len, type);
-    default:
-        return -ENOSYS;
-    }
-}
-
-int kvm_arch_remove_hw_breakpoint(target_ulong addr,
-                                  target_ulong len, int type)
-{
-    switch (type) {
-    case GDB_BREAKPOINT_HW:
-        return delete_hw_breakpoint(addr);
-    case GDB_WATCHPOINT_READ:
-    case GDB_WATCHPOINT_WRITE:
-    case GDB_WATCHPOINT_ACCESS:
-        return delete_hw_watchpoint(addr, len, type);
-    default:
-        return -ENOSYS;
-    }
-}
-
-
-void kvm_arch_remove_all_hw_breakpoints(void)
-{
-    if (cur_hw_wps > 0) {
-        g_array_remove_range(hw_watchpoints, 0, cur_hw_wps);
-    }
-    if (cur_hw_bps > 0) {
-        g_array_remove_range(hw_breakpoints, 0, cur_hw_bps);
-    }
-}
-
-void kvm_arm_copy_hw_debug_data(struct kvm_guest_debug_arch *ptr)
-{
-    int i;
-    memset(ptr, 0, sizeof(struct kvm_guest_debug_arch));
-
-    for (i = 0; i < max_hw_wps; i++) {
-        HWWatchpoint *wp = get_hw_wp(i);
-        ptr->dbg_wcr[i] = wp->wcr;
-        ptr->dbg_wvr[i] = wp->wvr;
-    }
-    for (i = 0; i < max_hw_bps; i++) {
-        HWBreakpoint *bp = get_hw_bp(i);
-        ptr->dbg_bcr[i] = bp->bcr;
-        ptr->dbg_bvr[i] = bp->bvr;
-    }
-}
-
-bool kvm_arm_hw_debug_active(CPUState *cs)
-{
-    return ((cur_hw_wps > 0) || (cur_hw_bps > 0));
-}
-
-static bool find_hw_breakpoint(CPUState *cpu, target_ulong pc)
-{
-    int i;
-
-    for (i = 0; i < cur_hw_bps; i++) {
-        HWBreakpoint *bp = get_hw_bp(i);
-        if (bp->bvr == pc) {
-            return true;
-        }
-    }
-    return false;
-}
-
-static CPUWatchpoint *find_hw_watchpoint(CPUState *cpu, target_ulong addr)
-{
-    int i;
-
-    for (i = 0; i < cur_hw_wps; i++) {
-        if (check_watchpoint_in_range(i, addr)) {
-            return &get_hw_wp(i)->details;
-        }
-    }
-    return NULL;
-}
-
-static bool kvm_arm_set_device_attr(CPUState *cs, struct kvm_device_attr *attr,
-                                    const char *name)
-{
-    int err;
-
-    err = kvm_vcpu_ioctl(cs, KVM_HAS_DEVICE_ATTR, attr);
-    if (err != 0) {
-        error_report("%s: KVM_HAS_DEVICE_ATTR: %s", name, strerror(-err));
-        return false;
-    }
-
-    err = kvm_vcpu_ioctl(cs, KVM_SET_DEVICE_ATTR, attr);
-    if (err != 0) {
-        error_report("%s: KVM_SET_DEVICE_ATTR: %s", name, strerror(-err));
-        return false;
-    }
-
-    return true;
-}
-
-void kvm_arm_pmu_init(CPUState *cs)
-{
-    struct kvm_device_attr attr = {
-        .group = KVM_ARM_VCPU_PMU_V3_CTRL,
-        .attr = KVM_ARM_VCPU_PMU_V3_INIT,
-    };
-
-    if (!ARM_CPU(cs)->has_pmu) {
-        return;
-    }
-    if (!kvm_arm_set_device_attr(cs, &attr, "PMU")) {
-        error_report("failed to init PMU");
-        abort();
-    }
-}
-
-void kvm_arm_pmu_set_irq(CPUState *cs, int irq)
-{
-    struct kvm_device_attr attr = {
-        .group = KVM_ARM_VCPU_PMU_V3_CTRL,
-        .addr = (intptr_t)&irq,
-        .attr = KVM_ARM_VCPU_PMU_V3_IRQ,
-    };
-
-    if (!ARM_CPU(cs)->has_pmu) {
-        return;
-    }
-    if (!kvm_arm_set_device_attr(cs, &attr, "PMU")) {
-        error_report("failed to set irq for PMU");
-        abort();
-    }
-}
-
-void kvm_arm_pvtime_init(CPUState *cs, uint64_t ipa)
-{
-    struct kvm_device_attr attr = {
-        .group = KVM_ARM_VCPU_PVTIME_CTRL,
-        .attr = KVM_ARM_VCPU_PVTIME_IPA,
-        .addr = (uint64_t)&ipa,
-    };
-
-    if (ARM_CPU(cs)->kvm_steal_time == ON_OFF_AUTO_OFF) {
-        return;
-    }
-    if (!kvm_arm_set_device_attr(cs, &attr, "PVTIME IPA")) {
-        error_report("failed to init PVTIME IPA");
-        abort();
-    }
-}
-
-static int read_sys_reg32(int fd, uint32_t *pret, uint64_t id)
-{
-    uint64_t ret;
-    struct kvm_one_reg idreg = { .id = id, .addr = (uintptr_t)&ret };
-    int err;
-
-    assert((id & KVM_REG_SIZE_MASK) == KVM_REG_SIZE_U64);
-    err = ioctl(fd, KVM_GET_ONE_REG, &idreg);
-    if (err < 0) {
-        return -1;
-    }
-    *pret = ret;
-    return 0;
-}
-
-static int read_sys_reg64(int fd, uint64_t *pret, uint64_t id)
-{
-    struct kvm_one_reg idreg = { .id = id, .addr = (uintptr_t)pret };
-
-    assert((id & KVM_REG_SIZE_MASK) == KVM_REG_SIZE_U64);
-    return ioctl(fd, KVM_GET_ONE_REG, &idreg);
-}
-
-static bool kvm_arm_pauth_supported(void)
-{
-    return (kvm_check_extension(kvm_state, KVM_CAP_ARM_PTRAUTH_ADDRESS) &&
-            kvm_check_extension(kvm_state, KVM_CAP_ARM_PTRAUTH_GENERIC));
-}
-
-bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
-{
-    /* Identify the feature bits corresponding to the host CPU, and
-     * fill out the ARMHostCPUClass fields accordingly. To do this
-     * we have to create a scratch VM, create a single CPU inside it,
-     * and then query that CPU for the relevant ID registers.
-     */
-    int fdarray[3];
-    bool sve_supported;
-    bool pmu_supported = false;
-    uint64_t features = 0;
-    int err;
-
-    /* Old kernels may not know about the PREFERRED_TARGET ioctl: however
-     * we know these will only support creating one kind of guest CPU,
-     * which is its preferred CPU type. Fortunately these old kernels
-     * support only a very limited number of CPUs.
-     */
-    static const uint32_t cpus_to_try[] = {
-        KVM_ARM_TARGET_AEM_V8,
-        KVM_ARM_TARGET_FOUNDATION_V8,
-        KVM_ARM_TARGET_CORTEX_A57,
-        QEMU_KVM_ARM_TARGET_NONE
-    };
-    /*
-     * target = -1 informs kvm_arm_create_scratch_host_vcpu()
-     * to use the preferred target
-     */
-    struct kvm_vcpu_init init = { .target = -1, };
-
-    /*
-     * Ask for SVE if supported, so that we can query ID_AA64ZFR0,
-     * which is otherwise RAZ.
-     */
-    sve_supported = kvm_arm_sve_supported();
-    if (sve_supported) {
-        init.features[0] |= 1 << KVM_ARM_VCPU_SVE;
-    }
-
-    /*
-     * Ask for Pointer Authentication if supported, so that we get
-     * the unsanitized field values for AA64ISAR1_EL1.
-     */
-    if (kvm_arm_pauth_supported()) {
-        init.features[0] |= (1 << KVM_ARM_VCPU_PTRAUTH_ADDRESS |
-                             1 << KVM_ARM_VCPU_PTRAUTH_GENERIC);
-    }
-
-    if (kvm_arm_pmu_supported()) {
-        init.features[0] |= 1 << KVM_ARM_VCPU_PMU_V3;
-        pmu_supported = true;
-    }
-
-    if (!kvm_arm_create_scratch_host_vcpu(cpus_to_try, fdarray, &init)) {
-        return false;
-    }
-
-    ahcf->target = init.target;
-    ahcf->dtb_compatible = "arm,arm-v8";
-
-    err = read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64pfr0,
-                         ARM64_SYS_REG(3, 0, 0, 4, 0));
-    if (unlikely(err < 0)) {
-        /*
-         * Before v4.15, the kernel only exposed a limited number of system
-         * registers, not including any of the interesting AArch64 ID regs.
-         * For the most part we could leave these fields as zero with minimal
-         * effect, since this does not affect the values seen by the guest.
-         *
-         * However, it could cause problems down the line for QEMU,
-         * so provide a minimal v8.0 default.
-         *
-         * ??? Could read MIDR and use knowledge from cpu64.c.
-         * ??? Could map a page of memory into our temp guest and
-         *     run the tiniest of hand-crafted kernels to extract
-         *     the values seen by the guest.
-         * ??? Either of these sounds like too much effort just
-         *     to work around running a modern host kernel.
-         */
-        ahcf->isar.id_aa64pfr0 = 0x00000011; /* EL1&0, AArch64 only */
-        err = 0;
-    } else {
-        err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64pfr1,
-                              ARM64_SYS_REG(3, 0, 0, 4, 1));
-        err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64smfr0,
-                              ARM64_SYS_REG(3, 0, 0, 4, 5));
-        err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64dfr0,
-                              ARM64_SYS_REG(3, 0, 0, 5, 0));
-        err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64dfr1,
-                              ARM64_SYS_REG(3, 0, 0, 5, 1));
-        err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64isar0,
-                              ARM64_SYS_REG(3, 0, 0, 6, 0));
-        err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64isar1,
-                              ARM64_SYS_REG(3, 0, 0, 6, 1));
-        err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64mmfr0,
-                              ARM64_SYS_REG(3, 0, 0, 7, 0));
-        err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64mmfr1,
-                              ARM64_SYS_REG(3, 0, 0, 7, 1));
-        err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64mmfr2,
-                              ARM64_SYS_REG(3, 0, 0, 7, 2));
-
-        /*
-         * Note that if AArch32 support is not present in the host,
-         * the AArch32 sysregs are present to be read, but will
-         * return UNKNOWN values.  This is neither better nor worse
-         * than skipping the reads and leaving 0, as we must avoid
-         * considering the values in every case.
-         */
-        err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_pfr0,
-                              ARM64_SYS_REG(3, 0, 0, 1, 0));
-        err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_pfr1,
-                              ARM64_SYS_REG(3, 0, 0, 1, 1));
-        err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_dfr0,
-                              ARM64_SYS_REG(3, 0, 0, 1, 2));
-        err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_mmfr0,
-                              ARM64_SYS_REG(3, 0, 0, 1, 4));
-        err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_mmfr1,
-                              ARM64_SYS_REG(3, 0, 0, 1, 5));
-        err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_mmfr2,
-                              ARM64_SYS_REG(3, 0, 0, 1, 6));
-        err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_mmfr3,
-                              ARM64_SYS_REG(3, 0, 0, 1, 7));
-        err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_isar0,
-                              ARM64_SYS_REG(3, 0, 0, 2, 0));
-        err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_isar1,
-                              ARM64_SYS_REG(3, 0, 0, 2, 1));
-        err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_isar2,
-                              ARM64_SYS_REG(3, 0, 0, 2, 2));
-        err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_isar3,
-                              ARM64_SYS_REG(3, 0, 0, 2, 3));
-        err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_isar4,
-                              ARM64_SYS_REG(3, 0, 0, 2, 4));
-        err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_isar5,
-                              ARM64_SYS_REG(3, 0, 0, 2, 5));
-        err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_mmfr4,
-                              ARM64_SYS_REG(3, 0, 0, 2, 6));
-        err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_isar6,
-                              ARM64_SYS_REG(3, 0, 0, 2, 7));
-
-        err |= read_sys_reg32(fdarray[2], &ahcf->isar.mvfr0,
-                              ARM64_SYS_REG(3, 0, 0, 3, 0));
-        err |= read_sys_reg32(fdarray[2], &ahcf->isar.mvfr1,
-                              ARM64_SYS_REG(3, 0, 0, 3, 1));
-        err |= read_sys_reg32(fdarray[2], &ahcf->isar.mvfr2,
-                              ARM64_SYS_REG(3, 0, 0, 3, 2));
-        err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_pfr2,
-                              ARM64_SYS_REG(3, 0, 0, 3, 4));
-        err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_dfr1,
-                              ARM64_SYS_REG(3, 0, 0, 3, 5));
-        err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_mmfr5,
-                              ARM64_SYS_REG(3, 0, 0, 3, 6));
-
-        /*
-         * DBGDIDR is a bit complicated because the kernel doesn't
-         * provide an accessor for it in 64-bit mode, which is what this
-         * scratch VM is in, and there's no architected "64-bit sysreg
-         * which reads the same as the 32-bit register" the way there is
-         * for other ID registers. Instead we synthesize a value from the
-         * AArch64 ID_AA64DFR0, the same way the kernel code in
-         * arch/arm64/kvm/sys_regs.c:trap_dbgidr() does.
-         * We only do this if the CPU supports AArch32 at EL1.
-         */
-        if (FIELD_EX32(ahcf->isar.id_aa64pfr0, ID_AA64PFR0, EL1) >= 2) {
-            int wrps = FIELD_EX64(ahcf->isar.id_aa64dfr0, ID_AA64DFR0, WRPS);
-            int brps = FIELD_EX64(ahcf->isar.id_aa64dfr0, ID_AA64DFR0, BRPS);
-            int ctx_cmps =
-                FIELD_EX64(ahcf->isar.id_aa64dfr0, ID_AA64DFR0, CTX_CMPS);
-            int version = 6; /* ARMv8 debug architecture */
-            bool has_el3 =
-                !!FIELD_EX32(ahcf->isar.id_aa64pfr0, ID_AA64PFR0, EL3);
-            uint32_t dbgdidr = 0;
-
-            dbgdidr = FIELD_DP32(dbgdidr, DBGDIDR, WRPS, wrps);
-            dbgdidr = FIELD_DP32(dbgdidr, DBGDIDR, BRPS, brps);
-            dbgdidr = FIELD_DP32(dbgdidr, DBGDIDR, CTX_CMPS, ctx_cmps);
-            dbgdidr = FIELD_DP32(dbgdidr, DBGDIDR, VERSION, version);
-            dbgdidr = FIELD_DP32(dbgdidr, DBGDIDR, NSUHD_IMP, has_el3);
-            dbgdidr = FIELD_DP32(dbgdidr, DBGDIDR, SE_IMP, has_el3);
-            dbgdidr |= (1 << 15); /* RES1 bit */
-            ahcf->isar.dbgdidr = dbgdidr;
-        }
-
-        if (pmu_supported) {
-            /* PMCR_EL0 is only accessible if the vCPU has feature PMU_V3 */
-            err |= read_sys_reg64(fdarray[2], &ahcf->isar.reset_pmcr_el0,
-                                  ARM64_SYS_REG(3, 3, 9, 12, 0));
-        }
-
-        if (sve_supported) {
-            /*
-             * There is a range of kernels between kernel commit 73433762fcae
-             * and f81cb2c3ad41 which have a bug where the kernel doesn't
-             * expose SYS_ID_AA64ZFR0_EL1 via the ONE_REG API unless the VM has
-             * enabled SVE support, which resulted in an error rather than RAZ.
-             * So only read the register if we set KVM_ARM_VCPU_SVE above.
-             */
-            err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64zfr0,
-                                  ARM64_SYS_REG(3, 0, 0, 4, 4));
-        }
-    }
-
-    kvm_arm_destroy_scratch_host_vcpu(fdarray);
-
-    if (err < 0) {
-        return false;
-    }
-
-    /*
-     * We can assume any KVM supporting CPU is at least a v8
-     * with VFPv4+Neon; this in turn implies most of the other
-     * feature bits.
-     */
-    features |= 1ULL << ARM_FEATURE_V8;
-    features |= 1ULL << ARM_FEATURE_NEON;
-    features |= 1ULL << ARM_FEATURE_AARCH64;
-    features |= 1ULL << ARM_FEATURE_PMU;
-    features |= 1ULL << ARM_FEATURE_GENERIC_TIMER;
-
-    ahcf->features = features;
-
-    return true;
-}
-
-void kvm_arm_steal_time_finalize(ARMCPU *cpu, Error **errp)
-{
-    bool has_steal_time = kvm_arm_steal_time_supported();
-
-    if (cpu->kvm_steal_time == ON_OFF_AUTO_AUTO) {
-        if (!has_steal_time || !arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) {
-            cpu->kvm_steal_time = ON_OFF_AUTO_OFF;
-        } else {
-            cpu->kvm_steal_time = ON_OFF_AUTO_ON;
-        }
-    } else if (cpu->kvm_steal_time == ON_OFF_AUTO_ON) {
-        if (!has_steal_time) {
-            error_setg(errp, "'kvm-steal-time' cannot be enabled "
-                             "on this host");
-            return;
-        } else if (!arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) {
-            /*
-             * DEN0057A chapter 2 says "This specification only covers
-             * systems in which the Execution state of the hypervisor
-             * as well as EL1 of virtual machines is AArch64.". And,
-             * to ensure that, the smc/hvc calls are only specified as
-             * smc64/hvc64.
-             */
-            error_setg(errp, "'kvm-steal-time' cannot be enabled "
-                             "for AArch32 guests");
-            return;
-        }
-    }
-}
-
-bool kvm_arm_aarch32_supported(void)
-{
-    return kvm_check_extension(kvm_state, KVM_CAP_ARM_EL1_32BIT);
-}
-
-bool kvm_arm_sve_supported(void)
-{
-    return kvm_check_extension(kvm_state, KVM_CAP_ARM_SVE);
-}
-
-bool kvm_arm_steal_time_supported(void)
-{
-    return kvm_check_extension(kvm_state, KVM_CAP_STEAL_TIME);
-}
-
-QEMU_BUILD_BUG_ON(KVM_ARM64_SVE_VQ_MIN != 1);
-
-uint32_t kvm_arm_sve_get_vls(CPUState *cs)
-{
-    /* Only call this function if kvm_arm_sve_supported() returns true. */
-    static uint64_t vls[KVM_ARM64_SVE_VLS_WORDS];
-    static bool probed;
-    uint32_t vq = 0;
-    int i;
-
-    /*
-     * KVM ensures all host CPUs support the same set of vector lengths.
-     * So we only need to create the scratch VCPUs once and then cache
-     * the results.
-     */
-    if (!probed) {
-        struct kvm_vcpu_init init = {
-            .target = -1,
-            .features[0] = (1 << KVM_ARM_VCPU_SVE),
-        };
-        struct kvm_one_reg reg = {
-            .id = KVM_REG_ARM64_SVE_VLS,
-            .addr = (uint64_t)&vls[0],
-        };
-        int fdarray[3], ret;
-
-        probed = true;
-
-        if (!kvm_arm_create_scratch_host_vcpu(NULL, fdarray, &init)) {
-            error_report("failed to create scratch VCPU with SVE enabled");
-            abort();
-        }
-        ret = ioctl(fdarray[2], KVM_GET_ONE_REG, &reg);
-        kvm_arm_destroy_scratch_host_vcpu(fdarray);
-        if (ret) {
-            error_report("failed to get KVM_REG_ARM64_SVE_VLS: %s",
-                         strerror(errno));
-            abort();
-        }
-
-        for (i = KVM_ARM64_SVE_VLS_WORDS - 1; i >= 0; --i) {
-            if (vls[i]) {
-                vq = 64 - clz64(vls[i]) + i * 64;
-                break;
-            }
-        }
-        if (vq > ARM_MAX_VQ) {
-            warn_report("KVM supports vector lengths larger than "
-                        "QEMU can enable");
-            vls[0] &= MAKE_64BIT_MASK(0, ARM_MAX_VQ);
-        }
-    }
-
-    return vls[0];
-}
-
-static int kvm_arm_sve_set_vls(CPUState *cs)
-{
-    ARMCPU *cpu = ARM_CPU(cs);
-    uint64_t vls[KVM_ARM64_SVE_VLS_WORDS] = { cpu->sve_vq.map };
-    struct kvm_one_reg reg = {
-        .id = KVM_REG_ARM64_SVE_VLS,
-        .addr = (uint64_t)&vls[0],
-    };
-
-    assert(cpu->sve_max_vq <= KVM_ARM64_SVE_VQ_MAX);
-
-    return kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
-}
-
-#define ARM_CPU_ID_MPIDR       3, 0, 0, 0, 5
-
-int kvm_arch_init_vcpu(CPUState *cs)
-{
-    int ret;
-    uint64_t mpidr;
-    ARMCPU *cpu = ARM_CPU(cs);
-    CPUARMState *env = &cpu->env;
-    uint64_t psciver;
-
-    if (cpu->kvm_target == QEMU_KVM_ARM_TARGET_NONE ||
-        !object_dynamic_cast(OBJECT(cpu), TYPE_AARCH64_CPU)) {
-        error_report("KVM is not supported for this guest CPU type");
-        return -EINVAL;
-    }
-
-    qemu_add_vm_change_state_handler(kvm_arm_vm_state_change, cs);
-
-    /* Determine init features for this CPU */
-    memset(cpu->kvm_init_features, 0, sizeof(cpu->kvm_init_features));
-    if (cs->start_powered_off) {
-        cpu->kvm_init_features[0] |= 1 << KVM_ARM_VCPU_POWER_OFF;
-    }
-    if (kvm_check_extension(cs->kvm_state, KVM_CAP_ARM_PSCI_0_2)) {
-        cpu->psci_version = QEMU_PSCI_VERSION_0_2;
-        cpu->kvm_init_features[0] |= 1 << KVM_ARM_VCPU_PSCI_0_2;
-    }
-    if (!arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) {
-        cpu->kvm_init_features[0] |= 1 << KVM_ARM_VCPU_EL1_32BIT;
-    }
-    if (!kvm_check_extension(cs->kvm_state, KVM_CAP_ARM_PMU_V3)) {
-        cpu->has_pmu = false;
-    }
-    if (cpu->has_pmu) {
-        cpu->kvm_init_features[0] |= 1 << KVM_ARM_VCPU_PMU_V3;
-    } else {
-        env->features &= ~(1ULL << ARM_FEATURE_PMU);
-    }
-    if (cpu_isar_feature(aa64_sve, cpu)) {
-        assert(kvm_arm_sve_supported());
-        cpu->kvm_init_features[0] |= 1 << KVM_ARM_VCPU_SVE;
-    }
-    if (cpu_isar_feature(aa64_pauth, cpu)) {
-        cpu->kvm_init_features[0] |= (1 << KVM_ARM_VCPU_PTRAUTH_ADDRESS |
-                                      1 << KVM_ARM_VCPU_PTRAUTH_GENERIC);
-    }
-
-    /* Do KVM_ARM_VCPU_INIT ioctl */
-    ret = kvm_arm_vcpu_init(cs);
-    if (ret) {
-        return ret;
-    }
-
-    if (cpu_isar_feature(aa64_sve, cpu)) {
-        ret = kvm_arm_sve_set_vls(cs);
-        if (ret) {
-            return ret;
-        }
-        ret = kvm_arm_vcpu_finalize(cs, KVM_ARM_VCPU_SVE);
-        if (ret) {
-            return ret;
-        }
-    }
-
-    /*
-     * KVM reports the exact PSCI version it is implementing via a
-     * special sysreg. If it is present, use its contents to determine
-     * what to report to the guest in the dtb (it is the PSCI version,
-     * in the same 15-bits major 16-bits minor format that PSCI_VERSION
-     * returns).
-     */
-    if (!kvm_get_one_reg(cs, KVM_REG_ARM_PSCI_VERSION, &psciver)) {
-        cpu->psci_version = psciver;
-    }
-
-    /*
-     * When KVM is in use, PSCI is emulated in-kernel and not by qemu.
-     * Currently KVM has its own idea about MPIDR assignment, so we
-     * override our defaults with what we get from KVM.
-     */
-    ret = kvm_get_one_reg(cs, ARM64_SYS_REG(ARM_CPU_ID_MPIDR),
-                          &cpu->mpidr_el1);
-    if (ret) {
-        return ret;
-    }
-
-    kvm_arm_init_debug(cs);
-
-    /* Check whether user space can specify guest syndrome value */
-    kvm_arm_init_serror_injection(cs);
-
-    return kvm_arm_init_cpreg_list(cpu);
-}
-
-int kvm_arch_destroy_vcpu(CPUState *cs)
-{
-    return 0;
-}
-
-bool kvm_arm_reg_syncs_via_cpreg_list(uint64_t regidx)
-{
-    /* Return true if the regidx is a register we should synchronize
-     * via the cpreg_tuples array (ie is not a core or sve reg that
-     * we sync by hand in kvm_arch_get/put_registers())
-     */
-    switch (regidx & KVM_REG_ARM_COPROC_MASK) {
-    case KVM_REG_ARM_CORE:
-    case KVM_REG_ARM64_SVE:
-        return false;
-    default:
-        return true;
-    }
-}
-
-typedef struct CPRegStateLevel {
-    uint64_t regidx;
-    int level;
-} CPRegStateLevel;
-
-/* All system registers not listed in the following table are assumed to be
- * of the level KVM_PUT_RUNTIME_STATE. If a register should be written less
- * often, you must add it to this table with a state of either
- * KVM_PUT_RESET_STATE or KVM_PUT_FULL_STATE.
- */
-static const CPRegStateLevel non_runtime_cpregs[] = {
-    { KVM_REG_ARM_TIMER_CNT, KVM_PUT_FULL_STATE },
-};
-
-int kvm_arm_cpreg_level(uint64_t regidx)
-{
-    int i;
-
-    for (i = 0; i < ARRAY_SIZE(non_runtime_cpregs); i++) {
-        const CPRegStateLevel *l = &non_runtime_cpregs[i];
-        if (l->regidx == regidx) {
-            return l->level;
-        }
-    }
-
-    return KVM_PUT_RUNTIME_STATE;
-}
-
-/* Callers must hold the iothread mutex lock */
-static void kvm_inject_arm_sea(CPUState *c)
-{
-    ARMCPU *cpu = ARM_CPU(c);
-    CPUARMState *env = &cpu->env;
-    uint32_t esr;
-    bool same_el;
-
-    c->exception_index = EXCP_DATA_ABORT;
-    env->exception.target_el = 1;
-
-    /*
-     * Set the DFSC to synchronous external abort and set FnV to not valid,
-     * this will tell guest the FAR_ELx is UNKNOWN for this abort.
-     */
-    same_el = arm_current_el(env) == env->exception.target_el;
-    esr = syn_data_abort_no_iss(same_el, 1, 0, 0, 0, 0, 0x10);
-
-    env->exception.syndrome = esr;
-
-    arm_cpu_do_interrupt(c);
-}
-
-#define AARCH64_CORE_REG(x)   (KVM_REG_ARM64 | KVM_REG_SIZE_U64 | \
-                 KVM_REG_ARM_CORE | KVM_REG_ARM_CORE_REG(x))
-
-#define AARCH64_SIMD_CORE_REG(x)   (KVM_REG_ARM64 | KVM_REG_SIZE_U128 | \
-                 KVM_REG_ARM_CORE | KVM_REG_ARM_CORE_REG(x))
-
-#define AARCH64_SIMD_CTRL_REG(x)   (KVM_REG_ARM64 | KVM_REG_SIZE_U32 | \
-                 KVM_REG_ARM_CORE | KVM_REG_ARM_CORE_REG(x))
-
-static int kvm_arch_put_fpsimd(CPUState *cs)
-{
-    CPUARMState *env = &ARM_CPU(cs)->env;
-    struct kvm_one_reg reg;
-    int i, ret;
-
-    for (i = 0; i < 32; i++) {
-        uint64_t *q = aa64_vfp_qreg(env, i);
-#if HOST_BIG_ENDIAN
-        uint64_t fp_val[2] = { q[1], q[0] };
-        reg.addr = (uintptr_t)fp_val;
-#else
-        reg.addr = (uintptr_t)q;
-#endif
-        reg.id = AARCH64_SIMD_CORE_REG(fp_regs.vregs[i]);
-        ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
-        if (ret) {
-            return ret;
-        }
-    }
-
-    return 0;
-}
-
-/*
- * KVM SVE registers come in slices where ZREGs have a slice size of 2048 bits
- * and PREGS and the FFR have a slice size of 256 bits. However we simply hard
- * code the slice index to zero for now as it's unlikely we'll need more than
- * one slice for quite some time.
- */
-static int kvm_arch_put_sve(CPUState *cs)
-{
-    ARMCPU *cpu = ARM_CPU(cs);
-    CPUARMState *env = &cpu->env;
-    uint64_t tmp[ARM_MAX_VQ * 2];
-    uint64_t *r;
-    struct kvm_one_reg reg;
-    int n, ret;
-
-    for (n = 0; n < KVM_ARM64_SVE_NUM_ZREGS; ++n) {
-        r = sve_bswap64(tmp, &env->vfp.zregs[n].d[0], cpu->sve_max_vq * 2);
-        reg.addr = (uintptr_t)r;
-        reg.id = KVM_REG_ARM64_SVE_ZREG(n, 0);
-        ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
-        if (ret) {
-            return ret;
-        }
-    }
-
-    for (n = 0; n < KVM_ARM64_SVE_NUM_PREGS; ++n) {
-        r = sve_bswap64(tmp, r = &env->vfp.pregs[n].p[0],
-                        DIV_ROUND_UP(cpu->sve_max_vq * 2, 8));
-        reg.addr = (uintptr_t)r;
-        reg.id = KVM_REG_ARM64_SVE_PREG(n, 0);
-        ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
-        if (ret) {
-            return ret;
-        }
-    }
-
-    r = sve_bswap64(tmp, &env->vfp.pregs[FFR_PRED_NUM].p[0],
-                    DIV_ROUND_UP(cpu->sve_max_vq * 2, 8));
-    reg.addr = (uintptr_t)r;
-    reg.id = KVM_REG_ARM64_SVE_FFR(0);
-    ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
-    if (ret) {
-        return ret;
-    }
-
-    return 0;
-}
-
-int kvm_arch_put_registers(CPUState *cs, int level)
-{
-    struct kvm_one_reg reg;
-    uint64_t val;
-    uint32_t fpr;
-    int i, ret;
-    unsigned int el;
-
-    ARMCPU *cpu = ARM_CPU(cs);
-    CPUARMState *env = &cpu->env;
-
-    /* If we are in AArch32 mode then we need to copy the AArch32 regs to the
-     * AArch64 registers before pushing them out to 64-bit KVM.
-     */
-    if (!is_a64(env)) {
-        aarch64_sync_32_to_64(env);
-    }
-
-    for (i = 0; i < 31; i++) {
-        reg.id = AARCH64_CORE_REG(regs.regs[i]);
-        reg.addr = (uintptr_t) &env->xregs[i];
-        ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
-        if (ret) {
-            return ret;
-        }
-    }
-
-    /* KVM puts SP_EL0 in regs.sp and SP_EL1 in regs.sp_el1. On the
-     * QEMU side we keep the current SP in xregs[31] as well.
-     */
-    aarch64_save_sp(env, 1);
-
-    reg.id = AARCH64_CORE_REG(regs.sp);
-    reg.addr = (uintptr_t) &env->sp_el[0];
-    ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
-    if (ret) {
-        return ret;
-    }
-
-    reg.id = AARCH64_CORE_REG(sp_el1);
-    reg.addr = (uintptr_t) &env->sp_el[1];
-    ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
-    if (ret) {
-        return ret;
-    }
-
-    /* Note that KVM thinks pstate is 64 bit but we use a uint32_t */
-    if (is_a64(env)) {
-        val = pstate_read(env);
-    } else {
-        val = cpsr_read(env);
-    }
-    reg.id = AARCH64_CORE_REG(regs.pstate);
-    reg.addr = (uintptr_t) &val;
-    ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
-    if (ret) {
-        return ret;
-    }
-
-    reg.id = AARCH64_CORE_REG(regs.pc);
-    reg.addr = (uintptr_t) &env->pc;
-    ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
-    if (ret) {
-        return ret;
-    }
-
-    reg.id = AARCH64_CORE_REG(elr_el1);
-    reg.addr = (uintptr_t) &env->elr_el[1];
-    ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
-    if (ret) {
-        return ret;
-    }
-
-    /* Saved Program State Registers
-     *
-     * Before we restore from the banked_spsr[] array we need to
-     * ensure that any modifications to env->spsr are correctly
-     * reflected in the banks.
-     */
-    el = arm_current_el(env);
-    if (el > 0 && !is_a64(env)) {
-        i = bank_number(env->uncached_cpsr & CPSR_M);
-        env->banked_spsr[i] = env->spsr;
-    }
-
-    /* KVM 0-4 map to QEMU banks 1-5 */
-    for (i = 0; i < KVM_NR_SPSR; i++) {
-        reg.id = AARCH64_CORE_REG(spsr[i]);
-        reg.addr = (uintptr_t) &env->banked_spsr[i + 1];
-        ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
-        if (ret) {
-            return ret;
-        }
-    }
-
-    if (cpu_isar_feature(aa64_sve, cpu)) {
-        ret = kvm_arch_put_sve(cs);
-    } else {
-        ret = kvm_arch_put_fpsimd(cs);
-    }
-    if (ret) {
-        return ret;
-    }
-
-    reg.addr = (uintptr_t)(&fpr);
-    fpr = vfp_get_fpsr(env);
-    reg.id = AARCH64_SIMD_CTRL_REG(fp_regs.fpsr);
-    ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
-    if (ret) {
-        return ret;
-    }
-
-    reg.addr = (uintptr_t)(&fpr);
-    fpr = vfp_get_fpcr(env);
-    reg.id = AARCH64_SIMD_CTRL_REG(fp_regs.fpcr);
-    ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
-    if (ret) {
-        return ret;
-    }
-
-    write_cpustate_to_list(cpu, true);
-
-    if (!write_list_to_kvmstate(cpu, level)) {
-        return -EINVAL;
-    }
-
-   /*
-    * Setting VCPU events should be triggered after syncing the registers
-    * to avoid overwriting potential changes made by KVM upon calling
-    * KVM_SET_VCPU_EVENTS ioctl
-    */
-    ret = kvm_put_vcpu_events(cpu);
-    if (ret) {
-        return ret;
-    }
-
-    kvm_arm_sync_mpstate_to_kvm(cpu);
-
-    return ret;
-}
-
-static int kvm_arch_get_fpsimd(CPUState *cs)
-{
-    CPUARMState *env = &ARM_CPU(cs)->env;
-    struct kvm_one_reg reg;
-    int i, ret;
-
-    for (i = 0; i < 32; i++) {
-        uint64_t *q = aa64_vfp_qreg(env, i);
-        reg.id = AARCH64_SIMD_CORE_REG(fp_regs.vregs[i]);
-        reg.addr = (uintptr_t)q;
-        ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
-        if (ret) {
-            return ret;
-        } else {
-#if HOST_BIG_ENDIAN
-            uint64_t t;
-            t = q[0], q[0] = q[1], q[1] = t;
-#endif
-        }
-    }
-
-    return 0;
-}
-
-/*
- * KVM SVE registers come in slices where ZREGs have a slice size of 2048 bits
- * and PREGS and the FFR have a slice size of 256 bits. However we simply hard
- * code the slice index to zero for now as it's unlikely we'll need more than
- * one slice for quite some time.
- */
-static int kvm_arch_get_sve(CPUState *cs)
-{
-    ARMCPU *cpu = ARM_CPU(cs);
-    CPUARMState *env = &cpu->env;
-    struct kvm_one_reg reg;
-    uint64_t *r;
-    int n, ret;
-
-    for (n = 0; n < KVM_ARM64_SVE_NUM_ZREGS; ++n) {
-        r = &env->vfp.zregs[n].d[0];
-        reg.addr = (uintptr_t)r;
-        reg.id = KVM_REG_ARM64_SVE_ZREG(n, 0);
-        ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
-        if (ret) {
-            return ret;
-        }
-        sve_bswap64(r, r, cpu->sve_max_vq * 2);
-    }
-
-    for (n = 0; n < KVM_ARM64_SVE_NUM_PREGS; ++n) {
-        r = &env->vfp.pregs[n].p[0];
-        reg.addr = (uintptr_t)r;
-        reg.id = KVM_REG_ARM64_SVE_PREG(n, 0);
-        ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
-        if (ret) {
-            return ret;
-        }
-        sve_bswap64(r, r, DIV_ROUND_UP(cpu->sve_max_vq * 2, 8));
-    }
-
-    r = &env->vfp.pregs[FFR_PRED_NUM].p[0];
-    reg.addr = (uintptr_t)r;
-    reg.id = KVM_REG_ARM64_SVE_FFR(0);
-    ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
-    if (ret) {
-        return ret;
-    }
-    sve_bswap64(r, r, DIV_ROUND_UP(cpu->sve_max_vq * 2, 8));
-
-    return 0;
-}
-
-int kvm_arch_get_registers(CPUState *cs)
-{
-    struct kvm_one_reg reg;
-    uint64_t val;
-    unsigned int el;
-    uint32_t fpr;
-    int i, ret;
-
-    ARMCPU *cpu = ARM_CPU(cs);
-    CPUARMState *env = &cpu->env;
-
-    for (i = 0; i < 31; i++) {
-        reg.id = AARCH64_CORE_REG(regs.regs[i]);
-        reg.addr = (uintptr_t) &env->xregs[i];
-        ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
-        if (ret) {
-            return ret;
-        }
-    }
-
-    reg.id = AARCH64_CORE_REG(regs.sp);
-    reg.addr = (uintptr_t) &env->sp_el[0];
-    ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
-    if (ret) {
-        return ret;
-    }
-
-    reg.id = AARCH64_CORE_REG(sp_el1);
-    reg.addr = (uintptr_t) &env->sp_el[1];
-    ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
-    if (ret) {
-        return ret;
-    }
-
-    reg.id = AARCH64_CORE_REG(regs.pstate);
-    reg.addr = (uintptr_t) &val;
-    ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
-    if (ret) {
-        return ret;
-    }
-
-    env->aarch64 = ((val & PSTATE_nRW) == 0);
-    if (is_a64(env)) {
-        pstate_write(env, val);
-    } else {
-        cpsr_write(env, val, 0xffffffff, CPSRWriteRaw);
-    }
-
-    /* KVM puts SP_EL0 in regs.sp and SP_EL1 in regs.sp_el1. On the
-     * QEMU side we keep the current SP in xregs[31] as well.
-     */
-    aarch64_restore_sp(env, 1);
-
-    reg.id = AARCH64_CORE_REG(regs.pc);
-    reg.addr = (uintptr_t) &env->pc;
-    ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
-    if (ret) {
-        return ret;
-    }
-
-    /* If we are in AArch32 mode then we need to sync the AArch32 regs with the
-     * incoming AArch64 regs received from 64-bit KVM.
-     * We must perform this after all of the registers have been acquired from
-     * the kernel.
-     */
-    if (!is_a64(env)) {
-        aarch64_sync_64_to_32(env);
-    }
-
-    reg.id = AARCH64_CORE_REG(elr_el1);
-    reg.addr = (uintptr_t) &env->elr_el[1];
-    ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
-    if (ret) {
-        return ret;
-    }
-
-    /* Fetch the SPSR registers
-     *
-     * KVM SPSRs 0-4 map to QEMU banks 1-5
-     */
-    for (i = 0; i < KVM_NR_SPSR; i++) {
-        reg.id = AARCH64_CORE_REG(spsr[i]);
-        reg.addr = (uintptr_t) &env->banked_spsr[i + 1];
-        ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
-        if (ret) {
-            return ret;
-        }
-    }
-
-    el = arm_current_el(env);
-    if (el > 0 && !is_a64(env)) {
-        i = bank_number(env->uncached_cpsr & CPSR_M);
-        env->spsr = env->banked_spsr[i];
-    }
-
-    if (cpu_isar_feature(aa64_sve, cpu)) {
-        ret = kvm_arch_get_sve(cs);
-    } else {
-        ret = kvm_arch_get_fpsimd(cs);
-    }
-    if (ret) {
-        return ret;
-    }
-
-    reg.addr = (uintptr_t)(&fpr);
-    reg.id = AARCH64_SIMD_CTRL_REG(fp_regs.fpsr);
-    ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
-    if (ret) {
-        return ret;
-    }
-    vfp_set_fpsr(env, fpr);
-
-    reg.addr = (uintptr_t)(&fpr);
-    reg.id = AARCH64_SIMD_CTRL_REG(fp_regs.fpcr);
-    ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
-    if (ret) {
-        return ret;
-    }
-    vfp_set_fpcr(env, fpr);
-
-    ret = kvm_get_vcpu_events(cpu);
-    if (ret) {
-        return ret;
-    }
-
-    if (!write_kvmstate_to_list(cpu)) {
-        return -EINVAL;
-    }
-    /* Note that it's OK to have registers which aren't in CPUState,
-     * so we can ignore a failure return here.
-     */
-    write_list_to_cpustate(cpu);
-
-    kvm_arm_sync_mpstate_to_qemu(cpu);
-
-    /* TODO: other registers */
-    return ret;
-}
-
-void kvm_arch_on_sigbus_vcpu(CPUState *c, int code, void *addr)
-{
-    ram_addr_t ram_addr;
-    hwaddr paddr;
-
-    assert(code == BUS_MCEERR_AR || code == BUS_MCEERR_AO);
-
-    if (acpi_ghes_present() && addr) {
-        ram_addr = qemu_ram_addr_from_host(addr);
-        if (ram_addr != RAM_ADDR_INVALID &&
-            kvm_physical_memory_addr_from_host(c->kvm_state, addr, &paddr)) {
-            kvm_hwpoison_page_add(ram_addr);
-            /*
-             * If this is a BUS_MCEERR_AR, we know we have been called
-             * synchronously from the vCPU thread, so we can easily
-             * synchronize the state and inject an error.
-             *
-             * TODO: we currently don't tell the guest at all about
-             * BUS_MCEERR_AO. In that case we might either be being
-             * called synchronously from the vCPU thread, or a bit
-             * later from the main thread, so doing the injection of
-             * the error would be more complicated.
-             */
-            if (code == BUS_MCEERR_AR) {
-                kvm_cpu_synchronize_state(c);
-                if (!acpi_ghes_record_errors(ACPI_HEST_SRC_ID_SEA, paddr)) {
-                    kvm_inject_arm_sea(c);
-                } else {
-                    error_report("failed to record the error");
-                    abort();
-                }
-            }
-            return;
-        }
-        if (code == BUS_MCEERR_AO) {
-            error_report("Hardware memory error at addr %p for memory used by "
-                "QEMU itself instead of guest system!", addr);
-        }
-    }
-
-    if (code == BUS_MCEERR_AR) {
-        error_report("Hardware memory error!");
-        exit(1);
-    }
-}
-
-/* C6.6.29 BRK instruction */
-static const uint32_t brk_insn = 0xd4200000;
-
-int kvm_arch_insert_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp)
-{
-    if (have_guest_debug) {
-        if (cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&bp->saved_insn, 4, 0) ||
-            cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&brk_insn, 4, 1)) {
-            return -EINVAL;
-        }
-        return 0;
-    } else {
-        error_report("guest debug not supported on this kernel");
-        return -EINVAL;
-    }
-}
-
-int kvm_arch_remove_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp)
-{
-    static uint32_t brk;
-
-    if (have_guest_debug) {
-        if (cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&brk, 4, 0) ||
-            brk != brk_insn ||
-            cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&bp->saved_insn, 4, 1)) {
-            return -EINVAL;
-        }
-        return 0;
-    } else {
-        error_report("guest debug not supported on this kernel");
-        return -EINVAL;
-    }
-}
-
-/* See v8 ARM ARM D7.2.27 ESR_ELx, Exception Syndrome Register
- *
- * To minimise translating between kernel and user-space the kernel
- * ABI just provides user-space with the full exception syndrome
- * register value to be decoded in QEMU.
- */
-
-bool kvm_arm_handle_debug(CPUState *cs, struct kvm_debug_exit_arch *debug_exit)
-{
-    int hsr_ec = syn_get_ec(debug_exit->hsr);
-    ARMCPU *cpu = ARM_CPU(cs);
-    CPUARMState *env = &cpu->env;
-
-    /* Ensure PC is synchronised */
-    kvm_cpu_synchronize_state(cs);
-
-    switch (hsr_ec) {
-    case EC_SOFTWARESTEP:
-        if (cs->singlestep_enabled) {
-            return true;
-        } else {
-            /*
-             * The kernel should have suppressed the guest's ability to
-             * single step at this point so something has gone wrong.
-             */
-            error_report("%s: guest single-step while debugging unsupported"
-                         " (%"PRIx64", %"PRIx32")",
-                         __func__, env->pc, debug_exit->hsr);
-            return false;
-        }
-        break;
-    case EC_AA64_BKPT:
-        if (kvm_find_sw_breakpoint(cs, env->pc)) {
-            return true;
-        }
-        break;
-    case EC_BREAKPOINT:
-        if (find_hw_breakpoint(cs, env->pc)) {
-            return true;
-        }
-        break;
-    case EC_WATCHPOINT:
-    {
-        CPUWatchpoint *wp = find_hw_watchpoint(cs, debug_exit->far);
-        if (wp) {
-            cs->watchpoint_hit = wp;
-            return true;
-        }
-        break;
-    }
-    default:
-        error_report("%s: unhandled debug exit (%"PRIx32", %"PRIx64")",
-                     __func__, debug_exit->hsr, env->pc);
-    }
-
-    /* If we are not handling the debug exception it must belong to
-     * the guest. Let's re-use the existing TCG interrupt code to set
-     * everything up properly.
-     */
-    cs->exception_index = EXCP_BKPT;
-    env->exception.syndrome = debug_exit->hsr;
-    env->exception.vaddress = debug_exit->far;
-    env->exception.target_el = 1;
-    qemu_mutex_lock_iothread();
-    arm_cpu_do_interrupt(cs);
-    qemu_mutex_unlock_iothread();
-
-    return false;
-}
-
-#define ARM64_REG_ESR_EL1 ARM64_SYS_REG(3, 0, 5, 2, 0)
-#define ARM64_REG_TCR_EL1 ARM64_SYS_REG(3, 0, 2, 0, 2)
-
-/*
- * ESR_EL1
- * ISS encoding
- * AARCH64: DFSC,   bits [5:0]
- * AARCH32:
- *      TTBCR.EAE == 0
- *          FS[4]   - DFSR[10]
- *          FS[3:0] - DFSR[3:0]
- *      TTBCR.EAE == 1
- *          FS, bits [5:0]
- */
-#define ESR_DFSC(aarch64, lpae, v)        \
-    ((aarch64 || (lpae)) ? ((v) & 0x3F)   \
-               : (((v) >> 6) | ((v) & 0x1F)))
-
-#define ESR_DFSC_EXTABT(aarch64, lpae) \
-    ((aarch64) ? 0x10 : (lpae) ? 0x10 : 0x8)
-
-bool kvm_arm_verify_ext_dabt_pending(CPUState *cs)
-{
-    uint64_t dfsr_val;
-
-    if (!kvm_get_one_reg(cs, ARM64_REG_ESR_EL1, &dfsr_val)) {
-        ARMCPU *cpu = ARM_CPU(cs);
-        CPUARMState *env = &cpu->env;
-        int aarch64_mode = arm_feature(env, ARM_FEATURE_AARCH64);
-        int lpae = 0;
-
-        if (!aarch64_mode) {
-            uint64_t ttbcr;
-
-            if (!kvm_get_one_reg(cs, ARM64_REG_TCR_EL1, &ttbcr)) {
-                lpae = arm_feature(env, ARM_FEATURE_LPAE)
-                        && (ttbcr & TTBCR_EAE);
-            }
-        }
-        /*
-         * The verification here is based on the DFSC bits
-         * of the ESR_EL1 reg only
-         */
-         return (ESR_DFSC(aarch64_mode, lpae, dfsr_val) ==
-                ESR_DFSC_EXTABT(aarch64_mode, lpae));
-    }
-    return false;
-}
diff --git a/target/arm/meson.build b/target/arm/meson.build
index 87e911b27f..f6c96ec184 100644
--- a/target/arm/meson.build
+++ b/target/arm/meson.build
@@ -40,7 +40,7 @@ arm_ss.add(files(
 ))
 arm_ss.add(zlib)
 
-arm_ss.add(when: 'CONFIG_KVM', if_true: files('kvm.c', 'kvm64.c'), if_false: files('kvm-stub.c'))
+arm_ss.add(when: 'CONFIG_KVM', if_true: files('kvm.c'), if_false: files('kvm-stub.c'))
 
 arm_ss.add(when: 'TARGET_AARCH64', if_true: files(
   'cpu64.c',
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* [RFC PATCH 21/40] target/arm: Remove aarch64 check from aarch64_host_object_init
  2023-01-03 18:16 [RFC PATCH 00/40] Toward class init of cpu features Richard Henderson
                   ` (19 preceding siblings ...)
  2023-01-03 18:16 ` [RFC PATCH 20/40] target/arm: Merge kvm64.c with kvm.c Richard Henderson
@ 2023-01-03 18:16 ` Richard Henderson
  2023-01-05 22:08   ` Philippe Mathieu-Daudé
  2023-01-03 18:16 ` [RFC PATCH 22/40] target/arm: Hoist feature and dtb_compatible from KVM, HVF Richard Henderson
                   ` (20 subsequent siblings)
  41 siblings, 1 reply; 77+ messages in thread
From: Richard Henderson @ 2023-01-03 18:16 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, berrange, eduardo, armbru, ajones, alex.bennee

Since kvm32 was removed, all kvm hosts support aarch64.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/cpu64.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
index 28b5a07244..668e979a24 100644
--- a/target/arm/cpu64.c
+++ b/target/arm/cpu64.c
@@ -1095,10 +1095,8 @@ static void aarch64_host_object_init(Object *obj)
 #if defined(CONFIG_KVM)
     ARMCPU *cpu = ARM_CPU(obj);
     kvm_arm_set_cpu_features_from_host(cpu);
-    if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) {
-        aarch64_add_sve_properties(obj);
-        aarch64_add_pauth_properties(obj);
-    }
+    aarch64_add_sve_properties(obj);
+    aarch64_add_pauth_properties(obj);
 #elif defined(CONFIG_HVF)
     ARMCPU *cpu = ARM_CPU(obj);
     hvf_arm_set_cpu_features_from_host(cpu);
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* [RFC PATCH 22/40] target/arm: Hoist feature and dtb_compatible from KVM, HVF
  2023-01-03 18:16 [RFC PATCH 00/40] Toward class init of cpu features Richard Henderson
                   ` (20 preceding siblings ...)
  2023-01-03 18:16 ` [RFC PATCH 21/40] target/arm: Remove aarch64 check from aarch64_host_object_init Richard Henderson
@ 2023-01-03 18:16 ` Richard Henderson
  2023-01-03 18:16 ` [RFC PATCH 23/40] target/arm: Probe KVM host into ARMCPUClass Richard Henderson
                   ` (19 subsequent siblings)
  41 siblings, 0 replies; 77+ messages in thread
From: Richard Henderson @ 2023-01-03 18:16 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, berrange, eduardo, armbru, ajones, alex.bennee

These settings are generic and identical between the two
host accelerators.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/cpu64.c   | 23 ++++++++++++++++++++++-
 target/arm/hvf/hvf.c | 13 +------------
 target/arm/kvm.c     | 29 ++---------------------------
 3 files changed, 25 insertions(+), 40 deletions(-)

diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
index 668e979a24..75a88f9deb 100644
--- a/target/arm/cpu64.c
+++ b/target/arm/cpu64.c
@@ -1090,6 +1090,21 @@ static void aarch64_neoverse_n1_class_init(ARMCPUClass *cpu)
     cpu->isar.reset_pmcr_el0 = 0x410c3000;
 }
 
+static void aarch64_host_class_init(ARMCPUClass *acc)
+{
+    /*
+     * While we don't know all the host details, we can assume at
+     * least v8 with VFPv4+Neon; this in turn implies most of the
+     * other feature bits.
+     */
+    acc->dtb_compatible = "arm,arm-v8";
+    set_class_feature(acc, ARM_FEATURE_V8);
+    set_class_feature(acc, ARM_FEATURE_NEON);
+    set_class_feature(acc, ARM_FEATURE_GENERIC_TIMER);
+    set_class_feature(acc, ARM_FEATURE_AARCH64);
+    set_class_feature(acc, ARM_FEATURE_PMU);
+}
+
 static void aarch64_host_object_init(Object *obj)
 {
 #if defined(CONFIG_KVM)
@@ -1122,8 +1137,12 @@ static bool aarch64_max_class_late_init(ARMCPUClass *cpu, Error **errp)
         return true;
     }
 
-    /* '-cpu max' for TCG: we currently do this as "A57 with extra things" */
+    /*
+     * '-cpu max' for TCG: we currently do this as "A57 with extra things"
+     * Retain the more generic dtb_compatible setting from host_class_init.
+     */
     aarch64_a57_class_init(cpu);
+    cpu->dtb_compatible = "arm,arm-v8";
 
     /*
      * Reset MIDR so the guest doesn't mistake our 'max' CPU type for a real
@@ -1316,10 +1335,12 @@ static const ARMCPUInfo aarch64_cpus[] = {
       .class_init = aarch64_a64fx_class_init,
       .object_init = aarch64_a64fx_object_init },
     { .name = "max",
+      .class_init = aarch64_host_class_init,
       .class_late_init = aarch64_max_class_late_init,
       .object_init = aarch64_max_object_init },
 #if defined(CONFIG_KVM) || defined(CONFIG_HVF)
     { .name = "host",
+      .class_init = aarch64_host_class_init,
       .object_init = aarch64_host_object_init },
 #endif
 };
diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c
index 278a4b2ede..8bb8b475cd 100644
--- a/target/arm/hvf/hvf.c
+++ b/target/arm/hvf/hvf.c
@@ -97,10 +97,8 @@ static HVFVTimer vtimer;
 
 typedef struct ARMHostCPUFeatures {
     ARMISARegisters isar;
-    uint64_t features;
     uint64_t midr;
     uint32_t reset_sctlr;
-    const char *dtb_compatible;
 } ARMHostCPUFeatures;
 
 static ARMHostCPUFeatures arm_host_cpu_features;
@@ -489,13 +487,6 @@ static bool hvf_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
     hv_vcpu_exit_t *exit;
     int i;
 
-    ahcf->dtb_compatible = "arm,arm-v8";
-    ahcf->features = (1ULL << ARM_FEATURE_V8) |
-                     (1ULL << ARM_FEATURE_NEON) |
-                     (1ULL << ARM_FEATURE_AARCH64) |
-                     (1ULL << ARM_FEATURE_PMU) |
-                     (1ULL << ARM_FEATURE_GENERIC_TIMER);
-
     /* We set up a small vcpu to extract host registers */
 
     if (hv_vcpu_create(&fd, &exit, NULL) != HV_SUCCESS) {
@@ -532,7 +523,7 @@ static bool hvf_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
 
 void hvf_arm_set_cpu_features_from_host(ARMCPU *cpu)
 {
-    if (!arm_host_cpu_features.dtb_compatible) {
+    if (!arm_host_cpu_features.reset_sctlr) {
         if (!hvf_enabled() ||
             !hvf_arm_get_host_cpu_features(&arm_host_cpu_features)) {
             /*
@@ -544,9 +535,7 @@ void hvf_arm_set_cpu_features_from_host(ARMCPU *cpu)
         }
     }
 
-    cpu->dtb_compatible = arm_host_cpu_features.dtb_compatible;
     cpu->isar = arm_host_cpu_features.isar;
-    cpu->env.features = arm_host_cpu_features.features;
     cpu->midr = arm_host_cpu_features.midr;
     cpu->reset_sctlr = arm_host_cpu_features.reset_sctlr;
 }
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index 02a15c6013..ac164a6130 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -50,9 +50,7 @@ static bool cap_has_inject_ext_dabt;
  */
 typedef struct ARMHostCPUFeatures {
     ARMISARegisters isar;
-    uint64_t features;
     uint32_t target;
-    const char *dtb_compatible;
 } ARMHostCPUFeatures;
 
 static ARMHostCPUFeatures arm_host_cpu_features;
@@ -1567,7 +1565,6 @@ static bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
     int fdarray[3];
     bool sve_supported;
     bool pmu_supported = false;
-    uint64_t features = 0;
     int err;
 
     /* Old kernels may not know about the PREFERRED_TARGET ioctl: however
@@ -1615,7 +1612,6 @@ static bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
     }
 
     ahcf->target = init.target;
-    ahcf->dtb_compatible = "arm,arm-v8";
 
     err = read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64pfr0,
                          ARM64_SYS_REG(3, 0, 0, 4, 0));
@@ -1760,31 +1756,12 @@ static bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
 
     kvm_arm_destroy_scratch_host_vcpu(fdarray);
 
-    if (err < 0) {
-        return false;
-    }
-
-    /*
-     * We can assume any KVM supporting CPU is at least a v8
-     * with VFPv4+Neon; this in turn implies most of the other
-     * feature bits.
-     */
-    features |= 1ULL << ARM_FEATURE_V8;
-    features |= 1ULL << ARM_FEATURE_NEON;
-    features |= 1ULL << ARM_FEATURE_AARCH64;
-    features |= 1ULL << ARM_FEATURE_PMU;
-    features |= 1ULL << ARM_FEATURE_GENERIC_TIMER;
-
-    ahcf->features = features;
-
-    return true;
+    return !err;
 }
 
 void kvm_arm_set_cpu_features_from_host(ARMCPU *cpu)
 {
-    CPUARMState *env = &cpu->env;
-
-    if (!arm_host_cpu_features.dtb_compatible) {
+    if (!arm_host_cpu_features.isar.id_aa64pfr0) {
         if (!kvm_enabled() ||
             !kvm_arm_get_host_cpu_features(&arm_host_cpu_features)) {
             /* We can't report this error yet, so flag that we need to
@@ -1797,9 +1774,7 @@ void kvm_arm_set_cpu_features_from_host(ARMCPU *cpu)
     }
 
     cpu->kvm_target = arm_host_cpu_features.target;
-    cpu->dtb_compatible = arm_host_cpu_features.dtb_compatible;
     cpu->isar = arm_host_cpu_features.isar;
-    env->features = arm_host_cpu_features.features;
 }
 
 /**
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* [RFC PATCH 23/40] target/arm: Probe KVM host into ARMCPUClass
  2023-01-03 18:16 [RFC PATCH 00/40] Toward class init of cpu features Richard Henderson
                   ` (21 preceding siblings ...)
  2023-01-03 18:16 ` [RFC PATCH 22/40] target/arm: Hoist feature and dtb_compatible from KVM, HVF Richard Henderson
@ 2023-01-03 18:16 ` Richard Henderson
  2023-01-03 18:16 ` [RFC PATCH 24/40] target/arm/hvf: Probe " Richard Henderson
                   ` (18 subsequent siblings)
  41 siblings, 0 replies; 77+ messages in thread
From: Richard Henderson @ 2023-01-03 18:16 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, berrange, eduardo, armbru, ajones, alex.bennee

We can now store these values into ARMCPUClass instead of into
a temporary ARMHostCPUFeatures structure.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/kvm_arm.h |  14 ++---
 target/arm/cpu64.c   |  18 +++++--
 target/arm/kvm.c     | 119 +++++++++++++++++--------------------------
 3 files changed, 69 insertions(+), 82 deletions(-)

diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h
index 8efbe0cc4b..d426e24c53 100644
--- a/target/arm/kvm_arm.h
+++ b/target/arm/kvm_arm.h
@@ -140,13 +140,15 @@ void kvm_arm_destroy_scratch_host_vcpu(int *fdarray);
 uint32_t kvm_arm_sve_get_vls(CPUState *cs);
 
 /**
- * kvm_arm_set_cpu_features_from_host:
- * @cpu: ARMCPU to set the features for
+ * kvm_arm_get_host_cpu_features:
+ * @acc: ARMCPUClass to fill in
  *
- * Set up the ARMCPU struct fields up to match the information probed
- * from the host CPU.
+ * Probe the capabilities of the host kernel's preferred CPU and fill
+ * in the ARMCPUClass struct accordingly.
+ *
+ * Returns true on success and false otherwise.
  */
-void kvm_arm_set_cpu_features_from_host(ARMCPU *cpu);
+bool kvm_arm_get_host_cpu_features(ARMCPUClass *acc, Error **errp);
 
 /**
  * kvm_arm_add_vcpu_properties:
@@ -245,7 +247,7 @@ static inline bool kvm_arm_steal_time_supported(void)
 /*
  * These functions should never actually be called without KVM support.
  */
-static inline void kvm_arm_set_cpu_features_from_host(ARMCPU *cpu)
+static inline bool kvm_arm_get_host_cpu_features(ARMCPUClass *c, Error **e)
 {
     g_assert_not_reached();
 }
diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
index 75a88f9deb..a21bc39449 100644
--- a/target/arm/cpu64.c
+++ b/target/arm/cpu64.c
@@ -1105,11 +1105,21 @@ static void aarch64_host_class_init(ARMCPUClass *acc)
     set_class_feature(acc, ARM_FEATURE_PMU);
 }
 
+static bool aarch64_host_class_late_init(ARMCPUClass *acc, Error **errp)
+{
+    if (kvm_enabled()) {
+        return kvm_arm_get_host_cpu_features(acc, errp);
+    }
+    if (hvf_enabled()) {
+        return true;
+    }
+    error_setg(errp, "The 'host' CPU type can only be used with KVM or HVF");
+    return false;
+}
+
 static void aarch64_host_object_init(Object *obj)
 {
 #if defined(CONFIG_KVM)
-    ARMCPU *cpu = ARM_CPU(obj);
-    kvm_arm_set_cpu_features_from_host(cpu);
     aarch64_add_sve_properties(obj);
     aarch64_add_pauth_properties(obj);
 #elif defined(CONFIG_HVF)
@@ -1134,7 +1144,8 @@ static bool aarch64_max_class_late_init(ARMCPUClass *cpu, Error **errp)
     uint32_t u;
 
     if (kvm_enabled() || hvf_enabled()) {
-        return true;
+        /* With KVM or HVF, '-cpu max' is identical to '-cpu host' */
+        return aarch64_host_class_late_init(cpu, errp);
     }
 
     /*
@@ -1341,6 +1352,7 @@ static const ARMCPUInfo aarch64_cpus[] = {
 #if defined(CONFIG_KVM) || defined(CONFIG_HVF)
     { .name = "host",
       .class_init = aarch64_host_class_init,
+      .class_late_init = aarch64_host_class_late_init,
       .object_init = aarch64_host_object_init },
 #endif
 };
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index ac164a6130..85971df07c 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -44,17 +44,6 @@ static bool cap_has_mp_state;
 static bool cap_has_inject_serror_esr;
 static bool cap_has_inject_ext_dabt;
 
-/**
- * ARMHostCPUFeatures: information about the host CPU (identified
- * by asking the host kernel)
- */
-typedef struct ARMHostCPUFeatures {
-    ARMISARegisters isar;
-    uint32_t target;
-} ARMHostCPUFeatures;
-
-static ARMHostCPUFeatures arm_host_cpu_features;
-
 /**
  * kvm_arm_vcpu_init:
  * @cs: CPUState
@@ -1548,14 +1537,14 @@ static bool kvm_arm_pauth_supported(void)
 
 /**
  * kvm_arm_get_host_cpu_features:
- * @ahcf: ARMHostCPUClass to fill in
+ * @acc: ARMCPUClass to fill in
  *
  * Probe the capabilities of the host kernel's preferred CPU and fill
- * in the ARMHostCPUClass struct accordingly.
+ * in the ARMCPUClass struct accordingly.
  *
  * Returns true on success and false otherwise.
  */
-static bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
+bool kvm_arm_get_host_cpu_features(ARMCPUClass *acc, Error **errp)
 {
     /* Identify the feature bits corresponding to the host CPU, and
      * fill out the ARMHostCPUClass fields accordingly. To do this
@@ -1608,12 +1597,14 @@ static bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
     }
 
     if (!kvm_arm_create_scratch_host_vcpu(cpus_to_try, fdarray, &init)) {
+        error_setg_errno(errp, "Failed to create host vcpu");
+        acc->kvm_target = QEMU_KVM_ARM_TARGET_NONE;
         return false;
     }
 
-    ahcf->target = init.target;
+    acc->kvm_target = init.target;
 
-    err = read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64pfr0,
+    err = read_sys_reg64(fdarray[2], &acc->isar.id_aa64pfr0,
                          ARM64_SYS_REG(3, 0, 0, 4, 0));
     if (unlikely(err < 0)) {
         /*
@@ -1632,26 +1623,26 @@ static bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
          * ??? Either of these sounds like too much effort just
          *     to work around running a modern host kernel.
          */
-        ahcf->isar.id_aa64pfr0 = 0x00000011; /* EL1&0, AArch64 only */
+        acc->isar.id_aa64pfr0 = 0x00000011; /* EL1&0, AArch64 only */
         err = 0;
     } else {
-        err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64pfr1,
+        err |= read_sys_reg64(fdarray[2], &acc->isar.id_aa64pfr1,
                               ARM64_SYS_REG(3, 0, 0, 4, 1));
-        err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64smfr0,
+        err |= read_sys_reg64(fdarray[2], &acc->isar.id_aa64smfr0,
                               ARM64_SYS_REG(3, 0, 0, 4, 5));
-        err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64dfr0,
+        err |= read_sys_reg64(fdarray[2], &acc->isar.id_aa64dfr0,
                               ARM64_SYS_REG(3, 0, 0, 5, 0));
-        err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64dfr1,
+        err |= read_sys_reg64(fdarray[2], &acc->isar.id_aa64dfr1,
                               ARM64_SYS_REG(3, 0, 0, 5, 1));
-        err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64isar0,
+        err |= read_sys_reg64(fdarray[2], &acc->isar.id_aa64isar0,
                               ARM64_SYS_REG(3, 0, 0, 6, 0));
-        err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64isar1,
+        err |= read_sys_reg64(fdarray[2], &acc->isar.id_aa64isar1,
                               ARM64_SYS_REG(3, 0, 0, 6, 1));
-        err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64mmfr0,
+        err |= read_sys_reg64(fdarray[2], &acc->isar.id_aa64mmfr0,
                               ARM64_SYS_REG(3, 0, 0, 7, 0));
-        err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64mmfr1,
+        err |= read_sys_reg64(fdarray[2], &acc->isar.id_aa64mmfr1,
                               ARM64_SYS_REG(3, 0, 0, 7, 1));
-        err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64mmfr2,
+        err |= read_sys_reg64(fdarray[2], &acc->isar.id_aa64mmfr2,
                               ARM64_SYS_REG(3, 0, 0, 7, 2));
 
         /*
@@ -1661,48 +1652,48 @@ static bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
          * than skipping the reads and leaving 0, as we must avoid
          * considering the values in every case.
          */
-        err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_pfr0,
+        err |= read_sys_reg32(fdarray[2], &acc->isar.id_pfr0,
                               ARM64_SYS_REG(3, 0, 0, 1, 0));
-        err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_pfr1,
+        err |= read_sys_reg32(fdarray[2], &acc->isar.id_pfr1,
                               ARM64_SYS_REG(3, 0, 0, 1, 1));
-        err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_dfr0,
+        err |= read_sys_reg32(fdarray[2], &acc->isar.id_dfr0,
                               ARM64_SYS_REG(3, 0, 0, 1, 2));
-        err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_mmfr0,
+        err |= read_sys_reg32(fdarray[2], &acc->isar.id_mmfr0,
                               ARM64_SYS_REG(3, 0, 0, 1, 4));
-        err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_mmfr1,
+        err |= read_sys_reg32(fdarray[2], &acc->isar.id_mmfr1,
                               ARM64_SYS_REG(3, 0, 0, 1, 5));
-        err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_mmfr2,
+        err |= read_sys_reg32(fdarray[2], &acc->isar.id_mmfr2,
                               ARM64_SYS_REG(3, 0, 0, 1, 6));
-        err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_mmfr3,
+        err |= read_sys_reg32(fdarray[2], &acc->isar.id_mmfr3,
                               ARM64_SYS_REG(3, 0, 0, 1, 7));
-        err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_isar0,
+        err |= read_sys_reg32(fdarray[2], &acc->isar.id_isar0,
                               ARM64_SYS_REG(3, 0, 0, 2, 0));
-        err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_isar1,
+        err |= read_sys_reg32(fdarray[2], &acc->isar.id_isar1,
                               ARM64_SYS_REG(3, 0, 0, 2, 1));
-        err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_isar2,
+        err |= read_sys_reg32(fdarray[2], &acc->isar.id_isar2,
                               ARM64_SYS_REG(3, 0, 0, 2, 2));
-        err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_isar3,
+        err |= read_sys_reg32(fdarray[2], &acc->isar.id_isar3,
                               ARM64_SYS_REG(3, 0, 0, 2, 3));
-        err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_isar4,
+        err |= read_sys_reg32(fdarray[2], &acc->isar.id_isar4,
                               ARM64_SYS_REG(3, 0, 0, 2, 4));
-        err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_isar5,
+        err |= read_sys_reg32(fdarray[2], &acc->isar.id_isar5,
                               ARM64_SYS_REG(3, 0, 0, 2, 5));
-        err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_mmfr4,
+        err |= read_sys_reg32(fdarray[2], &acc->isar.id_mmfr4,
                               ARM64_SYS_REG(3, 0, 0, 2, 6));
-        err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_isar6,
+        err |= read_sys_reg32(fdarray[2], &acc->isar.id_isar6,
                               ARM64_SYS_REG(3, 0, 0, 2, 7));
 
-        err |= read_sys_reg32(fdarray[2], &ahcf->isar.mvfr0,
+        err |= read_sys_reg32(fdarray[2], &acc->isar.mvfr0,
                               ARM64_SYS_REG(3, 0, 0, 3, 0));
-        err |= read_sys_reg32(fdarray[2], &ahcf->isar.mvfr1,
+        err |= read_sys_reg32(fdarray[2], &acc->isar.mvfr1,
                               ARM64_SYS_REG(3, 0, 0, 3, 1));
-        err |= read_sys_reg32(fdarray[2], &ahcf->isar.mvfr2,
+        err |= read_sys_reg32(fdarray[2], &acc->isar.mvfr2,
                               ARM64_SYS_REG(3, 0, 0, 3, 2));
-        err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_pfr2,
+        err |= read_sys_reg32(fdarray[2], &acc->isar.id_pfr2,
                               ARM64_SYS_REG(3, 0, 0, 3, 4));
-        err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_dfr1,
+        err |= read_sys_reg32(fdarray[2], &acc->isar.id_dfr1,
                               ARM64_SYS_REG(3, 0, 0, 3, 5));
-        err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_mmfr5,
+        err |= read_sys_reg32(fdarray[2], &acc->isar.id_mmfr5,
                               ARM64_SYS_REG(3, 0, 0, 3, 6));
 
         /*
@@ -1715,14 +1706,14 @@ static bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
          * arch/arm64/kvm/sys_regs.c:trap_dbgidr() does.
          * We only do this if the CPU supports AArch32 at EL1.
          */
-        if (FIELD_EX32(ahcf->isar.id_aa64pfr0, ID_AA64PFR0, EL1) >= 2) {
-            int wrps = FIELD_EX64(ahcf->isar.id_aa64dfr0, ID_AA64DFR0, WRPS);
-            int brps = FIELD_EX64(ahcf->isar.id_aa64dfr0, ID_AA64DFR0, BRPS);
+        if (FIELD_EX32(acc->isar.id_aa64pfr0, ID_AA64PFR0, EL1) >= 2) {
+            int wrps = FIELD_EX64(acc->isar.id_aa64dfr0, ID_AA64DFR0, WRPS);
+            int brps = FIELD_EX64(acc->isar.id_aa64dfr0, ID_AA64DFR0, BRPS);
             int ctx_cmps =
-                FIELD_EX64(ahcf->isar.id_aa64dfr0, ID_AA64DFR0, CTX_CMPS);
+                FIELD_EX64(acc->isar.id_aa64dfr0, ID_AA64DFR0, CTX_CMPS);
             int version = 6; /* ARMv8 debug architecture */
             bool has_el3 =
-                !!FIELD_EX32(ahcf->isar.id_aa64pfr0, ID_AA64PFR0, EL3);
+                !!FIELD_EX32(acc->isar.id_aa64pfr0, ID_AA64PFR0, EL3);
             uint32_t dbgdidr = 0;
 
             dbgdidr = FIELD_DP32(dbgdidr, DBGDIDR, WRPS, wrps);
@@ -1732,12 +1723,12 @@ static bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
             dbgdidr = FIELD_DP32(dbgdidr, DBGDIDR, NSUHD_IMP, has_el3);
             dbgdidr = FIELD_DP32(dbgdidr, DBGDIDR, SE_IMP, has_el3);
             dbgdidr |= (1 << 15); /* RES1 bit */
-            ahcf->isar.dbgdidr = dbgdidr;
+            acc->isar.dbgdidr = dbgdidr;
         }
 
         if (pmu_supported) {
             /* PMCR_EL0 is only accessible if the vCPU has feature PMU_V3 */
-            err |= read_sys_reg64(fdarray[2], &ahcf->isar.reset_pmcr_el0,
+            err |= read_sys_reg64(fdarray[2], &acc->isar.reset_pmcr_el0,
                                   ARM64_SYS_REG(3, 3, 9, 12, 0));
         }
 
@@ -1749,7 +1740,7 @@ static bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
              * enabled SVE support, which resulted in an error rather than RAZ.
              * So only read the register if we set KVM_ARM_VCPU_SVE above.
              */
-            err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64zfr0,
+            err |= read_sys_reg64(fdarray[2], &acc->isar.id_aa64zfr0,
                                   ARM64_SYS_REG(3, 0, 0, 4, 4));
         }
     }
@@ -1759,24 +1750,6 @@ static bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
     return !err;
 }
 
-void kvm_arm_set_cpu_features_from_host(ARMCPU *cpu)
-{
-    if (!arm_host_cpu_features.isar.id_aa64pfr0) {
-        if (!kvm_enabled() ||
-            !kvm_arm_get_host_cpu_features(&arm_host_cpu_features)) {
-            /* We can't report this error yet, so flag that we need to
-             * in arm_cpu_realizefn().
-             */
-            cpu->kvm_target = QEMU_KVM_ARM_TARGET_NONE;
-            cpu->host_cpu_probe_failed = true;
-            return;
-        }
-    }
-
-    cpu->kvm_target = arm_host_cpu_features.target;
-    cpu->isar = arm_host_cpu_features.isar;
-}
-
 /**
  * kvm_arm_steal_time_supported:
  *
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* [RFC PATCH 24/40] target/arm/hvf: Probe host into ARMCPUClass
  2023-01-03 18:16 [RFC PATCH 00/40] Toward class init of cpu features Richard Henderson
                   ` (22 preceding siblings ...)
  2023-01-03 18:16 ` [RFC PATCH 23/40] target/arm: Probe KVM host into ARMCPUClass Richard Henderson
@ 2023-01-03 18:16 ` Richard Henderson
  2023-01-05 22:10   ` Philippe Mathieu-Daudé
  2023-01-03 18:16 ` [RFC PATCH 25/40] target/arm/hvf: Use offsetof in hvf_arm_get_host_cpu_features Richard Henderson
                   ` (17 subsequent siblings)
  41 siblings, 1 reply; 77+ messages in thread
From: Richard Henderson @ 2023-01-03 18:16 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, berrange, eduardo, armbru, ajones, alex.bennee

We can now store these values into ARMCPUClass instead of into
a temporary ARMHostCPUFeatures structure.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/cpu.h     |  5 ----
 target/arm/hvf_arm.h |  2 +-
 target/arm/cpu.c     | 13 ----------
 target/arm/cpu64.c   |  4 +--
 target/arm/hvf/hvf.c | 59 +++++++++++---------------------------------
 5 files changed, 17 insertions(+), 66 deletions(-)

diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index 0c5b942ed0..e8dd75b003 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -935,11 +935,6 @@ struct ArchCPU {
     /* KVM steal time */
     OnOffAuto kvm_steal_time;
 
-    /* True if we tried kvm_arm_host_cpu_features() during CPU instance_init
-     * and the probe failed (so we need to report the error in realize)
-     */
-    bool host_cpu_probe_failed;
-
     /* Specify the number of cores in this CPU cluster. Used for the L2CTLR
      * register.
      */
diff --git a/target/arm/hvf_arm.h b/target/arm/hvf_arm.h
index 9a9d1a0bf5..c3b34ba31d 100644
--- a/target/arm/hvf_arm.h
+++ b/target/arm/hvf_arm.h
@@ -13,6 +13,6 @@
 
 #include "cpu.h"
 
-void hvf_arm_set_cpu_features_from_host(ARMCPU *cpu);
+bool hvf_arm_get_host_cpu_features(ARMCPUClass *acc, Error **errp);
 
 #endif
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index c58029fb4a..f4d8be6c4c 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -1584,19 +1584,6 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
     Error *local_err = NULL;
     bool no_aa32 = false;
 
-    /* If we needed to query the host kernel for the CPU features
-     * then it's possible that might have failed in the initfn, but
-     * this is the first point where we can report it.
-     */
-    if (cpu->host_cpu_probe_failed) {
-        if (!kvm_enabled() && !hvf_enabled()) {
-            error_setg(errp, "The 'host' CPU type can only be used with KVM or HVF");
-        } else {
-            error_setg(errp, "Failed to retrieve host CPU features");
-        }
-        return;
-    }
-
 #ifndef CONFIG_USER_ONLY
     /* The NVIC and M-profile CPU are two halves of a single piece of
      * hardware; trying to use one without the other is a command line
diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
index a21bc39449..f94f775585 100644
--- a/target/arm/cpu64.c
+++ b/target/arm/cpu64.c
@@ -1111,7 +1111,7 @@ static bool aarch64_host_class_late_init(ARMCPUClass *acc, Error **errp)
         return kvm_arm_get_host_cpu_features(acc, errp);
     }
     if (hvf_enabled()) {
-        return true;
+        return hvf_arm_get_host_cpu_features(acc, errp);
     }
     error_setg(errp, "The 'host' CPU type can only be used with KVM or HVF");
     return false;
@@ -1123,8 +1123,6 @@ static void aarch64_host_object_init(Object *obj)
     aarch64_add_sve_properties(obj);
     aarch64_add_pauth_properties(obj);
 #elif defined(CONFIG_HVF)
-    ARMCPU *cpu = ARM_CPU(obj);
-    hvf_arm_set_cpu_features_from_host(cpu);
     aarch64_add_pauth_properties(obj);
 #else
     g_assert_not_reached();
diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c
index 8bb8b475cd..d47159b9bf 100644
--- a/target/arm/hvf/hvf.c
+++ b/target/arm/hvf/hvf.c
@@ -95,14 +95,6 @@ typedef struct HVFVTimer {
 
 static HVFVTimer vtimer;
 
-typedef struct ARMHostCPUFeatures {
-    ARMISARegisters isar;
-    uint64_t midr;
-    uint32_t reset_sctlr;
-} ARMHostCPUFeatures;
-
-static ARMHostCPUFeatures arm_host_cpu_features;
-
 struct hvf_reg_match {
     int reg;
     uint64_t offset;
@@ -465,22 +457,21 @@ static uint64_t hvf_get_reg(CPUState *cpu, int rt)
     return val;
 }
 
-static bool hvf_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
+bool hvf_arm_get_host_cpu_features(ARMCPUClass *acc, Error **errp)
 {
-    ARMISARegisters host_isar = {};
     const struct isar_regs {
         int reg;
         uint64_t *val;
     } regs[] = {
-        { HV_SYS_REG_ID_AA64PFR0_EL1, &host_isar.id_aa64pfr0 },
-        { HV_SYS_REG_ID_AA64PFR1_EL1, &host_isar.id_aa64pfr1 },
-        { HV_SYS_REG_ID_AA64DFR0_EL1, &host_isar.id_aa64dfr0 },
-        { HV_SYS_REG_ID_AA64DFR1_EL1, &host_isar.id_aa64dfr1 },
-        { HV_SYS_REG_ID_AA64ISAR0_EL1, &host_isar.id_aa64isar0 },
-        { HV_SYS_REG_ID_AA64ISAR1_EL1, &host_isar.id_aa64isar1 },
-        { HV_SYS_REG_ID_AA64MMFR0_EL1, &host_isar.id_aa64mmfr0 },
-        { HV_SYS_REG_ID_AA64MMFR1_EL1, &host_isar.id_aa64mmfr1 },
-        { HV_SYS_REG_ID_AA64MMFR2_EL1, &host_isar.id_aa64mmfr2 },
+        { HV_SYS_REG_ID_AA64PFR0_EL1, &acc->isar.id_aa64pfr0 },
+        { HV_SYS_REG_ID_AA64PFR1_EL1, &acc->isar.id_aa64pfr1 },
+        { HV_SYS_REG_ID_AA64DFR0_EL1, &acc->isar.id_aa64dfr0 },
+        { HV_SYS_REG_ID_AA64DFR1_EL1, &acc->isar.id_aa64dfr1 },
+        { HV_SYS_REG_ID_AA64ISAR0_EL1, &acc->isar.id_aa64isar0 },
+        { HV_SYS_REG_ID_AA64ISAR1_EL1, &acc->isar.id_aa64isar1 },
+        { HV_SYS_REG_ID_AA64MMFR0_EL1, &acc->isar.id_aa64mmfr0 },
+        { HV_SYS_REG_ID_AA64MMFR1_EL1, &acc->isar.id_aa64mmfr1 },
+        { HV_SYS_REG_ID_AA64MMFR2_EL1, &acc->isar.id_aa64mmfr2 },
     };
     hv_vcpu_t fd;
     hv_return_t r = HV_SUCCESS;
@@ -496,50 +487,30 @@ static bool hvf_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
     for (i = 0; i < ARRAY_SIZE(regs); i++) {
         r |= hv_vcpu_get_sys_reg(fd, regs[i].reg, regs[i].val);
     }
-    r |= hv_vcpu_get_sys_reg(fd, HV_SYS_REG_MIDR_EL1, &ahcf->midr);
+    r |= hv_vcpu_get_sys_reg(fd, HV_SYS_REG_MIDR_EL1, &acc->midr);
     r |= hv_vcpu_destroy(fd);
 
-    ahcf->isar = host_isar;
-
     /*
      * A scratch vCPU returns SCTLR 0, so let's fill our default with the M1
      * boot SCTLR from https://github.com/AsahiLinux/m1n1/issues/97
      */
-    ahcf->reset_sctlr = 0x30100180;
+    acc->reset_sctlr = 0x30100180;
+
     /*
      * SPAN is disabled by default when SCTLR.SPAN=1. To improve compatibility,
      * let's disable it on boot and then allow guest software to turn it on by
      * setting it to 0.
      */
-    ahcf->reset_sctlr |= 0x00800000;
+    acc->reset_sctlr |= 0x00800000;
 
     /* Make sure we don't advertise AArch32 support for EL0/EL1 */
-    if ((host_isar.id_aa64pfr0 & 0xff) != 0x11) {
+    if ((acc->isar.id_aa64pfr0 & 0xff) != 0x11) {
         return false;
     }
 
     return r == HV_SUCCESS;
 }
 
-void hvf_arm_set_cpu_features_from_host(ARMCPU *cpu)
-{
-    if (!arm_host_cpu_features.reset_sctlr) {
-        if (!hvf_enabled() ||
-            !hvf_arm_get_host_cpu_features(&arm_host_cpu_features)) {
-            /*
-             * We can't report this error yet, so flag that we need to
-             * in arm_cpu_realizefn().
-             */
-            cpu->host_cpu_probe_failed = true;
-            return;
-        }
-    }
-
-    cpu->isar = arm_host_cpu_features.isar;
-    cpu->midr = arm_host_cpu_features.midr;
-    cpu->reset_sctlr = arm_host_cpu_features.reset_sctlr;
-}
-
 void hvf_arch_vcpu_destroy(CPUState *cpu)
 {
 }
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* [RFC PATCH 25/40] target/arm/hvf: Use offsetof in hvf_arm_get_host_cpu_features
  2023-01-03 18:16 [RFC PATCH 00/40] Toward class init of cpu features Richard Henderson
                   ` (23 preceding siblings ...)
  2023-01-03 18:16 ` [RFC PATCH 24/40] target/arm/hvf: Probe " Richard Henderson
@ 2023-01-03 18:16 ` Richard Henderson
  2023-01-03 18:16 ` [RFC PATCH 26/40] target/arm: Rename 'cpu' to 'acc' in class init functions Richard Henderson
                   ` (16 subsequent siblings)
  41 siblings, 0 replies; 77+ messages in thread
From: Richard Henderson @ 2023-01-03 18:16 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, berrange, eduardo, armbru, ajones, alex.bennee

Use an offsetof vs ARMCPUClass, which means that the regs[]
array may be static const, and we can include midr in the list.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/hvf/hvf.c | 38 ++++++++++++++++++++++++--------------
 1 file changed, 24 insertions(+), 14 deletions(-)

diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c
index d47159b9bf..362dd4ac2e 100644
--- a/target/arm/hvf/hvf.c
+++ b/target/arm/hvf/hvf.c
@@ -459,19 +459,29 @@ static uint64_t hvf_get_reg(CPUState *cpu, int rt)
 
 bool hvf_arm_get_host_cpu_features(ARMCPUClass *acc, Error **errp)
 {
-    const struct isar_regs {
-        int reg;
-        uint64_t *val;
+    static const struct isar_regs {
+        int reg, offset;
     } regs[] = {
-        { HV_SYS_REG_ID_AA64PFR0_EL1, &acc->isar.id_aa64pfr0 },
-        { HV_SYS_REG_ID_AA64PFR1_EL1, &acc->isar.id_aa64pfr1 },
-        { HV_SYS_REG_ID_AA64DFR0_EL1, &acc->isar.id_aa64dfr0 },
-        { HV_SYS_REG_ID_AA64DFR1_EL1, &acc->isar.id_aa64dfr1 },
-        { HV_SYS_REG_ID_AA64ISAR0_EL1, &acc->isar.id_aa64isar0 },
-        { HV_SYS_REG_ID_AA64ISAR1_EL1, &acc->isar.id_aa64isar1 },
-        { HV_SYS_REG_ID_AA64MMFR0_EL1, &acc->isar.id_aa64mmfr0 },
-        { HV_SYS_REG_ID_AA64MMFR1_EL1, &acc->isar.id_aa64mmfr1 },
-        { HV_SYS_REG_ID_AA64MMFR2_EL1, &acc->isar.id_aa64mmfr2 },
+        { HV_SYS_REG_ID_AA64PFR0_EL1,
+          offsetof(ARMCPUClass, isar.id_aa64pfr0) },
+        { HV_SYS_REG_ID_AA64PFR1_EL1,
+          offsetof(ARMCPUClass, isar.id_aa64pfr1) },
+        { HV_SYS_REG_ID_AA64DFR0_EL1,
+          offsetof(ARMCPUClass, isar.id_aa64dfr0) },
+        { HV_SYS_REG_ID_AA64DFR1_EL1,
+          offsetof(ARMCPUClass, isar.id_aa64dfr1) },
+        { HV_SYS_REG_ID_AA64ISAR0_EL1,
+          offsetof(ARMCPUClass, isar.id_aa64isar0) },
+        { HV_SYS_REG_ID_AA64ISAR1_EL1,
+          offsetof(ARMCPUClass, isar.id_aa64isar1) },
+        { HV_SYS_REG_ID_AA64MMFR0_EL1,
+          offsetof(ARMCPUClass, isar.id_aa64mmfr0) },
+        { HV_SYS_REG_ID_AA64MMFR1_EL1,
+          offsetof(ARMCPUClass, isar.id_aa64mmfr1) },
+        { HV_SYS_REG_ID_AA64MMFR2_EL1,
+          offsetof(ARMCPUClass, isar.id_aa64mmfr2) },
+        { HV_SYS_REG_MIDR_EL1,
+          offsetof(ARMCPUClass, midr) },
     };
     hv_vcpu_t fd;
     hv_return_t r = HV_SUCCESS;
@@ -485,9 +495,9 @@ bool hvf_arm_get_host_cpu_features(ARMCPUClass *acc, Error **errp)
     }
 
     for (i = 0; i < ARRAY_SIZE(regs); i++) {
-        r |= hv_vcpu_get_sys_reg(fd, regs[i].reg, regs[i].val);
+        uint64_t *p = (void *)acc + regs[i].offset;
+        r |= hv_vcpu_get_sys_reg(fd, regs[i].reg, p);
     }
-    r |= hv_vcpu_get_sys_reg(fd, HV_SYS_REG_MIDR_EL1, &acc->midr);
     r |= hv_vcpu_destroy(fd);
 
     /*
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* [RFC PATCH 26/40] target/arm: Rename 'cpu' to 'acc' in class init functions
  2023-01-03 18:16 [RFC PATCH 00/40] Toward class init of cpu features Richard Henderson
                   ` (24 preceding siblings ...)
  2023-01-03 18:16 ` [RFC PATCH 25/40] target/arm/hvf: Use offsetof in hvf_arm_get_host_cpu_features Richard Henderson
@ 2023-01-03 18:16 ` Richard Henderson
  2023-01-03 19:24   ` Philippe Mathieu-Daudé
  2023-01-03 18:16 ` [RFC PATCH 27/40] target/arm: Split out strongarm_class_init Richard Henderson
                   ` (15 subsequent siblings)
  41 siblings, 1 reply; 77+ messages in thread
From: Richard Henderson @ 2023-01-03 18:16 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, berrange, eduardo, armbru, ajones, alex.bennee

These were previously left 'misnamed' to minimize the size
of the patch.  Rename them all in bulk with no other change.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/cpu64.c   |  858 ++++++++++++++--------------
 target/arm/cpu_tcg.c | 1260 +++++++++++++++++++++---------------------
 2 files changed, 1059 insertions(+), 1059 deletions(-)

diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
index f94f775585..6ad5f9e444 100644
--- a/target/arm/cpu64.c
+++ b/target/arm/cpu64.c
@@ -36,82 +36,82 @@
 #include "hw/qdev-properties.h"
 #include "internals.h"
 
-static void aarch64_a35_class_init(ARMCPUClass *cpu)
+static void aarch64_a35_class_init(ARMCPUClass *acc)
 {
-    cpu->dtb_compatible = "arm,cortex-a35";
-    set_class_feature(cpu, ARM_FEATURE_V8);
-    set_class_feature(cpu, ARM_FEATURE_NEON);
-    set_class_feature(cpu, ARM_FEATURE_GENERIC_TIMER);
-    set_class_feature(cpu, ARM_FEATURE_AARCH64);
-    set_class_feature(cpu, ARM_FEATURE_CBAR_RO);
-    set_class_feature(cpu, ARM_FEATURE_EL2);
-    set_class_feature(cpu, ARM_FEATURE_EL3);
-    set_class_feature(cpu, ARM_FEATURE_PMU);
+    acc->dtb_compatible = "arm,cortex-a35";
+    set_class_feature(acc, ARM_FEATURE_V8);
+    set_class_feature(acc, ARM_FEATURE_NEON);
+    set_class_feature(acc, ARM_FEATURE_GENERIC_TIMER);
+    set_class_feature(acc, ARM_FEATURE_AARCH64);
+    set_class_feature(acc, ARM_FEATURE_CBAR_RO);
+    set_class_feature(acc, ARM_FEATURE_EL2);
+    set_class_feature(acc, ARM_FEATURE_EL3);
+    set_class_feature(acc, ARM_FEATURE_PMU);
 
     /* From B2.2 AArch64 identification registers. */
-    cpu->midr = 0x411fd040;
-    cpu->revidr = 0;
-    cpu->ctr = 0x84448004;
-    cpu->isar.id_pfr0 = 0x00000131;
-    cpu->isar.id_pfr1 = 0x00011011;
-    cpu->isar.id_dfr0 = 0x03010066;
-    cpu->id_afr0 = 0;
-    cpu->isar.id_mmfr0 = 0x10201105;
-    cpu->isar.id_mmfr1 = 0x40000000;
-    cpu->isar.id_mmfr2 = 0x01260000;
-    cpu->isar.id_mmfr3 = 0x02102211;
-    cpu->isar.id_isar0 = 0x02101110;
-    cpu->isar.id_isar1 = 0x13112111;
-    cpu->isar.id_isar2 = 0x21232042;
-    cpu->isar.id_isar3 = 0x01112131;
-    cpu->isar.id_isar4 = 0x00011142;
-    cpu->isar.id_isar5 = 0x00011121;
-    cpu->isar.id_aa64pfr0 = 0x00002222;
-    cpu->isar.id_aa64pfr1 = 0;
-    cpu->isar.id_aa64dfr0 = 0x10305106;
-    cpu->isar.id_aa64dfr1 = 0;
-    cpu->isar.id_aa64isar0 = 0x00011120;
-    cpu->isar.id_aa64isar1 = 0;
-    cpu->isar.id_aa64mmfr0 = 0x00101122;
-    cpu->isar.id_aa64mmfr1 = 0;
-    cpu->clidr = 0x0a200023;
-    cpu->dcz_blocksize = 4;
+    acc->midr = 0x411fd040;
+    acc->revidr = 0;
+    acc->ctr = 0x84448004;
+    acc->isar.id_pfr0 = 0x00000131;
+    acc->isar.id_pfr1 = 0x00011011;
+    acc->isar.id_dfr0 = 0x03010066;
+    acc->id_afr0 = 0;
+    acc->isar.id_mmfr0 = 0x10201105;
+    acc->isar.id_mmfr1 = 0x40000000;
+    acc->isar.id_mmfr2 = 0x01260000;
+    acc->isar.id_mmfr3 = 0x02102211;
+    acc->isar.id_isar0 = 0x02101110;
+    acc->isar.id_isar1 = 0x13112111;
+    acc->isar.id_isar2 = 0x21232042;
+    acc->isar.id_isar3 = 0x01112131;
+    acc->isar.id_isar4 = 0x00011142;
+    acc->isar.id_isar5 = 0x00011121;
+    acc->isar.id_aa64pfr0 = 0x00002222;
+    acc->isar.id_aa64pfr1 = 0;
+    acc->isar.id_aa64dfr0 = 0x10305106;
+    acc->isar.id_aa64dfr1 = 0;
+    acc->isar.id_aa64isar0 = 0x00011120;
+    acc->isar.id_aa64isar1 = 0;
+    acc->isar.id_aa64mmfr0 = 0x00101122;
+    acc->isar.id_aa64mmfr1 = 0;
+    acc->clidr = 0x0a200023;
+    acc->dcz_blocksize = 4;
 
     /* From B2.4 AArch64 Virtual Memory control registers */
-    cpu->reset_sctlr = 0x00c50838;
+    acc->reset_sctlr = 0x00c50838;
 
     /* From B2.10 AArch64 performance monitor registers */
-    cpu->isar.reset_pmcr_el0 = 0x410a3000;
+    acc->isar.reset_pmcr_el0 = 0x410a3000;
 
     /* From B2.29 Cache ID registers */
-    cpu->ccsidr[0] = 0x700fe01a; /* 32KB L1 dcache */
-    cpu->ccsidr[1] = 0x201fe00a; /* 32KB L1 icache */
-    cpu->ccsidr[2] = 0x703fe03a; /* 512KB L2 cache */
+    acc->ccsidr[0] = 0x700fe01a; /* 32KB L1 dcache */
+    acc->ccsidr[1] = 0x201fe00a; /* 32KB L1 icache */
+    acc->ccsidr[2] = 0x703fe03a; /* 512KB L2 cache */
 
     /* From B3.5 VGIC Type register */
-    cpu->gic_num_lrs = 4;
-    cpu->gic_vpribits = 5;
-    cpu->gic_vprebits = 5;
-    cpu->gic_pribits = 5;
+    acc->gic_num_lrs = 4;
+    acc->gic_vpribits = 5;
+    acc->gic_vprebits = 5;
+    acc->gic_pribits = 5;
 
     /* From C6.4 Debug ID Register */
-    cpu->isar.dbgdidr = 0x3516d000;
+    acc->isar.dbgdidr = 0x3516d000;
     /* From C6.5 Debug Device ID Register */
-    cpu->isar.dbgdevid = 0x00110f13;
+    acc->isar.dbgdevid = 0x00110f13;
     /* From C6.6 Debug Device ID Register 1 */
-    cpu->isar.dbgdevid1 = 0x2;
+    acc->isar.dbgdevid1 = 0x2;
 
     /* From Cortex-A35 SIMD and Floating-point Support r1p0 */
     /* From 3.2 AArch32 register summary */
-    cpu->reset_fpsid = 0x41034043;
+    acc->reset_fpsid = 0x41034043;
 
     /* From 2.2 AArch64 register summary */
-    cpu->isar.mvfr0 = 0x10110222;
-    cpu->isar.mvfr1 = 0x12111111;
-    cpu->isar.mvfr2 = 0x00000043;
+    acc->isar.mvfr0 = 0x10110222;
+    acc->isar.mvfr1 = 0x12111111;
+    acc->isar.mvfr2 = 0x00000043;
 
     /* These values are the same with A53/A57/A72. */
-    define_cortex_a72_a57_a53_cp_reginfo(cpu);
+    define_cortex_a72_a57_a53_cp_reginfo(acc);
 }
 
 void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp)
@@ -676,338 +676,338 @@ void arm_cpu_lpa2_finalize(ARMCPU *cpu, Error **errp)
     cpu->isar.id_aa64mmfr0 = t;
 }
 
-static void aarch64_a57_class_init(ARMCPUClass *cpu)
+static void aarch64_a57_class_init(ARMCPUClass *acc)
 {
-    cpu->dtb_compatible = "arm,cortex-a57";
-    set_class_feature(cpu, ARM_FEATURE_V8);
-    set_class_feature(cpu, ARM_FEATURE_NEON);
-    set_class_feature(cpu, ARM_FEATURE_GENERIC_TIMER);
-    set_class_feature(cpu, ARM_FEATURE_AARCH64);
-    set_class_feature(cpu, ARM_FEATURE_CBAR_RO);
-    set_class_feature(cpu, ARM_FEATURE_EL2);
-    set_class_feature(cpu, ARM_FEATURE_EL3);
-    set_class_feature(cpu, ARM_FEATURE_PMU);
-    cpu->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A57;
-    cpu->midr = 0x411fd070;
-    cpu->revidr = 0x00000000;
-    cpu->reset_fpsid = 0x41034070;
-    cpu->isar.mvfr0 = 0x10110222;
-    cpu->isar.mvfr1 = 0x12111111;
-    cpu->isar.mvfr2 = 0x00000043;
-    cpu->ctr = 0x8444c004;
-    cpu->reset_sctlr = 0x00c50838;
-    cpu->isar.id_pfr0 = 0x00000131;
-    cpu->isar.id_pfr1 = 0x00011011;
-    cpu->isar.id_dfr0 = 0x03010066;
-    cpu->id_afr0 = 0x00000000;
-    cpu->isar.id_mmfr0 = 0x10101105;
-    cpu->isar.id_mmfr1 = 0x40000000;
-    cpu->isar.id_mmfr2 = 0x01260000;
-    cpu->isar.id_mmfr3 = 0x02102211;
-    cpu->isar.id_isar0 = 0x02101110;
-    cpu->isar.id_isar1 = 0x13112111;
-    cpu->isar.id_isar2 = 0x21232042;
-    cpu->isar.id_isar3 = 0x01112131;
-    cpu->isar.id_isar4 = 0x00011142;
-    cpu->isar.id_isar5 = 0x00011121;
-    cpu->isar.id_isar6 = 0;
-    cpu->isar.id_aa64pfr0 = 0x00002222;
-    cpu->isar.id_aa64dfr0 = 0x10305106;
-    cpu->isar.id_aa64isar0 = 0x00011120;
-    cpu->isar.id_aa64mmfr0 = 0x00001124;
-    cpu->isar.dbgdidr = 0x3516d000;
-    cpu->isar.dbgdevid = 0x01110f13;
-    cpu->isar.dbgdevid1 = 0x2;
-    cpu->isar.reset_pmcr_el0 = 0x41013000;
-    cpu->clidr = 0x0a200023;
-    cpu->ccsidr[0] = 0x701fe00a; /* 32KB L1 dcache */
-    cpu->ccsidr[1] = 0x201fe012; /* 48KB L1 icache */
-    cpu->ccsidr[2] = 0x70ffe07a; /* 2048KB L2 cache */
-    cpu->dcz_blocksize = 4; /* 64 bytes */
-    cpu->gic_num_lrs = 4;
-    cpu->gic_vpribits = 5;
-    cpu->gic_vprebits = 5;
-    cpu->gic_pribits = 5;
-    define_cortex_a72_a57_a53_cp_reginfo(cpu);
+    acc->dtb_compatible = "arm,cortex-a57";
+    set_class_feature(acc, ARM_FEATURE_V8);
+    set_class_feature(acc, ARM_FEATURE_NEON);
+    set_class_feature(acc, ARM_FEATURE_GENERIC_TIMER);
+    set_class_feature(acc, ARM_FEATURE_AARCH64);
+    set_class_feature(acc, ARM_FEATURE_CBAR_RO);
+    set_class_feature(acc, ARM_FEATURE_EL2);
+    set_class_feature(acc, ARM_FEATURE_EL3);
+    set_class_feature(acc, ARM_FEATURE_PMU);
+    acc->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A57;
+    acc->midr = 0x411fd070;
+    acc->revidr = 0x00000000;
+    acc->reset_fpsid = 0x41034070;
+    acc->isar.mvfr0 = 0x10110222;
+    acc->isar.mvfr1 = 0x12111111;
+    acc->isar.mvfr2 = 0x00000043;
+    acc->ctr = 0x8444c004;
+    acc->reset_sctlr = 0x00c50838;
+    acc->isar.id_pfr0 = 0x00000131;
+    acc->isar.id_pfr1 = 0x00011011;
+    acc->isar.id_dfr0 = 0x03010066;
+    acc->id_afr0 = 0x00000000;
+    acc->isar.id_mmfr0 = 0x10101105;
+    acc->isar.id_mmfr1 = 0x40000000;
+    acc->isar.id_mmfr2 = 0x01260000;
+    acc->isar.id_mmfr3 = 0x02102211;
+    acc->isar.id_isar0 = 0x02101110;
+    acc->isar.id_isar1 = 0x13112111;
+    acc->isar.id_isar2 = 0x21232042;
+    acc->isar.id_isar3 = 0x01112131;
+    acc->isar.id_isar4 = 0x00011142;
+    acc->isar.id_isar5 = 0x00011121;
+    acc->isar.id_isar6 = 0;
+    acc->isar.id_aa64pfr0 = 0x00002222;
+    acc->isar.id_aa64dfr0 = 0x10305106;
+    acc->isar.id_aa64isar0 = 0x00011120;
+    acc->isar.id_aa64mmfr0 = 0x00001124;
+    acc->isar.dbgdidr = 0x3516d000;
+    acc->isar.dbgdevid = 0x01110f13;
+    acc->isar.dbgdevid1 = 0x2;
+    acc->isar.reset_pmcr_el0 = 0x41013000;
+    acc->clidr = 0x0a200023;
+    acc->ccsidr[0] = 0x701fe00a; /* 32KB L1 dcache */
+    acc->ccsidr[1] = 0x201fe012; /* 48KB L1 icache */
+    acc->ccsidr[2] = 0x70ffe07a; /* 2048KB L2 cache */
+    acc->dcz_blocksize = 4; /* 64 bytes */
+    acc->gic_num_lrs = 4;
+    acc->gic_vpribits = 5;
+    acc->gic_vprebits = 5;
+    acc->gic_pribits = 5;
+    define_cortex_a72_a57_a53_cp_reginfo(acc);
 }
 
-static void aarch64_a53_class_init(ARMCPUClass *cpu)
+static void aarch64_a53_class_init(ARMCPUClass *acc)
 {
-    cpu->dtb_compatible = "arm,cortex-a53";
-    set_class_feature(cpu, ARM_FEATURE_V8);
-    set_class_feature(cpu, ARM_FEATURE_NEON);
-    set_class_feature(cpu, ARM_FEATURE_GENERIC_TIMER);
-    set_class_feature(cpu, ARM_FEATURE_AARCH64);
-    set_class_feature(cpu, ARM_FEATURE_CBAR_RO);
-    set_class_feature(cpu, ARM_FEATURE_EL2);
-    set_class_feature(cpu, ARM_FEATURE_EL3);
-    set_class_feature(cpu, ARM_FEATURE_PMU);
-    cpu->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A53;
-    cpu->midr = 0x410fd034;
-    cpu->revidr = 0x00000000;
-    cpu->reset_fpsid = 0x41034070;
-    cpu->isar.mvfr0 = 0x10110222;
-    cpu->isar.mvfr1 = 0x12111111;
-    cpu->isar.mvfr2 = 0x00000043;
-    cpu->ctr = 0x84448004; /* L1Ip = VIPT */
-    cpu->reset_sctlr = 0x00c50838;
-    cpu->isar.id_pfr0 = 0x00000131;
-    cpu->isar.id_pfr1 = 0x00011011;
-    cpu->isar.id_dfr0 = 0x03010066;
-    cpu->id_afr0 = 0x00000000;
-    cpu->isar.id_mmfr0 = 0x10101105;
-    cpu->isar.id_mmfr1 = 0x40000000;
-    cpu->isar.id_mmfr2 = 0x01260000;
-    cpu->isar.id_mmfr3 = 0x02102211;
-    cpu->isar.id_isar0 = 0x02101110;
-    cpu->isar.id_isar1 = 0x13112111;
-    cpu->isar.id_isar2 = 0x21232042;
-    cpu->isar.id_isar3 = 0x01112131;
-    cpu->isar.id_isar4 = 0x00011142;
-    cpu->isar.id_isar5 = 0x00011121;
-    cpu->isar.id_isar6 = 0;
-    cpu->isar.id_aa64pfr0 = 0x00002222;
-    cpu->isar.id_aa64dfr0 = 0x10305106;
-    cpu->isar.id_aa64isar0 = 0x00011120;
-    cpu->isar.id_aa64mmfr0 = 0x00001122; /* 40 bit physical addr */
-    cpu->isar.dbgdidr = 0x3516d000;
-    cpu->isar.dbgdevid = 0x00110f13;
-    cpu->isar.dbgdevid1 = 0x1;
-    cpu->isar.reset_pmcr_el0 = 0x41033000;
-    cpu->clidr = 0x0a200023;
-    cpu->ccsidr[0] = 0x700fe01a; /* 32KB L1 dcache */
-    cpu->ccsidr[1] = 0x201fe00a; /* 32KB L1 icache */
-    cpu->ccsidr[2] = 0x707fe07a; /* 1024KB L2 cache */
-    cpu->dcz_blocksize = 4; /* 64 bytes */
-    cpu->gic_num_lrs = 4;
-    cpu->gic_vpribits = 5;
-    cpu->gic_vprebits = 5;
-    cpu->gic_pribits = 5;
-    define_cortex_a72_a57_a53_cp_reginfo(cpu);
+    acc->dtb_compatible = "arm,cortex-a53";
+    set_class_feature(acc, ARM_FEATURE_V8);
+    set_class_feature(acc, ARM_FEATURE_NEON);
+    set_class_feature(acc, ARM_FEATURE_GENERIC_TIMER);
+    set_class_feature(acc, ARM_FEATURE_AARCH64);
+    set_class_feature(acc, ARM_FEATURE_CBAR_RO);
+    set_class_feature(acc, ARM_FEATURE_EL2);
+    set_class_feature(acc, ARM_FEATURE_EL3);
+    set_class_feature(acc, ARM_FEATURE_PMU);
+    acc->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A53;
+    acc->midr = 0x410fd034;
+    acc->revidr = 0x00000000;
+    acc->reset_fpsid = 0x41034070;
+    acc->isar.mvfr0 = 0x10110222;
+    acc->isar.mvfr1 = 0x12111111;
+    acc->isar.mvfr2 = 0x00000043;
+    acc->ctr = 0x84448004; /* L1Ip = VIPT */
+    acc->reset_sctlr = 0x00c50838;
+    acc->isar.id_pfr0 = 0x00000131;
+    acc->isar.id_pfr1 = 0x00011011;
+    acc->isar.id_dfr0 = 0x03010066;
+    acc->id_afr0 = 0x00000000;
+    acc->isar.id_mmfr0 = 0x10101105;
+    acc->isar.id_mmfr1 = 0x40000000;
+    acc->isar.id_mmfr2 = 0x01260000;
+    acc->isar.id_mmfr3 = 0x02102211;
+    acc->isar.id_isar0 = 0x02101110;
+    acc->isar.id_isar1 = 0x13112111;
+    acc->isar.id_isar2 = 0x21232042;
+    acc->isar.id_isar3 = 0x01112131;
+    acc->isar.id_isar4 = 0x00011142;
+    acc->isar.id_isar5 = 0x00011121;
+    acc->isar.id_isar6 = 0;
+    acc->isar.id_aa64pfr0 = 0x00002222;
+    acc->isar.id_aa64dfr0 = 0x10305106;
+    acc->isar.id_aa64isar0 = 0x00011120;
+    acc->isar.id_aa64mmfr0 = 0x00001122; /* 40 bit physical addr */
+    acc->isar.dbgdidr = 0x3516d000;
+    acc->isar.dbgdevid = 0x00110f13;
+    acc->isar.dbgdevid1 = 0x1;
+    acc->isar.reset_pmcr_el0 = 0x41033000;
+    acc->clidr = 0x0a200023;
+    acc->ccsidr[0] = 0x700fe01a; /* 32KB L1 dcache */
+    acc->ccsidr[1] = 0x201fe00a; /* 32KB L1 icache */
+    acc->ccsidr[2] = 0x707fe07a; /* 1024KB L2 cache */
+    acc->dcz_blocksize = 4; /* 64 bytes */
+    acc->gic_num_lrs = 4;
+    acc->gic_vpribits = 5;
+    acc->gic_vprebits = 5;
+    acc->gic_pribits = 5;
+    define_cortex_a72_a57_a53_cp_reginfo(acc);
 }
 
-static void aarch64_a55_class_init(ARMCPUClass *cpu)
+static void aarch64_a55_class_init(ARMCPUClass *acc)
 {
-    cpu->dtb_compatible = "arm,cortex-a55";
-    set_class_feature(cpu, ARM_FEATURE_V8);
-    set_class_feature(cpu, ARM_FEATURE_NEON);
-    set_class_feature(cpu, ARM_FEATURE_GENERIC_TIMER);
-    set_class_feature(cpu, ARM_FEATURE_AARCH64);
-    set_class_feature(cpu, ARM_FEATURE_CBAR_RO);
-    set_class_feature(cpu, ARM_FEATURE_EL2);
-    set_class_feature(cpu, ARM_FEATURE_EL3);
-    set_class_feature(cpu, ARM_FEATURE_PMU);
+    acc->dtb_compatible = "arm,cortex-a55";
+    set_class_feature(acc, ARM_FEATURE_V8);
+    set_class_feature(acc, ARM_FEATURE_NEON);
+    set_class_feature(acc, ARM_FEATURE_GENERIC_TIMER);
+    set_class_feature(acc, ARM_FEATURE_AARCH64);
+    set_class_feature(acc, ARM_FEATURE_CBAR_RO);
+    set_class_feature(acc, ARM_FEATURE_EL2);
+    set_class_feature(acc, ARM_FEATURE_EL3);
+    set_class_feature(acc, ARM_FEATURE_PMU);
 
     /* Ordered by B2.4 AArch64 registers by functional group */
-    cpu->clidr = 0x82000023;
-    cpu->ctr = 0x84448004; /* L1Ip = VIPT */
-    cpu->dcz_blocksize = 4; /* 64 bytes */
-    cpu->isar.id_aa64dfr0  = 0x0000000010305408ull;
-    cpu->isar.id_aa64isar0 = 0x0000100010211120ull;
-    cpu->isar.id_aa64isar1 = 0x0000000000100001ull;
-    cpu->isar.id_aa64mmfr0 = 0x0000000000101122ull;
-    cpu->isar.id_aa64mmfr1 = 0x0000000010212122ull;
-    cpu->isar.id_aa64mmfr2 = 0x0000000000001011ull;
-    cpu->isar.id_aa64pfr0  = 0x0000000010112222ull;
-    cpu->isar.id_aa64pfr1  = 0x0000000000000010ull;
-    cpu->id_afr0       = 0x00000000;
-    cpu->isar.id_dfr0  = 0x04010088;
-    cpu->isar.id_isar0 = 0x02101110;
-    cpu->isar.id_isar1 = 0x13112111;
-    cpu->isar.id_isar2 = 0x21232042;
-    cpu->isar.id_isar3 = 0x01112131;
-    cpu->isar.id_isar4 = 0x00011142;
-    cpu->isar.id_isar5 = 0x01011121;
-    cpu->isar.id_isar6 = 0x00000010;
-    cpu->isar.id_mmfr0 = 0x10201105;
-    cpu->isar.id_mmfr1 = 0x40000000;
-    cpu->isar.id_mmfr2 = 0x01260000;
-    cpu->isar.id_mmfr3 = 0x02122211;
-    cpu->isar.id_mmfr4 = 0x00021110;
-    cpu->isar.id_pfr0  = 0x10010131;
-    cpu->isar.id_pfr1  = 0x00011011;
-    cpu->isar.id_pfr2  = 0x00000011;
-    cpu->midr = 0x412FD050;          /* r2p0 */
-    cpu->revidr = 0;
+    acc->clidr = 0x82000023;
+    acc->ctr = 0x84448004; /* L1Ip = VIPT */
+    acc->dcz_blocksize = 4; /* 64 bytes */
+    acc->isar.id_aa64dfr0  = 0x0000000010305408ull;
+    acc->isar.id_aa64isar0 = 0x0000100010211120ull;
+    acc->isar.id_aa64isar1 = 0x0000000000100001ull;
+    acc->isar.id_aa64mmfr0 = 0x0000000000101122ull;
+    acc->isar.id_aa64mmfr1 = 0x0000000010212122ull;
+    acc->isar.id_aa64mmfr2 = 0x0000000000001011ull;
+    acc->isar.id_aa64pfr0  = 0x0000000010112222ull;
+    acc->isar.id_aa64pfr1  = 0x0000000000000010ull;
+    acc->id_afr0       = 0x00000000;
+    acc->isar.id_dfr0  = 0x04010088;
+    acc->isar.id_isar0 = 0x02101110;
+    acc->isar.id_isar1 = 0x13112111;
+    acc->isar.id_isar2 = 0x21232042;
+    acc->isar.id_isar3 = 0x01112131;
+    acc->isar.id_isar4 = 0x00011142;
+    acc->isar.id_isar5 = 0x01011121;
+    acc->isar.id_isar6 = 0x00000010;
+    acc->isar.id_mmfr0 = 0x10201105;
+    acc->isar.id_mmfr1 = 0x40000000;
+    acc->isar.id_mmfr2 = 0x01260000;
+    acc->isar.id_mmfr3 = 0x02122211;
+    acc->isar.id_mmfr4 = 0x00021110;
+    acc->isar.id_pfr0  = 0x10010131;
+    acc->isar.id_pfr1  = 0x00011011;
+    acc->isar.id_pfr2  = 0x00000011;
+    acc->midr = 0x412FD050;          /* r2p0 */
+    acc->revidr = 0;
 
     /* From B2.23 CCSIDR_EL1 */
-    cpu->ccsidr[0] = 0x700fe01a; /* 32KB L1 dcache */
-    cpu->ccsidr[1] = 0x200fe01a; /* 32KB L1 icache */
-    cpu->ccsidr[2] = 0x703fe07a; /* 512KB L2 cache */
+    acc->ccsidr[0] = 0x700fe01a; /* 32KB L1 dcache */
+    acc->ccsidr[1] = 0x200fe01a; /* 32KB L1 icache */
+    acc->ccsidr[2] = 0x703fe07a; /* 512KB L2 cache */
 
     /* From B2.96 SCTLR_EL3 */
-    cpu->reset_sctlr = 0x30c50838;
+    acc->reset_sctlr = 0x30c50838;
 
     /* From B4.45 ICH_VTR_EL2 */
-    cpu->gic_num_lrs = 4;
-    cpu->gic_vpribits = 5;
-    cpu->gic_vprebits = 5;
-    cpu->gic_pribits = 5;
+    acc->gic_num_lrs = 4;
+    acc->gic_vpribits = 5;
+    acc->gic_vprebits = 5;
+    acc->gic_pribits = 5;
 
-    cpu->isar.mvfr0 = 0x10110222;
-    cpu->isar.mvfr1 = 0x13211111;
-    cpu->isar.mvfr2 = 0x00000043;
+    acc->isar.mvfr0 = 0x10110222;
+    acc->isar.mvfr1 = 0x13211111;
+    acc->isar.mvfr2 = 0x00000043;
 
     /* From D5.4 AArch64 PMU register summary */
-    cpu->isar.reset_pmcr_el0 = 0x410b3000;
+    acc->isar.reset_pmcr_el0 = 0x410b3000;
 }
 
-static void aarch64_a72_class_init(ARMCPUClass *cpu)
+static void aarch64_a72_class_init(ARMCPUClass *acc)
 {
-    cpu->dtb_compatible = "arm,cortex-a72";
-    set_class_feature(cpu, ARM_FEATURE_V8);
-    set_class_feature(cpu, ARM_FEATURE_NEON);
-    set_class_feature(cpu, ARM_FEATURE_GENERIC_TIMER);
-    set_class_feature(cpu, ARM_FEATURE_AARCH64);
-    set_class_feature(cpu, ARM_FEATURE_CBAR_RO);
-    set_class_feature(cpu, ARM_FEATURE_EL2);
-    set_class_feature(cpu, ARM_FEATURE_EL3);
-    set_class_feature(cpu, ARM_FEATURE_PMU);
-    cpu->midr = 0x410fd083;
-    cpu->revidr = 0x00000000;
-    cpu->reset_fpsid = 0x41034080;
-    cpu->isar.mvfr0 = 0x10110222;
-    cpu->isar.mvfr1 = 0x12111111;
-    cpu->isar.mvfr2 = 0x00000043;
-    cpu->ctr = 0x8444c004;
-    cpu->reset_sctlr = 0x00c50838;
-    cpu->isar.id_pfr0 = 0x00000131;
-    cpu->isar.id_pfr1 = 0x00011011;
-    cpu->isar.id_dfr0 = 0x03010066;
-    cpu->id_afr0 = 0x00000000;
-    cpu->isar.id_mmfr0 = 0x10201105;
-    cpu->isar.id_mmfr1 = 0x40000000;
-    cpu->isar.id_mmfr2 = 0x01260000;
-    cpu->isar.id_mmfr3 = 0x02102211;
-    cpu->isar.id_isar0 = 0x02101110;
-    cpu->isar.id_isar1 = 0x13112111;
-    cpu->isar.id_isar2 = 0x21232042;
-    cpu->isar.id_isar3 = 0x01112131;
-    cpu->isar.id_isar4 = 0x00011142;
-    cpu->isar.id_isar5 = 0x00011121;
-    cpu->isar.id_aa64pfr0 = 0x00002222;
-    cpu->isar.id_aa64dfr0 = 0x10305106;
-    cpu->isar.id_aa64isar0 = 0x00011120;
-    cpu->isar.id_aa64mmfr0 = 0x00001124;
-    cpu->isar.dbgdidr = 0x3516d000;
-    cpu->isar.dbgdevid = 0x01110f13;
-    cpu->isar.dbgdevid1 = 0x2;
-    cpu->isar.reset_pmcr_el0 = 0x41023000;
-    cpu->clidr = 0x0a200023;
-    cpu->ccsidr[0] = 0x701fe00a; /* 32KB L1 dcache */
-    cpu->ccsidr[1] = 0x201fe012; /* 48KB L1 icache */
-    cpu->ccsidr[2] = 0x707fe07a; /* 1MB L2 cache */
-    cpu->dcz_blocksize = 4; /* 64 bytes */
-    cpu->gic_num_lrs = 4;
-    cpu->gic_vpribits = 5;
-    cpu->gic_vprebits = 5;
-    cpu->gic_pribits = 5;
-    define_cortex_a72_a57_a53_cp_reginfo(cpu);
+    acc->dtb_compatible = "arm,cortex-a72";
+    set_class_feature(acc, ARM_FEATURE_V8);
+    set_class_feature(acc, ARM_FEATURE_NEON);
+    set_class_feature(acc, ARM_FEATURE_GENERIC_TIMER);
+    set_class_feature(acc, ARM_FEATURE_AARCH64);
+    set_class_feature(acc, ARM_FEATURE_CBAR_RO);
+    set_class_feature(acc, ARM_FEATURE_EL2);
+    set_class_feature(acc, ARM_FEATURE_EL3);
+    set_class_feature(acc, ARM_FEATURE_PMU);
+    acc->midr = 0x410fd083;
+    acc->revidr = 0x00000000;
+    acc->reset_fpsid = 0x41034080;
+    acc->isar.mvfr0 = 0x10110222;
+    acc->isar.mvfr1 = 0x12111111;
+    acc->isar.mvfr2 = 0x00000043;
+    acc->ctr = 0x8444c004;
+    acc->reset_sctlr = 0x00c50838;
+    acc->isar.id_pfr0 = 0x00000131;
+    acc->isar.id_pfr1 = 0x00011011;
+    acc->isar.id_dfr0 = 0x03010066;
+    acc->id_afr0 = 0x00000000;
+    acc->isar.id_mmfr0 = 0x10201105;
+    acc->isar.id_mmfr1 = 0x40000000;
+    acc->isar.id_mmfr2 = 0x01260000;
+    acc->isar.id_mmfr3 = 0x02102211;
+    acc->isar.id_isar0 = 0x02101110;
+    acc->isar.id_isar1 = 0x13112111;
+    acc->isar.id_isar2 = 0x21232042;
+    acc->isar.id_isar3 = 0x01112131;
+    acc->isar.id_isar4 = 0x00011142;
+    acc->isar.id_isar5 = 0x00011121;
+    acc->isar.id_aa64pfr0 = 0x00002222;
+    acc->isar.id_aa64dfr0 = 0x10305106;
+    acc->isar.id_aa64isar0 = 0x00011120;
+    acc->isar.id_aa64mmfr0 = 0x00001124;
+    acc->isar.dbgdidr = 0x3516d000;
+    acc->isar.dbgdevid = 0x01110f13;
+    acc->isar.dbgdevid1 = 0x2;
+    acc->isar.reset_pmcr_el0 = 0x41023000;
+    acc->clidr = 0x0a200023;
+    acc->ccsidr[0] = 0x701fe00a; /* 32KB L1 dcache */
+    acc->ccsidr[1] = 0x201fe012; /* 48KB L1 icache */
+    acc->ccsidr[2] = 0x707fe07a; /* 1MB L2 cache */
+    acc->dcz_blocksize = 4; /* 64 bytes */
+    acc->gic_num_lrs = 4;
+    acc->gic_vpribits = 5;
+    acc->gic_vprebits = 5;
+    acc->gic_pribits = 5;
+    define_cortex_a72_a57_a53_cp_reginfo(acc);
 }
 
-static void aarch64_a76_class_init(ARMCPUClass *cpu)
+static void aarch64_a76_class_init(ARMCPUClass *acc)
 {
-    cpu->dtb_compatible = "arm,cortex-a76";
-    set_class_feature(cpu, ARM_FEATURE_V8);
-    set_class_feature(cpu, ARM_FEATURE_NEON);
-    set_class_feature(cpu, ARM_FEATURE_GENERIC_TIMER);
-    set_class_feature(cpu, ARM_FEATURE_AARCH64);
-    set_class_feature(cpu, ARM_FEATURE_CBAR_RO);
-    set_class_feature(cpu, ARM_FEATURE_EL2);
-    set_class_feature(cpu, ARM_FEATURE_EL3);
-    set_class_feature(cpu, ARM_FEATURE_PMU);
+    acc->dtb_compatible = "arm,cortex-a76";
+    set_class_feature(acc, ARM_FEATURE_V8);
+    set_class_feature(acc, ARM_FEATURE_NEON);
+    set_class_feature(acc, ARM_FEATURE_GENERIC_TIMER);
+    set_class_feature(acc, ARM_FEATURE_AARCH64);
+    set_class_feature(acc, ARM_FEATURE_CBAR_RO);
+    set_class_feature(acc, ARM_FEATURE_EL2);
+    set_class_feature(acc, ARM_FEATURE_EL3);
+    set_class_feature(acc, ARM_FEATURE_PMU);
 
     /* Ordered by B2.4 AArch64 registers by functional group */
-    cpu->clidr = 0x82000023;
-    cpu->ctr = 0x8444C004;
-    cpu->dcz_blocksize = 4;
-    cpu->isar.id_aa64dfr0  = 0x0000000010305408ull;
-    cpu->isar.id_aa64isar0 = 0x0000100010211120ull;
-    cpu->isar.id_aa64isar1 = 0x0000000000100001ull;
-    cpu->isar.id_aa64mmfr0 = 0x0000000000101122ull;
-    cpu->isar.id_aa64mmfr1 = 0x0000000010212122ull;
-    cpu->isar.id_aa64mmfr2 = 0x0000000000001011ull;
-    cpu->isar.id_aa64pfr0  = 0x1100000010111112ull; /* GIC filled in later */
-    cpu->isar.id_aa64pfr1  = 0x0000000000000010ull;
-    cpu->id_afr0       = 0x00000000;
-    cpu->isar.id_dfr0  = 0x04010088;
-    cpu->isar.id_isar0 = 0x02101110;
-    cpu->isar.id_isar1 = 0x13112111;
-    cpu->isar.id_isar2 = 0x21232042;
-    cpu->isar.id_isar3 = 0x01112131;
-    cpu->isar.id_isar4 = 0x00010142;
-    cpu->isar.id_isar5 = 0x01011121;
-    cpu->isar.id_isar6 = 0x00000010;
-    cpu->isar.id_mmfr0 = 0x10201105;
-    cpu->isar.id_mmfr1 = 0x40000000;
-    cpu->isar.id_mmfr2 = 0x01260000;
-    cpu->isar.id_mmfr3 = 0x02122211;
-    cpu->isar.id_mmfr4 = 0x00021110;
-    cpu->isar.id_pfr0  = 0x10010131;
-    cpu->isar.id_pfr1  = 0x00010000; /* GIC filled in later */
-    cpu->isar.id_pfr2  = 0x00000011;
-    cpu->midr = 0x414fd0b1;          /* r4p1 */
-    cpu->revidr = 0;
+    acc->clidr = 0x82000023;
+    acc->ctr = 0x8444C004;
+    acc->dcz_blocksize = 4;
+    acc->isar.id_aa64dfr0  = 0x0000000010305408ull;
+    acc->isar.id_aa64isar0 = 0x0000100010211120ull;
+    acc->isar.id_aa64isar1 = 0x0000000000100001ull;
+    acc->isar.id_aa64mmfr0 = 0x0000000000101122ull;
+    acc->isar.id_aa64mmfr1 = 0x0000000010212122ull;
+    acc->isar.id_aa64mmfr2 = 0x0000000000001011ull;
+    acc->isar.id_aa64pfr0  = 0x1100000010111112ull; /* GIC filled in later */
+    acc->isar.id_aa64pfr1  = 0x0000000000000010ull;
+    acc->id_afr0       = 0x00000000;
+    acc->isar.id_dfr0  = 0x04010088;
+    acc->isar.id_isar0 = 0x02101110;
+    acc->isar.id_isar1 = 0x13112111;
+    acc->isar.id_isar2 = 0x21232042;
+    acc->isar.id_isar3 = 0x01112131;
+    acc->isar.id_isar4 = 0x00010142;
+    acc->isar.id_isar5 = 0x01011121;
+    acc->isar.id_isar6 = 0x00000010;
+    acc->isar.id_mmfr0 = 0x10201105;
+    acc->isar.id_mmfr1 = 0x40000000;
+    acc->isar.id_mmfr2 = 0x01260000;
+    acc->isar.id_mmfr3 = 0x02122211;
+    acc->isar.id_mmfr4 = 0x00021110;
+    acc->isar.id_pfr0  = 0x10010131;
+    acc->isar.id_pfr1  = 0x00010000; /* GIC filled in later */
+    acc->isar.id_pfr2  = 0x00000011;
+    acc->midr = 0x414fd0b1;          /* r4p1 */
+    acc->revidr = 0;
 
     /* From B2.18 CCSIDR_EL1 */
-    cpu->ccsidr[0] = 0x701fe01a; /* 64KB L1 dcache */
-    cpu->ccsidr[1] = 0x201fe01a; /* 64KB L1 icache */
-    cpu->ccsidr[2] = 0x707fe03a; /* 512KB L2 cache */
+    acc->ccsidr[0] = 0x701fe01a; /* 64KB L1 dcache */
+    acc->ccsidr[1] = 0x201fe01a; /* 64KB L1 icache */
+    acc->ccsidr[2] = 0x707fe03a; /* 512KB L2 cache */
 
     /* From B2.93 SCTLR_EL3 */
-    cpu->reset_sctlr = 0x30c50838;
+    acc->reset_sctlr = 0x30c50838;
 
     /* From B4.23 ICH_VTR_EL2 */
-    cpu->gic_num_lrs = 4;
-    cpu->gic_vpribits = 5;
-    cpu->gic_vprebits = 5;
-    cpu->gic_pribits = 5;
+    acc->gic_num_lrs = 4;
+    acc->gic_vpribits = 5;
+    acc->gic_vprebits = 5;
+    acc->gic_pribits = 5;
 
     /* From B5.1 AdvSIMD AArch64 register summary */
-    cpu->isar.mvfr0 = 0x10110222;
-    cpu->isar.mvfr1 = 0x13211111;
-    cpu->isar.mvfr2 = 0x00000043;
+    acc->isar.mvfr0 = 0x10110222;
+    acc->isar.mvfr1 = 0x13211111;
+    acc->isar.mvfr2 = 0x00000043;
 
     /* From D5.1 AArch64 PMU register summary */
-    cpu->isar.reset_pmcr_el0 = 0x410b3000;
+    acc->isar.reset_pmcr_el0 = 0x410b3000;
 }
 
-static void aarch64_a64fx_class_init(ARMCPUClass *cpu)
+static void aarch64_a64fx_class_init(ARMCPUClass *acc)
 {
-    cpu->dtb_compatible = "arm,a64fx";
-    set_class_feature(cpu, ARM_FEATURE_V8);
-    set_class_feature(cpu, ARM_FEATURE_NEON);
-    set_class_feature(cpu, ARM_FEATURE_GENERIC_TIMER);
-    set_class_feature(cpu, ARM_FEATURE_AARCH64);
-    set_class_feature(cpu, ARM_FEATURE_EL2);
-    set_class_feature(cpu, ARM_FEATURE_EL3);
-    set_class_feature(cpu, ARM_FEATURE_PMU);
-    cpu->midr = 0x461f0010;
-    cpu->revidr = 0x00000000;
-    cpu->ctr = 0x86668006;
-    cpu->reset_sctlr = 0x30000180;
-    cpu->isar.id_aa64pfr0 =   0x0000000101111111; /* No RAS Extensions */
-    cpu->isar.id_aa64pfr1 = 0x0000000000000000;
-    cpu->isar.id_aa64dfr0 = 0x0000000010305408;
-    cpu->isar.id_aa64dfr1 = 0x0000000000000000;
-    cpu->id_aa64afr0 = 0x0000000000000000;
-    cpu->id_aa64afr1 = 0x0000000000000000;
-    cpu->isar.id_aa64mmfr0 = 0x0000000000001122;
-    cpu->isar.id_aa64mmfr1 = 0x0000000011212100;
-    cpu->isar.id_aa64mmfr2 = 0x0000000000001011;
-    cpu->isar.id_aa64isar0 = 0x0000000010211120;
-    cpu->isar.id_aa64isar1 = 0x0000000000010001;
-    cpu->isar.id_aa64zfr0 = 0x0000000000000000;
-    cpu->clidr = 0x0000000080000023;
-    cpu->ccsidr[0] = 0x7007e01c; /* 64KB L1 dcache */
-    cpu->ccsidr[1] = 0x2007e01c; /* 64KB L1 icache */
-    cpu->ccsidr[2] = 0x70ffe07c; /* 8MB L2 cache */
-    cpu->dcz_blocksize = 6; /* 256 bytes */
-    cpu->gic_num_lrs = 4;
-    cpu->gic_vpribits = 5;
-    cpu->gic_vprebits = 5;
-    cpu->gic_pribits = 5;
-    cpu->isar.reset_pmcr_el0 = 0x46014040;
+    acc->dtb_compatible = "arm,a64fx";
+    set_class_feature(acc, ARM_FEATURE_V8);
+    set_class_feature(acc, ARM_FEATURE_NEON);
+    set_class_feature(acc, ARM_FEATURE_GENERIC_TIMER);
+    set_class_feature(acc, ARM_FEATURE_AARCH64);
+    set_class_feature(acc, ARM_FEATURE_EL2);
+    set_class_feature(acc, ARM_FEATURE_EL3);
+    set_class_feature(acc, ARM_FEATURE_PMU);
+    acc->midr = 0x461f0010;
+    acc->revidr = 0x00000000;
+    acc->ctr = 0x86668006;
+    acc->reset_sctlr = 0x30000180;
+    acc->isar.id_aa64pfr0 =   0x0000000101111111; /* No RAS Extensions */
+    acc->isar.id_aa64pfr1 = 0x0000000000000000;
+    acc->isar.id_aa64dfr0 = 0x0000000010305408;
+    acc->isar.id_aa64dfr1 = 0x0000000000000000;
+    acc->id_aa64afr0 = 0x0000000000000000;
+    acc->id_aa64afr1 = 0x0000000000000000;
+    acc->isar.id_aa64mmfr0 = 0x0000000000001122;
+    acc->isar.id_aa64mmfr1 = 0x0000000011212100;
+    acc->isar.id_aa64mmfr2 = 0x0000000000001011;
+    acc->isar.id_aa64isar0 = 0x0000000010211120;
+    acc->isar.id_aa64isar1 = 0x0000000000010001;
+    acc->isar.id_aa64zfr0 = 0x0000000000000000;
+    acc->clidr = 0x0000000080000023;
+    acc->ccsidr[0] = 0x7007e01c; /* 64KB L1 dcache */
+    acc->ccsidr[1] = 0x2007e01c; /* 64KB L1 icache */
+    acc->ccsidr[2] = 0x70ffe07c; /* 8MB L2 cache */
+    acc->dcz_blocksize = 6; /* 256 bytes */
+    acc->gic_num_lrs = 4;
+    acc->gic_vpribits = 5;
+    acc->gic_vprebits = 5;
+    acc->gic_pribits = 5;
+    acc->isar.reset_pmcr_el0 = 0x46014040;
 
     /* TODO:  Add A64FX specific HPC extension registers */
 }
@@ -1023,71 +1023,71 @@ static void aarch64_a64fx_object_init(Object *obj)
                           | (1 << 3); /* 512bit */
 }
 
-static void aarch64_neoverse_n1_class_init(ARMCPUClass *cpu)
+static void aarch64_neoverse_n1_class_init(ARMCPUClass *acc)
 {
-    cpu->dtb_compatible = "arm,neoverse-n1";
-    set_class_feature(cpu, ARM_FEATURE_V8);
-    set_class_feature(cpu, ARM_FEATURE_NEON);
-    set_class_feature(cpu, ARM_FEATURE_GENERIC_TIMER);
-    set_class_feature(cpu, ARM_FEATURE_AARCH64);
-    set_class_feature(cpu, ARM_FEATURE_CBAR_RO);
-    set_class_feature(cpu, ARM_FEATURE_EL2);
-    set_class_feature(cpu, ARM_FEATURE_EL3);
-    set_class_feature(cpu, ARM_FEATURE_PMU);
+    acc->dtb_compatible = "arm,neoverse-n1";
+    set_class_feature(acc, ARM_FEATURE_V8);
+    set_class_feature(acc, ARM_FEATURE_NEON);
+    set_class_feature(acc, ARM_FEATURE_GENERIC_TIMER);
+    set_class_feature(acc, ARM_FEATURE_AARCH64);
+    set_class_feature(acc, ARM_FEATURE_CBAR_RO);
+    set_class_feature(acc, ARM_FEATURE_EL2);
+    set_class_feature(acc, ARM_FEATURE_EL3);
+    set_class_feature(acc, ARM_FEATURE_PMU);
 
     /* Ordered by B2.4 AArch64 registers by functional group */
-    cpu->clidr = 0x82000023;
-    cpu->ctr = 0x8444c004;
-    cpu->dcz_blocksize = 4;
-    cpu->isar.id_aa64dfr0  = 0x0000000110305408ull;
-    cpu->isar.id_aa64isar0 = 0x0000100010211120ull;
-    cpu->isar.id_aa64isar1 = 0x0000000000100001ull;
-    cpu->isar.id_aa64mmfr0 = 0x0000000000101125ull;
-    cpu->isar.id_aa64mmfr1 = 0x0000000010212122ull;
-    cpu->isar.id_aa64mmfr2 = 0x0000000000001011ull;
-    cpu->isar.id_aa64pfr0  = 0x1100000010111112ull; /* GIC filled in later */
-    cpu->isar.id_aa64pfr1  = 0x0000000000000020ull;
-    cpu->id_afr0       = 0x00000000;
-    cpu->isar.id_dfr0  = 0x04010088;
-    cpu->isar.id_isar0 = 0x02101110;
-    cpu->isar.id_isar1 = 0x13112111;
-    cpu->isar.id_isar2 = 0x21232042;
-    cpu->isar.id_isar3 = 0x01112131;
-    cpu->isar.id_isar4 = 0x00010142;
-    cpu->isar.id_isar5 = 0x01011121;
-    cpu->isar.id_isar6 = 0x00000010;
-    cpu->isar.id_mmfr0 = 0x10201105;
-    cpu->isar.id_mmfr1 = 0x40000000;
-    cpu->isar.id_mmfr2 = 0x01260000;
-    cpu->isar.id_mmfr3 = 0x02122211;
-    cpu->isar.id_mmfr4 = 0x00021110;
-    cpu->isar.id_pfr0  = 0x10010131;
-    cpu->isar.id_pfr1  = 0x00010000; /* GIC filled in later */
-    cpu->isar.id_pfr2  = 0x00000011;
-    cpu->midr = 0x414fd0c1;          /* r4p1 */
-    cpu->revidr = 0;
+    acc->clidr = 0x82000023;
+    acc->ctr = 0x8444c004;
+    acc->dcz_blocksize = 4;
+    acc->isar.id_aa64dfr0  = 0x0000000110305408ull;
+    acc->isar.id_aa64isar0 = 0x0000100010211120ull;
+    acc->isar.id_aa64isar1 = 0x0000000000100001ull;
+    acc->isar.id_aa64mmfr0 = 0x0000000000101125ull;
+    acc->isar.id_aa64mmfr1 = 0x0000000010212122ull;
+    acc->isar.id_aa64mmfr2 = 0x0000000000001011ull;
+    acc->isar.id_aa64pfr0  = 0x1100000010111112ull; /* GIC filled in later */
+    acc->isar.id_aa64pfr1  = 0x0000000000000020ull;
+    acc->id_afr0       = 0x00000000;
+    acc->isar.id_dfr0  = 0x04010088;
+    acc->isar.id_isar0 = 0x02101110;
+    acc->isar.id_isar1 = 0x13112111;
+    acc->isar.id_isar2 = 0x21232042;
+    acc->isar.id_isar3 = 0x01112131;
+    acc->isar.id_isar4 = 0x00010142;
+    acc->isar.id_isar5 = 0x01011121;
+    acc->isar.id_isar6 = 0x00000010;
+    acc->isar.id_mmfr0 = 0x10201105;
+    acc->isar.id_mmfr1 = 0x40000000;
+    acc->isar.id_mmfr2 = 0x01260000;
+    acc->isar.id_mmfr3 = 0x02122211;
+    acc->isar.id_mmfr4 = 0x00021110;
+    acc->isar.id_pfr0  = 0x10010131;
+    acc->isar.id_pfr1  = 0x00010000; /* GIC filled in later */
+    acc->isar.id_pfr2  = 0x00000011;
+    acc->midr = 0x414fd0c1;          /* r4p1 */
+    acc->revidr = 0;
 
     /* From B2.23 CCSIDR_EL1 */
-    cpu->ccsidr[0] = 0x701fe01a; /* 64KB L1 dcache */
-    cpu->ccsidr[1] = 0x201fe01a; /* 64KB L1 icache */
-    cpu->ccsidr[2] = 0x70ffe03a; /* 1MB L2 cache */
+    acc->ccsidr[0] = 0x701fe01a; /* 64KB L1 dcache */
+    acc->ccsidr[1] = 0x201fe01a; /* 64KB L1 icache */
+    acc->ccsidr[2] = 0x70ffe03a; /* 1MB L2 cache */
 
     /* From B2.98 SCTLR_EL3 */
-    cpu->reset_sctlr = 0x30c50838;
+    acc->reset_sctlr = 0x30c50838;
 
     /* From B4.23 ICH_VTR_EL2 */
-    cpu->gic_num_lrs = 4;
-    cpu->gic_vpribits = 5;
-    cpu->gic_vprebits = 5;
-    cpu->gic_pribits = 5;
+    acc->gic_num_lrs = 4;
+    acc->gic_vpribits = 5;
+    acc->gic_vprebits = 5;
+    acc->gic_pribits = 5;
 
     /* From B5.1 AdvSIMD AArch64 register summary */
-    cpu->isar.mvfr0 = 0x10110222;
-    cpu->isar.mvfr1 = 0x13211111;
-    cpu->isar.mvfr2 = 0x00000043;
+    acc->isar.mvfr0 = 0x10110222;
+    acc->isar.mvfr1 = 0x13211111;
+    acc->isar.mvfr2 = 0x00000043;
 
     /* From D5.1 AArch64 PMU register summary */
-    cpu->isar.reset_pmcr_el0 = 0x410c3000;
+    acc->isar.reset_pmcr_el0 = 0x410c3000;
 }
 
 static void aarch64_host_class_init(ARMCPUClass *acc)
@@ -1136,22 +1136,22 @@ static void aarch64_host_object_init(Object *obj)
  * The version of '-cpu max' for qemu-system-arm is defined in cpu.c;
  * this version only needs to handle 64 bits.
  */
-static bool aarch64_max_class_late_init(ARMCPUClass *cpu, Error **errp)
+static bool aarch64_max_class_late_init(ARMCPUClass *acc, Error **errp)
 {
     uint64_t t;
     uint32_t u;
 
     if (kvm_enabled() || hvf_enabled()) {
         /* With KVM or HVF, '-cpu max' is identical to '-cpu host' */
-        return aarch64_host_class_late_init(cpu, errp);
+        return aarch64_host_class_late_init(acc, errp);
     }
 
     /*
      * '-cpu max' for TCG: we currently do this as "A57 with extra things"
      * Retain the more generic dtb_compatible setting from host_class_init.
      */
-    aarch64_a57_class_init(cpu);
-    cpu->dtb_compatible = "arm,arm-v8";
+    aarch64_a57_class_init(acc);
+    acc->dtb_compatible = "arm,arm-v8";
 
     /*
      * Reset MIDR so the guest doesn't mistake our 'max' CPU type for a real
@@ -1170,18 +1170,18 @@ static bool aarch64_max_class_late_init(ARMCPUClass *cpu, Error **errp)
     t = FIELD_DP64(t, MIDR_EL1, PARTNUM, 'Q');
     t = FIELD_DP64(t, MIDR_EL1, VARIANT, 0);
     t = FIELD_DP64(t, MIDR_EL1, REVISION, 0);
-    cpu->midr = t;
+    acc->midr = t;
 
     /*
      * We're going to set FEAT_S2FWB, which mandates that CLIDR_EL1.{LoUU,LoUIS}
      * are zero.
      */
-    u = cpu->clidr;
+    u = acc->clidr;
     u = FIELD_DP32(u, CLIDR_EL1, LOUIS, 0);
     u = FIELD_DP32(u, CLIDR_EL1, LOUU, 0);
-    cpu->clidr = u;
+    acc->clidr = u;
 
-    t = cpu->isar.id_aa64isar0;
+    t = acc->isar.id_aa64isar0;
     t = FIELD_DP64(t, ID_AA64ISAR0, AES, 2);      /* FEAT_PMULL */
     t = FIELD_DP64(t, ID_AA64ISAR0, SHA1, 1);     /* FEAT_SHA1 */
     t = FIELD_DP64(t, ID_AA64ISAR0, SHA2, 2);     /* FEAT_SHA512 */
@@ -1196,9 +1196,9 @@ static bool aarch64_max_class_late_init(ARMCPUClass *cpu, Error **errp)
     t = FIELD_DP64(t, ID_AA64ISAR0, TS, 2);       /* FEAT_FlagM2 */
     t = FIELD_DP64(t, ID_AA64ISAR0, TLB, 2);      /* FEAT_TLBIRANGE */
     t = FIELD_DP64(t, ID_AA64ISAR0, RNDR, 1);     /* FEAT_RNG */
-    cpu->isar.id_aa64isar0 = t;
+    acc->isar.id_aa64isar0 = t;
 
-    t = cpu->isar.id_aa64isar1;
+    t = acc->isar.id_aa64isar1;
     t = FIELD_DP64(t, ID_AA64ISAR1, DPB, 2);      /* FEAT_DPB2 */
     t = FIELD_DP64(t, ID_AA64ISAR1, JSCVT, 1);    /* FEAT_JSCVT */
     t = FIELD_DP64(t, ID_AA64ISAR1, FCMA, 1);     /* FEAT_FCMA */
@@ -1209,9 +1209,9 @@ static bool aarch64_max_class_late_init(ARMCPUClass *cpu, Error **errp)
     t = FIELD_DP64(t, ID_AA64ISAR1, BF16, 1);     /* FEAT_BF16 */
     t = FIELD_DP64(t, ID_AA64ISAR1, DGH, 1);      /* FEAT_DGH */
     t = FIELD_DP64(t, ID_AA64ISAR1, I8MM, 1);     /* FEAT_I8MM */
-    cpu->isar.id_aa64isar1 = t;
+    acc->isar.id_aa64isar1 = t;
 
-    t = cpu->isar.id_aa64pfr0;
+    t = acc->isar.id_aa64pfr0;
     t = FIELD_DP64(t, ID_AA64PFR0, FP, 1);        /* FEAT_FP16 */
     t = FIELD_DP64(t, ID_AA64PFR0, ADVSIMD, 1);   /* FEAT_FP16 */
     t = FIELD_DP64(t, ID_AA64PFR0, RAS, 2);       /* FEAT_RASv1p1 + FEAT_DoubleFault */
@@ -1220,9 +1220,9 @@ static bool aarch64_max_class_late_init(ARMCPUClass *cpu, Error **errp)
     t = FIELD_DP64(t, ID_AA64PFR0, DIT, 1);       /* FEAT_DIT */
     t = FIELD_DP64(t, ID_AA64PFR0, CSV2, 2);      /* FEAT_CSV2_2 */
     t = FIELD_DP64(t, ID_AA64PFR0, CSV3, 1);      /* FEAT_CSV3 */
-    cpu->isar.id_aa64pfr0 = t;
+    acc->isar.id_aa64pfr0 = t;
 
-    t = cpu->isar.id_aa64pfr1;
+    t = acc->isar.id_aa64pfr1;
     t = FIELD_DP64(t, ID_AA64PFR1, BT, 1);        /* FEAT_BTI */
     t = FIELD_DP64(t, ID_AA64PFR1, SSBS, 2);      /* FEAT_SSBS2 */
     /*
@@ -1234,17 +1234,17 @@ static bool aarch64_max_class_late_init(ARMCPUClass *cpu, Error **errp)
     t = FIELD_DP64(t, ID_AA64PFR1, RAS_FRAC, 0);  /* FEAT_RASv1p1 + FEAT_DoubleFault */
     t = FIELD_DP64(t, ID_AA64PFR1, SME, 1);       /* FEAT_SME */
     t = FIELD_DP64(t, ID_AA64PFR1, CSV2_FRAC, 0); /* FEAT_CSV2_2 */
-    cpu->isar.id_aa64pfr1 = t;
+    acc->isar.id_aa64pfr1 = t;
 
-    t = cpu->isar.id_aa64mmfr0;
+    t = acc->isar.id_aa64mmfr0;
     t = FIELD_DP64(t, ID_AA64MMFR0, PARANGE, 6); /* FEAT_LPA: 52 bits */
     t = FIELD_DP64(t, ID_AA64MMFR0, TGRAN16, 1);   /* 16k pages supported */
     t = FIELD_DP64(t, ID_AA64MMFR0, TGRAN16_2, 2); /* 16k stage2 supported */
     t = FIELD_DP64(t, ID_AA64MMFR0, TGRAN64_2, 2); /* 64k stage2 supported */
     t = FIELD_DP64(t, ID_AA64MMFR0, TGRAN4_2, 2);  /*  4k stage2 supported */
-    cpu->isar.id_aa64mmfr0 = t;
+    acc->isar.id_aa64mmfr0 = t;
 
-    t = cpu->isar.id_aa64mmfr1;
+    t = acc->isar.id_aa64mmfr1;
     t = FIELD_DP64(t, ID_AA64MMFR1, HAFDBS, 2);   /* FEAT_HAFDBS */
     t = FIELD_DP64(t, ID_AA64MMFR1, VMIDBITS, 2); /* FEAT_VMID16 */
     t = FIELD_DP64(t, ID_AA64MMFR1, VH, 1);       /* FEAT_VHE */
@@ -1254,9 +1254,9 @@ static bool aarch64_max_class_late_init(ARMCPUClass *cpu, Error **errp)
     t = FIELD_DP64(t, ID_AA64MMFR1, XNX, 1);      /* FEAT_XNX */
     t = FIELD_DP64(t, ID_AA64MMFR1, ETS, 1);      /* FEAT_ETS */
     t = FIELD_DP64(t, ID_AA64MMFR1, HCX, 1);      /* FEAT_HCX */
-    cpu->isar.id_aa64mmfr1 = t;
+    acc->isar.id_aa64mmfr1 = t;
 
-    t = cpu->isar.id_aa64mmfr2;
+    t = acc->isar.id_aa64mmfr2;
     t = FIELD_DP64(t, ID_AA64MMFR2, CNP, 1);      /* FEAT_TTCNP */
     t = FIELD_DP64(t, ID_AA64MMFR2, UAO, 1);      /* FEAT_UAO */
     t = FIELD_DP64(t, ID_AA64MMFR2, IESB, 1);     /* FEAT_IESB */
@@ -1268,9 +1268,9 @@ static bool aarch64_max_class_late_init(ARMCPUClass *cpu, Error **errp)
     t = FIELD_DP64(t, ID_AA64MMFR2, BBM, 2);      /* FEAT_BBM at level 2 */
     t = FIELD_DP64(t, ID_AA64MMFR2, EVT, 2);      /* FEAT_EVT */
     t = FIELD_DP64(t, ID_AA64MMFR2, E0PD, 1);     /* FEAT_E0PD */
-    cpu->isar.id_aa64mmfr2 = t;
+    acc->isar.id_aa64mmfr2 = t;
 
-    t = cpu->isar.id_aa64zfr0;
+    t = acc->isar.id_aa64zfr0;
     t = FIELD_DP64(t, ID_AA64ZFR0, SVEVER, 1);
     t = FIELD_DP64(t, ID_AA64ZFR0, AES, 2);       /* FEAT_SVE_PMULL128 */
     t = FIELD_DP64(t, ID_AA64ZFR0, BITPERM, 1);   /* FEAT_SVE_BitPerm */
@@ -1280,14 +1280,14 @@ static bool aarch64_max_class_late_init(ARMCPUClass *cpu, Error **errp)
     t = FIELD_DP64(t, ID_AA64ZFR0, I8MM, 1);      /* FEAT_I8MM */
     t = FIELD_DP64(t, ID_AA64ZFR0, F32MM, 1);     /* FEAT_F32MM */
     t = FIELD_DP64(t, ID_AA64ZFR0, F64MM, 1);     /* FEAT_F64MM */
-    cpu->isar.id_aa64zfr0 = t;
+    acc->isar.id_aa64zfr0 = t;
 
-    t = cpu->isar.id_aa64dfr0;
+    t = acc->isar.id_aa64dfr0;
     t = FIELD_DP64(t, ID_AA64DFR0, DEBUGVER, 9);  /* FEAT_Debugv8p4 */
     t = FIELD_DP64(t, ID_AA64DFR0, PMUVER, 6);    /* FEAT_PMUv3p5 */
-    cpu->isar.id_aa64dfr0 = t;
+    acc->isar.id_aa64dfr0 = t;
 
-    t = cpu->isar.id_aa64smfr0;
+    t = acc->isar.id_aa64smfr0;
     t = FIELD_DP64(t, ID_AA64SMFR0, F32F32, 1);   /* FEAT_SME */
     t = FIELD_DP64(t, ID_AA64SMFR0, B16F32, 1);   /* FEAT_SME */
     t = FIELD_DP64(t, ID_AA64SMFR0, F16F32, 1);   /* FEAT_SME */
@@ -1295,18 +1295,18 @@ static bool aarch64_max_class_late_init(ARMCPUClass *cpu, Error **errp)
     t = FIELD_DP64(t, ID_AA64SMFR0, F64F64, 1);   /* FEAT_SME_F64F64 */
     t = FIELD_DP64(t, ID_AA64SMFR0, I16I64, 0xf); /* FEAT_SME_I16I64 */
     t = FIELD_DP64(t, ID_AA64SMFR0, FA64, 1);     /* FEAT_SME_FA64 */
-    cpu->isar.id_aa64smfr0 = t;
+    acc->isar.id_aa64smfr0 = t;
 
     /* Replicate the same data to the 32-bit id registers.  */
-    aa32_max_features(cpu);
+    aa32_max_features(acc);
 
 #ifdef CONFIG_USER_ONLY
     /*
      * For usermode -cpu max we can use a larger and more efficient DCZ
      * blocksize since we don't have to follow what the hardware does.
      */
-    cpu->ctr = 0x80038003; /* 32 byte I and D cacheline size, VIPT icache */
-    cpu->dcz_blocksize = 7; /*  512 bytes */
+    acc->ctr = 0x80038003; /* 32 byte I and D cacheline size, VIPT icache */
+    acc->dcz_blocksize = 7; /*  512 bytes */
 #endif
     return true;
 }
diff --git a/target/arm/cpu_tcg.c b/target/arm/cpu_tcg.c
index f35b4a52b0..1ef825b39e 100644
--- a/target/arm/cpu_tcg.c
+++ b/target/arm/cpu_tcg.c
@@ -22,21 +22,21 @@
 
 
 /* Share AArch32 -cpu max features with AArch64. */
-void aa32_max_features(ARMCPUClass *cpu)
+void aa32_max_features(ARMCPUClass *acc)
 {
     uint32_t t;
 
     /* Add additional features supported by QEMU */
-    t = cpu->isar.id_isar5;
+    t = acc->isar.id_isar5;
     t = FIELD_DP32(t, ID_ISAR5, AES, 2);          /* FEAT_PMULL */
     t = FIELD_DP32(t, ID_ISAR5, SHA1, 1);         /* FEAT_SHA1 */
     t = FIELD_DP32(t, ID_ISAR5, SHA2, 1);         /* FEAT_SHA256 */
     t = FIELD_DP32(t, ID_ISAR5, CRC32, 1);
     t = FIELD_DP32(t, ID_ISAR5, RDM, 1);          /* FEAT_RDM */
     t = FIELD_DP32(t, ID_ISAR5, VCMA, 1);         /* FEAT_FCMA */
-    cpu->isar.id_isar5 = t;
+    acc->isar.id_isar5 = t;
 
-    t = cpu->isar.id_isar6;
+    t = acc->isar.id_isar6;
     t = FIELD_DP32(t, ID_ISAR6, JSCVT, 1);        /* FEAT_JSCVT */
     t = FIELD_DP32(t, ID_ISAR6, DP, 1);           /* Feat_DotProd */
     t = FIELD_DP32(t, ID_ISAR6, FHM, 1);          /* FEAT_FHM */
@@ -44,50 +44,50 @@ void aa32_max_features(ARMCPUClass *cpu)
     t = FIELD_DP32(t, ID_ISAR6, SPECRES, 1);      /* FEAT_SPECRES */
     t = FIELD_DP32(t, ID_ISAR6, BF16, 1);         /* FEAT_AA32BF16 */
     t = FIELD_DP32(t, ID_ISAR6, I8MM, 1);         /* FEAT_AA32I8MM */
-    cpu->isar.id_isar6 = t;
+    acc->isar.id_isar6 = t;
 
-    t = cpu->isar.mvfr1;
+    t = acc->isar.mvfr1;
     t = FIELD_DP32(t, MVFR1, FPHP, 3);            /* FEAT_FP16 */
     t = FIELD_DP32(t, MVFR1, SIMDHP, 2);          /* FEAT_FP16 */
-    cpu->isar.mvfr1 = t;
+    acc->isar.mvfr1 = t;
 
-    t = cpu->isar.mvfr2;
+    t = acc->isar.mvfr2;
     t = FIELD_DP32(t, MVFR2, SIMDMISC, 3);        /* SIMD MaxNum */
     t = FIELD_DP32(t, MVFR2, FPMISC, 4);          /* FP MaxNum */
-    cpu->isar.mvfr2 = t;
+    acc->isar.mvfr2 = t;
 
-    t = cpu->isar.id_mmfr3;
+    t = acc->isar.id_mmfr3;
     t = FIELD_DP32(t, ID_MMFR3, PAN, 2);          /* FEAT_PAN2 */
-    cpu->isar.id_mmfr3 = t;
+    acc->isar.id_mmfr3 = t;
 
-    t = cpu->isar.id_mmfr4;
+    t = acc->isar.id_mmfr4;
     t = FIELD_DP32(t, ID_MMFR4, HPDS, 1);         /* FEAT_AA32HPD */
     t = FIELD_DP32(t, ID_MMFR4, AC2, 1);          /* ACTLR2, HACTLR2 */
     t = FIELD_DP32(t, ID_MMFR4, CNP, 1);          /* FEAT_TTCNP */
     t = FIELD_DP32(t, ID_MMFR4, XNX, 1);          /* FEAT_XNX */
     t = FIELD_DP32(t, ID_MMFR4, EVT, 2);          /* FEAT_EVT */
-    cpu->isar.id_mmfr4 = t;
+    acc->isar.id_mmfr4 = t;
 
-    t = cpu->isar.id_mmfr5;
+    t = acc->isar.id_mmfr5;
     t = FIELD_DP32(t, ID_MMFR5, ETS, 1);          /* FEAT_ETS */
-    cpu->isar.id_mmfr5 = t;
+    acc->isar.id_mmfr5 = t;
 
-    t = cpu->isar.id_pfr0;
+    t = acc->isar.id_pfr0;
     t = FIELD_DP32(t, ID_PFR0, CSV2, 2);          /* FEAT_CVS2 */
     t = FIELD_DP32(t, ID_PFR0, DIT, 1);           /* FEAT_DIT */
     t = FIELD_DP32(t, ID_PFR0, RAS, 1);           /* FEAT_RAS */
-    cpu->isar.id_pfr0 = t;
+    acc->isar.id_pfr0 = t;
 
-    t = cpu->isar.id_pfr2;
+    t = acc->isar.id_pfr2;
     t = FIELD_DP32(t, ID_PFR2, CSV3, 1);          /* FEAT_CSV3 */
     t = FIELD_DP32(t, ID_PFR2, SSBS, 1);          /* FEAT_SSBS */
-    cpu->isar.id_pfr2 = t;
+    acc->isar.id_pfr2 = t;
 
-    t = cpu->isar.id_dfr0;
+    t = acc->isar.id_dfr0;
     t = FIELD_DP32(t, ID_DFR0, COPDBG, 9);        /* FEAT_Debugv8p4 */
     t = FIELD_DP32(t, ID_DFR0, COPSDBG, 9);       /* FEAT_Debugv8p4 */
     t = FIELD_DP32(t, ID_DFR0, PERFMON, 6);       /* FEAT_PMUv3p5 */
-    cpu->isar.id_dfr0 = t;
+    acc->isar.id_dfr0 = t;
 }
 
 #ifndef CONFIG_USER_ONLY
@@ -178,43 +178,43 @@ static bool arm_v7m_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
 }
 #endif /* !CONFIG_USER_ONLY && CONFIG_TCG */
 
-static void arm926_class_init(ARMCPUClass *cpu)
+static void arm926_class_init(ARMCPUClass *acc)
 {
-    cpu->dtb_compatible = "arm,arm926";
-    set_class_feature(cpu, ARM_FEATURE_V5);
-    set_class_feature(cpu, ARM_FEATURE_DUMMY_C15_REGS);
-    set_class_feature(cpu, ARM_FEATURE_CACHE_TEST_CLEAN);
-    cpu->midr = 0x41069265;
-    cpu->reset_fpsid = 0x41011090;
-    cpu->ctr = 0x1dd20d2;
-    cpu->reset_sctlr = 0x00090078;
+    acc->dtb_compatible = "arm,arm926";
+    set_class_feature(acc, ARM_FEATURE_V5);
+    set_class_feature(acc, ARM_FEATURE_DUMMY_C15_REGS);
+    set_class_feature(acc, ARM_FEATURE_CACHE_TEST_CLEAN);
+    acc->midr = 0x41069265;
+    acc->reset_fpsid = 0x41011090;
+    acc->ctr = 0x1dd20d2;
+    acc->reset_sctlr = 0x00090078;
 
     /*
      * ARMv5 does not have the ID_ISAR registers, but we can still
      * set the field to indicate Jazelle support within QEMU.
      */
-    cpu->isar.id_isar1 = FIELD_DP32(cpu->isar.id_isar1, ID_ISAR1, JAZELLE, 1);
+    acc->isar.id_isar1 = FIELD_DP32(acc->isar.id_isar1, ID_ISAR1, JAZELLE, 1);
     /*
      * Similarly, we need to set MVFR0 fields to enable vfp and short vector
      * support even though ARMv5 doesn't have this register.
      */
-    cpu->isar.mvfr0 = FIELD_DP32(cpu->isar.mvfr0, MVFR0, FPSHVEC, 1);
-    cpu->isar.mvfr0 = FIELD_DP32(cpu->isar.mvfr0, MVFR0, FPSP, 1);
-    cpu->isar.mvfr0 = FIELD_DP32(cpu->isar.mvfr0, MVFR0, FPDP, 1);
+    acc->isar.mvfr0 = FIELD_DP32(acc->isar.mvfr0, MVFR0, FPSHVEC, 1);
+    acc->isar.mvfr0 = FIELD_DP32(acc->isar.mvfr0, MVFR0, FPSP, 1);
+    acc->isar.mvfr0 = FIELD_DP32(acc->isar.mvfr0, MVFR0, FPDP, 1);
 }
 
-static void arm946_class_init(ARMCPUClass *cpu)
+static void arm946_class_init(ARMCPUClass *acc)
 {
-    cpu->dtb_compatible = "arm,arm946";
-    set_class_feature(cpu, ARM_FEATURE_V5);
-    set_class_feature(cpu, ARM_FEATURE_PMSA);
-    set_class_feature(cpu, ARM_FEATURE_DUMMY_C15_REGS);
-    cpu->midr = 0x41059461;
-    cpu->ctr = 0x0f004006;
-    cpu->reset_sctlr = 0x00000078;
+    acc->dtb_compatible = "arm,arm946";
+    set_class_feature(acc, ARM_FEATURE_V5);
+    set_class_feature(acc, ARM_FEATURE_PMSA);
+    set_class_feature(acc, ARM_FEATURE_DUMMY_C15_REGS);
+    acc->midr = 0x41059461;
+    acc->ctr = 0x0f004006;
+    acc->reset_sctlr = 0x00000078;
 }
 
-static void arm1026_class_init(ARMCPUClass *cpu)
+static void arm1026_class_init(ARMCPUClass *acc)
 {
     /* The 1026 had an IFAR at c6,c0,0,1 rather than the ARMv6 c6,c0,0,2 */
     static const ARMCPRegInfo ifar[1] = {
@@ -224,34 +224,34 @@ static void arm1026_class_init(ARMCPUClass *cpu)
           .resetvalue = 0 }
     };
 
-    cpu->dtb_compatible = "arm,arm1026";
-    set_class_feature(cpu, ARM_FEATURE_V5);
-    set_class_feature(cpu, ARM_FEATURE_AUXCR);
-    set_class_feature(cpu, ARM_FEATURE_DUMMY_C15_REGS);
-    set_class_feature(cpu, ARM_FEATURE_CACHE_TEST_CLEAN);
-    cpu->midr = 0x4106a262;
-    cpu->reset_fpsid = 0x410110a0;
-    cpu->ctr = 0x1dd20d2;
-    cpu->reset_sctlr = 0x00090078;
-    cpu->reset_auxcr = 1;
+    acc->dtb_compatible = "arm,arm1026";
+    set_class_feature(acc, ARM_FEATURE_V5);
+    set_class_feature(acc, ARM_FEATURE_AUXCR);
+    set_class_feature(acc, ARM_FEATURE_DUMMY_C15_REGS);
+    set_class_feature(acc, ARM_FEATURE_CACHE_TEST_CLEAN);
+    acc->midr = 0x4106a262;
+    acc->reset_fpsid = 0x410110a0;
+    acc->ctr = 0x1dd20d2;
+    acc->reset_sctlr = 0x00090078;
+    acc->reset_auxcr = 1;
 
     /*
      * ARMv5 does not have the ID_ISAR registers, but we can still
      * set the field to indicate Jazelle support within QEMU.
      */
-    cpu->isar.id_isar1 = FIELD_DP32(cpu->isar.id_isar1, ID_ISAR1, JAZELLE, 1);
+    acc->isar.id_isar1 = FIELD_DP32(acc->isar.id_isar1, ID_ISAR1, JAZELLE, 1);
     /*
      * Similarly, we need to set MVFR0 fields to enable vfp and short vector
      * support even though ARMv5 doesn't have this register.
      */
-    cpu->isar.mvfr0 = FIELD_DP32(cpu->isar.mvfr0, MVFR0, FPSHVEC, 1);
-    cpu->isar.mvfr0 = FIELD_DP32(cpu->isar.mvfr0, MVFR0, FPSP, 1);
-    cpu->isar.mvfr0 = FIELD_DP32(cpu->isar.mvfr0, MVFR0, FPDP, 1);
+    acc->isar.mvfr0 = FIELD_DP32(acc->isar.mvfr0, MVFR0, FPSHVEC, 1);
+    acc->isar.mvfr0 = FIELD_DP32(acc->isar.mvfr0, MVFR0, FPSP, 1);
+    acc->isar.mvfr0 = FIELD_DP32(acc->isar.mvfr0, MVFR0, FPDP, 1);
 
-    define_arm_cp_regs_with_class(cpu, ifar, NULL);
+    define_arm_cp_regs_with_class(acc, ifar, NULL);
 }
 
-static void arm1136_r2_class_init(ARMCPUClass *cpu)
+static void arm1136_r2_class_init(ARMCPUClass *acc)
 {
     /*
      * What qemu calls "arm1136_r2" is actually the 1136 r0p2, ie an
@@ -262,116 +262,116 @@ static void arm1136_r2_class_init(ARMCPUClass *cpu)
      * of the ID registers).
      */
 
-    cpu->dtb_compatible = "arm,arm1136";
-    set_class_feature(cpu, ARM_FEATURE_V6);
-    set_class_feature(cpu, ARM_FEATURE_DUMMY_C15_REGS);
-    set_class_feature(cpu, ARM_FEATURE_CACHE_DIRTY_REG);
-    set_class_feature(cpu, ARM_FEATURE_CACHE_BLOCK_OPS);
-    cpu->midr = 0x4107b362;
-    cpu->reset_fpsid = 0x410120b4;
-    cpu->isar.mvfr0 = 0x11111111;
-    cpu->isar.mvfr1 = 0x00000000;
-    cpu->ctr = 0x1dd20d2;
-    cpu->reset_sctlr = 0x00050078;
-    cpu->isar.id_pfr0 = 0x111;
-    cpu->isar.id_pfr1 = 0x1;
-    cpu->isar.id_dfr0 = 0x2;
-    cpu->id_afr0 = 0x3;
-    cpu->isar.id_mmfr0 = 0x01130003;
-    cpu->isar.id_mmfr1 = 0x10030302;
-    cpu->isar.id_mmfr2 = 0x01222110;
-    cpu->isar.id_isar0 = 0x00140011;
-    cpu->isar.id_isar1 = 0x12002111;
-    cpu->isar.id_isar2 = 0x11231111;
-    cpu->isar.id_isar3 = 0x01102131;
-    cpu->isar.id_isar4 = 0x141;
-    cpu->reset_auxcr = 7;
+    acc->dtb_compatible = "arm,arm1136";
+    set_class_feature(acc, ARM_FEATURE_V6);
+    set_class_feature(acc, ARM_FEATURE_DUMMY_C15_REGS);
+    set_class_feature(acc, ARM_FEATURE_CACHE_DIRTY_REG);
+    set_class_feature(acc, ARM_FEATURE_CACHE_BLOCK_OPS);
+    acc->midr = 0x4107b362;
+    acc->reset_fpsid = 0x410120b4;
+    acc->isar.mvfr0 = 0x11111111;
+    acc->isar.mvfr1 = 0x00000000;
+    acc->ctr = 0x1dd20d2;
+    acc->reset_sctlr = 0x00050078;
+    acc->isar.id_pfr0 = 0x111;
+    acc->isar.id_pfr1 = 0x1;
+    acc->isar.id_dfr0 = 0x2;
+    acc->id_afr0 = 0x3;
+    acc->isar.id_mmfr0 = 0x01130003;
+    acc->isar.id_mmfr1 = 0x10030302;
+    acc->isar.id_mmfr2 = 0x01222110;
+    acc->isar.id_isar0 = 0x00140011;
+    acc->isar.id_isar1 = 0x12002111;
+    acc->isar.id_isar2 = 0x11231111;
+    acc->isar.id_isar3 = 0x01102131;
+    acc->isar.id_isar4 = 0x141;
+    acc->reset_auxcr = 7;
 }
 
-static void arm1136_class_init(ARMCPUClass *cpu)
+static void arm1136_class_init(ARMCPUClass *acc)
 {
-    cpu->dtb_compatible = "arm,arm1136";
-    set_class_feature(cpu, ARM_FEATURE_V6K);
-    set_class_feature(cpu, ARM_FEATURE_V6);
-    set_class_feature(cpu, ARM_FEATURE_DUMMY_C15_REGS);
-    set_class_feature(cpu, ARM_FEATURE_CACHE_DIRTY_REG);
-    set_class_feature(cpu, ARM_FEATURE_CACHE_BLOCK_OPS);
-    cpu->midr = 0x4117b363;
-    cpu->reset_fpsid = 0x410120b4;
-    cpu->isar.mvfr0 = 0x11111111;
-    cpu->isar.mvfr1 = 0x00000000;
-    cpu->ctr = 0x1dd20d2;
-    cpu->reset_sctlr = 0x00050078;
-    cpu->isar.id_pfr0 = 0x111;
-    cpu->isar.id_pfr1 = 0x1;
-    cpu->isar.id_dfr0 = 0x2;
-    cpu->id_afr0 = 0x3;
-    cpu->isar.id_mmfr0 = 0x01130003;
-    cpu->isar.id_mmfr1 = 0x10030302;
-    cpu->isar.id_mmfr2 = 0x01222110;
-    cpu->isar.id_isar0 = 0x00140011;
-    cpu->isar.id_isar1 = 0x12002111;
-    cpu->isar.id_isar2 = 0x11231111;
-    cpu->isar.id_isar3 = 0x01102131;
-    cpu->isar.id_isar4 = 0x141;
-    cpu->reset_auxcr = 7;
+    acc->dtb_compatible = "arm,arm1136";
+    set_class_feature(acc, ARM_FEATURE_V6K);
+    set_class_feature(acc, ARM_FEATURE_V6);
+    set_class_feature(acc, ARM_FEATURE_DUMMY_C15_REGS);
+    set_class_feature(acc, ARM_FEATURE_CACHE_DIRTY_REG);
+    set_class_feature(acc, ARM_FEATURE_CACHE_BLOCK_OPS);
+    acc->midr = 0x4117b363;
+    acc->reset_fpsid = 0x410120b4;
+    acc->isar.mvfr0 = 0x11111111;
+    acc->isar.mvfr1 = 0x00000000;
+    acc->ctr = 0x1dd20d2;
+    acc->reset_sctlr = 0x00050078;
+    acc->isar.id_pfr0 = 0x111;
+    acc->isar.id_pfr1 = 0x1;
+    acc->isar.id_dfr0 = 0x2;
+    acc->id_afr0 = 0x3;
+    acc->isar.id_mmfr0 = 0x01130003;
+    acc->isar.id_mmfr1 = 0x10030302;
+    acc->isar.id_mmfr2 = 0x01222110;
+    acc->isar.id_isar0 = 0x00140011;
+    acc->isar.id_isar1 = 0x12002111;
+    acc->isar.id_isar2 = 0x11231111;
+    acc->isar.id_isar3 = 0x01102131;
+    acc->isar.id_isar4 = 0x141;
+    acc->reset_auxcr = 7;
 }
 
-static void arm1176_class_init(ARMCPUClass *cpu)
+static void arm1176_class_init(ARMCPUClass *acc)
 {
-    cpu->dtb_compatible = "arm,arm1176";
-    set_class_feature(cpu, ARM_FEATURE_V6K);
-    set_class_feature(cpu, ARM_FEATURE_VAPA);
-    set_class_feature(cpu, ARM_FEATURE_DUMMY_C15_REGS);
-    set_class_feature(cpu, ARM_FEATURE_CACHE_DIRTY_REG);
-    set_class_feature(cpu, ARM_FEATURE_CACHE_BLOCK_OPS);
-    set_class_feature(cpu, ARM_FEATURE_EL3);
-    cpu->midr = 0x410fb767;
-    cpu->reset_fpsid = 0x410120b5;
-    cpu->isar.mvfr0 = 0x11111111;
-    cpu->isar.mvfr1 = 0x00000000;
-    cpu->ctr = 0x1dd20d2;
-    cpu->reset_sctlr = 0x00050078;
-    cpu->isar.id_pfr0 = 0x111;
-    cpu->isar.id_pfr1 = 0x11;
-    cpu->isar.id_dfr0 = 0x33;
-    cpu->id_afr0 = 0;
-    cpu->isar.id_mmfr0 = 0x01130003;
-    cpu->isar.id_mmfr1 = 0x10030302;
-    cpu->isar.id_mmfr2 = 0x01222100;
-    cpu->isar.id_isar0 = 0x0140011;
-    cpu->isar.id_isar1 = 0x12002111;
-    cpu->isar.id_isar2 = 0x11231121;
-    cpu->isar.id_isar3 = 0x01102131;
-    cpu->isar.id_isar4 = 0x01141;
-    cpu->reset_auxcr = 7;
+    acc->dtb_compatible = "arm,arm1176";
+    set_class_feature(acc, ARM_FEATURE_V6K);
+    set_class_feature(acc, ARM_FEATURE_VAPA);
+    set_class_feature(acc, ARM_FEATURE_DUMMY_C15_REGS);
+    set_class_feature(acc, ARM_FEATURE_CACHE_DIRTY_REG);
+    set_class_feature(acc, ARM_FEATURE_CACHE_BLOCK_OPS);
+    set_class_feature(acc, ARM_FEATURE_EL3);
+    acc->midr = 0x410fb767;
+    acc->reset_fpsid = 0x410120b5;
+    acc->isar.mvfr0 = 0x11111111;
+    acc->isar.mvfr1 = 0x00000000;
+    acc->ctr = 0x1dd20d2;
+    acc->reset_sctlr = 0x00050078;
+    acc->isar.id_pfr0 = 0x111;
+    acc->isar.id_pfr1 = 0x11;
+    acc->isar.id_dfr0 = 0x33;
+    acc->id_afr0 = 0;
+    acc->isar.id_mmfr0 = 0x01130003;
+    acc->isar.id_mmfr1 = 0x10030302;
+    acc->isar.id_mmfr2 = 0x01222100;
+    acc->isar.id_isar0 = 0x0140011;
+    acc->isar.id_isar1 = 0x12002111;
+    acc->isar.id_isar2 = 0x11231121;
+    acc->isar.id_isar3 = 0x01102131;
+    acc->isar.id_isar4 = 0x01141;
+    acc->reset_auxcr = 7;
 }
 
-static void arm11mpcore_class_init(ARMCPUClass *cpu)
+static void arm11mpcore_class_init(ARMCPUClass *acc)
 {
-    cpu->dtb_compatible = "arm,arm11mpcore";
-    set_class_feature(cpu, ARM_FEATURE_V6K);
-    set_class_feature(cpu, ARM_FEATURE_VAPA);
-    set_class_feature(cpu, ARM_FEATURE_MPIDR);
-    set_class_feature(cpu, ARM_FEATURE_DUMMY_C15_REGS);
-    cpu->midr = 0x410fb022;
-    cpu->reset_fpsid = 0x410120b4;
-    cpu->isar.mvfr0 = 0x11111111;
-    cpu->isar.mvfr1 = 0x00000000;
-    cpu->ctr = 0x1d192992; /* 32K icache 32K dcache */
-    cpu->isar.id_pfr0 = 0x111;
-    cpu->isar.id_pfr1 = 0x1;
-    cpu->isar.id_dfr0 = 0;
-    cpu->id_afr0 = 0x2;
-    cpu->isar.id_mmfr0 = 0x01100103;
-    cpu->isar.id_mmfr1 = 0x10020302;
-    cpu->isar.id_mmfr2 = 0x01222000;
-    cpu->isar.id_isar0 = 0x00100011;
-    cpu->isar.id_isar1 = 0x12002111;
-    cpu->isar.id_isar2 = 0x11221011;
-    cpu->isar.id_isar3 = 0x01102131;
-    cpu->isar.id_isar4 = 0x141;
-    cpu->reset_auxcr = 1;
+    acc->dtb_compatible = "arm,arm11mpcore";
+    set_class_feature(acc, ARM_FEATURE_V6K);
+    set_class_feature(acc, ARM_FEATURE_VAPA);
+    set_class_feature(acc, ARM_FEATURE_MPIDR);
+    set_class_feature(acc, ARM_FEATURE_DUMMY_C15_REGS);
+    acc->midr = 0x410fb022;
+    acc->reset_fpsid = 0x410120b4;
+    acc->isar.mvfr0 = 0x11111111;
+    acc->isar.mvfr1 = 0x00000000;
+    acc->ctr = 0x1d192992; /* 32K icache 32K dcache */
+    acc->isar.id_pfr0 = 0x111;
+    acc->isar.id_pfr1 = 0x1;
+    acc->isar.id_dfr0 = 0;
+    acc->id_afr0 = 0x2;
+    acc->isar.id_mmfr0 = 0x01100103;
+    acc->isar.id_mmfr1 = 0x10020302;
+    acc->isar.id_mmfr2 = 0x01222000;
+    acc->isar.id_isar0 = 0x00100011;
+    acc->isar.id_isar1 = 0x12002111;
+    acc->isar.id_isar2 = 0x11221011;
+    acc->isar.id_isar3 = 0x01102131;
+    acc->isar.id_isar4 = 0x141;
+    acc->reset_auxcr = 1;
 }
 
 static const ARMCPRegInfo cortexa8_cp_reginfo[] = {
@@ -381,41 +381,41 @@ static const ARMCPRegInfo cortexa8_cp_reginfo[] = {
       .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
 };
 
-static void cortex_a8_class_init(ARMCPUClass *cpu)
+static void cortex_a8_class_init(ARMCPUClass *acc)
 {
-    cpu->dtb_compatible = "arm,cortex-a8";
-    set_class_feature(cpu, ARM_FEATURE_V7);
-    set_class_feature(cpu, ARM_FEATURE_NEON);
-    set_class_feature(cpu, ARM_FEATURE_THUMB2EE);
-    set_class_feature(cpu, ARM_FEATURE_DUMMY_C15_REGS);
-    set_class_feature(cpu, ARM_FEATURE_EL3);
-    cpu->midr = 0x410fc080;
-    cpu->reset_fpsid = 0x410330c0;
-    cpu->isar.mvfr0 = 0x11110222;
-    cpu->isar.mvfr1 = 0x00011111;
-    cpu->ctr = 0x82048004;
-    cpu->reset_sctlr = 0x00c50078;
-    cpu->isar.id_pfr0 = 0x1031;
-    cpu->isar.id_pfr1 = 0x11;
-    cpu->isar.id_dfr0 = 0x400;
-    cpu->id_afr0 = 0;
-    cpu->isar.id_mmfr0 = 0x31100003;
-    cpu->isar.id_mmfr1 = 0x20000000;
-    cpu->isar.id_mmfr2 = 0x01202000;
-    cpu->isar.id_mmfr3 = 0x11;
-    cpu->isar.id_isar0 = 0x00101111;
-    cpu->isar.id_isar1 = 0x12112111;
-    cpu->isar.id_isar2 = 0x21232031;
-    cpu->isar.id_isar3 = 0x11112131;
-    cpu->isar.id_isar4 = 0x00111142;
-    cpu->isar.dbgdidr = 0x15141000;
-    cpu->clidr = (1 << 27) | (2 << 24) | 3;
-    cpu->ccsidr[0] = 0xe007e01a; /* 16k L1 dcache. */
-    cpu->ccsidr[1] = 0x2007e01a; /* 16k L1 icache. */
-    cpu->ccsidr[2] = 0xf0000000; /* No L2 icache. */
-    cpu->reset_auxcr = 2;
-    cpu->isar.reset_pmcr_el0 = 0x41002000;
-    define_arm_cp_regs_with_class(cpu, cortexa8_cp_reginfo, NULL);
+    acc->dtb_compatible = "arm,cortex-a8";
+    set_class_feature(acc, ARM_FEATURE_V7);
+    set_class_feature(acc, ARM_FEATURE_NEON);
+    set_class_feature(acc, ARM_FEATURE_THUMB2EE);
+    set_class_feature(acc, ARM_FEATURE_DUMMY_C15_REGS);
+    set_class_feature(acc, ARM_FEATURE_EL3);
+    acc->midr = 0x410fc080;
+    acc->reset_fpsid = 0x410330c0;
+    acc->isar.mvfr0 = 0x11110222;
+    acc->isar.mvfr1 = 0x00011111;
+    acc->ctr = 0x82048004;
+    acc->reset_sctlr = 0x00c50078;
+    acc->isar.id_pfr0 = 0x1031;
+    acc->isar.id_pfr1 = 0x11;
+    acc->isar.id_dfr0 = 0x400;
+    acc->id_afr0 = 0;
+    acc->isar.id_mmfr0 = 0x31100003;
+    acc->isar.id_mmfr1 = 0x20000000;
+    acc->isar.id_mmfr2 = 0x01202000;
+    acc->isar.id_mmfr3 = 0x11;
+    acc->isar.id_isar0 = 0x00101111;
+    acc->isar.id_isar1 = 0x12112111;
+    acc->isar.id_isar2 = 0x21232031;
+    acc->isar.id_isar3 = 0x11112131;
+    acc->isar.id_isar4 = 0x00111142;
+    acc->isar.dbgdidr = 0x15141000;
+    acc->clidr = (1 << 27) | (2 << 24) | 3;
+    acc->ccsidr[0] = 0xe007e01a; /* 16k L1 dcache. */
+    acc->ccsidr[1] = 0x2007e01a; /* 16k L1 icache. */
+    acc->ccsidr[2] = 0xf0000000; /* No L2 icache. */
+    acc->reset_auxcr = 2;
+    acc->isar.reset_pmcr_el0 = 0x41002000;
+    define_arm_cp_regs_with_class(acc, cortexa8_cp_reginfo, NULL);
 }
 
 static const ARMCPRegInfo cortexa9_cp_reginfo[] = {
@@ -447,45 +447,45 @@ static const ARMCPRegInfo cortexa9_cp_reginfo[] = {
       .access = PL1_RW, .resetvalue = 0, .type = ARM_CP_CONST },
 };
 
-static void cortex_a9_class_init(ARMCPUClass *cpu)
+static void cortex_a9_class_init(ARMCPUClass *acc)
 {
-    cpu->dtb_compatible = "arm,cortex-a9";
-    set_class_feature(cpu, ARM_FEATURE_V7);
-    set_class_feature(cpu, ARM_FEATURE_NEON);
-    set_class_feature(cpu, ARM_FEATURE_THUMB2EE);
-    set_class_feature(cpu, ARM_FEATURE_EL3);
+    acc->dtb_compatible = "arm,cortex-a9";
+    set_class_feature(acc, ARM_FEATURE_V7);
+    set_class_feature(acc, ARM_FEATURE_NEON);
+    set_class_feature(acc, ARM_FEATURE_THUMB2EE);
+    set_class_feature(acc, ARM_FEATURE_EL3);
     /*
      * Note that A9 supports the MP extensions even for
      * A9UP and single-core A9MP (which are both different
      * and valid configurations; we don't model A9UP).
      */
-    set_class_feature(cpu, ARM_FEATURE_V7MP);
-    set_class_feature(cpu, ARM_FEATURE_CBAR);
-    cpu->midr = 0x410fc090;
-    cpu->reset_fpsid = 0x41033090;
-    cpu->isar.mvfr0 = 0x11110222;
-    cpu->isar.mvfr1 = 0x01111111;
-    cpu->ctr = 0x80038003;
-    cpu->reset_sctlr = 0x00c50078;
-    cpu->isar.id_pfr0 = 0x1031;
-    cpu->isar.id_pfr1 = 0x11;
-    cpu->isar.id_dfr0 = 0x000;
-    cpu->id_afr0 = 0;
-    cpu->isar.id_mmfr0 = 0x00100103;
-    cpu->isar.id_mmfr1 = 0x20000000;
-    cpu->isar.id_mmfr2 = 0x01230000;
-    cpu->isar.id_mmfr3 = 0x00002111;
-    cpu->isar.id_isar0 = 0x00101111;
-    cpu->isar.id_isar1 = 0x13112111;
-    cpu->isar.id_isar2 = 0x21232041;
-    cpu->isar.id_isar3 = 0x11112131;
-    cpu->isar.id_isar4 = 0x00111142;
-    cpu->isar.dbgdidr = 0x35141000;
-    cpu->clidr = (1 << 27) | (1 << 24) | 3;
-    cpu->ccsidr[0] = 0xe00fe019; /* 16k L1 dcache. */
-    cpu->ccsidr[1] = 0x200fe019; /* 16k L1 icache. */
-    cpu->isar.reset_pmcr_el0 = 0x41093000;
-    define_arm_cp_regs_with_class(cpu, cortexa9_cp_reginfo, NULL);
+    set_class_feature(acc, ARM_FEATURE_V7MP);
+    set_class_feature(acc, ARM_FEATURE_CBAR);
+    acc->midr = 0x410fc090;
+    acc->reset_fpsid = 0x41033090;
+    acc->isar.mvfr0 = 0x11110222;
+    acc->isar.mvfr1 = 0x01111111;
+    acc->ctr = 0x80038003;
+    acc->reset_sctlr = 0x00c50078;
+    acc->isar.id_pfr0 = 0x1031;
+    acc->isar.id_pfr1 = 0x11;
+    acc->isar.id_dfr0 = 0x000;
+    acc->id_afr0 = 0;
+    acc->isar.id_mmfr0 = 0x00100103;
+    acc->isar.id_mmfr1 = 0x20000000;
+    acc->isar.id_mmfr2 = 0x01230000;
+    acc->isar.id_mmfr3 = 0x00002111;
+    acc->isar.id_isar0 = 0x00101111;
+    acc->isar.id_isar1 = 0x13112111;
+    acc->isar.id_isar2 = 0x21232041;
+    acc->isar.id_isar3 = 0x11112131;
+    acc->isar.id_isar4 = 0x00111142;
+    acc->isar.dbgdidr = 0x35141000;
+    acc->clidr = (1 << 27) | (1 << 24) | 3;
+    acc->ccsidr[0] = 0xe00fe019; /* 16k L1 dcache. */
+    acc->ccsidr[1] = 0x200fe019; /* 16k L1 icache. */
+    acc->isar.reset_pmcr_el0 = 0x41093000;
+    define_arm_cp_regs_with_class(acc, cortexa9_cp_reginfo, NULL);
 }
 
 #ifndef CONFIG_USER_ONLY
@@ -511,106 +511,106 @@ static const ARMCPRegInfo cortexa15_cp_reginfo[] = {
       .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
 };
 
-static void cortex_a7_class_init(ARMCPUClass *cpu)
+static void cortex_a7_class_init(ARMCPUClass *acc)
 {
-    cpu->dtb_compatible = "arm,cortex-a7";
-    set_class_feature(cpu, ARM_FEATURE_V7VE);
-    set_class_feature(cpu, ARM_FEATURE_NEON);
-    set_class_feature(cpu, ARM_FEATURE_THUMB2EE);
-    set_class_feature(cpu, ARM_FEATURE_GENERIC_TIMER);
-    set_class_feature(cpu, ARM_FEATURE_DUMMY_C15_REGS);
-    set_class_feature(cpu, ARM_FEATURE_CBAR_RO);
-    set_class_feature(cpu, ARM_FEATURE_EL2);
-    set_class_feature(cpu, ARM_FEATURE_EL3);
-    set_class_feature(cpu, ARM_FEATURE_PMU);
-    cpu->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A7;
-    cpu->midr = 0x410fc075;
-    cpu->reset_fpsid = 0x41023075;
-    cpu->isar.mvfr0 = 0x10110222;
-    cpu->isar.mvfr1 = 0x11111111;
-    cpu->ctr = 0x84448003;
-    cpu->reset_sctlr = 0x00c50078;
-    cpu->isar.id_pfr0 = 0x00001131;
-    cpu->isar.id_pfr1 = 0x00011011;
-    cpu->isar.id_dfr0 = 0x02010555;
-    cpu->id_afr0 = 0x00000000;
-    cpu->isar.id_mmfr0 = 0x10101105;
-    cpu->isar.id_mmfr1 = 0x40000000;
-    cpu->isar.id_mmfr2 = 0x01240000;
-    cpu->isar.id_mmfr3 = 0x02102211;
+    acc->dtb_compatible = "arm,cortex-a7";
+    set_class_feature(acc, ARM_FEATURE_V7VE);
+    set_class_feature(acc, ARM_FEATURE_NEON);
+    set_class_feature(acc, ARM_FEATURE_THUMB2EE);
+    set_class_feature(acc, ARM_FEATURE_GENERIC_TIMER);
+    set_class_feature(acc, ARM_FEATURE_DUMMY_C15_REGS);
+    set_class_feature(acc, ARM_FEATURE_CBAR_RO);
+    set_class_feature(acc, ARM_FEATURE_EL2);
+    set_class_feature(acc, ARM_FEATURE_EL3);
+    set_class_feature(acc, ARM_FEATURE_PMU);
+    acc->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A7;
+    acc->midr = 0x410fc075;
+    acc->reset_fpsid = 0x41023075;
+    acc->isar.mvfr0 = 0x10110222;
+    acc->isar.mvfr1 = 0x11111111;
+    acc->ctr = 0x84448003;
+    acc->reset_sctlr = 0x00c50078;
+    acc->isar.id_pfr0 = 0x00001131;
+    acc->isar.id_pfr1 = 0x00011011;
+    acc->isar.id_dfr0 = 0x02010555;
+    acc->id_afr0 = 0x00000000;
+    acc->isar.id_mmfr0 = 0x10101105;
+    acc->isar.id_mmfr1 = 0x40000000;
+    acc->isar.id_mmfr2 = 0x01240000;
+    acc->isar.id_mmfr3 = 0x02102211;
     /*
      * a7_mpcore_r0p5_trm, page 4-4 gives 0x01101110; but
      * table 4-41 gives 0x02101110, which includes the arm div insns.
      */
-    cpu->isar.id_isar0 = 0x02101110;
-    cpu->isar.id_isar1 = 0x13112111;
-    cpu->isar.id_isar2 = 0x21232041;
-    cpu->isar.id_isar3 = 0x11112131;
-    cpu->isar.id_isar4 = 0x10011142;
-    cpu->isar.dbgdidr = 0x3515f005;
-    cpu->isar.dbgdevid = 0x01110f13;
-    cpu->isar.dbgdevid1 = 0x1;
-    cpu->clidr = 0x0a200023;
-    cpu->ccsidr[0] = 0x701fe00a; /* 32K L1 dcache */
-    cpu->ccsidr[1] = 0x201fe00a; /* 32K L1 icache */
-    cpu->ccsidr[2] = 0x711fe07a; /* 4096K L2 unified cache */
-    cpu->isar.reset_pmcr_el0 = 0x41072000;
+    acc->isar.id_isar0 = 0x02101110;
+    acc->isar.id_isar1 = 0x13112111;
+    acc->isar.id_isar2 = 0x21232041;
+    acc->isar.id_isar3 = 0x11112131;
+    acc->isar.id_isar4 = 0x10011142;
+    acc->isar.dbgdidr = 0x3515f005;
+    acc->isar.dbgdevid = 0x01110f13;
+    acc->isar.dbgdevid1 = 0x1;
+    acc->clidr = 0x0a200023;
+    acc->ccsidr[0] = 0x701fe00a; /* 32K L1 dcache */
+    acc->ccsidr[1] = 0x201fe00a; /* 32K L1 icache */
+    acc->ccsidr[2] = 0x711fe07a; /* 4096K L2 unified cache */
+    acc->isar.reset_pmcr_el0 = 0x41072000;
 
     /* Same as A15 */
-    define_arm_cp_regs_with_class(cpu, cortexa15_cp_reginfo, NULL);
+    define_arm_cp_regs_with_class(acc, cortexa15_cp_reginfo, NULL);
 }
 
-static void cortex_a15_class_init(ARMCPUClass *cpu)
+static void cortex_a15_class_init(ARMCPUClass *acc)
 {
-    cpu->dtb_compatible = "arm,cortex-a15";
-    set_class_feature(cpu, ARM_FEATURE_V7VE);
-    set_class_feature(cpu, ARM_FEATURE_NEON);
-    set_class_feature(cpu, ARM_FEATURE_THUMB2EE);
-    set_class_feature(cpu, ARM_FEATURE_GENERIC_TIMER);
-    set_class_feature(cpu, ARM_FEATURE_DUMMY_C15_REGS);
-    set_class_feature(cpu, ARM_FEATURE_CBAR_RO);
-    set_class_feature(cpu, ARM_FEATURE_EL2);
-    set_class_feature(cpu, ARM_FEATURE_EL3);
-    set_class_feature(cpu, ARM_FEATURE_PMU);
-    cpu->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A15;
-    /* r4p0 cpu, not requiring expensive tlb flush errata */
-    cpu->midr = 0x414fc0f0;
-    cpu->revidr = 0x0;
-    cpu->reset_fpsid = 0x410430f0;
-    cpu->isar.mvfr0 = 0x10110222;
-    cpu->isar.mvfr1 = 0x11111111;
-    cpu->ctr = 0x8444c004;
-    cpu->reset_sctlr = 0x00c50078;
-    cpu->isar.id_pfr0 = 0x00001131;
-    cpu->isar.id_pfr1 = 0x00011011;
-    cpu->isar.id_dfr0 = 0x02010555;
-    cpu->id_afr0 = 0x00000000;
-    cpu->isar.id_mmfr0 = 0x10201105;
-    cpu->isar.id_mmfr1 = 0x20000000;
-    cpu->isar.id_mmfr2 = 0x01240000;
-    cpu->isar.id_mmfr3 = 0x02102211;
-    cpu->isar.id_isar0 = 0x02101110;
-    cpu->isar.id_isar1 = 0x13112111;
-    cpu->isar.id_isar2 = 0x21232041;
-    cpu->isar.id_isar3 = 0x11112131;
-    cpu->isar.id_isar4 = 0x10011142;
-    cpu->isar.dbgdidr = 0x3515f021;
-    cpu->isar.dbgdevid = 0x01110f13;
-    cpu->isar.dbgdevid1 = 0x0;
-    cpu->clidr = 0x0a200023;
-    cpu->ccsidr[0] = 0x701fe00a; /* 32K L1 dcache */
-    cpu->ccsidr[1] = 0x201fe00a; /* 32K L1 icache */
-    cpu->ccsidr[2] = 0x711fe07a; /* 4096K L2 unified cache */
-    cpu->isar.reset_pmcr_el0 = 0x410F3000;
-    define_arm_cp_regs_with_class(cpu, cortexa15_cp_reginfo, NULL);
+    acc->dtb_compatible = "arm,cortex-a15";
+    set_class_feature(acc, ARM_FEATURE_V7VE);
+    set_class_feature(acc, ARM_FEATURE_NEON);
+    set_class_feature(acc, ARM_FEATURE_THUMB2EE);
+    set_class_feature(acc, ARM_FEATURE_GENERIC_TIMER);
+    set_class_feature(acc, ARM_FEATURE_DUMMY_C15_REGS);
+    set_class_feature(acc, ARM_FEATURE_CBAR_RO);
+    set_class_feature(acc, ARM_FEATURE_EL2);
+    set_class_feature(acc, ARM_FEATURE_EL3);
+    set_class_feature(acc, ARM_FEATURE_PMU);
+    acc->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A15;
+    /* r4p0 acc, not requiring expensive tlb flush errata */
+    acc->midr = 0x414fc0f0;
+    acc->revidr = 0x0;
+    acc->reset_fpsid = 0x410430f0;
+    acc->isar.mvfr0 = 0x10110222;
+    acc->isar.mvfr1 = 0x11111111;
+    acc->ctr = 0x8444c004;
+    acc->reset_sctlr = 0x00c50078;
+    acc->isar.id_pfr0 = 0x00001131;
+    acc->isar.id_pfr1 = 0x00011011;
+    acc->isar.id_dfr0 = 0x02010555;
+    acc->id_afr0 = 0x00000000;
+    acc->isar.id_mmfr0 = 0x10201105;
+    acc->isar.id_mmfr1 = 0x20000000;
+    acc->isar.id_mmfr2 = 0x01240000;
+    acc->isar.id_mmfr3 = 0x02102211;
+    acc->isar.id_isar0 = 0x02101110;
+    acc->isar.id_isar1 = 0x13112111;
+    acc->isar.id_isar2 = 0x21232041;
+    acc->isar.id_isar3 = 0x11112131;
+    acc->isar.id_isar4 = 0x10011142;
+    acc->isar.dbgdidr = 0x3515f021;
+    acc->isar.dbgdevid = 0x01110f13;
+    acc->isar.dbgdevid1 = 0x0;
+    acc->clidr = 0x0a200023;
+    acc->ccsidr[0] = 0x701fe00a; /* 32K L1 dcache */
+    acc->ccsidr[1] = 0x201fe00a; /* 32K L1 icache */
+    acc->ccsidr[2] = 0x711fe07a; /* 4096K L2 unified cache */
+    acc->isar.reset_pmcr_el0 = 0x410F3000;
+    define_arm_cp_regs_with_class(acc, cortexa15_cp_reginfo, NULL);
 }
 
-static void cortex_m0_class_init(ARMCPUClass *cpu)
+static void cortex_m0_class_init(ARMCPUClass *acc)
 {
-    set_class_feature(cpu, ARM_FEATURE_V6);
-    set_class_feature(cpu, ARM_FEATURE_M);
+    set_class_feature(acc, ARM_FEATURE_V6);
+    set_class_feature(acc, ARM_FEATURE_M);
 
-    cpu->midr = 0x410cc200;
+    acc->midr = 0x410cc200;
 
     /*
      * These ID register values are not guest visible, because
@@ -620,168 +620,168 @@ static void cortex_m0_class_init(ARMCPUClass *cpu)
      * by looking at ID register fields. We use the same values as
      * for the M3.
      */
-    cpu->isar.id_pfr0 = 0x00000030;
-    cpu->isar.id_pfr1 = 0x00000200;
-    cpu->isar.id_dfr0 = 0x00100000;
-    cpu->id_afr0 = 0x00000000;
-    cpu->isar.id_mmfr0 = 0x00000030;
-    cpu->isar.id_mmfr1 = 0x00000000;
-    cpu->isar.id_mmfr2 = 0x00000000;
-    cpu->isar.id_mmfr3 = 0x00000000;
-    cpu->isar.id_isar0 = 0x01141110;
-    cpu->isar.id_isar1 = 0x02111000;
-    cpu->isar.id_isar2 = 0x21112231;
-    cpu->isar.id_isar3 = 0x01111110;
-    cpu->isar.id_isar4 = 0x01310102;
-    cpu->isar.id_isar5 = 0x00000000;
-    cpu->isar.id_isar6 = 0x00000000;
+    acc->isar.id_pfr0 = 0x00000030;
+    acc->isar.id_pfr1 = 0x00000200;
+    acc->isar.id_dfr0 = 0x00100000;
+    acc->id_afr0 = 0x00000000;
+    acc->isar.id_mmfr0 = 0x00000030;
+    acc->isar.id_mmfr1 = 0x00000000;
+    acc->isar.id_mmfr2 = 0x00000000;
+    acc->isar.id_mmfr3 = 0x00000000;
+    acc->isar.id_isar0 = 0x01141110;
+    acc->isar.id_isar1 = 0x02111000;
+    acc->isar.id_isar2 = 0x21112231;
+    acc->isar.id_isar3 = 0x01111110;
+    acc->isar.id_isar4 = 0x01310102;
+    acc->isar.id_isar5 = 0x00000000;
+    acc->isar.id_isar6 = 0x00000000;
 }
 
-static void cortex_m3_class_init(ARMCPUClass *cpu)
+static void cortex_m3_class_init(ARMCPUClass *acc)
 {
-    set_class_feature(cpu, ARM_FEATURE_V7);
-    set_class_feature(cpu, ARM_FEATURE_M);
-    set_class_feature(cpu, ARM_FEATURE_M_MAIN);
-    cpu->midr = 0x410fc231;
-    cpu->pmsav7_dregion = 8;
-    cpu->isar.id_pfr0 = 0x00000030;
-    cpu->isar.id_pfr1 = 0x00000200;
-    cpu->isar.id_dfr0 = 0x00100000;
-    cpu->id_afr0 = 0x00000000;
-    cpu->isar.id_mmfr0 = 0x00000030;
-    cpu->isar.id_mmfr1 = 0x00000000;
-    cpu->isar.id_mmfr2 = 0x00000000;
-    cpu->isar.id_mmfr3 = 0x00000000;
-    cpu->isar.id_isar0 = 0x01141110;
-    cpu->isar.id_isar1 = 0x02111000;
-    cpu->isar.id_isar2 = 0x21112231;
-    cpu->isar.id_isar3 = 0x01111110;
-    cpu->isar.id_isar4 = 0x01310102;
-    cpu->isar.id_isar5 = 0x00000000;
-    cpu->isar.id_isar6 = 0x00000000;
+    set_class_feature(acc, ARM_FEATURE_V7);
+    set_class_feature(acc, ARM_FEATURE_M);
+    set_class_feature(acc, ARM_FEATURE_M_MAIN);
+    acc->midr = 0x410fc231;
+    acc->pmsav7_dregion = 8;
+    acc->isar.id_pfr0 = 0x00000030;
+    acc->isar.id_pfr1 = 0x00000200;
+    acc->isar.id_dfr0 = 0x00100000;
+    acc->id_afr0 = 0x00000000;
+    acc->isar.id_mmfr0 = 0x00000030;
+    acc->isar.id_mmfr1 = 0x00000000;
+    acc->isar.id_mmfr2 = 0x00000000;
+    acc->isar.id_mmfr3 = 0x00000000;
+    acc->isar.id_isar0 = 0x01141110;
+    acc->isar.id_isar1 = 0x02111000;
+    acc->isar.id_isar2 = 0x21112231;
+    acc->isar.id_isar3 = 0x01111110;
+    acc->isar.id_isar4 = 0x01310102;
+    acc->isar.id_isar5 = 0x00000000;
+    acc->isar.id_isar6 = 0x00000000;
 }
 
-static void cortex_m4_class_init(ARMCPUClass *cpu)
+static void cortex_m4_class_init(ARMCPUClass *acc)
 {
-    set_class_feature(cpu, ARM_FEATURE_V7);
-    set_class_feature(cpu, ARM_FEATURE_M);
-    set_class_feature(cpu, ARM_FEATURE_M_MAIN);
-    set_class_feature(cpu, ARM_FEATURE_THUMB_DSP);
-    cpu->midr = 0x410fc240; /* r0p0 */
-    cpu->pmsav7_dregion = 8;
-    cpu->isar.mvfr0 = 0x10110021;
-    cpu->isar.mvfr1 = 0x11000011;
-    cpu->isar.mvfr2 = 0x00000000;
-    cpu->isar.id_pfr0 = 0x00000030;
-    cpu->isar.id_pfr1 = 0x00000200;
-    cpu->isar.id_dfr0 = 0x00100000;
-    cpu->id_afr0 = 0x00000000;
-    cpu->isar.id_mmfr0 = 0x00000030;
-    cpu->isar.id_mmfr1 = 0x00000000;
-    cpu->isar.id_mmfr2 = 0x00000000;
-    cpu->isar.id_mmfr3 = 0x00000000;
-    cpu->isar.id_isar0 = 0x01141110;
-    cpu->isar.id_isar1 = 0x02111000;
-    cpu->isar.id_isar2 = 0x21112231;
-    cpu->isar.id_isar3 = 0x01111110;
-    cpu->isar.id_isar4 = 0x01310102;
-    cpu->isar.id_isar5 = 0x00000000;
-    cpu->isar.id_isar6 = 0x00000000;
+    set_class_feature(acc, ARM_FEATURE_V7);
+    set_class_feature(acc, ARM_FEATURE_M);
+    set_class_feature(acc, ARM_FEATURE_M_MAIN);
+    set_class_feature(acc, ARM_FEATURE_THUMB_DSP);
+    acc->midr = 0x410fc240; /* r0p0 */
+    acc->pmsav7_dregion = 8;
+    acc->isar.mvfr0 = 0x10110021;
+    acc->isar.mvfr1 = 0x11000011;
+    acc->isar.mvfr2 = 0x00000000;
+    acc->isar.id_pfr0 = 0x00000030;
+    acc->isar.id_pfr1 = 0x00000200;
+    acc->isar.id_dfr0 = 0x00100000;
+    acc->id_afr0 = 0x00000000;
+    acc->isar.id_mmfr0 = 0x00000030;
+    acc->isar.id_mmfr1 = 0x00000000;
+    acc->isar.id_mmfr2 = 0x00000000;
+    acc->isar.id_mmfr3 = 0x00000000;
+    acc->isar.id_isar0 = 0x01141110;
+    acc->isar.id_isar1 = 0x02111000;
+    acc->isar.id_isar2 = 0x21112231;
+    acc->isar.id_isar3 = 0x01111110;
+    acc->isar.id_isar4 = 0x01310102;
+    acc->isar.id_isar5 = 0x00000000;
+    acc->isar.id_isar6 = 0x00000000;
 }
 
-static void cortex_m7_class_init(ARMCPUClass *cpu)
+static void cortex_m7_class_init(ARMCPUClass *acc)
 {
-    set_class_feature(cpu, ARM_FEATURE_V7);
-    set_class_feature(cpu, ARM_FEATURE_M);
-    set_class_feature(cpu, ARM_FEATURE_M_MAIN);
-    set_class_feature(cpu, ARM_FEATURE_THUMB_DSP);
-    cpu->midr = 0x411fc272; /* r1p2 */
-    cpu->pmsav7_dregion = 8;
-    cpu->isar.mvfr0 = 0x10110221;
-    cpu->isar.mvfr1 = 0x12000011;
-    cpu->isar.mvfr2 = 0x00000040;
-    cpu->isar.id_pfr0 = 0x00000030;
-    cpu->isar.id_pfr1 = 0x00000200;
-    cpu->isar.id_dfr0 = 0x00100000;
-    cpu->id_afr0 = 0x00000000;
-    cpu->isar.id_mmfr0 = 0x00100030;
-    cpu->isar.id_mmfr1 = 0x00000000;
-    cpu->isar.id_mmfr2 = 0x01000000;
-    cpu->isar.id_mmfr3 = 0x00000000;
-    cpu->isar.id_isar0 = 0x01101110;
-    cpu->isar.id_isar1 = 0x02112000;
-    cpu->isar.id_isar2 = 0x20232231;
-    cpu->isar.id_isar3 = 0x01111131;
-    cpu->isar.id_isar4 = 0x01310132;
-    cpu->isar.id_isar5 = 0x00000000;
-    cpu->isar.id_isar6 = 0x00000000;
+    set_class_feature(acc, ARM_FEATURE_V7);
+    set_class_feature(acc, ARM_FEATURE_M);
+    set_class_feature(acc, ARM_FEATURE_M_MAIN);
+    set_class_feature(acc, ARM_FEATURE_THUMB_DSP);
+    acc->midr = 0x411fc272; /* r1p2 */
+    acc->pmsav7_dregion = 8;
+    acc->isar.mvfr0 = 0x10110221;
+    acc->isar.mvfr1 = 0x12000011;
+    acc->isar.mvfr2 = 0x00000040;
+    acc->isar.id_pfr0 = 0x00000030;
+    acc->isar.id_pfr1 = 0x00000200;
+    acc->isar.id_dfr0 = 0x00100000;
+    acc->id_afr0 = 0x00000000;
+    acc->isar.id_mmfr0 = 0x00100030;
+    acc->isar.id_mmfr1 = 0x00000000;
+    acc->isar.id_mmfr2 = 0x01000000;
+    acc->isar.id_mmfr3 = 0x00000000;
+    acc->isar.id_isar0 = 0x01101110;
+    acc->isar.id_isar1 = 0x02112000;
+    acc->isar.id_isar2 = 0x20232231;
+    acc->isar.id_isar3 = 0x01111131;
+    acc->isar.id_isar4 = 0x01310132;
+    acc->isar.id_isar5 = 0x00000000;
+    acc->isar.id_isar6 = 0x00000000;
 }
 
-static void cortex_m33_class_init(ARMCPUClass *cpu)
+static void cortex_m33_class_init(ARMCPUClass *acc)
 {
-    set_class_feature(cpu, ARM_FEATURE_V8);
-    set_class_feature(cpu, ARM_FEATURE_M);
-    set_class_feature(cpu, ARM_FEATURE_M_MAIN);
-    set_class_feature(cpu, ARM_FEATURE_M_SECURITY);
-    set_class_feature(cpu, ARM_FEATURE_THUMB_DSP);
-    cpu->midr = 0x410fd213; /* r0p3 */
-    cpu->pmsav7_dregion = 16;
-    cpu->sau_sregion = 8;
-    cpu->isar.mvfr0 = 0x10110021;
-    cpu->isar.mvfr1 = 0x11000011;
-    cpu->isar.mvfr2 = 0x00000040;
-    cpu->isar.id_pfr0 = 0x00000030;
-    cpu->isar.id_pfr1 = 0x00000210;
-    cpu->isar.id_dfr0 = 0x00200000;
-    cpu->id_afr0 = 0x00000000;
-    cpu->isar.id_mmfr0 = 0x00101F40;
-    cpu->isar.id_mmfr1 = 0x00000000;
-    cpu->isar.id_mmfr2 = 0x01000000;
-    cpu->isar.id_mmfr3 = 0x00000000;
-    cpu->isar.id_isar0 = 0x01101110;
-    cpu->isar.id_isar1 = 0x02212000;
-    cpu->isar.id_isar2 = 0x20232232;
-    cpu->isar.id_isar3 = 0x01111131;
-    cpu->isar.id_isar4 = 0x01310132;
-    cpu->isar.id_isar5 = 0x00000000;
-    cpu->isar.id_isar6 = 0x00000000;
-    cpu->clidr = 0x00000000;
-    cpu->ctr = 0x8000c000;
+    set_class_feature(acc, ARM_FEATURE_V8);
+    set_class_feature(acc, ARM_FEATURE_M);
+    set_class_feature(acc, ARM_FEATURE_M_MAIN);
+    set_class_feature(acc, ARM_FEATURE_M_SECURITY);
+    set_class_feature(acc, ARM_FEATURE_THUMB_DSP);
+    acc->midr = 0x410fd213; /* r0p3 */
+    acc->pmsav7_dregion = 16;
+    acc->sau_sregion = 8;
+    acc->isar.mvfr0 = 0x10110021;
+    acc->isar.mvfr1 = 0x11000011;
+    acc->isar.mvfr2 = 0x00000040;
+    acc->isar.id_pfr0 = 0x00000030;
+    acc->isar.id_pfr1 = 0x00000210;
+    acc->isar.id_dfr0 = 0x00200000;
+    acc->id_afr0 = 0x00000000;
+    acc->isar.id_mmfr0 = 0x00101F40;
+    acc->isar.id_mmfr1 = 0x00000000;
+    acc->isar.id_mmfr2 = 0x01000000;
+    acc->isar.id_mmfr3 = 0x00000000;
+    acc->isar.id_isar0 = 0x01101110;
+    acc->isar.id_isar1 = 0x02212000;
+    acc->isar.id_isar2 = 0x20232232;
+    acc->isar.id_isar3 = 0x01111131;
+    acc->isar.id_isar4 = 0x01310132;
+    acc->isar.id_isar5 = 0x00000000;
+    acc->isar.id_isar6 = 0x00000000;
+    acc->clidr = 0x00000000;
+    acc->ctr = 0x8000c000;
 }
 
-static void cortex_m55_class_init(ARMCPUClass *cpu)
+static void cortex_m55_class_init(ARMCPUClass *acc)
 {
-    set_class_feature(cpu, ARM_FEATURE_V8);
-    set_class_feature(cpu, ARM_FEATURE_V8_1M);
-    set_class_feature(cpu, ARM_FEATURE_M);
-    set_class_feature(cpu, ARM_FEATURE_M_MAIN);
-    set_class_feature(cpu, ARM_FEATURE_M_SECURITY);
-    set_class_feature(cpu, ARM_FEATURE_THUMB_DSP);
-    cpu->midr = 0x410fd221; /* r0p1 */
-    cpu->revidr = 0;
-    cpu->pmsav7_dregion = 16;
-    cpu->sau_sregion = 8;
+    set_class_feature(acc, ARM_FEATURE_V8);
+    set_class_feature(acc, ARM_FEATURE_V8_1M);
+    set_class_feature(acc, ARM_FEATURE_M);
+    set_class_feature(acc, ARM_FEATURE_M_MAIN);
+    set_class_feature(acc, ARM_FEATURE_M_SECURITY);
+    set_class_feature(acc, ARM_FEATURE_THUMB_DSP);
+    acc->midr = 0x410fd221; /* r0p1 */
+    acc->revidr = 0;
+    acc->pmsav7_dregion = 16;
+    acc->sau_sregion = 8;
     /* These are the MVFR* values for the FPU + full MVE configuration */
-    cpu->isar.mvfr0 = 0x10110221;
-    cpu->isar.mvfr1 = 0x12100211;
-    cpu->isar.mvfr2 = 0x00000040;
-    cpu->isar.id_pfr0 = 0x20000030;
-    cpu->isar.id_pfr1 = 0x00000230;
-    cpu->isar.id_dfr0 = 0x10200000;
-    cpu->id_afr0 = 0x00000000;
-    cpu->isar.id_mmfr0 = 0x00111040;
-    cpu->isar.id_mmfr1 = 0x00000000;
-    cpu->isar.id_mmfr2 = 0x01000000;
-    cpu->isar.id_mmfr3 = 0x00000011;
-    cpu->isar.id_isar0 = 0x01103110;
-    cpu->isar.id_isar1 = 0x02212000;
-    cpu->isar.id_isar2 = 0x20232232;
-    cpu->isar.id_isar3 = 0x01111131;
-    cpu->isar.id_isar4 = 0x01310132;
-    cpu->isar.id_isar5 = 0x00000000;
-    cpu->isar.id_isar6 = 0x00000000;
-    cpu->clidr = 0x00000000; /* caches not implemented */
-    cpu->ctr = 0x8303c003;
+    acc->isar.mvfr0 = 0x10110221;
+    acc->isar.mvfr1 = 0x12100211;
+    acc->isar.mvfr2 = 0x00000040;
+    acc->isar.id_pfr0 = 0x20000030;
+    acc->isar.id_pfr1 = 0x00000230;
+    acc->isar.id_dfr0 = 0x10200000;
+    acc->id_afr0 = 0x00000000;
+    acc->isar.id_mmfr0 = 0x00111040;
+    acc->isar.id_mmfr1 = 0x00000000;
+    acc->isar.id_mmfr2 = 0x01000000;
+    acc->isar.id_mmfr3 = 0x00000011;
+    acc->isar.id_isar0 = 0x01103110;
+    acc->isar.id_isar1 = 0x02212000;
+    acc->isar.id_isar2 = 0x20232232;
+    acc->isar.id_isar3 = 0x01111131;
+    acc->isar.id_isar4 = 0x01310132;
+    acc->isar.id_isar5 = 0x00000000;
+    acc->isar.id_isar6 = 0x00000000;
+    acc->clidr = 0x00000000; /* caches not implemented */
+    acc->ctr = 0x8303c003;
 }
 
 static const ARMCPRegInfo cortexr5_cp_reginfo[] = {
@@ -794,180 +794,180 @@ static const ARMCPRegInfo cortexr5_cp_reginfo[] = {
       .opc2 = 0, .access = PL1_W, .type = ARM_CP_NOP },
 };
 
-static void cortex_r5_class_init(ARMCPUClass *cpu)
+static void cortex_r5_class_init(ARMCPUClass *acc)
 {
-    set_class_feature(cpu, ARM_FEATURE_V7);
-    set_class_feature(cpu, ARM_FEATURE_V7MP);
-    set_class_feature(cpu, ARM_FEATURE_PMSA);
-    set_class_feature(cpu, ARM_FEATURE_PMU);
-    cpu->midr = 0x411fc153; /* r1p3 */
-    cpu->isar.id_pfr0 = 0x0131;
-    cpu->isar.id_pfr1 = 0x001;
-    cpu->isar.id_dfr0 = 0x010400;
-    cpu->id_afr0 = 0x0;
-    cpu->isar.id_mmfr0 = 0x0210030;
-    cpu->isar.id_mmfr1 = 0x00000000;
-    cpu->isar.id_mmfr2 = 0x01200000;
-    cpu->isar.id_mmfr3 = 0x0211;
-    cpu->isar.id_isar0 = 0x02101111;
-    cpu->isar.id_isar1 = 0x13112111;
-    cpu->isar.id_isar2 = 0x21232141;
-    cpu->isar.id_isar3 = 0x01112131;
-    cpu->isar.id_isar4 = 0x0010142;
-    cpu->isar.id_isar5 = 0x0;
-    cpu->isar.id_isar6 = 0x0;
-    cpu->pmsav7_dregion = 16;
-    cpu->isar.reset_pmcr_el0 = 0x41151800;
-    define_arm_cp_regs_with_class(cpu, cortexr5_cp_reginfo, NULL);
+    set_class_feature(acc, ARM_FEATURE_V7);
+    set_class_feature(acc, ARM_FEATURE_V7MP);
+    set_class_feature(acc, ARM_FEATURE_PMSA);
+    set_class_feature(acc, ARM_FEATURE_PMU);
+    acc->midr = 0x411fc153; /* r1p3 */
+    acc->isar.id_pfr0 = 0x0131;
+    acc->isar.id_pfr1 = 0x001;
+    acc->isar.id_dfr0 = 0x010400;
+    acc->id_afr0 = 0x0;
+    acc->isar.id_mmfr0 = 0x0210030;
+    acc->isar.id_mmfr1 = 0x00000000;
+    acc->isar.id_mmfr2 = 0x01200000;
+    acc->isar.id_mmfr3 = 0x0211;
+    acc->isar.id_isar0 = 0x02101111;
+    acc->isar.id_isar1 = 0x13112111;
+    acc->isar.id_isar2 = 0x21232141;
+    acc->isar.id_isar3 = 0x01112131;
+    acc->isar.id_isar4 = 0x0010142;
+    acc->isar.id_isar5 = 0x0;
+    acc->isar.id_isar6 = 0x0;
+    acc->pmsav7_dregion = 16;
+    acc->isar.reset_pmcr_el0 = 0x41151800;
+    define_arm_cp_regs_with_class(acc, cortexr5_cp_reginfo, NULL);
 }
 
-static void cortex_r5f_class_init(ARMCPUClass *cpu)
+static void cortex_r5f_class_init(ARMCPUClass *acc)
 {
-    cortex_r5_class_init(cpu);
-    cpu->isar.mvfr0 = 0x10110221;
-    cpu->isar.mvfr1 = 0x00000011;
+    cortex_r5_class_init(acc);
+    acc->isar.mvfr0 = 0x10110221;
+    acc->isar.mvfr1 = 0x00000011;
 }
 
-static void ti925t_class_init(ARMCPUClass *cpu)
+static void ti925t_class_init(ARMCPUClass *acc)
 {
-    set_class_feature(cpu, ARM_FEATURE_V4T);
-    set_class_feature(cpu, ARM_FEATURE_OMAPCP);
-    cpu->midr = ARM_CPUID_TI925T;
-    cpu->ctr = 0x5109149;
-    cpu->reset_sctlr = 0x00000070;
+    set_class_feature(acc, ARM_FEATURE_V4T);
+    set_class_feature(acc, ARM_FEATURE_OMAPCP);
+    acc->midr = ARM_CPUID_TI925T;
+    acc->ctr = 0x5109149;
+    acc->reset_sctlr = 0x00000070;
 }
 
-static void sa1100_class_init(ARMCPUClass *cpu)
+static void sa1100_class_init(ARMCPUClass *acc)
 {
-    cpu->dtb_compatible = "intel,sa1100";
-    set_class_feature(cpu, ARM_FEATURE_STRONGARM);
-    set_class_feature(cpu, ARM_FEATURE_DUMMY_C15_REGS);
-    cpu->midr = 0x4401A11B;
-    cpu->reset_sctlr = 0x00000070;
+    acc->dtb_compatible = "intel,sa1100";
+    set_class_feature(acc, ARM_FEATURE_STRONGARM);
+    set_class_feature(acc, ARM_FEATURE_DUMMY_C15_REGS);
+    acc->midr = 0x4401A11B;
+    acc->reset_sctlr = 0x00000070;
 }
 
-static void sa1110_class_init(ARMCPUClass *cpu)
+static void sa1110_class_init(ARMCPUClass *acc)
 {
-    set_class_feature(cpu, ARM_FEATURE_STRONGARM);
-    set_class_feature(cpu, ARM_FEATURE_DUMMY_C15_REGS);
-    cpu->midr = 0x6901B119;
-    cpu->reset_sctlr = 0x00000070;
+    set_class_feature(acc, ARM_FEATURE_STRONGARM);
+    set_class_feature(acc, ARM_FEATURE_DUMMY_C15_REGS);
+    acc->midr = 0x6901B119;
+    acc->reset_sctlr = 0x00000070;
 }
 
-static void pxa250_class_init(ARMCPUClass *cpu)
+static void pxa250_class_init(ARMCPUClass *acc)
 {
-    cpu->dtb_compatible = "marvell,xscale";
-    set_class_feature(cpu, ARM_FEATURE_V5);
-    set_class_feature(cpu, ARM_FEATURE_XSCALE);
-    cpu->midr = 0x69052100;
-    cpu->ctr = 0xd172172;
-    cpu->reset_sctlr = 0x00000078;
+    acc->dtb_compatible = "marvell,xscale";
+    set_class_feature(acc, ARM_FEATURE_V5);
+    set_class_feature(acc, ARM_FEATURE_XSCALE);
+    acc->midr = 0x69052100;
+    acc->ctr = 0xd172172;
+    acc->reset_sctlr = 0x00000078;
 }
 
-static void pxa255_class_init(ARMCPUClass *cpu)
+static void pxa255_class_init(ARMCPUClass *acc)
 {
-    cpu->dtb_compatible = "marvell,xscale";
-    set_class_feature(cpu, ARM_FEATURE_V5);
-    set_class_feature(cpu, ARM_FEATURE_XSCALE);
-    cpu->midr = 0x69052d00;
-    cpu->ctr = 0xd172172;
-    cpu->reset_sctlr = 0x00000078;
+    acc->dtb_compatible = "marvell,xscale";
+    set_class_feature(acc, ARM_FEATURE_V5);
+    set_class_feature(acc, ARM_FEATURE_XSCALE);
+    acc->midr = 0x69052d00;
+    acc->ctr = 0xd172172;
+    acc->reset_sctlr = 0x00000078;
 }
 
-static void pxa260_class_init(ARMCPUClass *cpu)
+static void pxa260_class_init(ARMCPUClass *acc)
 {
-    cpu->dtb_compatible = "marvell,xscale";
-    set_class_feature(cpu, ARM_FEATURE_V5);
-    set_class_feature(cpu, ARM_FEATURE_XSCALE);
-    cpu->midr = 0x69052903;
-    cpu->ctr = 0xd172172;
-    cpu->reset_sctlr = 0x00000078;
+    acc->dtb_compatible = "marvell,xscale";
+    set_class_feature(acc, ARM_FEATURE_V5);
+    set_class_feature(acc, ARM_FEATURE_XSCALE);
+    acc->midr = 0x69052903;
+    acc->ctr = 0xd172172;
+    acc->reset_sctlr = 0x00000078;
 }
 
-static void pxa261_class_init(ARMCPUClass *cpu)
+static void pxa261_class_init(ARMCPUClass *acc)
 {
-    cpu->dtb_compatible = "marvell,xscale";
-    set_class_feature(cpu, ARM_FEATURE_V5);
-    set_class_feature(cpu, ARM_FEATURE_XSCALE);
-    cpu->midr = 0x69052d05;
-    cpu->ctr = 0xd172172;
-    cpu->reset_sctlr = 0x00000078;
+    acc->dtb_compatible = "marvell,xscale";
+    set_class_feature(acc, ARM_FEATURE_V5);
+    set_class_feature(acc, ARM_FEATURE_XSCALE);
+    acc->midr = 0x69052d05;
+    acc->ctr = 0xd172172;
+    acc->reset_sctlr = 0x00000078;
 }
 
-static void pxa262_class_init(ARMCPUClass *cpu)
+static void pxa262_class_init(ARMCPUClass *acc)
 {
-    cpu->dtb_compatible = "marvell,xscale";
-    set_class_feature(cpu, ARM_FEATURE_V5);
-    set_class_feature(cpu, ARM_FEATURE_XSCALE);
-    cpu->midr = 0x69052d06;
-    cpu->ctr = 0xd172172;
-    cpu->reset_sctlr = 0x00000078;
+    acc->dtb_compatible = "marvell,xscale";
+    set_class_feature(acc, ARM_FEATURE_V5);
+    set_class_feature(acc, ARM_FEATURE_XSCALE);
+    acc->midr = 0x69052d06;
+    acc->ctr = 0xd172172;
+    acc->reset_sctlr = 0x00000078;
 }
 
-static void pxa270a0_class_init(ARMCPUClass *cpu)
+static void pxa270a0_class_init(ARMCPUClass *acc)
 {
-    cpu->dtb_compatible = "marvell,xscale";
-    set_class_feature(cpu, ARM_FEATURE_V5);
-    set_class_feature(cpu, ARM_FEATURE_XSCALE);
-    set_class_feature(cpu, ARM_FEATURE_IWMMXT);
-    cpu->midr = 0x69054110;
-    cpu->ctr = 0xd172172;
-    cpu->reset_sctlr = 0x00000078;
+    acc->dtb_compatible = "marvell,xscale";
+    set_class_feature(acc, ARM_FEATURE_V5);
+    set_class_feature(acc, ARM_FEATURE_XSCALE);
+    set_class_feature(acc, ARM_FEATURE_IWMMXT);
+    acc->midr = 0x69054110;
+    acc->ctr = 0xd172172;
+    acc->reset_sctlr = 0x00000078;
 }
 
-static void pxa270a1_class_init(ARMCPUClass *cpu)
+static void pxa270a1_class_init(ARMCPUClass *acc)
 {
-    cpu->dtb_compatible = "marvell,xscale";
-    set_class_feature(cpu, ARM_FEATURE_V5);
-    set_class_feature(cpu, ARM_FEATURE_XSCALE);
-    set_class_feature(cpu, ARM_FEATURE_IWMMXT);
-    cpu->midr = 0x69054111;
-    cpu->ctr = 0xd172172;
-    cpu->reset_sctlr = 0x00000078;
+    acc->dtb_compatible = "marvell,xscale";
+    set_class_feature(acc, ARM_FEATURE_V5);
+    set_class_feature(acc, ARM_FEATURE_XSCALE);
+    set_class_feature(acc, ARM_FEATURE_IWMMXT);
+    acc->midr = 0x69054111;
+    acc->ctr = 0xd172172;
+    acc->reset_sctlr = 0x00000078;
 }
 
-static void pxa270b0_class_init(ARMCPUClass *cpu)
+static void pxa270b0_class_init(ARMCPUClass *acc)
 {
-    cpu->dtb_compatible = "marvell,xscale";
-    set_class_feature(cpu, ARM_FEATURE_V5);
-    set_class_feature(cpu, ARM_FEATURE_XSCALE);
-    set_class_feature(cpu, ARM_FEATURE_IWMMXT);
-    cpu->midr = 0x69054112;
-    cpu->ctr = 0xd172172;
-    cpu->reset_sctlr = 0x00000078;
+    acc->dtb_compatible = "marvell,xscale";
+    set_class_feature(acc, ARM_FEATURE_V5);
+    set_class_feature(acc, ARM_FEATURE_XSCALE);
+    set_class_feature(acc, ARM_FEATURE_IWMMXT);
+    acc->midr = 0x69054112;
+    acc->ctr = 0xd172172;
+    acc->reset_sctlr = 0x00000078;
 }
 
-static void pxa270b1_class_init(ARMCPUClass *cpu)
+static void pxa270b1_class_init(ARMCPUClass *acc)
 {
-    cpu->dtb_compatible = "marvell,xscale";
-    set_class_feature(cpu, ARM_FEATURE_V5);
-    set_class_feature(cpu, ARM_FEATURE_XSCALE);
-    set_class_feature(cpu, ARM_FEATURE_IWMMXT);
-    cpu->midr = 0x69054113;
-    cpu->ctr = 0xd172172;
-    cpu->reset_sctlr = 0x00000078;
+    acc->dtb_compatible = "marvell,xscale";
+    set_class_feature(acc, ARM_FEATURE_V5);
+    set_class_feature(acc, ARM_FEATURE_XSCALE);
+    set_class_feature(acc, ARM_FEATURE_IWMMXT);
+    acc->midr = 0x69054113;
+    acc->ctr = 0xd172172;
+    acc->reset_sctlr = 0x00000078;
 }
 
-static void pxa270c0_class_init(ARMCPUClass *cpu)
+static void pxa270c0_class_init(ARMCPUClass *acc)
 {
-    cpu->dtb_compatible = "marvell,xscale";
-    set_class_feature(cpu, ARM_FEATURE_V5);
-    set_class_feature(cpu, ARM_FEATURE_XSCALE);
-    set_class_feature(cpu, ARM_FEATURE_IWMMXT);
-    cpu->midr = 0x69054114;
-    cpu->ctr = 0xd172172;
-    cpu->reset_sctlr = 0x00000078;
+    acc->dtb_compatible = "marvell,xscale";
+    set_class_feature(acc, ARM_FEATURE_V5);
+    set_class_feature(acc, ARM_FEATURE_XSCALE);
+    set_class_feature(acc, ARM_FEATURE_IWMMXT);
+    acc->midr = 0x69054114;
+    acc->ctr = 0xd172172;
+    acc->reset_sctlr = 0x00000078;
 }
 
-static void pxa270c5_class_init(ARMCPUClass *cpu)
+static void pxa270c5_class_init(ARMCPUClass *acc)
 {
-    cpu->dtb_compatible = "marvell,xscale";
-    set_class_feature(cpu, ARM_FEATURE_V5);
-    set_class_feature(cpu, ARM_FEATURE_XSCALE);
-    set_class_feature(cpu, ARM_FEATURE_IWMMXT);
-    cpu->midr = 0x69054117;
-    cpu->ctr = 0xd172172;
-    cpu->reset_sctlr = 0x00000078;
+    acc->dtb_compatible = "marvell,xscale";
+    set_class_feature(acc, ARM_FEATURE_V5);
+    set_class_feature(acc, ARM_FEATURE_XSCALE);
+    set_class_feature(acc, ARM_FEATURE_IWMMXT);
+    acc->midr = 0x69054117;
+    acc->ctr = 0xd172172;
+    acc->reset_sctlr = 0x00000078;
 }
 
 #ifdef CONFIG_TCG
@@ -1010,51 +1010,51 @@ static void arm_v7m_class_init(ObjectClass *oc, void *data)
  * The version of '-cpu max' for qemu-system-aarch64 is defined in cpu64.c;
  * this only needs to handle 32 bits, and need not care about KVM.
  */
-static void arm_max_class_init(ARMCPUClass *cpu)
+static void arm_max_class_init(ARMCPUClass *acc)
 {
     /* aarch64_a57_class_init, advertising none of the aarch64 features */
-    cpu->dtb_compatible = "arm,cortex-a57";
-    set_class_feature(cpu, ARM_FEATURE_V8);
-    set_class_feature(cpu, ARM_FEATURE_NEON);
-    set_class_feature(cpu, ARM_FEATURE_GENERIC_TIMER);
-    set_class_feature(cpu, ARM_FEATURE_CBAR_RO);
-    set_class_feature(cpu, ARM_FEATURE_EL2);
-    set_class_feature(cpu, ARM_FEATURE_EL3);
-    set_class_feature(cpu, ARM_FEATURE_PMU);
-    cpu->midr = 0x411fd070;
-    cpu->revidr = 0x00000000;
-    cpu->reset_fpsid = 0x41034070;
-    cpu->isar.mvfr0 = 0x10110222;
-    cpu->isar.mvfr1 = 0x12111111;
-    cpu->isar.mvfr2 = 0x00000043;
-    cpu->ctr = 0x8444c004;
-    cpu->reset_sctlr = 0x00c50838;
-    cpu->isar.id_pfr0 = 0x00000131;
-    cpu->isar.id_pfr1 = 0x00011011;
-    cpu->isar.id_dfr0 = 0x03010066;
-    cpu->id_afr0 = 0x00000000;
-    cpu->isar.id_mmfr0 = 0x10101105;
-    cpu->isar.id_mmfr1 = 0x40000000;
-    cpu->isar.id_mmfr2 = 0x01260000;
-    cpu->isar.id_mmfr3 = 0x02102211;
-    cpu->isar.id_isar0 = 0x02101110;
-    cpu->isar.id_isar1 = 0x13112111;
-    cpu->isar.id_isar2 = 0x21232042;
-    cpu->isar.id_isar3 = 0x01112131;
-    cpu->isar.id_isar4 = 0x00011142;
-    cpu->isar.id_isar5 = 0x00011121;
-    cpu->isar.id_isar6 = 0;
-    cpu->isar.dbgdidr = 0x3516d000;
-    cpu->isar.dbgdevid = 0x00110f13;
-    cpu->isar.dbgdevid1 = 0x2;
-    cpu->isar.reset_pmcr_el0 = 0x41013000;
-    cpu->clidr = 0x0a200023;
-    cpu->ccsidr[0] = 0x701fe00a; /* 32KB L1 dcache */
-    cpu->ccsidr[1] = 0x201fe012; /* 48KB L1 icache */
-    cpu->ccsidr[2] = 0x70ffe07a; /* 2048KB L2 cache */
-    define_cortex_a72_a57_a53_cp_reginfo(cpu);
+    acc->dtb_compatible = "arm,cortex-a57";
+    set_class_feature(acc, ARM_FEATURE_V8);
+    set_class_feature(acc, ARM_FEATURE_NEON);
+    set_class_feature(acc, ARM_FEATURE_GENERIC_TIMER);
+    set_class_feature(acc, ARM_FEATURE_CBAR_RO);
+    set_class_feature(acc, ARM_FEATURE_EL2);
+    set_class_feature(acc, ARM_FEATURE_EL3);
+    set_class_feature(acc, ARM_FEATURE_PMU);
+    acc->midr = 0x411fd070;
+    acc->revidr = 0x00000000;
+    acc->reset_fpsid = 0x41034070;
+    acc->isar.mvfr0 = 0x10110222;
+    acc->isar.mvfr1 = 0x12111111;
+    acc->isar.mvfr2 = 0x00000043;
+    acc->ctr = 0x8444c004;
+    acc->reset_sctlr = 0x00c50838;
+    acc->isar.id_pfr0 = 0x00000131;
+    acc->isar.id_pfr1 = 0x00011011;
+    acc->isar.id_dfr0 = 0x03010066;
+    acc->id_afr0 = 0x00000000;
+    acc->isar.id_mmfr0 = 0x10101105;
+    acc->isar.id_mmfr1 = 0x40000000;
+    acc->isar.id_mmfr2 = 0x01260000;
+    acc->isar.id_mmfr3 = 0x02102211;
+    acc->isar.id_isar0 = 0x02101110;
+    acc->isar.id_isar1 = 0x13112111;
+    acc->isar.id_isar2 = 0x21232042;
+    acc->isar.id_isar3 = 0x01112131;
+    acc->isar.id_isar4 = 0x00011142;
+    acc->isar.id_isar5 = 0x00011121;
+    acc->isar.id_isar6 = 0;
+    acc->isar.dbgdidr = 0x3516d000;
+    acc->isar.dbgdevid = 0x00110f13;
+    acc->isar.dbgdevid1 = 0x2;
+    acc->isar.reset_pmcr_el0 = 0x41013000;
+    acc->clidr = 0x0a200023;
+    acc->ccsidr[0] = 0x701fe00a; /* 32KB L1 dcache */
+    acc->ccsidr[1] = 0x201fe012; /* 48KB L1 icache */
+    acc->ccsidr[2] = 0x70ffe07a; /* 2048KB L2 cache */
+    define_cortex_a72_a57_a53_cp_reginfo(acc);
 
-    aa32_max_features(cpu);
+    aa32_max_features(acc);
 
 #ifdef CONFIG_USER_ONLY
     /*
@@ -1062,7 +1062,7 @@ static void arm_max_class_init(ARMCPUClass *cpu)
      * Only do this for user-mode, where -cpu max is the default, so that
      * older v6 and v7 programs are more likely to work without adjustment.
      */
-    cpu->isar.mvfr0 = FIELD_DP32(cpu->isar.mvfr0, MVFR0, FPSHVEC, 1);
+    acc->isar.mvfr0 = FIELD_DP32(acc->isar.mvfr0, MVFR0, FPSHVEC, 1);
 #endif
 }
 #endif /* !TARGET_AARCH64 */
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* [RFC PATCH 27/40] target/arm: Split out strongarm_class_init
  2023-01-03 18:16 [RFC PATCH 00/40] Toward class init of cpu features Richard Henderson
                   ` (25 preceding siblings ...)
  2023-01-03 18:16 ` [RFC PATCH 26/40] target/arm: Rename 'cpu' to 'acc' in class init functions Richard Henderson
@ 2023-01-03 18:16 ` Richard Henderson
  2023-01-05 22:12   ` Philippe Mathieu-Daudé
  2023-01-03 18:16 ` [RFC PATCH 28/40] target/arm: Split out xscale*_class_init Richard Henderson
                   ` (14 subsequent siblings)
  41 siblings, 1 reply; 77+ messages in thread
From: Richard Henderson @ 2023-01-03 18:16 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, berrange, eduardo, armbru, ajones, alex.bennee

Use an intermediate function to share code between
sa1100_class_init and sa1110_class_init.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/cpu_tcg.c | 15 +++++++++------
 1 file changed, 9 insertions(+), 6 deletions(-)

diff --git a/target/arm/cpu_tcg.c b/target/arm/cpu_tcg.c
index 1ef825b39e..c6d50f326e 100644
--- a/target/arm/cpu_tcg.c
+++ b/target/arm/cpu_tcg.c
@@ -837,21 +837,24 @@ static void ti925t_class_init(ARMCPUClass *acc)
     acc->reset_sctlr = 0x00000070;
 }
 
-static void sa1100_class_init(ARMCPUClass *acc)
+static void strongarm_class_init(ARMCPUClass *acc)
 {
-    acc->dtb_compatible = "intel,sa1100";
     set_class_feature(acc, ARM_FEATURE_STRONGARM);
     set_class_feature(acc, ARM_FEATURE_DUMMY_C15_REGS);
-    acc->midr = 0x4401A11B;
     acc->reset_sctlr = 0x00000070;
 }
 
+static void sa1100_class_init(ARMCPUClass *acc)
+{
+    strongarm_class_init(acc);
+    acc->dtb_compatible = "intel,sa1100";
+    acc->midr = 0x4401A11B;
+}
+
 static void sa1110_class_init(ARMCPUClass *acc)
 {
-    set_class_feature(acc, ARM_FEATURE_STRONGARM);
-    set_class_feature(acc, ARM_FEATURE_DUMMY_C15_REGS);
+    strongarm_class_init(acc);
     acc->midr = 0x6901B119;
-    acc->reset_sctlr = 0x00000070;
 }
 
 static void pxa250_class_init(ARMCPUClass *acc)
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* [RFC PATCH 28/40] target/arm: Split out xscale*_class_init
  2023-01-03 18:16 [RFC PATCH 00/40] Toward class init of cpu features Richard Henderson
                   ` (26 preceding siblings ...)
  2023-01-03 18:16 ` [RFC PATCH 27/40] target/arm: Split out strongarm_class_init Richard Henderson
@ 2023-01-03 18:16 ` Richard Henderson
  2023-01-05 22:13   ` Philippe Mathieu-Daudé
  2023-01-03 18:16 ` [RFC PATCH 29/40] target/arm: Remove m-profile has_vfp and has_dsp properties Richard Henderson
                   ` (13 subsequent siblings)
  41 siblings, 1 reply; 77+ messages in thread
From: Richard Henderson @ 2023-01-03 18:16 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, berrange, eduardo, armbru, ajones, alex.bennee

Use two intermediate functions to share code between
the 13 variants of pxa*_class_init.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/cpu_tcg.c | 81 +++++++++++++-------------------------------
 1 file changed, 23 insertions(+), 58 deletions(-)

diff --git a/target/arm/cpu_tcg.c b/target/arm/cpu_tcg.c
index c6d50f326e..a3b6940040 100644
--- a/target/arm/cpu_tcg.c
+++ b/target/arm/cpu_tcg.c
@@ -857,120 +857,85 @@ static void sa1110_class_init(ARMCPUClass *acc)
     acc->midr = 0x6901B119;
 }
 
-static void pxa250_class_init(ARMCPUClass *acc)
+static void xscale_class_init(ARMCPUClass *acc)
 {
     acc->dtb_compatible = "marvell,xscale";
     set_class_feature(acc, ARM_FEATURE_V5);
     set_class_feature(acc, ARM_FEATURE_XSCALE);
-    acc->midr = 0x69052100;
     acc->ctr = 0xd172172;
     acc->reset_sctlr = 0x00000078;
 }
 
+static void pxa250_class_init(ARMCPUClass *acc)
+{
+    xscale_class_init(acc);
+    acc->midr = 0x69052100;
+}
+
 static void pxa255_class_init(ARMCPUClass *acc)
 {
-    acc->dtb_compatible = "marvell,xscale";
-    set_class_feature(acc, ARM_FEATURE_V5);
-    set_class_feature(acc, ARM_FEATURE_XSCALE);
+    xscale_class_init(acc);
     acc->midr = 0x69052d00;
-    acc->ctr = 0xd172172;
-    acc->reset_sctlr = 0x00000078;
 }
 
 static void pxa260_class_init(ARMCPUClass *acc)
 {
-    acc->dtb_compatible = "marvell,xscale";
-    set_class_feature(acc, ARM_FEATURE_V5);
-    set_class_feature(acc, ARM_FEATURE_XSCALE);
+    xscale_class_init(acc);
     acc->midr = 0x69052903;
-    acc->ctr = 0xd172172;
-    acc->reset_sctlr = 0x00000078;
 }
 
 static void pxa261_class_init(ARMCPUClass *acc)
 {
-    acc->dtb_compatible = "marvell,xscale";
-    set_class_feature(acc, ARM_FEATURE_V5);
-    set_class_feature(acc, ARM_FEATURE_XSCALE);
+    xscale_class_init(acc);
     acc->midr = 0x69052d05;
-    acc->ctr = 0xd172172;
-    acc->reset_sctlr = 0x00000078;
 }
 
 static void pxa262_class_init(ARMCPUClass *acc)
 {
-    acc->dtb_compatible = "marvell,xscale";
-    set_class_feature(acc, ARM_FEATURE_V5);
-    set_class_feature(acc, ARM_FEATURE_XSCALE);
+    xscale_class_init(acc);
     acc->midr = 0x69052d06;
-    acc->ctr = 0xd172172;
-    acc->reset_sctlr = 0x00000078;
+}
+
+static void xscale_iwmmxt_class_init(ARMCPUClass *acc)
+{
+    xscale_class_init(acc);
+    set_class_feature(acc, ARM_FEATURE_IWMMXT);
 }
 
 static void pxa270a0_class_init(ARMCPUClass *acc)
 {
-    acc->dtb_compatible = "marvell,xscale";
-    set_class_feature(acc, ARM_FEATURE_V5);
-    set_class_feature(acc, ARM_FEATURE_XSCALE);
-    set_class_feature(acc, ARM_FEATURE_IWMMXT);
+    xscale_iwmmxt_class_init(acc);
     acc->midr = 0x69054110;
-    acc->ctr = 0xd172172;
-    acc->reset_sctlr = 0x00000078;
 }
 
 static void pxa270a1_class_init(ARMCPUClass *acc)
 {
-    acc->dtb_compatible = "marvell,xscale";
-    set_class_feature(acc, ARM_FEATURE_V5);
-    set_class_feature(acc, ARM_FEATURE_XSCALE);
-    set_class_feature(acc, ARM_FEATURE_IWMMXT);
+    xscale_iwmmxt_class_init(acc);
     acc->midr = 0x69054111;
-    acc->ctr = 0xd172172;
-    acc->reset_sctlr = 0x00000078;
 }
 
 static void pxa270b0_class_init(ARMCPUClass *acc)
 {
-    acc->dtb_compatible = "marvell,xscale";
-    set_class_feature(acc, ARM_FEATURE_V5);
-    set_class_feature(acc, ARM_FEATURE_XSCALE);
-    set_class_feature(acc, ARM_FEATURE_IWMMXT);
+    xscale_iwmmxt_class_init(acc);
     acc->midr = 0x69054112;
-    acc->ctr = 0xd172172;
-    acc->reset_sctlr = 0x00000078;
 }
 
 static void pxa270b1_class_init(ARMCPUClass *acc)
 {
-    acc->dtb_compatible = "marvell,xscale";
-    set_class_feature(acc, ARM_FEATURE_V5);
-    set_class_feature(acc, ARM_FEATURE_XSCALE);
-    set_class_feature(acc, ARM_FEATURE_IWMMXT);
+    xscale_iwmmxt_class_init(acc);
     acc->midr = 0x69054113;
-    acc->ctr = 0xd172172;
-    acc->reset_sctlr = 0x00000078;
 }
 
 static void pxa270c0_class_init(ARMCPUClass *acc)
 {
-    acc->dtb_compatible = "marvell,xscale";
-    set_class_feature(acc, ARM_FEATURE_V5);
-    set_class_feature(acc, ARM_FEATURE_XSCALE);
-    set_class_feature(acc, ARM_FEATURE_IWMMXT);
+    xscale_iwmmxt_class_init(acc);
     acc->midr = 0x69054114;
-    acc->ctr = 0xd172172;
-    acc->reset_sctlr = 0x00000078;
 }
 
 static void pxa270c5_class_init(ARMCPUClass *acc)
 {
-    acc->dtb_compatible = "marvell,xscale";
-    set_class_feature(acc, ARM_FEATURE_V5);
-    set_class_feature(acc, ARM_FEATURE_XSCALE);
-    set_class_feature(acc, ARM_FEATURE_IWMMXT);
+    xscale_iwmmxt_class_init(acc);
     acc->midr = 0x69054117;
-    acc->ctr = 0xd172172;
-    acc->reset_sctlr = 0x00000078;
 }
 
 #ifdef CONFIG_TCG
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* [RFC PATCH 29/40] target/arm: Remove m-profile has_vfp and has_dsp properties
  2023-01-03 18:16 [RFC PATCH 00/40] Toward class init of cpu features Richard Henderson
                   ` (27 preceding siblings ...)
  2023-01-03 18:16 ` [RFC PATCH 28/40] target/arm: Split out xscale*_class_init Richard Henderson
@ 2023-01-03 18:16 ` Richard Henderson
  2023-01-03 18:16 ` [RFC PATCH 30/40] target/arm: Move feature bit propagation to class init Richard Henderson
                   ` (12 subsequent siblings)
  41 siblings, 0 replies; 77+ messages in thread
From: Richard Henderson @ 2023-01-03 18:16 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, berrange, eduardo, armbru, ajones, alex.bennee

Replace the properties with separate cpu classes that have
these features disabled.  These stand in the way of moving
all id-register properties to the cpu class level, because
of the case of SSE200, which has one cortex-m33 with dsp+vfp
and one without.

Create the full set of m-profile cpus with and without the
corresponding options.  As per

  https://developer.arm.com/documentation/102787/0100

cortex m-{4,7,33,55} have a configurable fpu, while only
cortex-m33 has a configurable dsp (we don't implement m35).

The armv7m boards besides armsse will be able to use
  -cpu cortex-mX-nofpu
instead of
  -cpu cortex-mX,has_fpu=off.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 include/hw/arm/armsse.h |  3 +-
 include/hw/arm/armv7m.h |  2 -
 target/arm/cpu.h        |  2 -
 hw/arm/armsse.c         | 53 +++++++++++++++------------
 hw/arm/armv7m.c         | 12 ------
 hw/arm/musca.c          | 14 +++----
 target/arm/cpu.c        | 30 +--------------
 target/arm/cpu_tcg.c    | 81 +++++++++++++++++++++++++++++++++++++++++
 8 files changed, 118 insertions(+), 79 deletions(-)

diff --git a/include/hw/arm/armsse.h b/include/hw/arm/armsse.h
index 9648e7a419..98e371c83c 100644
--- a/include/hw/arm/armsse.h
+++ b/include/hw/arm/armsse.h
@@ -123,6 +123,7 @@ OBJECT_DECLARE_TYPE(ARMSSE, ARMSSEClass,
  */
 #define TYPE_IOTKIT "iotkit"
 #define TYPE_SSE200 "sse-200"
+#define TYPE_SSE200_B "sse-200-b"
 #define TYPE_SSE300 "sse-300"
 
 /* We have an IRQ splitter and an OR gate input for each external PPC
@@ -221,8 +222,6 @@ struct ARMSSE {
     uint32_t exp_numirq;
     uint32_t sram_addr_width;
     uint32_t init_svtor;
-    bool cpu_fpu[SSE_MAX_CPUS];
-    bool cpu_dsp[SSE_MAX_CPUS];
 };
 
 typedef struct ARMSSEInfo ARMSSEInfo;
diff --git a/include/hw/arm/armv7m.h b/include/hw/arm/armv7m.h
index b7ba0ff409..a24433172c 100644
--- a/include/hw/arm/armv7m.h
+++ b/include/hw/arm/armv7m.h
@@ -97,8 +97,6 @@ struct ARMv7MState {
     uint32_t init_nsvtor;
     bool enable_bitband;
     bool start_powered_off;
-    bool vfp;
-    bool dsp;
 };
 
 #endif
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index e8dd75b003..4b47a420d5 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -897,8 +897,6 @@ struct ArchCPU {
     bool has_vfp;
     /* CPU has Neon */
     bool has_neon;
-    /* CPU has M-profile DSP extension */
-    bool has_dsp;
 
     /* CPU has memory protection unit */
     bool has_mpu;
diff --git a/hw/arm/armsse.c b/hw/arm/armsse.c
index 0202bad787..9d6280eec5 100644
--- a/hw/arm/armsse.c
+++ b/hw/arm/armsse.c
@@ -57,7 +57,7 @@ typedef struct ARMSSEDeviceInfo {
 
 struct ARMSSEInfo {
     const char *name;
-    const char *cpu_type;
+    const char *cpu_type[SSE_MAX_CPUS];
     uint32_t sse_version;
     int sram_banks;
     uint32_t sram_bank_base;
@@ -83,8 +83,6 @@ static Property iotkit_properties[] = {
     DEFINE_PROP_UINT32("EXP_NUMIRQ", ARMSSE, exp_numirq, 64),
     DEFINE_PROP_UINT32("SRAM_ADDR_WIDTH", ARMSSE, sram_addr_width, 15),
     DEFINE_PROP_UINT32("init-svtor", ARMSSE, init_svtor, 0x10000000),
-    DEFINE_PROP_BOOL("CPU0_FPU", ARMSSE, cpu_fpu[0], true),
-    DEFINE_PROP_BOOL("CPU0_DSP", ARMSSE, cpu_dsp[0], true),
     DEFINE_PROP_END_OF_LIST()
 };
 
@@ -94,10 +92,6 @@ static Property sse200_properties[] = {
     DEFINE_PROP_UINT32("EXP_NUMIRQ", ARMSSE, exp_numirq, 64),
     DEFINE_PROP_UINT32("SRAM_ADDR_WIDTH", ARMSSE, sram_addr_width, 15),
     DEFINE_PROP_UINT32("init-svtor", ARMSSE, init_svtor, 0x10000000),
-    DEFINE_PROP_BOOL("CPU0_FPU", ARMSSE, cpu_fpu[0], false),
-    DEFINE_PROP_BOOL("CPU0_DSP", ARMSSE, cpu_dsp[0], false),
-    DEFINE_PROP_BOOL("CPU1_FPU", ARMSSE, cpu_fpu[1], true),
-    DEFINE_PROP_BOOL("CPU1_DSP", ARMSSE, cpu_dsp[1], true),
     DEFINE_PROP_END_OF_LIST()
 };
 
@@ -107,8 +101,6 @@ static Property sse300_properties[] = {
     DEFINE_PROP_UINT32("EXP_NUMIRQ", ARMSSE, exp_numirq, 64),
     DEFINE_PROP_UINT32("SRAM_ADDR_WIDTH", ARMSSE, sram_addr_width, 18),
     DEFINE_PROP_UINT32("init-svtor", ARMSSE, init_svtor, 0x10000000),
-    DEFINE_PROP_BOOL("CPU0_FPU", ARMSSE, cpu_fpu[0], true),
-    DEFINE_PROP_BOOL("CPU0_DSP", ARMSSE, cpu_dsp[0], true),
     DEFINE_PROP_END_OF_LIST()
 };
 
@@ -505,7 +497,7 @@ static const ARMSSEInfo armsse_variants[] = {
     {
         .name = TYPE_IOTKIT,
         .sse_version = ARMSSE_IOTKIT,
-        .cpu_type = ARM_CPU_TYPE_NAME("cortex-m33"),
+        .cpu_type[0] = ARM_CPU_TYPE_NAME("cortex-m33"),
         .sram_banks = 1,
         .sram_bank_base = 0x20000000,
         .num_cpus = 1,
@@ -526,7 +518,31 @@ static const ARMSSEInfo armsse_variants[] = {
     {
         .name = TYPE_SSE200,
         .sse_version = ARMSSE_SSE200,
-        .cpu_type = ARM_CPU_TYPE_NAME("cortex-m33"),
+        .cpu_type[0] = ARM_CPU_TYPE_NAME("cortex-m33-nodsp-novfp"),
+        .cpu_type[1] = ARM_CPU_TYPE_NAME("cortex-m33"),
+        .sram_banks = 4,
+        .sram_bank_base = 0x20000000,
+        .num_cpus = 2,
+        .sys_version = 0x22041743,
+        .iidr = 0,
+        .cpuwait_rst = 2,
+        .has_mhus = true,
+        .has_cachectrl = true,
+        .has_cpusecctrl = true,
+        .has_cpuid = true,
+        .has_cpu_pwrctrl = false,
+        .has_sse_counter = false,
+        .has_tcms = false,
+        .props = sse200_properties,
+        .devinfo = sse200_devices,
+        .irq_is_common = sse200_irq_is_common,
+    },
+    {
+        /* For Musca-B1, differs only on cpu[0]. */
+        .name = TYPE_SSE200_B,
+        .sse_version = ARMSSE_SSE200,
+        .cpu_type[0] = ARM_CPU_TYPE_NAME("cortex-m33"),
+        .cpu_type[1] = ARM_CPU_TYPE_NAME("cortex-m33"),
         .sram_banks = 4,
         .sram_bank_base = 0x20000000,
         .num_cpus = 2,
@@ -547,7 +563,7 @@ static const ARMSSEInfo armsse_variants[] = {
     {
         .name = TYPE_SSE300,
         .sse_version = ARMSSE_SSE300,
-        .cpu_type = ARM_CPU_TYPE_NAME("cortex-m55"),
+        .cpu_type[0] = ARM_CPU_TYPE_NAME("cortex-m55"),
         .sram_banks = 2,
         .sram_bank_base = 0x21000000,
         .num_cpus = 1,
@@ -720,7 +736,8 @@ static void armsse_init(Object *obj)
         name = g_strdup_printf("armv7m%d", i);
         object_initialize_child(OBJECT(&s->cluster[i]), name, &s->armv7m[i],
                                 TYPE_ARMV7M);
-        qdev_prop_set_string(DEVICE(&s->armv7m[i]), "cpu-type", info->cpu_type);
+        qdev_prop_set_string(DEVICE(&s->armv7m[i]), "cpu-type",
+                             info->cpu_type[i]);
         g_free(name);
         name = g_strdup_printf("arm-sse-cpu-container%d", i);
         memory_region_init(&s->cpu_container[i], obj, name, UINT64_MAX);
@@ -1019,16 +1036,6 @@ static void armsse_realize(DeviceState *dev, Error **errp)
                 return;
             }
         }
-        if (!s->cpu_fpu[i]) {
-            if (!object_property_set_bool(cpuobj, "vfp", false, errp)) {
-                return;
-            }
-        }
-        if (!s->cpu_dsp[i]) {
-            if (!object_property_set_bool(cpuobj, "dsp", false, errp)) {
-                return;
-            }
-        }
 
         if (i > 0) {
             memory_region_add_subregion_overlap(&s->cpu_container[i], 0,
diff --git a/hw/arm/armv7m.c b/hw/arm/armv7m.c
index 50a9507c0b..fdd1c77c08 100644
--- a/hw/arm/armv7m.c
+++ b/hw/arm/armv7m.c
@@ -323,16 +323,6 @@ static void armv7m_realize(DeviceState *dev, Error **errp)
             return;
         }
     }
-    if (object_property_find(OBJECT(s->cpu), "vfp")) {
-        if (!object_property_set_bool(OBJECT(s->cpu), "vfp", s->vfp, errp)) {
-            return;
-        }
-    }
-    if (object_property_find(OBJECT(s->cpu), "dsp")) {
-        if (!object_property_set_bool(OBJECT(s->cpu), "dsp", s->dsp, errp)) {
-            return;
-        }
-    }
 
     /*
      * Tell the CPU where the NVIC is; it will fail realize if it doesn't
@@ -528,8 +518,6 @@ static Property armv7m_properties[] = {
     DEFINE_PROP_BOOL("enable-bitband", ARMv7MState, enable_bitband, false),
     DEFINE_PROP_BOOL("start-powered-off", ARMv7MState, start_powered_off,
                      false),
-    DEFINE_PROP_BOOL("vfp", ARMv7MState, vfp, true),
-    DEFINE_PROP_BOOL("dsp", ARMv7MState, dsp, true),
     DEFINE_PROP_END_OF_LIST(),
 };
 
diff --git a/hw/arm/musca.c b/hw/arm/musca.c
index 6eeee57c9d..1cb76ba2a9 100644
--- a/hw/arm/musca.c
+++ b/hw/arm/musca.c
@@ -377,8 +377,12 @@ static void musca_init(MachineState *machine)
     mms->s32kclk = clock_new(OBJECT(machine), "S32KCLK");
     clock_set_hz(mms->s32kclk, S32KCLK_FRQ);
 
+    /*
+     * Musca-A takes the default SSE-200 FPU/DSP settings (ie no for
+     * CPU0 and yes for CPU1); Musca-B1 explicitly enables them for CPU0.
+     */
     object_initialize_child(OBJECT(machine), "sse-200", &mms->sse,
-                            TYPE_SSE200);
+                            mmc->type == MUSCA_A ? TYPE_SSE200 : TYPE_SSE200_B);
     ssedev = DEVICE(&mms->sse);
     object_property_set_link(OBJECT(&mms->sse), "memory",
                              OBJECT(system_memory), &error_fatal);
@@ -387,14 +391,6 @@ static void musca_init(MachineState *machine)
     qdev_prop_set_uint32(ssedev, "SRAM_ADDR_WIDTH", mmc->sram_addr_width);
     qdev_connect_clock_in(ssedev, "MAINCLK", mms->sysclk);
     qdev_connect_clock_in(ssedev, "S32KCLK", mms->s32kclk);
-    /*
-     * Musca-A takes the default SSE-200 FPU/DSP settings (ie no for
-     * CPU0 and yes for CPU1); Musca-B1 explicitly enables them for CPU0.
-     */
-    if (mmc->type == MUSCA_B1) {
-        qdev_prop_set_bit(ssedev, "CPU0_FPU", true);
-        qdev_prop_set_bit(ssedev, "CPU0_DSP", true);
-    }
     sysbus_realize(SYS_BUS_DEVICE(&mms->sse), &error_fatal);
 
     /*
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index f4d8be6c4c..0824af601f 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -1305,9 +1305,6 @@ static Property arm_cpu_has_vfp_property =
 static Property arm_cpu_has_neon_property =
             DEFINE_PROP_BOOL("neon", ARMCPU, has_neon, true);
 
-static Property arm_cpu_has_dsp_property =
-            DEFINE_PROP_BOOL("dsp", ARMCPU, has_dsp, true);
-
 static Property arm_cpu_has_mpu_property =
             DEFINE_PROP_BOOL("has-mpu", ARMCPU, has_mpu, true);
 
@@ -1428,7 +1425,7 @@ static void arm_cpu_post_init(Object *obj)
         ? cpu_isar_feature(aa64_fp_simd, cpu)
         : cpu_isar_feature(aa32_vfp, cpu)) {
         cpu->has_vfp = true;
-        if (!kvm_enabled()) {
+        if (!kvm_enabled() && !arm_feature(&cpu->env, ARM_FEATURE_M)) {
             qdev_property_add_static(DEVICE(obj), &arm_cpu_has_vfp_property);
         }
     }
@@ -1440,11 +1437,6 @@ static void arm_cpu_post_init(Object *obj)
         }
     }
 
-    if (arm_feature(&cpu->env, ARM_FEATURE_M) &&
-        arm_feature(&cpu->env, ARM_FEATURE_THUMB_DSP)) {
-        qdev_property_add_static(DEVICE(obj), &arm_cpu_has_dsp_property);
-    }
-
     if (arm_feature(&cpu->env, ARM_FEATURE_PMSA)) {
         qdev_property_add_static(DEVICE(obj), &arm_cpu_has_mpu_property);
         if (arm_feature(&cpu->env, ARM_FEATURE_V7)) {
@@ -1801,26 +1793,6 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
         cpu->isar.mvfr1 = u;
     }
 
-    if (arm_feature(env, ARM_FEATURE_M) && !cpu->has_dsp) {
-        uint32_t u;
-
-        unset_feature(env, ARM_FEATURE_THUMB_DSP);
-
-        u = cpu->isar.id_isar1;
-        u = FIELD_DP32(u, ID_ISAR1, EXTEND, 1);
-        cpu->isar.id_isar1 = u;
-
-        u = cpu->isar.id_isar2;
-        u = FIELD_DP32(u, ID_ISAR2, MULTU, 1);
-        u = FIELD_DP32(u, ID_ISAR2, MULTS, 1);
-        cpu->isar.id_isar2 = u;
-
-        u = cpu->isar.id_isar3;
-        u = FIELD_DP32(u, ID_ISAR3, SIMD, 1);
-        u = FIELD_DP32(u, ID_ISAR3, SATURATE, 0);
-        cpu->isar.id_isar3 = u;
-    }
-
     /* Some features automatically imply others: */
     if (arm_feature(env, ARM_FEATURE_V8)) {
         if (arm_feature(env, ARM_FEATURE_M)) {
diff --git a/target/arm/cpu_tcg.c b/target/arm/cpu_tcg.c
index a3b6940040..2292597c3c 100644
--- a/target/arm/cpu_tcg.c
+++ b/target/arm/cpu_tcg.c
@@ -661,6 +661,34 @@ static void cortex_m3_class_init(ARMCPUClass *acc)
     acc->isar.id_isar6 = 0x00000000;
 }
 
+static void disable_m_dsp(ARMCPUClass *acc)
+{
+    uint32_t u;
+
+    u = acc->isar.id_isar1;
+    u = FIELD_DP32(u, ID_ISAR1, EXTEND, 1);
+    acc->isar.id_isar1 = u;
+
+    u = acc->isar.id_isar2;
+    u = FIELD_DP32(u, ID_ISAR2, MULTU, 1);
+    u = FIELD_DP32(u, ID_ISAR2, MULTS, 1);
+    acc->isar.id_isar2 = u;
+
+    u = acc->isar.id_isar3;
+    u = FIELD_DP32(u, ID_ISAR3, SIMD, 1);
+    u = FIELD_DP32(u, ID_ISAR3, SATURATE, 0);
+    acc->isar.id_isar3 = u;
+
+    unset_class_feature(acc, ARM_FEATURE_THUMB_DSP);
+}
+
+static void disable_m_vfp(ARMCPUClass *acc)
+{
+    acc->isar.mvfr0 = 0;
+    acc->isar.mvfr1 = 0;
+    acc->isar.mvfr2 = 0;
+}
+
 static void cortex_m4_class_init(ARMCPUClass *acc)
 {
     set_class_feature(acc, ARM_FEATURE_V7);
@@ -689,6 +717,12 @@ static void cortex_m4_class_init(ARMCPUClass *acc)
     acc->isar.id_isar6 = 0x00000000;
 }
 
+static void cortex_m4_nf_class_init(ARMCPUClass *acc)
+{
+    cortex_m4_class_init(acc);
+    disable_m_vfp(acc);
+}
+
 static void cortex_m7_class_init(ARMCPUClass *acc)
 {
     set_class_feature(acc, ARM_FEATURE_V7);
@@ -717,6 +751,12 @@ static void cortex_m7_class_init(ARMCPUClass *acc)
     acc->isar.id_isar6 = 0x00000000;
 }
 
+static void cortex_m7_nf_class_init(ARMCPUClass *acc)
+{
+    cortex_m7_class_init(acc);
+    disable_m_vfp(acc);
+}
+
 static void cortex_m33_class_init(ARMCPUClass *acc)
 {
     set_class_feature(acc, ARM_FEATURE_V8);
@@ -749,6 +789,25 @@ static void cortex_m33_class_init(ARMCPUClass *acc)
     acc->ctr = 0x8000c000;
 }
 
+static void cortex_m33_nd_class_init(ARMCPUClass *acc)
+{
+    cortex_m33_class_init(acc);
+    disable_m_dsp(acc);
+}
+
+static void cortex_m33_nf_class_init(ARMCPUClass *acc)
+{
+    cortex_m33_class_init(acc);
+    disable_m_vfp(acc);
+}
+
+static void cortex_m33_ndnf_class_init(ARMCPUClass *acc)
+{
+    cortex_m33_class_init(acc);
+    disable_m_dsp(acc);
+    disable_m_vfp(acc);
+}
+
 static void cortex_m55_class_init(ARMCPUClass *acc)
 {
     set_class_feature(acc, ARM_FEATURE_V8);
@@ -784,6 +843,12 @@ static void cortex_m55_class_init(ARMCPUClass *acc)
     acc->ctr = 0x8303c003;
 }
 
+static void cortex_m55_nf_class_init(ARMCPUClass *acc)
+{
+    cortex_m55_class_init(acc);
+    disable_m_vfp(acc);
+}
+
 static const ARMCPRegInfo cortexr5_cp_reginfo[] = {
     /* Dummy the TCM region regs for the moment */
     { .name = "ATCM", .cp = 15, .opc1 = 0, .crn = 9, .crm = 1, .opc2 = 0,
@@ -1081,10 +1146,26 @@ static const ARMCPUInfo arm_tcg_cpus[] = {
 static const ARMCPUInfo arm_v7m_tcg_cpus[] = {
     { .name = "cortex-m0",   .class_init = cortex_m0_class_init },
     { .name = "cortex-m3",   .class_init = cortex_m3_class_init },
+
     { .name = "cortex-m4",   .class_init = cortex_m4_class_init },
+    { .name = "cortex-m4-novfp",
+      .class_init = cortex_m4_nf_class_init },
+
     { .name = "cortex-m7",   .class_init = cortex_m7_class_init },
+    { .name = "cortex-m7-novfp",
+      .class_init = cortex_m7_nf_class_init },
+
     { .name = "cortex-m33",  .class_init = cortex_m33_class_init },
+    { .name = "cortex-m33-nodsp",
+      .class_init = cortex_m33_nd_class_init },
+    { .name = "cortex-m33-novfp",
+      .class_init = cortex_m33_nf_class_init },
+    { .name = "cortex-m33-nodsp-novfp",
+      .class_init = cortex_m33_ndnf_class_init },
+
     { .name = "cortex-m55",  .class_init = cortex_m55_class_init },
+    { .name = "cortex-m55-novfp",
+      .class_init = cortex_m55_nf_class_init },
 };
 
 static const TypeInfo arm_v7m_cpu_type_info = {
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* [RFC PATCH 30/40] target/arm: Move feature bit propagation to class init
  2023-01-03 18:16 [RFC PATCH 00/40] Toward class init of cpu features Richard Henderson
                   ` (28 preceding siblings ...)
  2023-01-03 18:16 ` [RFC PATCH 29/40] target/arm: Remove m-profile has_vfp and has_dsp properties Richard Henderson
@ 2023-01-03 18:16 ` Richard Henderson
  2023-01-03 18:16 ` [RFC PATCH 31/40] target/arm: Get and set class properties in the monitor Richard Henderson
                   ` (11 subsequent siblings)
  41 siblings, 0 replies; 77+ messages in thread
From: Richard Henderson @ 2023-01-03 18:16 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, berrange, eduardo, armbru, ajones, alex.bennee

With the introduction of aarch64_host_class_init, we have
enough feature bits set to do propagation early.  Move the
tcg consistency checks to class_late_init, after we have
populated all of the id registers.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/cpu.c | 162 ++++++++++++++++++++++-------------------------
 1 file changed, 77 insertions(+), 85 deletions(-)

diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index 0824af601f..22a6ccaece 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -1369,14 +1369,6 @@ static void arm_cpu_post_init(Object *obj)
 {
     ARMCPU *cpu = ARM_CPU(obj);
 
-    /* M profile implies PMSA. We have to do this here rather than
-     * in realize with the other feature-implication checks because
-     * we look at the PMSA bit to see if we should add some properties.
-     */
-    if (arm_feature(&cpu->env, ARM_FEATURE_M)) {
-        set_feature(&cpu->env, ARM_FEATURE_PMSA);
-    }
-
     if (arm_feature(&cpu->env, ARM_FEATURE_CBAR) ||
         arm_feature(&cpu->env, ARM_FEATURE_CBAR_RO)) {
         qdev_property_add_static(DEVICE(obj), &arm_cpu_reset_cbar_property);
@@ -1574,7 +1566,6 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
     CPUARMState *env = &cpu->env;
     int pagebits;
     Error *local_err = NULL;
-    bool no_aa32 = false;
 
 #ifndef CONFIG_USER_ONLY
     /* The NVIC and M-profile CPU are two halves of a single piece of
@@ -1793,82 +1784,6 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
         cpu->isar.mvfr1 = u;
     }
 
-    /* Some features automatically imply others: */
-    if (arm_feature(env, ARM_FEATURE_V8)) {
-        if (arm_feature(env, ARM_FEATURE_M)) {
-            set_feature(env, ARM_FEATURE_V7);
-        } else {
-            set_feature(env, ARM_FEATURE_V7VE);
-        }
-    }
-
-    /*
-     * There exist AArch64 cpus without AArch32 support.  When KVM
-     * queries ID_ISAR0_EL1 on such a host, the value is UNKNOWN.
-     * Similarly, we cannot check ID_AA64PFR0 without AArch64 support.
-     * As a general principle, we also do not make ID register
-     * consistency checks anywhere unless using TCG, because only
-     * for TCG would a consistency-check failure be a QEMU bug.
-     */
-    if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) {
-        no_aa32 = !cpu_isar_feature(aa64_aa32, cpu);
-    }
-
-    if (arm_feature(env, ARM_FEATURE_V7VE)) {
-        /* v7 Virtualization Extensions. In real hardware this implies
-         * EL2 and also the presence of the Security Extensions.
-         * For QEMU, for backwards-compatibility we implement some
-         * CPUs or CPU configs which have no actual EL2 or EL3 but do
-         * include the various other features that V7VE implies.
-         * Presence of EL2 itself is ARM_FEATURE_EL2, and of the
-         * Security Extensions is ARM_FEATURE_EL3.
-         */
-        assert(!tcg_enabled() || no_aa32 ||
-               cpu_isar_feature(aa32_arm_div, cpu));
-        set_feature(env, ARM_FEATURE_LPAE);
-        set_feature(env, ARM_FEATURE_V7);
-    }
-    if (arm_feature(env, ARM_FEATURE_V7)) {
-        set_feature(env, ARM_FEATURE_VAPA);
-        set_feature(env, ARM_FEATURE_THUMB2);
-        set_feature(env, ARM_FEATURE_MPIDR);
-        if (!arm_feature(env, ARM_FEATURE_M)) {
-            set_feature(env, ARM_FEATURE_V6K);
-        } else {
-            set_feature(env, ARM_FEATURE_V6);
-        }
-
-        /* Always define VBAR for V7 CPUs even if it doesn't exist in
-         * non-EL3 configs. This is needed by some legacy boards.
-         */
-        set_feature(env, ARM_FEATURE_VBAR);
-    }
-    if (arm_feature(env, ARM_FEATURE_V6K)) {
-        set_feature(env, ARM_FEATURE_V6);
-        set_feature(env, ARM_FEATURE_MVFR);
-    }
-    if (arm_feature(env, ARM_FEATURE_V6)) {
-        set_feature(env, ARM_FEATURE_V5);
-        if (!arm_feature(env, ARM_FEATURE_M)) {
-            assert(!tcg_enabled() || no_aa32 ||
-                   cpu_isar_feature(aa32_jazelle, cpu));
-            set_feature(env, ARM_FEATURE_AUXCR);
-        }
-    }
-    if (arm_feature(env, ARM_FEATURE_V5)) {
-        set_feature(env, ARM_FEATURE_V4T);
-    }
-    if (arm_feature(env, ARM_FEATURE_LPAE)) {
-        set_feature(env, ARM_FEATURE_V7MP);
-    }
-    if (arm_feature(env, ARM_FEATURE_CBAR_RO)) {
-        set_feature(env, ARM_FEATURE_CBAR);
-    }
-    if (arm_feature(env, ARM_FEATURE_THUMB2) &&
-        !arm_feature(env, ARM_FEATURE_M)) {
-        set_feature(env, ARM_FEATURE_THUMB_DSP);
-    }
-
     /*
      * We rely on no XScale CPU having VFP so we can use the same bits in the
      * TB flags field for VECSTRIDE and XSCALE_CPAR.
@@ -2318,6 +2233,67 @@ static void arm_cpu_leaf_class_init(ObjectClass *oc, void *data)
     if (acc->info->class_init) {
         acc->info->class_init(acc);
     }
+
+    /* Some features automatically imply others: */
+    if (arm_class_feature(acc, ARM_FEATURE_V8)) {
+        if (arm_class_feature(acc, ARM_FEATURE_M)) {
+            set_class_feature(acc, ARM_FEATURE_V7);
+        } else {
+            set_class_feature(acc, ARM_FEATURE_V7VE);
+        }
+    }
+    if (arm_class_feature(acc, ARM_FEATURE_V7VE)) {
+        /*
+         * v7 Virtualization Extensions. In real hardware this implies
+         * EL2 and also the presence of the Security Extensions.
+         * For QEMU, for backwards-compatibility we implement some
+         * CPUs or CPU configs which have no actual EL2 or EL3 but do
+         * include the various other features that V7VE implies.
+         */
+        set_class_feature(acc, ARM_FEATURE_LPAE);
+        set_class_feature(acc, ARM_FEATURE_V7);
+    }
+    if (arm_class_feature(acc, ARM_FEATURE_V7)) {
+        set_class_feature(acc, ARM_FEATURE_VAPA);
+        set_class_feature(acc, ARM_FEATURE_THUMB2);
+        set_class_feature(acc, ARM_FEATURE_MPIDR);
+        if (!arm_class_feature(acc, ARM_FEATURE_M)) {
+            set_class_feature(acc, ARM_FEATURE_V6K);
+        } else {
+            set_class_feature(acc, ARM_FEATURE_V6);
+        }
+        /*
+         * Always define VBAR for V7 CPUs even if it doesn't exist in
+         * non-EL3 configs. This is needed by some legacy boards.
+         */
+        set_class_feature(acc, ARM_FEATURE_VBAR);
+    }
+    if (arm_class_feature(acc, ARM_FEATURE_V6K)) {
+        set_class_feature(acc, ARM_FEATURE_V6);
+        set_class_feature(acc, ARM_FEATURE_MVFR);
+    }
+    if (arm_class_feature(acc, ARM_FEATURE_V6)) {
+        set_class_feature(acc, ARM_FEATURE_V5);
+        if (!arm_class_feature(acc, ARM_FEATURE_M)) {
+            set_class_feature(acc, ARM_FEATURE_AUXCR);
+        }
+    }
+    if (arm_class_feature(acc, ARM_FEATURE_V5)) {
+        set_class_feature(acc, ARM_FEATURE_V4T);
+    }
+    if (arm_class_feature(acc, ARM_FEATURE_LPAE)) {
+        set_class_feature(acc, ARM_FEATURE_V7MP);
+    }
+    if (arm_class_feature(acc, ARM_FEATURE_CBAR_RO)) {
+        set_class_feature(acc, ARM_FEATURE_CBAR);
+    }
+    if (arm_class_feature(acc, ARM_FEATURE_THUMB2) &&
+        !arm_class_feature(acc, ARM_FEATURE_M)) {
+        set_class_feature(acc, ARM_FEATURE_THUMB_DSP);
+    }
+    if (arm_class_feature(acc, ARM_FEATURE_M)) {
+        set_class_feature(acc, ARM_FEATURE_PMSA);
+    }
 }
 
 static bool arm_cpu_class_late_init(ObjectClass *oc, Error **errp)
@@ -2329,6 +2305,22 @@ static bool arm_cpu_class_late_init(ObjectClass *oc, Error **errp)
             return false;
         }
     }
+
+    /* Run some consistency checks for TCG. */
+    if (tcg_enabled()) {
+        bool no_aa32 = arm_class_feature(acc, ARM_FEATURE_AARCH64) &&
+                       !class_isar_feature(aa64_aa32, acc);
+
+        if (!no_aa32) {
+            if (arm_class_feature(acc, ARM_FEATURE_V7VE)) {
+                assert(class_isar_feature(aa32_arm_div, acc));
+            }
+            if (arm_class_feature(acc, ARM_FEATURE_V6) &&
+                !arm_class_feature(acc, ARM_FEATURE_M)) {
+                assert(class_isar_feature(aa32_jazelle, acc));
+            }
+        }
+    }
     return true;
 }
 
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* [RFC PATCH 31/40] target/arm: Get and set class properties in the monitor
  2023-01-03 18:16 [RFC PATCH 00/40] Toward class init of cpu features Richard Henderson
                   ` (29 preceding siblings ...)
  2023-01-03 18:16 ` [RFC PATCH 30/40] target/arm: Move feature bit propagation to class init Richard Henderson
@ 2023-01-03 18:16 ` Richard Henderson
  2023-01-03 18:16 ` [RFC PATCH 32/40] target/arm: Move "midr" to class property Richard Henderson
                   ` (10 subsequent siblings)
  41 siblings, 0 replies; 77+ messages in thread
From: Richard Henderson @ 2023-01-03 18:16 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, berrange, eduardo, armbru, ajones, alex.bennee

Setting is not actually functional here, because it is always done
after the creation of the first object, and so will generate an error.
But at least it's a different error than 'Property not found'.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/monitor.c | 21 ++++++++++++++++-----
 1 file changed, 16 insertions(+), 5 deletions(-)

diff --git a/target/arm/monitor.c b/target/arm/monitor.c
index ecdd5ee817..262785e713 100644
--- a/target/arm/monitor.c
+++ b/target/arm/monitor.c
@@ -89,7 +89,7 @@ QEMU_BUILD_BUG_ON(ARM_MAX_VQ > 16);
  * will attempt to set them. If there are dependencies between features,
  * then the order that considers those dependencies must be used.
  */
-static const char *cpu_model_advertised_features[] = {
+static const char * const cpu_model_advertised_features[] = {
     "aarch64", "pmu", "sve",
     "sve128", "sve256", "sve384", "sve512",
     "sve640", "sve768", "sve896", "sve1024", "sve1152", "sve1280",
@@ -159,7 +159,7 @@ CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type,
         }
     }
 
-    obj = object_new(object_class_get_name(oc));
+    obj = object_new_with_class(oc);
 
     if (qdict_in) {
         Visitor *visitor;
@@ -175,7 +175,10 @@ CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type,
         i = 0;
         while ((name = cpu_model_advertised_features[i++]) != NULL) {
             if (qdict_get(qdict_in, name)) {
-                if (!object_property_set(obj, name, visitor, &err)) {
+                ClassProperty *cp = class_property_find(oc, name);
+                if (cp
+                    ? !class_property_set(oc, cp, visitor, &err)
+                    : !object_property_set(obj, name, visitor, &err)) {
                     break;
                 }
             }
@@ -207,12 +210,20 @@ CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type,
     i = 0;
     while ((name = cpu_model_advertised_features[i++]) != NULL) {
         ObjectProperty *prop = object_property_find(obj, name);
-        if (prop) {
-            QObject *value;
+        QObject *value = NULL;
 
+        if (prop) {
             assert(prop->get);
             value = object_property_get_qobject(obj, name, &error_abort);
+        } else {
+            ClassProperty *cprop = class_property_find(oc, name);
 
+            if (cprop) {
+                assert(cprop->get);
+                value = class_property_get_qobject(oc, name, &error_abort);
+            }
+        }
+        if (value) {
             qdict_put_obj(qdict_out, name, value);
         }
     }
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* [RFC PATCH 32/40] target/arm: Move "midr" to class property
  2023-01-03 18:16 [RFC PATCH 00/40] Toward class init of cpu features Richard Henderson
                   ` (30 preceding siblings ...)
  2023-01-03 18:16 ` [RFC PATCH 31/40] target/arm: Get and set class properties in the monitor Richard Henderson
@ 2023-01-03 18:16 ` Richard Henderson
  2023-01-05 22:18   ` Philippe Mathieu-Daudé
  2023-01-03 18:16 ` [RFC PATCH 33/40] target/arm: Move "cntfrq" " Richard Henderson
                   ` (9 subsequent siblings)
  41 siblings, 1 reply; 77+ messages in thread
From: Richard Henderson @ 2023-01-03 18:16 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, berrange, eduardo, armbru, ajones, alex.bennee

With the movement of the property, we can remove the field
from the cpu entirely, using only the class.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/cpu.h      |  1 -
 hw/arm/xilinx_zynq.c  |  9 ++++++---
 hw/intc/armv7m_nvic.c |  2 +-
 target/arm/cpu.c      | 18 ++++++++++++++++--
 target/arm/helper.c   | 14 ++++++++------
 5 files changed, 31 insertions(+), 13 deletions(-)

diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index 4b47a420d5..f2dceae0e7 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -956,7 +956,6 @@ struct ArchCPU {
      * field by reading the value from the KVM vCPU.
      */
     ARMISARegisters isar;
-    uint64_t midr;
     uint32_t revidr;
     uint32_t reset_fpsid;
     uint64_t ctr;
diff --git a/hw/arm/xilinx_zynq.c b/hw/arm/xilinx_zynq.c
index 3190cc0b8d..3e5b4f4483 100644
--- a/hw/arm/xilinx_zynq.c
+++ b/hw/arm/xilinx_zynq.c
@@ -177,6 +177,7 @@ static inline int zynq_init_spi_flashes(uint32_t base_addr, qemu_irq irq,
 static void zynq_init(MachineState *machine)
 {
     ZynqMachineState *zynq_machine = ZYNQ_MACHINE(machine);
+    ObjectClass *cpu_class;
     ARMCPU *cpu;
     MemoryRegion *address_space_mem = get_system_memory();
     MemoryRegion *ocm_ram = g_new(MemoryRegion, 1);
@@ -191,7 +192,11 @@ static void zynq_init(MachineState *machine)
         exit(EXIT_FAILURE);
     }
 
-    cpu = ARM_CPU(object_new(machine->cpu_type));
+    cpu_class = object_class_by_name(machine->cpu_type);
+
+    class_property_set_uint(cpu_class, "midr", ZYNQ_BOARD_MIDR, &error_fatal);
+
+    cpu = ARM_CPU(object_new_with_class(cpu_class));
 
     /* By default A9 CPUs have EL3 enabled.  This board does not
      * currently support EL3 so the CPU EL3 property is disabled before
@@ -201,8 +206,6 @@ static void zynq_init(MachineState *machine)
         object_property_set_bool(OBJECT(cpu), "has_el3", false, &error_fatal);
     }
 
-    object_property_set_int(OBJECT(cpu), "midr", ZYNQ_BOARD_MIDR,
-                            &error_fatal);
     object_property_set_int(OBJECT(cpu), "reset-cbar", MPCORE_PERIPHBASE,
                             &error_fatal);
     qdev_realize(DEVICE(cpu), NULL, &error_fatal);
diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c
index 1f7763964c..92f754a74f 100644
--- a/hw/intc/armv7m_nvic.c
+++ b/hw/intc/armv7m_nvic.c
@@ -1039,7 +1039,7 @@ static uint32_t nvic_readl(NVICState *s, uint32_t offset, MemTxAttrs attrs)
         }
         return cpu->revidr;
     case 0xd00: /* CPUID Base.  */
-        return cpu->midr;
+        return ARM_CPU_GET_CLASS(cpu)->midr;
     case 0xd04: /* Interrupt Control State (ICSR) */
         /* VECTACTIVE */
         val = cpu->env.v7m.exception;
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index 22a6ccaece..7d68c50d7c 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -1209,7 +1209,6 @@ static void arm_cpu_initfn(Object *obj)
     cpu->env.features = acc->features;
     cpu->isar = acc->isar;
 
-    cpu->midr = acc->midr;
     cpu->ctr = acc->ctr;
     cpu->pmceid0 = acc->pmceid0;
     cpu->pmceid1 = acc->pmceid1;
@@ -2120,7 +2119,6 @@ static void cpu_arm_get_mp_affinity(Object *obj, Visitor *v, const char *name,
 }
 
 static Property arm_cpu_properties[] = {
-    DEFINE_PROP_UINT64("midr", ARMCPU, midr, 0),
     DEFINE_PROP_INT32("node-id", ARMCPU, node_id, CPU_UNSET_NUMA_NODE_ID),
     DEFINE_PROP_INT32("core-count", ARMCPU, core_count, -1),
     DEFINE_PROP_END_OF_LIST()
@@ -2173,6 +2171,17 @@ static const struct TCGCPUOps arm_tcg_ops = {
 };
 #endif /* CONFIG_TCG */
 
+static bool arm_class_prop_uint64_ofs(ObjectClass *oc, Visitor *v,
+                                      const char *name, void *opaque,
+                                      Error **errp)
+{
+    ARMCPUClass *acc = ARM_CPU_CLASS(oc);
+    uintptr_t ofs = (uintptr_t)opaque;
+    uint64_t *ptr = (void *)acc + ofs;
+
+    return visit_type_uint64(v, name, ptr, errp);
+}
+
 static void arm_cpu_class_init(ObjectClass *oc, void *data)
 {
     ARMCPUClass *acc = ARM_CPU_CLASS(oc);
@@ -2220,6 +2229,11 @@ static void arm_cpu_class_init(ObjectClass *oc, void *data)
      */
     acc->dtb_compatible = "qemu,unknown";
     acc->kvm_target = QEMU_KVM_ARM_TARGET_NONE;
+
+    class_property_add(oc, "midr", "uint64", NULL,
+                       arm_class_prop_uint64_ofs,
+                       arm_class_prop_uint64_ofs,
+                       (void *)(uintptr_t)offsetof(ARMCPUClass, midr));
 }
 
 static void arm_cpu_leaf_class_init(ObjectClass *oc, void *data)
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 43756e130a..d18200ed16 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -7443,6 +7443,8 @@ void register_cp_regs_for_features(ARMCPU *cpu)
 {
     /* Register all the coprocessor registers based on feature bits */
     CPUARMState *env = &cpu->env;
+    ARMCPUClass *acc = ARM_CPU_GET_CLASS(cpu);
+
     if (arm_feature(env, ARM_FEATURE_M)) {
         /* M profile has no coprocessor registers */
         return;
@@ -7926,12 +7928,12 @@ void register_cp_regs_for_features(ARMCPU *cpu)
             { .name = "VPIDR", .state = ARM_CP_STATE_AA32,
               .cp = 15, .opc1 = 4, .crn = 0, .crm = 0, .opc2 = 0,
               .access = PL2_RW, .accessfn = access_el3_aa32ns,
-              .resetvalue = cpu->midr,
+              .resetvalue = acc->midr,
               .type = ARM_CP_ALIAS | ARM_CP_EL3_NO_EL2_C_NZ,
               .fieldoffset = offsetoflow32(CPUARMState, cp15.vpidr_el2) },
             { .name = "VPIDR_EL2", .state = ARM_CP_STATE_AA64,
               .opc0 = 3, .opc1 = 4, .crn = 0, .crm = 0, .opc2 = 0,
-              .access = PL2_RW, .resetvalue = cpu->midr,
+              .access = PL2_RW, .resetvalue = acc->midr,
               .type = ARM_CP_EL3_NO_EL2_C_NZ,
               .fieldoffset = offsetof(CPUARMState, cp15.vpidr_el2) },
             { .name = "VMPIDR", .state = ARM_CP_STATE_AA32,
@@ -8106,7 +8108,7 @@ void register_cp_regs_for_features(ARMCPU *cpu)
              */
             { .name = "MIDR",
               .cp = 15, .crn = 0, .crm = 0, .opc1 = 0, .opc2 = CP_ANY,
-              .access = PL1_R, .resetvalue = cpu->midr,
+              .access = PL1_R, .resetvalue = acc->midr,
               .writefn = arm_cp_write_ignore, .raw_writefn = raw_write,
               .readfn = midr_read,
               .fieldoffset = offsetof(CPUARMState, cp15.c0_cpuid),
@@ -8131,16 +8133,16 @@ void register_cp_regs_for_features(ARMCPU *cpu)
         ARMCPRegInfo id_v8_midr_cp_reginfo[] = {
             { .name = "MIDR_EL1", .state = ARM_CP_STATE_BOTH,
               .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 0, .opc2 = 0,
-              .access = PL1_R, .type = ARM_CP_NO_RAW, .resetvalue = cpu->midr,
+              .access = PL1_R, .type = ARM_CP_NO_RAW, .resetvalue = acc->midr,
               .fieldoffset = offsetof(CPUARMState, cp15.c0_cpuid),
               .readfn = midr_read },
             /* crn = 0 op1 = 0 crm = 0 op2 = 4,7 : AArch32 aliases of MIDR */
             { .name = "MIDR", .type = ARM_CP_ALIAS | ARM_CP_CONST,
               .cp = 15, .crn = 0, .crm = 0, .opc1 = 0, .opc2 = 4,
-              .access = PL1_R, .resetvalue = cpu->midr },
+              .access = PL1_R, .resetvalue = acc->midr },
             { .name = "MIDR", .type = ARM_CP_ALIAS | ARM_CP_CONST,
               .cp = 15, .crn = 0, .crm = 0, .opc1 = 0, .opc2 = 7,
-              .access = PL1_R, .resetvalue = cpu->midr },
+              .access = PL1_R, .resetvalue = acc->midr },
             { .name = "REVIDR_EL1", .state = ARM_CP_STATE_BOTH,
               .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 0, .opc2 = 6,
               .access = PL1_R,
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* [RFC PATCH 33/40] target/arm: Move "cntfrq" to class property
  2023-01-03 18:16 [RFC PATCH 00/40] Toward class init of cpu features Richard Henderson
                   ` (31 preceding siblings ...)
  2023-01-03 18:16 ` [RFC PATCH 32/40] target/arm: Move "midr" to class property Richard Henderson
@ 2023-01-03 18:16 ` Richard Henderson
  2023-01-05 22:21   ` Philippe Mathieu-Daudé
  2023-01-03 18:16 ` [RFC PATCH 34/40] target/arm: Move "reset-hivecs" " Richard Henderson
                   ` (8 subsequent siblings)
  41 siblings, 1 reply; 77+ messages in thread
From: Richard Henderson @ 2023-01-03 18:16 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, berrange, eduardo, armbru, ajones, alex.bennee

With the movement of the property, we can remove the field
from the cpu entirely, using only the class.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/cpu-qom.h    |  3 +++
 target/arm/cpu.h        |  3 ---
 hw/arm/aspeed_ast2600.c |  6 +++--
 target/arm/cpu.c        | 50 +++++++++++++++++++++++------------------
 target/arm/helper.c     |  3 ++-
 5 files changed, 37 insertions(+), 28 deletions(-)

diff --git a/target/arm/cpu-qom.h b/target/arm/cpu-qom.h
index 6b113d7fe6..2d6fa38a30 100644
--- a/target/arm/cpu-qom.h
+++ b/target/arm/cpu-qom.h
@@ -154,6 +154,9 @@ struct ARMCPUClass {
      */
     uint64_t ccsidr[16];
 
+    /* Generic timer counter frequency, in Hz */
+    uint64_t gt_cntfrq_hz;
+
     uint32_t revidr;
     uint32_t id_afr0;
     uint32_t reset_fpsid;
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index f2dceae0e7..e425846007 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -1019,9 +1019,6 @@ struct ArchCPU {
 
     ARMVQMap sve_vq;
     ARMVQMap sme_vq;
-
-    /* Generic timer counter frequency, in Hz */
-    uint64_t gt_cntfrq_hz;
 };
 
 unsigned int gt_cntfrq_period_ns(ARMCPU *cpu);
diff --git a/hw/arm/aspeed_ast2600.c b/hw/arm/aspeed_ast2600.c
index cd75465c2b..bb8579546e 100644
--- a/hw/arm/aspeed_ast2600.c
+++ b/hw/arm/aspeed_ast2600.c
@@ -145,6 +145,7 @@ static void aspeed_soc_ast2600_init(Object *obj)
 {
     AspeedSoCState *s = ASPEED_SOC(obj);
     AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
+    ObjectClass *cpu_class;
     int i;
     char socname[8];
     char typename[64];
@@ -153,6 +154,9 @@ static void aspeed_soc_ast2600_init(Object *obj)
         g_assert_not_reached();
     }
 
+    cpu_class = object_class_by_name(sc->cpu_type);
+    class_property_set_uint(cpu_class, "cntfrq", 1125000000, &error_abort);
+
     for (i = 0; i < sc->num_cpus; i++) {
         object_initialize_child(obj, "cpu[*]", &s->cpu[i], sc->cpu_type);
     }
@@ -305,8 +309,6 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp)
         object_property_set_int(OBJECT(&s->cpu[i]), "mp-affinity",
                                 aspeed_calc_affinity(i), &error_abort);
 
-        object_property_set_int(OBJECT(&s->cpu[i]), "cntfrq", 1125000000,
-                                &error_abort);
         object_property_set_bool(OBJECT(&s->cpu[i]), "neon", false,
                                 &error_abort);
         object_property_set_link(OBJECT(&s->cpu[i]), "memory",
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index 7d68c50d7c..bc4a052e4c 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -1277,10 +1277,6 @@ static void arm_cpu_initfn(Object *obj)
     }
 }
 
-static Property arm_cpu_gt_cntfrq_property =
-            DEFINE_PROP_UINT64("cntfrq", ARMCPU, gt_cntfrq_hz,
-                               NANOSECONDS_PER_SECOND / GTIMER_SCALE);
-
 static Property arm_cpu_reset_cbar_property =
             DEFINE_PROP_UINT64("reset-cbar", ARMCPU, reset_cbar, 0);
 
@@ -1342,6 +1338,12 @@ static void arm_set_pmu(Object *obj, bool value, Error **errp)
 
 unsigned int gt_cntfrq_period_ns(ARMCPU *cpu)
 {
+    ARMCPUClass *acc = ARM_CPU_GET_CLASS(cpu);
+
+    if (!arm_class_feature(acc, ARM_FEATURE_GENERIC_TIMER)) {
+        return GTIMER_SCALE;
+    }
+
     /*
      * The exact approach to calculating guest ticks is:
      *
@@ -1360,8 +1362,8 @@ unsigned int gt_cntfrq_period_ns(ARMCPU *cpu)
      * Finally, CNTFRQ is effectively capped at 1GHz to ensure our scale factor
      * cannot become zero.
      */
-    return NANOSECONDS_PER_SECOND > cpu->gt_cntfrq_hz ?
-      NANOSECONDS_PER_SECOND / cpu->gt_cntfrq_hz : 1;
+    return (NANOSECONDS_PER_SECOND > acc->gt_cntfrq_hz ?
+            NANOSECONDS_PER_SECOND / acc->gt_cntfrq_hz : 1);
 }
 
 static void arm_cpu_post_init(Object *obj)
@@ -1466,10 +1468,6 @@ static void arm_cpu_post_init(Object *obj)
 
     qdev_property_add_static(DEVICE(obj), &arm_cpu_cfgend_property);
 
-    if (arm_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER)) {
-        qdev_property_add_static(DEVICE(cpu), &arm_cpu_gt_cntfrq_property);
-    }
-
     if (kvm_enabled()) {
         kvm_arm_add_vcpu_properties(obj);
     }
@@ -1614,18 +1612,7 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
     }
 
     {
-        uint64_t scale;
-
-        if (arm_feature(env, ARM_FEATURE_GENERIC_TIMER)) {
-            if (!cpu->gt_cntfrq_hz) {
-                error_setg(errp, "Invalid CNTFRQ: %"PRId64"Hz",
-                           cpu->gt_cntfrq_hz);
-                return;
-            }
-            scale = gt_cntfrq_period_ns(cpu);
-        } else {
-            scale = GTIMER_SCALE;
-        }
+        uint64_t scale = gt_cntfrq_period_ns(cpu);
 
         cpu->gt_timer[GTIMER_PHYS] = timer_new(QEMU_CLOCK_VIRTUAL, scale,
                                                arm_gt_ptimer_cb, cpu);
@@ -2242,6 +2229,7 @@ static void arm_cpu_leaf_class_init(ObjectClass *oc, void *data)
 
     acc->cp_regs = g_hash_table_new_full(g_direct_hash, g_direct_equal,
                                          NULL, g_free);
+    acc->gt_cntfrq_hz = NANOSECONDS_PER_SECOND / GTIMER_SCALE;
 
     acc->info = data;
     if (acc->info->class_init) {
@@ -2308,6 +2296,16 @@ static void arm_cpu_leaf_class_init(ObjectClass *oc, void *data)
     if (arm_class_feature(acc, ARM_FEATURE_M)) {
         set_class_feature(acc, ARM_FEATURE_PMSA);
     }
+
+#ifndef CONFIG_USER_ONLY
+    if (arm_class_feature(acc, ARM_FEATURE_GENERIC_TIMER)) {
+        class_property_add(oc, "cntfrq", "uint64", NULL,
+                           arm_class_prop_uint64_ofs,
+                           arm_class_prop_uint64_ofs,
+                           (void *)(uintptr_t)
+                           offsetof(ARMCPUClass, gt_cntfrq_hz));
+    }
+#endif /* CONFIG_USER_ONLY */
 }
 
 static bool arm_cpu_class_late_init(ObjectClass *oc, Error **errp)
@@ -2320,6 +2318,14 @@ static bool arm_cpu_class_late_init(ObjectClass *oc, Error **errp)
         }
     }
 
+#ifndef CONFIG_USER_ONLY
+    /* TODO: Perhaps better to put this check in a property set hook. */
+    if (!acc->gt_cntfrq_hz) {
+        error_setg(errp, "Invalid CNTFRQ: %"PRId64"Hz", acc->gt_cntfrq_hz);
+        return false;
+    }
+#endif /* CONFIG_USER_ONLY */
+
     /* Run some consistency checks for TCG. */
     if (tcg_enabled()) {
         bool no_aa32 = arm_class_feature(acc, ARM_FEATURE_AARCH64) &&
diff --git a/target/arm/helper.c b/target/arm/helper.c
index d18200ed16..67d32c2e59 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -2977,8 +2977,9 @@ void arm_gt_hvtimer_cb(void *opaque)
 static void arm_gt_cntfrq_reset(CPUARMState *env, const ARMCPRegInfo *opaque)
 {
     ARMCPU *cpu = env_archcpu(env);
+    ARMCPUClass *acc = ARM_CPU_GET_CLASS(cpu);
 
-    cpu->env.cp15.c14_cntfrq = cpu->gt_cntfrq_hz;
+    cpu->env.cp15.c14_cntfrq = acc->gt_cntfrq_hz;
 }
 
 static const ARMCPRegInfo generic_timer_cp_reginfo[] = {
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* [RFC PATCH 34/40] target/arm: Move "reset-hivecs" to class property
  2023-01-03 18:16 [RFC PATCH 00/40] Toward class init of cpu features Richard Henderson
                   ` (32 preceding siblings ...)
  2023-01-03 18:16 ` [RFC PATCH 33/40] target/arm: Move "cntfrq" " Richard Henderson
@ 2023-01-03 18:16 ` Richard Henderson
  2023-01-03 18:16 ` [RFC PATCH 35/40] target/arm: Move "has_el2" " Richard Henderson
                   ` (7 subsequent siblings)
  41 siblings, 0 replies; 77+ messages in thread
From: Richard Henderson @ 2023-01-03 18:16 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, berrange, eduardo, armbru, ajones, alex.bennee

Remove the reset_hivecs variable entirely and create
property accessor functions that directly read/write
a bit of the reset value of SCTLR.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/cpu.h     |  1 -
 hw/arm/digic.c       | 11 ++++-----
 hw/arm/npcm7xx.c     |  9 ++++----
 hw/arm/xlnx-zynqmp.c | 11 +++++----
 target/arm/cpu.c     | 55 +++++++++++++++++++++++++++++++++-----------
 5 files changed, 59 insertions(+), 28 deletions(-)

diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index e425846007..c0baec37d7 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -973,7 +973,6 @@ struct ArchCPU {
     uint64_t ccsidr[16];
     uint64_t reset_cbar;
     uint32_t reset_auxcr;
-    bool reset_hivecs;
 
     /*
      * Intermediate values used during property parsing.
diff --git a/hw/arm/digic.c b/hw/arm/digic.c
index 6df5547977..fed5d38695 100644
--- a/hw/arm/digic.c
+++ b/hw/arm/digic.c
@@ -34,9 +34,13 @@
 static void digic_init(Object *obj)
 {
     DigicState *s = DIGIC(obj);
+    const char *cpu_type = ARM_CPU_TYPE_NAME("arm946");
+    ObjectClass *cpu_class = object_class_by_name(cpu_type);
     int i;
 
-    object_initialize_child(obj, "cpu", &s->cpu, ARM_CPU_TYPE_NAME("arm946"));
+    class_property_set_bool(cpu_class, "reset-hivecs", true, &error_abort);
+
+    object_initialize_child(obj, "cpu", &s->cpu, cpu_type);
 
     for (i = 0; i < DIGIC4_NB_TIMERS; i++) {
         g_autofree char *name = g_strdup_printf("timer[%d]", i);
@@ -52,11 +56,6 @@ static void digic_realize(DeviceState *dev, Error **errp)
     SysBusDevice *sbd;
     int i;
 
-    if (!object_property_set_bool(OBJECT(&s->cpu), "reset-hivecs", true,
-                                  errp)) {
-        return;
-    }
-
     if (!qdev_realize(DEVICE(&s->cpu), NULL, errp)) {
         return;
     }
diff --git a/hw/arm/npcm7xx.c b/hw/arm/npcm7xx.c
index 41124b7444..97ac4ac7e9 100644
--- a/hw/arm/npcm7xx.c
+++ b/hw/arm/npcm7xx.c
@@ -390,11 +390,14 @@ static qemu_irq npcm7xx_irq(NPCM7xxState *s, int n)
 static void npcm7xx_init(Object *obj)
 {
     NPCM7xxState *s = NPCM7XX(obj);
+    const char *cpu_type = ARM_CPU_TYPE_NAME("cortex-a9");
+    ObjectClass *cpu_class = object_class_by_name(cpu_type);
     int i;
 
+    class_property_set_bool(cpu_class, "reset-hivecs", true, &error_abort);
+
     for (i = 0; i < NPCM7XX_MAX_NUM_CPUS; i++) {
-        object_initialize_child(obj, "cpu[*]", &s->cpu[i],
-                                ARM_CPU_TYPE_NAME("cortex-a9"));
+        object_initialize_child(obj, "cpu[*]", &s->cpu[i], cpu_type);
     }
 
     object_initialize_child(obj, "a9mpcore", &s->a9mpcore, TYPE_A9MPCORE_PRIV);
@@ -466,8 +469,6 @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
                                 &error_abort);
         object_property_set_int(OBJECT(&s->cpu[i]), "reset-cbar",
                                 NPCM7XX_GIC_CPU_IF_ADDR, &error_abort);
-        object_property_set_bool(OBJECT(&s->cpu[i]), "reset-hivecs", true,
-                                 &error_abort);
 
         /* Disable security extensions. */
         object_property_set_bool(OBJECT(&s->cpu[i]), "has_el3", false,
diff --git a/hw/arm/xlnx-zynqmp.c b/hw/arm/xlnx-zynqmp.c
index 335cfc417d..13ab999eb8 100644
--- a/hw/arm/xlnx-zynqmp.c
+++ b/hw/arm/xlnx-zynqmp.c
@@ -243,8 +243,6 @@ static void xlnx_zynqmp_create_rpu(MachineState *ms, XlnxZynqMPState *s,
             s->boot_cpu_ptr = &s->rpu_cpu[i];
         }
 
-        object_property_set_bool(OBJECT(&s->rpu_cpu[i]), "reset-hivecs", true,
-                                 &error_abort);
         if (!qdev_realize(DEVICE(&s->rpu_cpu[i]), NULL, errp)) {
             return;
         }
@@ -375,6 +373,8 @@ static void xlnx_zynqmp_init(Object *obj)
 {
     MachineState *ms = MACHINE(qdev_get_machine());
     XlnxZynqMPState *s = XLNX_ZYNQMP(obj);
+    const char *cpu_type;
+    ObjectClass *cpu_class;
     int i;
     int num_apus = MIN(ms->smp.cpus, XLNX_ZYNQMP_NUM_APU_CPUS);
 
@@ -382,10 +382,13 @@ static void xlnx_zynqmp_init(Object *obj)
                             TYPE_CPU_CLUSTER);
     qdev_prop_set_uint32(DEVICE(&s->apu_cluster), "cluster-id", 0);
 
+    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);
+
     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-a53"));
+                                &s->apu_cpu[i], cpu_type);
     }
 
     object_initialize_child(obj, "gic", &s->gic, gic_class_name());
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index bc4a052e4c..032a2cc00a 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -1280,9 +1280,6 @@ static void arm_cpu_initfn(Object *obj)
 static Property arm_cpu_reset_cbar_property =
             DEFINE_PROP_UINT64("reset-cbar", ARMCPU, reset_cbar, 0);
 
-static Property arm_cpu_reset_hivecs_property =
-            DEFINE_PROP_BOOL("reset-hivecs", ARMCPU, reset_hivecs, false);
-
 #ifndef CONFIG_USER_ONLY
 static Property arm_cpu_has_el2_property =
             DEFINE_PROP_BOOL("has_el2", ARMCPU, has_el2, true);
@@ -1375,10 +1372,6 @@ static void arm_cpu_post_init(Object *obj)
         qdev_property_add_static(DEVICE(obj), &arm_cpu_reset_cbar_property);
     }
 
-    if (!arm_feature(&cpu->env, ARM_FEATURE_M)) {
-        qdev_property_add_static(DEVICE(obj), &arm_cpu_reset_hivecs_property);
-    }
-
     if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) {
         object_property_add_uint64_ptr(obj, "rvbar",
                                        &cpu->rvbar_prop,
@@ -1801,10 +1794,6 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
         return;
     }
 
-    if (cpu->reset_hivecs) {
-            cpu->reset_sctlr |= (1 << 13);
-    }
-
     if (cpu->cfgend) {
         if (arm_feature(&cpu->env, ARM_FEATURE_V7)) {
             cpu->reset_sctlr |= SCTLR_EE;
@@ -2169,6 +2158,39 @@ static bool arm_class_prop_uint64_ofs(ObjectClass *oc, Visitor *v,
     return visit_type_uint64(v, name, ptr, errp);
 }
 
+#ifndef CONFIG_USER_ONLY
+static bool arm_class_prop_set_sctlrbit(ObjectClass *oc, Visitor *v,
+                                        const char *name, void *opaque,
+                                        Error **errp)
+{
+    ARMCPUClass *acc = ARM_CPU_CLASS(oc);
+    uint32_t mask = (uintptr_t)opaque;
+    bool val;
+
+    if (!visit_type_bool(v, name, &val, errp)) {
+        return false;
+    }
+
+    if (val) {
+        acc->reset_sctlr |= mask;
+    } else {
+        acc->reset_sctlr &= ~mask;
+    }
+    return true;
+}
+
+static bool arm_class_prop_get_sctlrbit(ObjectClass *oc, Visitor *v,
+                                        const char *name, void *opaque,
+                                        Error **errp)
+{
+    ARMCPUClass *acc = ARM_CPU_CLASS(oc);
+    uint32_t mask = (uintptr_t)opaque;
+    bool val = acc->reset_sctlr & mask;
+
+    return visit_type_bool(v, name, &val, errp);
+}
+#endif /* !CONFIG_USER_ONLY */
+
 static void arm_cpu_class_init(ObjectClass *oc, void *data)
 {
     ARMCPUClass *acc = ARM_CPU_CLASS(oc);
@@ -2305,7 +2327,14 @@ static void arm_cpu_leaf_class_init(ObjectClass *oc, void *data)
                            (void *)(uintptr_t)
                            offsetof(ARMCPUClass, gt_cntfrq_hz));
     }
-#endif /* CONFIG_USER_ONLY */
+
+    if (!arm_class_feature(acc, ARM_FEATURE_M)) {
+        class_property_add(oc, "reset-hivecs", "bool", NULL,
+                           arm_class_prop_get_sctlrbit,
+                           arm_class_prop_set_sctlrbit,
+                           (void *)((uintptr_t)1 << 13));
+    }
+#endif /* !CONFIG_USER_ONLY */
 }
 
 static bool arm_cpu_class_late_init(ObjectClass *oc, Error **errp)
@@ -2324,7 +2353,7 @@ static bool arm_cpu_class_late_init(ObjectClass *oc, Error **errp)
         error_setg(errp, "Invalid CNTFRQ: %"PRId64"Hz", acc->gt_cntfrq_hz);
         return false;
     }
-#endif /* CONFIG_USER_ONLY */
+#endif /* !CONFIG_USER_ONLY */
 
     /* Run some consistency checks for TCG. */
     if (tcg_enabled()) {
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* [RFC PATCH 35/40] target/arm: Move "has_el2" to class property
  2023-01-03 18:16 [RFC PATCH 00/40] Toward class init of cpu features Richard Henderson
                   ` (33 preceding siblings ...)
  2023-01-03 18:16 ` [RFC PATCH 34/40] target/arm: Move "reset-hivecs" " Richard Henderson
@ 2023-01-03 18:16 ` Richard Henderson
  2023-01-03 18:16 ` [RFC PATCH 36/40] target/arm: Move "has_el3" " Richard Henderson
                   ` (6 subsequent siblings)
  41 siblings, 0 replies; 77+ messages in thread
From: Richard Henderson @ 2023-01-03 18:16 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, berrange, eduardo, armbru, ajones, alex.bennee

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(-)

diff --git a/target/arm/cpu-qom.h b/target/arm/cpu-qom.h
index 2d6fa38a30..fceb557a4d 100644
--- a/target/arm/cpu-qom.h
+++ b/target/arm/cpu-qom.h
@@ -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)
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index c0baec37d7..3888cdafdf 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -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) */
diff --git a/hw/arm/allwinner-h3.c b/hw/arm/allwinner-h3.c
index 308ed15552..07484b9f97 100644
--- a/hw/arm/allwinner-h3.c
+++ b/hw/arm/allwinner-h3.c
@@ -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);
diff --git a/hw/arm/vexpress.c b/hw/arm/vexpress.c
index e1d1983ae6..211daa8fde 100644
--- a/hw/arm/vexpress.c
+++ b/hw/arm/vexpress.c
@@ -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,
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index aed86997c0..dd02e42f97 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -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);
diff --git a/hw/arm/xlnx-zynqmp.c b/hw/arm/xlnx-zynqmp.c
index 13ab999eb8..17bad9b4ed 100644
--- a/hw/arm/xlnx-zynqmp.c
+++ b/hw/arm/xlnx-zynqmp.c
@@ -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",
diff --git a/hw/cpu/a15mpcore.c b/hw/cpu/a15mpcore.c
index 774ca9987a..6329d25f68 100644
--- a/hw/cpu/a15mpcore.c
+++ b/hw/cpu/a15mpcore.c
@@ -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);
     }
 
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index 032a2cc00a..db996d8c3a 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -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. */
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* [RFC PATCH 36/40] target/arm: Move "has_el3" to class property
  2023-01-03 18:16 [RFC PATCH 00/40] Toward class init of cpu features Richard Henderson
                   ` (34 preceding siblings ...)
  2023-01-03 18:16 ` [RFC PATCH 35/40] target/arm: Move "has_el2" " Richard Henderson
@ 2023-01-03 18:16 ` Richard Henderson
  2023-01-03 18:16 ` [RFC PATCH 37/40] target/arm: Move "cfgend" " Richard Henderson
                   ` (5 subsequent siblings)
  41 siblings, 0 replies; 77+ messages in thread
From: Richard Henderson @ 2023-01-03 18:16 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, berrange, eduardo, armbru, ajones, alex.bennee

With the movement of the property, we can remove the field
from the cpu entirely, using only the class.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/cpu-qom.h  |  2 ++
 target/arm/cpu.h      |  2 --
 hw/arm/allwinner-h3.c |  5 ++-
 hw/arm/exynos4210.c   | 18 +++++-----
 hw/arm/integratorcp.c | 12 ++++---
 hw/arm/npcm7xx.c      |  5 +--
 hw/arm/realview.c     | 20 +++++------
 hw/arm/versatilepb.c  | 12 ++++---
 hw/arm/vexpress.c     |  9 +++--
 hw/arm/virt.c         |  5 +--
 hw/arm/xilinx_zynq.c  | 14 ++++----
 hw/arm/xlnx-zynqmp.c  |  3 +-
 hw/cpu/a15mpcore.c    |  5 ++-
 hw/cpu/a9mpcore.c     |  6 ++--
 target/arm/cpu.c      | 78 +++++++++++++++++++++++++------------------
 15 files changed, 102 insertions(+), 94 deletions(-)

diff --git a/target/arm/cpu-qom.h b/target/arm/cpu-qom.h
index fceb557a4d..f4e01e0ddb 100644
--- a/target/arm/cpu-qom.h
+++ b/target/arm/cpu-qom.h
@@ -184,6 +184,8 @@ struct ARMCPUClass {
      */
     uint32_t kvm_target;
 
+    /* CPU has security extension */
+    OnOffAuto has_el3;
     /* CPU has virtualization extension */
     OnOffAuto has_el2;
 };
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index 3888cdafdf..5921660d86 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -886,8 +886,6 @@ struct ArchCPU {
     /* Current power state, access guarded by BQL */
     ARMPSCIState power_state;
 
-    /* CPU has security extension */
-    bool has_el3;
     /* CPU has PMU (Performance Monitor Unit) */
     bool has_pmu;
     /* CPU has VFP */
diff --git a/hw/arm/allwinner-h3.c b/hw/arm/allwinner-h3.c
index 07484b9f97..8ec97961de 100644
--- a/hw/arm/allwinner-h3.c
+++ b/hw/arm/allwinner-h3.c
@@ -193,7 +193,9 @@ static void allwinner_h3_init(Object *obj)
 
     s->memmap = allwinner_h3_memmap;
 
+    /* All exception levels required. */
     /* ??? This is the default for A7. */
+    class_property_set_bool(cpu_class, "has_el3", true, &error_abort);
     class_property_set_bool(cpu_class, "has_el2", true, &error_abort);
 
     for (int i = 0; i < AW_H3_NUM_CPUS; i++) {
@@ -246,9 +248,6 @@ static void allwinner_h3_realize(DeviceState *dev, Error **errp)
         qdev_prop_set_bit(DEVICE(&s->cpus[i]), "start-powered-off",
                           i > 0);
 
-        /* All exception levels required */
-        qdev_prop_set_bit(DEVICE(&s->cpus[i]), "has_el3", true);
-
         /* Mark realized */
         qdev_realize(DEVICE(&s->cpus[i]), NULL, &error_fatal);
     }
diff --git a/hw/arm/exynos4210.c b/hw/arm/exynos4210.c
index 8dafa2215b..bf056ecad7 100644
--- a/hw/arm/exynos4210.c
+++ b/hw/arm/exynos4210.c
@@ -548,18 +548,20 @@ static void exynos4210_realize(DeviceState *socdev, Error **errp)
     Exynos4210State *s = EXYNOS4210_SOC(socdev);
     MemoryRegion *system_mem = get_system_memory();
     SysBusDevice *busdev;
+    ObjectClass *cpu_class;
     DeviceState *dev, *uart[4], *pl330[3];
     int i, n;
 
-    for (n = 0; n < EXYNOS4210_NCPUS; n++) {
-        Object *cpuobj = object_new(ARM_CPU_TYPE_NAME("cortex-a9"));
+    cpu_class = object_class_by_name(ARM_CPU_TYPE_NAME("cortex-a9"));
 
-        /* By default A9 CPUs have EL3 enabled.  This board does not currently
-         * support EL3 so the CPU EL3 property is disabled before realization.
-         */
-        if (object_property_find(cpuobj, "has_el3")) {
-            object_property_set_bool(cpuobj, "has_el3", false, &error_fatal);
-        }
+    /*
+     * By default A9 CPUs have EL3 enabled.  This board does not currently
+     * support EL3 so the CPU EL3 property is disabled.
+     */
+    class_property_set_bool(cpu_class, "has_el3", false, &error_abort);
+
+    for (n = 0; n < EXYNOS4210_NCPUS; n++) {
+        Object *cpuobj = object_new_with_class(cpu_class);
 
         s->cpu[n] = ARM_CPU(cpuobj);
         object_property_set_int(cpuobj, "mp-affinity",
diff --git a/hw/arm/integratorcp.c b/hw/arm/integratorcp.c
index b109ece3ae..9244026f3f 100644
--- a/hw/arm/integratorcp.c
+++ b/hw/arm/integratorcp.c
@@ -595,17 +595,19 @@ static void integratorcp_init(MachineState *machine)
     qemu_irq pic[32];
     DeviceState *dev, *sic, *icp;
     DriveInfo *dinfo;
+    ObjectClass *cpu_class;
     int i;
 
-    cpuobj = object_new(machine->cpu_type);
+    cpu_class = object_class_by_name(machine->cpu_type);
 
-    /* By default ARM1176 CPUs have EL3 enabled.  This board does not
+    /*
+     * By default ARM1176 CPUs have EL3 enabled.  This board does not
      * currently support EL3 so the CPU EL3 property is disabled before
      * realization.
      */
-    if (object_property_find(cpuobj, "has_el3")) {
-        object_property_set_bool(cpuobj, "has_el3", false, &error_fatal);
-    }
+    class_property_set_bool(cpu_class, "has_el3", false, NULL);
+
+    cpuobj = object_new_with_class(cpu_class);
 
     qdev_realize(DEVICE(cpuobj), NULL, &error_fatal);
 
diff --git a/hw/arm/npcm7xx.c b/hw/arm/npcm7xx.c
index 97ac4ac7e9..8dec8e0d12 100644
--- a/hw/arm/npcm7xx.c
+++ b/hw/arm/npcm7xx.c
@@ -395,6 +395,7 @@ static void npcm7xx_init(Object *obj)
     int i;
 
     class_property_set_bool(cpu_class, "reset-hivecs", true, &error_abort);
+    class_property_set_bool(cpu_class, "has_el3", false, &error_abort);
 
     for (i = 0; i < NPCM7XX_MAX_NUM_CPUS; i++) {
         object_initialize_child(obj, "cpu[*]", &s->cpu[i], cpu_type);
@@ -470,10 +471,6 @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
         object_property_set_int(OBJECT(&s->cpu[i]), "reset-cbar",
                                 NPCM7XX_GIC_CPU_IF_ADDR, &error_abort);
 
-        /* Disable security extensions. */
-        object_property_set_bool(OBJECT(&s->cpu[i]), "has_el3", false,
-                                 &error_abort);
-
         if (!qdev_realize(DEVICE(&s->cpu[i]), NULL, errp)) {
             return;
         }
diff --git a/hw/arm/realview.c b/hw/arm/realview.c
index d2dc8a8952..0e1a4ff396 100644
--- a/hw/arm/realview.c
+++ b/hw/arm/realview.c
@@ -81,6 +81,7 @@ static void realview_init(MachineState *machine,
     MemoryRegion *ram_hack = g_new(MemoryRegion, 1);
     DeviceState *dev, *sysctl, *gpio2, *pl041;
     SysBusDevice *busdev;
+    ObjectClass *cpu_class;
     qemu_irq pic[64];
     PCIBus *pci_bus = NULL;
     NICInfo *nd;
@@ -115,22 +116,21 @@ static void realview_init(MachineState *machine,
         break;
     }
 
-    for (n = 0; n < smp_cpus; n++) {
-        Object *cpuobj = object_new(machine->cpu_type);
+    cpu_class = object_class_by_name(machine->cpu_type);
+    /*
+     * By default A9, A15 and ARM1176 CPUs have EL3 enabled.  This board
+     * does not currently support EL3 so the CPU EL3 property is disabled
+     * before realization.
+     */
+    class_property_set_bool(cpu_class, "has_el3", false, NULL);
 
-        /* By default A9,A15 and ARM1176 CPUs have EL3 enabled.  This board
-         * does not currently support EL3 so the CPU EL3 property is disabled
-         * before realization.
-         */
-        if (object_property_find(cpuobj, "has_el3")) {
-            object_property_set_bool(cpuobj, "has_el3", false, &error_fatal);
-        }
+    for (n = 0; n < smp_cpus; n++) {
+        Object *cpuobj = object_new_with_class(cpu_class);
 
         if (is_pb && is_mpcore) {
             object_property_set_int(cpuobj, "reset-cbar", periphbase,
                                     &error_fatal);
         }
-
         qdev_realize(DEVICE(cpuobj), NULL, &error_fatal);
 
         cpu_irq[n] = qdev_get_gpio_in(DEVICE(cpuobj), ARM_CPU_IRQ);
diff --git a/hw/arm/versatilepb.c b/hw/arm/versatilepb.c
index ecc1f6cf74..5b8c332f64 100644
--- a/hw/arm/versatilepb.c
+++ b/hw/arm/versatilepb.c
@@ -182,6 +182,7 @@ static struct arm_boot_info versatile_binfo;
 
 static void versatile_init(MachineState *machine, int board_id)
 {
+    ObjectClass *cpu_class;
     Object *cpuobj;
     ARMCPU *cpu;
     MemoryRegion *sysmem = get_system_memory();
@@ -206,15 +207,16 @@ static void versatile_init(MachineState *machine, int board_id)
         exit(1);
     }
 
-    cpuobj = object_new(machine->cpu_type);
+    cpu_class = object_class_by_name(machine->cpu_type);
 
-    /* By default ARM1176 CPUs have EL3 enabled.  This board does not
+    /*
+     * By default ARM1176 CPUs have EL3 enabled.  This board does not
      * currently support EL3 so the CPU EL3 property is disabled before
      * realization.
      */
-    if (object_property_find(cpuobj, "has_el3")) {
-        object_property_set_bool(cpuobj, "has_el3", false, &error_fatal);
-    }
+    class_property_set_bool(cpu_class, "has_el3", false, NULL);
+
+    cpuobj = object_new_with_class(cpu_class);
 
     qdev_realize(DEVICE(cpuobj), NULL, &error_fatal);
 
diff --git a/hw/arm/vexpress.c b/hw/arm/vexpress.c
index 211daa8fde..d23b678d04 100644
--- a/hw/arm/vexpress.c
+++ b/hw/arm/vexpress.c
@@ -210,17 +210,16 @@ static void init_cpus(MachineState *ms, const char *cpu_type,
     unsigned int smp_cpus = ms->smp.cpus;
     ObjectClass *cpu_class = object_class_by_name(cpu_type);
 
+    if (!secure) {
+        class_property_set_bool(cpu_class, "has_el3", false, NULL);
+    }
     if (!virt) {
         class_property_set_bool(cpu_class, "has_el2", false, NULL);
     }
 
     /* Create the actual CPUs */
     for (n = 0; n < smp_cpus; n++) {
-        Object *cpuobj = object_new(cpu_type);
-
-        if (!secure) {
-            object_property_set_bool(cpuobj, "has_el3", false, NULL);
-        }
+        Object *cpuobj = object_new_with_class(cpu_class);
 
         if (object_property_find(cpuobj, "reset-cbar")) {
             object_property_set_int(cpuobj, "reset-cbar", periphbase,
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index dd02e42f97..c1cabe2413 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -2039,6 +2039,7 @@ static void machvirt_init(MachineState *machine)
     }
 
     cpu_class = object_class_by_name(machine->cpu_type);
+    class_property_set_bool(cpu_class, "has_el3", vms->secure, &error_abort);
     if (!vms->virt) {
         class_property_set_bool(cpu_class, "has_el2", false, &error_abort);
     }
@@ -2174,10 +2175,6 @@ static void machvirt_init(MachineState *machine)
 
         aarch64 &= object_property_get_bool(cpuobj, "aarch64", NULL);
 
-        if (!vms->secure) {
-            object_property_set_bool(cpuobj, "has_el3", false, NULL);
-        }
-
         if (vmc->kvm_no_adjvtime &&
             object_property_find(cpuobj, "kvm-no-adjvtime")) {
             object_property_set_bool(cpuobj, "kvm-no-adjvtime", true, NULL);
diff --git a/hw/arm/xilinx_zynq.c b/hw/arm/xilinx_zynq.c
index 3e5b4f4483..8b8fe6736a 100644
--- a/hw/arm/xilinx_zynq.c
+++ b/hw/arm/xilinx_zynq.c
@@ -194,17 +194,15 @@ static void zynq_init(MachineState *machine)
 
     cpu_class = object_class_by_name(machine->cpu_type);
 
-    class_property_set_uint(cpu_class, "midr", ZYNQ_BOARD_MIDR, &error_fatal);
-
-    cpu = ARM_CPU(object_new_with_class(cpu_class));
-
-    /* By default A9 CPUs have EL3 enabled.  This board does not
+    /*
+     * By default A9 CPUs have EL3 enabled.  This board does not
      * currently support EL3 so the CPU EL3 property is disabled before
      * realization.
      */
-    if (object_property_find(OBJECT(cpu), "has_el3")) {
-        object_property_set_bool(OBJECT(cpu), "has_el3", false, &error_fatal);
-    }
+    class_property_set_bool(cpu_class, "has_el3", false, &error_abort);
+    class_property_set_uint(cpu_class, "midr", ZYNQ_BOARD_MIDR, &error_abort);
+
+    cpu = ARM_CPU(object_new_with_class(cpu_class));
 
     object_property_set_int(OBJECT(cpu), "reset-cbar", MPCORE_PERIPHBASE,
                             &error_fatal);
diff --git a/hw/arm/xlnx-zynqmp.c b/hw/arm/xlnx-zynqmp.c
index 17bad9b4ed..86f08a91d9 100644
--- a/hw/arm/xlnx-zynqmp.c
+++ b/hw/arm/xlnx-zynqmp.c
@@ -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_el3", s->secure, &error_abort);
     class_property_set_bool(cpu_class, "has_el2", s->virt, &error_abort);
 
     for (i = 0; i < num_apus; i++) {
@@ -528,8 +529,6 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
             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_int(OBJECT(&s->apu_cpu[i]), "reset-cbar",
                                 GIC_BASE_ADDR, &error_abort);
         object_property_set_int(OBJECT(&s->apu_cpu[i]), "core-count",
diff --git a/hw/cpu/a15mpcore.c b/hw/cpu/a15mpcore.c
index 6329d25f68..e8c0bac02a 100644
--- a/hw/cpu/a15mpcore.c
+++ b/hw/cpu/a15mpcore.c
@@ -53,7 +53,6 @@ static void a15mp_priv_realize(DeviceState *dev, Error **errp)
     DeviceState *gicdev;
     SysBusDevice *busdev;
     int i;
-    bool has_el3;
     bool has_el2 = false;
 
     gicdev = DEVICE(&s->gic);
@@ -66,9 +65,9 @@ static void a15mp_priv_realize(DeviceState *dev, Error **errp)
          */
         Object *cpuobj = OBJECT(qemu_get_cpu(0));
         ObjectClass *cpucls = object_get_class(cpuobj);
+        bool has_el3;
 
-        has_el3 = object_property_find(cpuobj, "has_el3") &&
-            object_property_get_bool(cpuobj, "has_el3", &error_abort);
+        has_el3 = class_property_get_bool(cpucls, "has_el3", NULL);
         qdev_prop_set_bit(gicdev, "has-security-extensions", has_el3);
 
         /* Similarly for virtualization support */
diff --git a/hw/cpu/a9mpcore.c b/hw/cpu/a9mpcore.c
index d03f57e579..984e373400 100644
--- a/hw/cpu/a9mpcore.c
+++ b/hw/cpu/a9mpcore.c
@@ -55,9 +55,12 @@ static void a9mp_priv_realize(DeviceState *dev, Error **errp)
     bool has_el3;
     CPUState *cpu0;
     Object *cpuobj;
+    ObjectClass *cpucls;
 
     cpu0 = qemu_get_cpu(0);
     cpuobj = OBJECT(cpu0);
+    cpucls = object_get_class(cpuobj);
+
     if (strcmp(object_get_typename(cpuobj), ARM_CPU_TYPE_NAME("cortex-a9"))) {
         /* We might allow Cortex-A5 once we model it */
         error_setg(errp,
@@ -81,8 +84,7 @@ static void a9mp_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.
      */
-    has_el3 = object_property_find(cpuobj, "has_el3") &&
-        object_property_get_bool(cpuobj, "has_el3", &error_abort);
+    has_el3 = class_property_get_bool(cpucls, "has_el3", &error_abort);
     qdev_prop_set_bit(gicdev, "has-security-extensions", has_el3);
 
     if (!sysbus_realize(SYS_BUS_DEVICE(&s->gic), errp)) {
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index db996d8c3a..3262e86e61 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -1280,11 +1280,6 @@ static void arm_cpu_initfn(Object *obj)
 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_el3_property =
-            DEFINE_PROP_BOOL("has_el3", ARMCPU, has_el3, true);
-#endif
-
 static Property arm_cpu_cfgend_property =
             DEFINE_PROP_BOOL("cfgend", ARMCPU, cfgend, false);
 
@@ -1377,11 +1372,6 @@ static void arm_cpu_post_init(Object *obj)
 
 #ifndef CONFIG_USER_ONLY
     if (arm_feature(&cpu->env, ARM_FEATURE_EL3)) {
-        /* Add the has_el3 state CPU property only if EL3 is allowed.  This will
-         * prevent "has_el3" from existing on CPUs which cannot support EL3.
-         */
-        qdev_property_add_static(DEVICE(obj), &arm_cpu_has_el3_property);
-
         object_property_add_link(obj, "secure-memory",
                                  TYPE_MEMORY_REGION,
                                  (Object **)&cpu->secure_memory,
@@ -1583,12 +1573,6 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
                        current_accel_name());
             return;
         }
-        if (cpu->has_el3) {
-            error_setg(errp,
-                       "Cannot enable %s when guest CPU has EL3 enabled",
-                       current_accel_name());
-            return;
-        }
         if (cpu->tag_memory) {
             error_setg(errp,
                        "Cannot enable %s when guest CPUs has MTE enabled",
@@ -1795,22 +1779,6 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
         }
     }
 
-    if (!arm_feature(env, ARM_FEATURE_M) && !cpu->has_el3) {
-        /* If the has_el3 CPU property is disabled then we need to disable the
-         * feature.
-         */
-        unset_feature(env, ARM_FEATURE_EL3);
-
-        /*
-         * Disable the security extension feature bits in the processor
-         * feature registers as well.
-         */
-        cpu->isar.id_pfr1 = FIELD_DP32(cpu->isar.id_pfr1, ID_PFR1, SECURITY, 0);
-        cpu->isar.id_dfr0 = FIELD_DP32(cpu->isar.id_dfr0, ID_DFR0, COPSDBG, 0);
-        cpu->isar.id_aa64pfr0 = FIELD_DP64(cpu->isar.id_aa64pfr0,
-                                           ID_AA64PFR0, EL3, 0);
-    }
-
     if (!cpu->has_pmu) {
         unset_feature(env, ARM_FEATURE_PMU);
     }
@@ -1929,7 +1897,8 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
 #ifndef CONFIG_USER_ONLY
     MachineState *ms = MACHINE(qdev_get_machine());
     unsigned int smp_cpus = ms->smp.cpus;
-    bool has_secure = cpu->has_el3 || arm_feature(env, ARM_FEATURE_M_SECURITY);
+    bool has_secure = arm_feature(env, ARM_FEATURE_EL3) ||
+                      arm_feature(env, ARM_FEATURE_M_SECURITY);
 
     /*
      * We must set cs->num_ases to the final value before
@@ -2364,6 +2333,13 @@ static void arm_cpu_leaf_class_init(ObjectClass *oc, void *data)
                            arm_class_prop_set_auto_ofs,
                            (void *)(uintptr_t)offsetof(ARMCPUClass, has_el2));
     }
+    if (arm_class_feature(acc, ARM_FEATURE_EL3) ||
+        arm_class_feature(acc, ARM_FEATURE_V8)) {
+        class_property_add(oc, "has_el3", "bool", NULL,
+                           arm_class_prop_get_auto_ofs,
+                           arm_class_prop_set_auto_ofs,
+                           (void *)(uintptr_t)offsetof(ARMCPUClass, has_el3));
+    }
 #endif /* !CONFIG_USER_ONLY */
 }
 
@@ -2405,6 +2381,42 @@ static bool arm_cpu_class_late_init(ObjectClass *oc, Error **errp)
     default:
         g_assert_not_reached();
     }
+
+    if (acc->has_el3 == ON_OFF_AUTO_AUTO) {
+        if (tcg_enabled() || qtest_enabled()) {
+            acc->has_el3 = (arm_class_feature(acc, ARM_FEATURE_EL3)
+                            ? ON_OFF_AUTO_ON : ON_OFF_AUTO_OFF);
+        } else {
+            acc->has_el3 = ON_OFF_AUTO_OFF;
+        }
+    }
+    switch (acc->has_el3) {
+    case ON_OFF_AUTO_OFF:
+        unset_class_feature(acc, ARM_FEATURE_EL3);
+        /*
+         * Disable the security extension feature bits in the processor
+         * feature registers as well.
+         */
+        acc->isar.id_pfr1 = FIELD_DP32(acc->isar.id_pfr1, ID_PFR1, SECURITY, 0);
+        acc->isar.id_dfr0 = FIELD_DP32(acc->isar.id_dfr0, ID_DFR0, COPSDBG, 0);
+        acc->isar.id_aa64pfr0 = FIELD_DP64(acc->isar.id_aa64pfr0,
+                                           ID_AA64PFR0, EL3, 0);
+        break;
+    case ON_OFF_AUTO_ON:
+        if (!tcg_enabled() && !qtest_enabled()) {
+            error_setg(errp,
+                       "Cannot enable %s when guest CPU has EL3 enabled",
+                       current_accel_name());
+            return false;
+        }
+        if (!arm_class_feature(acc, ARM_FEATURE_EL3)) {
+            error_setg(errp, "CPU does not support EL3");
+            return false;
+        }
+        break;
+    default:
+        g_assert_not_reached();
+    }
 #endif /* !CONFIG_USER_ONLY */
 
     /* Run some consistency checks for TCG. */
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* [RFC PATCH 37/40] target/arm: Move "cfgend" to class property
  2023-01-03 18:16 [RFC PATCH 00/40] Toward class init of cpu features Richard Henderson
                   ` (35 preceding siblings ...)
  2023-01-03 18:16 ` [RFC PATCH 36/40] target/arm: Move "has_el3" " Richard Henderson
@ 2023-01-03 18:16 ` Richard Henderson
  2023-01-05 22:23   ` Philippe Mathieu-Daudé
  2023-01-03 18:16 ` [RFC PATCH 38/40] target/arm: Move "vfp" and "neon" to class properties Richard Henderson
                   ` (4 subsequent siblings)
  41 siblings, 1 reply; 77+ messages in thread
From: Richard Henderson @ 2023-01-03 18:16 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, berrange, eduardo, armbru, ajones, alex.bennee

Remove the cfgend variable entirely and reuse the property
accessor functions created for reset-hivecs.  This removes
the last setting of cpu->reset_sctlr, to we can remove that
as well, using only the class value.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/cpu.h    |  8 --------
 target/arm/cpu.c    | 26 ++++++++++++--------------
 target/arm/helper.c |  4 ++--
 3 files changed, 14 insertions(+), 24 deletions(-)

diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index 5921660d86..23070a9c25 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -954,7 +954,6 @@ struct ArchCPU {
     uint32_t revidr;
     uint32_t reset_fpsid;
     uint64_t ctr;
-    uint32_t reset_sctlr;
     uint64_t pmceid0;
     uint64_t pmceid1;
     uint32_t id_afr0;
@@ -987,13 +986,6 @@ struct ArchCPU {
     int gic_vprebits; /* number of virtual preemption bits */
     int gic_pribits; /* number of physical priority bits */
 
-    /* Whether the cfgend input is high (i.e. this CPU should reset into
-     * big-endian mode).  This setting isn't used directly: instead it modifies
-     * the reset_sctlr value to have SCTLR_B or SCTLR_EE set, depending on the
-     * architecture version.
-     */
-    bool cfgend;
-
     QLIST_HEAD(, ARMELChangeHook) pre_el_change_hooks;
     QLIST_HEAD(, ARMELChangeHook) el_change_hooks;
 
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index 3262e86e61..17d08e0e9c 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -1222,7 +1222,6 @@ static void arm_cpu_initfn(Object *obj)
     cpu->revidr = acc->revidr;
     cpu->id_afr0 = acc->id_afr0;
     cpu->reset_fpsid = acc->reset_fpsid;
-    cpu->reset_sctlr = acc->reset_sctlr;
     cpu->reset_auxcr = acc->reset_auxcr;
     cpu->pmsav7_dregion = acc->pmsav7_dregion;
     cpu->sau_sregion = acc->sau_sregion;
@@ -1280,9 +1279,6 @@ static void arm_cpu_initfn(Object *obj)
 static Property arm_cpu_reset_cbar_property =
             DEFINE_PROP_UINT64("reset-cbar", ARMCPU, reset_cbar, 0);
 
-static Property arm_cpu_cfgend_property =
-            DEFINE_PROP_BOOL("cfgend", ARMCPU, cfgend, false);
-
 static Property arm_cpu_has_vfp_property =
             DEFINE_PROP_BOOL("vfp", ARMCPU, has_vfp, true);
 
@@ -1442,8 +1438,6 @@ static void arm_cpu_post_init(Object *obj)
                                    &cpu->psci_conduit,
                                    OBJ_PROP_FLAG_READWRITE);
 
-    qdev_property_add_static(DEVICE(obj), &arm_cpu_cfgend_property);
-
     if (kvm_enabled()) {
         kvm_arm_add_vcpu_properties(obj);
     }
@@ -1771,14 +1765,6 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
         return;
     }
 
-    if (cpu->cfgend) {
-        if (arm_feature(&cpu->env, ARM_FEATURE_V7)) {
-            cpu->reset_sctlr |= SCTLR_EE;
-        } else {
-            cpu->reset_sctlr |= SCTLR_B;
-        }
-    }
-
     if (!cpu->has_pmu) {
         unset_feature(env, ARM_FEATURE_PMU);
     }
@@ -2306,6 +2292,18 @@ static void arm_cpu_leaf_class_init(ObjectClass *oc, void *data)
     }
 
 #ifndef CONFIG_USER_ONLY
+    /*
+     * When the cfgend input is high, the CPU should reset into
+     * big-endian mode.  Modify the reset_sctlr value to have SCTLR_B
+     * or SCTLR_EE set, depending on the architecture version.
+     */
+    class_property_add(oc, "cfgend", "bool", NULL,
+                       arm_class_prop_get_sctlrbit,
+                       arm_class_prop_set_sctlrbit,
+                       (void *)(uintptr_t)
+                       (arm_class_feature(acc, ARM_FEATURE_V7)
+                        ? SCTLR_EE : SCTLR_B));
+
     if (arm_class_feature(acc, ARM_FEATURE_GENERIC_TIMER)) {
         class_property_add(oc, "cntfrq", "uint64", NULL,
                            arm_class_prop_uint64_ofs,
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 67d32c2e59..e414fa11dd 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -7995,7 +7995,7 @@ void register_cp_regs_for_features(ARMCPU *cpu)
               .access = PL3_RW,
               .raw_writefn = raw_write, .writefn = sctlr_write,
               .fieldoffset = offsetof(CPUARMState, cp15.sctlr_el[3]),
-              .resetvalue = cpu->reset_sctlr },
+              .resetvalue = acc->reset_sctlr },
         };
 
         define_arm_cp_regs(cpu, el3_regs);
@@ -8331,7 +8331,7 @@ void register_cp_regs_for_features(ARMCPU *cpu)
             .access = PL1_RW, .accessfn = access_tvm_trvm,
             .bank_fieldoffsets = { offsetof(CPUARMState, cp15.sctlr_s),
                                    offsetof(CPUARMState, cp15.sctlr_ns) },
-            .writefn = sctlr_write, .resetvalue = cpu->reset_sctlr,
+            .writefn = sctlr_write, .resetvalue = acc->reset_sctlr,
             .raw_writefn = raw_write,
         };
         if (arm_feature(env, ARM_FEATURE_XSCALE)) {
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* [RFC PATCH 38/40] target/arm: Move "vfp" and "neon" to class properties
  2023-01-03 18:16 [RFC PATCH 00/40] Toward class init of cpu features Richard Henderson
                   ` (36 preceding siblings ...)
  2023-01-03 18:16 ` [RFC PATCH 37/40] target/arm: Move "cfgend" " Richard Henderson
@ 2023-01-03 18:16 ` Richard Henderson
  2023-01-03 18:16 ` [RFC PATCH 39/40] target/arm: Move "has-mpu" and "pmsav7-dregion" " Richard Henderson
                   ` (3 subsequent siblings)
  41 siblings, 0 replies; 77+ messages in thread
From: Richard Henderson @ 2023-01-03 18:16 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, berrange, eduardo, armbru, ajones, alex.bennee

With the movement of the properties, we can remove the fields
from the cpu entirely, using only the class.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/cpu-qom.h    |   4 +
 target/arm/cpu.h        |   4 -
 hw/arm/aspeed_ast2600.c |   3 +-
 target/arm/cpu.c        | 340 +++++++++++++++++++++-------------------
 4 files changed, 186 insertions(+), 165 deletions(-)

diff --git a/target/arm/cpu-qom.h b/target/arm/cpu-qom.h
index f4e01e0ddb..0e71569ab5 100644
--- a/target/arm/cpu-qom.h
+++ b/target/arm/cpu-qom.h
@@ -188,6 +188,10 @@ struct ARMCPUClass {
     OnOffAuto has_el3;
     /* CPU has virtualization extension */
     OnOffAuto has_el2;
+    /* CPU has VFP */
+    OnOffAuto has_vfp;
+    /* CPU has Neon */
+    OnOffAuto has_neon;
 };
 
 static inline int arm_class_feature(ARMCPUClass *acc, int feature)
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index 23070a9c25..8d2f78b601 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -888,10 +888,6 @@ struct ArchCPU {
 
     /* CPU has PMU (Performance Monitor Unit) */
     bool has_pmu;
-    /* CPU has VFP */
-    bool has_vfp;
-    /* CPU has Neon */
-    bool has_neon;
 
     /* CPU has memory protection unit */
     bool has_mpu;
diff --git a/hw/arm/aspeed_ast2600.c b/hw/arm/aspeed_ast2600.c
index bb8579546e..de5cda2093 100644
--- a/hw/arm/aspeed_ast2600.c
+++ b/hw/arm/aspeed_ast2600.c
@@ -156,6 +156,7 @@ static void aspeed_soc_ast2600_init(Object *obj)
 
     cpu_class = object_class_by_name(sc->cpu_type);
     class_property_set_uint(cpu_class, "cntfrq", 1125000000, &error_abort);
+    class_property_set_bool(cpu_class, "neon", false, &error_abort);
 
     for (i = 0; i < sc->num_cpus; i++) {
         object_initialize_child(obj, "cpu[*]", &s->cpu[i], sc->cpu_type);
@@ -309,8 +310,6 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp)
         object_property_set_int(OBJECT(&s->cpu[i]), "mp-affinity",
                                 aspeed_calc_affinity(i), &error_abort);
 
-        object_property_set_bool(OBJECT(&s->cpu[i]), "neon", false,
-                                &error_abort);
         object_property_set_link(OBJECT(&s->cpu[i]), "memory",
                                  OBJECT(s->memory), &error_abort);
 
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index 17d08e0e9c..e48f62a6fc 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -1279,12 +1279,6 @@ static void arm_cpu_initfn(Object *obj)
 static Property arm_cpu_reset_cbar_property =
             DEFINE_PROP_UINT64("reset-cbar", ARMCPU, reset_cbar, 0);
 
-static Property arm_cpu_has_vfp_property =
-            DEFINE_PROP_BOOL("vfp", ARMCPU, has_vfp, true);
-
-static Property arm_cpu_has_neon_property =
-            DEFINE_PROP_BOOL("neon", ARMCPU, has_neon, true);
-
 static Property arm_cpu_has_mpu_property =
             DEFINE_PROP_BOOL("has-mpu", ARMCPU, has_mpu, true);
 
@@ -1381,27 +1375,6 @@ static void arm_cpu_post_init(Object *obj)
         object_property_add_bool(obj, "pmu", arm_get_pmu, arm_set_pmu);
     }
 
-    /*
-     * Allow user to turn off VFP and Neon support, but only for TCG --
-     * KVM does not currently allow us to lie to the guest about its
-     * ID/feature registers, so the guest always sees what the host has.
-     */
-    if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)
-        ? cpu_isar_feature(aa64_fp_simd, cpu)
-        : cpu_isar_feature(aa32_vfp, cpu)) {
-        cpu->has_vfp = true;
-        if (!kvm_enabled() && !arm_feature(&cpu->env, ARM_FEATURE_M)) {
-            qdev_property_add_static(DEVICE(obj), &arm_cpu_has_vfp_property);
-        }
-    }
-
-    if (arm_feature(&cpu->env, ARM_FEATURE_NEON)) {
-        cpu->has_neon = true;
-        if (!kvm_enabled()) {
-            qdev_property_add_static(DEVICE(obj), &arm_cpu_has_neon_property);
-        }
-    }
-
     if (arm_feature(&cpu->env, ARM_FEATURE_PMSA)) {
         qdev_property_add_static(DEVICE(obj), &arm_cpu_has_mpu_property);
         if (arm_feature(&cpu->env, ARM_FEATURE_V7)) {
@@ -1603,137 +1576,6 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
         return;
     }
 
-    if (arm_feature(env, ARM_FEATURE_AARCH64) &&
-        cpu->has_vfp != cpu->has_neon) {
-        /*
-         * This is an architectural requirement for AArch64; AArch32 is
-         * more flexible and permits VFP-no-Neon and Neon-no-VFP.
-         */
-        error_setg(errp,
-                   "AArch64 CPUs must have both VFP and Neon or neither");
-        return;
-    }
-
-    if (!cpu->has_vfp) {
-        uint64_t t;
-        uint32_t u;
-
-        t = cpu->isar.id_aa64isar1;
-        t = FIELD_DP64(t, ID_AA64ISAR1, JSCVT, 0);
-        cpu->isar.id_aa64isar1 = t;
-
-        t = cpu->isar.id_aa64pfr0;
-        t = FIELD_DP64(t, ID_AA64PFR0, FP, 0xf);
-        cpu->isar.id_aa64pfr0 = t;
-
-        u = cpu->isar.id_isar6;
-        u = FIELD_DP32(u, ID_ISAR6, JSCVT, 0);
-        u = FIELD_DP32(u, ID_ISAR6, BF16, 0);
-        cpu->isar.id_isar6 = u;
-
-        u = cpu->isar.mvfr0;
-        u = FIELD_DP32(u, MVFR0, FPSP, 0);
-        u = FIELD_DP32(u, MVFR0, FPDP, 0);
-        u = FIELD_DP32(u, MVFR0, FPDIVIDE, 0);
-        u = FIELD_DP32(u, MVFR0, FPSQRT, 0);
-        u = FIELD_DP32(u, MVFR0, FPROUND, 0);
-        if (!arm_feature(env, ARM_FEATURE_M)) {
-            u = FIELD_DP32(u, MVFR0, FPTRAP, 0);
-            u = FIELD_DP32(u, MVFR0, FPSHVEC, 0);
-        }
-        cpu->isar.mvfr0 = u;
-
-        u = cpu->isar.mvfr1;
-        u = FIELD_DP32(u, MVFR1, FPFTZ, 0);
-        u = FIELD_DP32(u, MVFR1, FPDNAN, 0);
-        u = FIELD_DP32(u, MVFR1, FPHP, 0);
-        if (arm_feature(env, ARM_FEATURE_M)) {
-            u = FIELD_DP32(u, MVFR1, FP16, 0);
-        }
-        cpu->isar.mvfr1 = u;
-
-        u = cpu->isar.mvfr2;
-        u = FIELD_DP32(u, MVFR2, FPMISC, 0);
-        cpu->isar.mvfr2 = u;
-    }
-
-    if (!cpu->has_neon) {
-        uint64_t t;
-        uint32_t u;
-
-        unset_feature(env, ARM_FEATURE_NEON);
-
-        t = cpu->isar.id_aa64isar0;
-        t = FIELD_DP64(t, ID_AA64ISAR0, AES, 0);
-        t = FIELD_DP64(t, ID_AA64ISAR0, SHA1, 0);
-        t = FIELD_DP64(t, ID_AA64ISAR0, SHA2, 0);
-        t = FIELD_DP64(t, ID_AA64ISAR0, SHA3, 0);
-        t = FIELD_DP64(t, ID_AA64ISAR0, SM3, 0);
-        t = FIELD_DP64(t, ID_AA64ISAR0, SM4, 0);
-        t = FIELD_DP64(t, ID_AA64ISAR0, DP, 0);
-        cpu->isar.id_aa64isar0 = t;
-
-        t = cpu->isar.id_aa64isar1;
-        t = FIELD_DP64(t, ID_AA64ISAR1, FCMA, 0);
-        t = FIELD_DP64(t, ID_AA64ISAR1, BF16, 0);
-        t = FIELD_DP64(t, ID_AA64ISAR1, I8MM, 0);
-        cpu->isar.id_aa64isar1 = t;
-
-        t = cpu->isar.id_aa64pfr0;
-        t = FIELD_DP64(t, ID_AA64PFR0, ADVSIMD, 0xf);
-        cpu->isar.id_aa64pfr0 = t;
-
-        u = cpu->isar.id_isar5;
-        u = FIELD_DP32(u, ID_ISAR5, AES, 0);
-        u = FIELD_DP32(u, ID_ISAR5, SHA1, 0);
-        u = FIELD_DP32(u, ID_ISAR5, SHA2, 0);
-        u = FIELD_DP32(u, ID_ISAR5, RDM, 0);
-        u = FIELD_DP32(u, ID_ISAR5, VCMA, 0);
-        cpu->isar.id_isar5 = u;
-
-        u = cpu->isar.id_isar6;
-        u = FIELD_DP32(u, ID_ISAR6, DP, 0);
-        u = FIELD_DP32(u, ID_ISAR6, FHM, 0);
-        u = FIELD_DP32(u, ID_ISAR6, BF16, 0);
-        u = FIELD_DP32(u, ID_ISAR6, I8MM, 0);
-        cpu->isar.id_isar6 = u;
-
-        if (!arm_feature(env, ARM_FEATURE_M)) {
-            u = cpu->isar.mvfr1;
-            u = FIELD_DP32(u, MVFR1, SIMDLS, 0);
-            u = FIELD_DP32(u, MVFR1, SIMDINT, 0);
-            u = FIELD_DP32(u, MVFR1, SIMDSP, 0);
-            u = FIELD_DP32(u, MVFR1, SIMDHP, 0);
-            cpu->isar.mvfr1 = u;
-
-            u = cpu->isar.mvfr2;
-            u = FIELD_DP32(u, MVFR2, SIMDMISC, 0);
-            cpu->isar.mvfr2 = u;
-        }
-    }
-
-    if (!cpu->has_neon && !cpu->has_vfp) {
-        uint64_t t;
-        uint32_t u;
-
-        t = cpu->isar.id_aa64isar0;
-        t = FIELD_DP64(t, ID_AA64ISAR0, FHM, 0);
-        cpu->isar.id_aa64isar0 = t;
-
-        t = cpu->isar.id_aa64isar1;
-        t = FIELD_DP64(t, ID_AA64ISAR1, FRINTTS, 0);
-        cpu->isar.id_aa64isar1 = t;
-
-        u = cpu->isar.mvfr0;
-        u = FIELD_DP32(u, MVFR0, SIMDREG, 0);
-        cpu->isar.mvfr0 = u;
-
-        /* Despite the name, this field covers both VFP and Neon */
-        u = cpu->isar.mvfr1;
-        u = FIELD_DP32(u, MVFR1, SIMDFMAC, 0);
-        cpu->isar.mvfr1 = u;
-    }
-
     /*
      * We rely on no XScale CPU having VFP so we can use the same bits in the
      * TB flags field for VECSTRIDE and XSCALE_CPAR.
@@ -2102,7 +1944,6 @@ static bool arm_class_prop_uint64_ofs(ObjectClass *oc, Visitor *v,
     return visit_type_uint64(v, name, ptr, errp);
 }
 
-#ifndef CONFIG_USER_ONLY
 static bool arm_class_prop_get_auto_ofs(ObjectClass *oc, Visitor *v,
                                         const char *name, void *opaque,
                                         Error **errp)
@@ -2131,6 +1972,7 @@ static bool arm_class_prop_set_auto_ofs(ObjectClass *oc, Visitor *v,
     return false;
 }
 
+#ifndef CONFIG_USER_ONLY
 static bool arm_class_prop_set_sctlrbit(ObjectClass *oc, Visitor *v,
                                         const char *name, void *opaque,
                                         Error **errp)
@@ -2339,11 +2181,34 @@ static void arm_cpu_leaf_class_init(ObjectClass *oc, void *data)
                            (void *)(uintptr_t)offsetof(ARMCPUClass, has_el3));
     }
 #endif /* !CONFIG_USER_ONLY */
+
+    /*
+     * Similarly, allow user to turn off VFP and Neon support with TCG.
+     * While the id registers may not yet be configured for properly
+     * detecting VFP for "host" or "max", we know that all aarch64 has
+     * support, so substitute AARCH64.  Neon is always set correctly.
+     */
+    if (arm_class_feature(acc, ARM_FEATURE_AARCH64) ||
+        (class_isar_feature(aa32_vfp, acc) &&
+         !arm_class_feature(acc, ARM_FEATURE_M))) {
+        class_property_add(oc, "vfp", "bool", NULL,
+                           arm_class_prop_get_auto_ofs,
+                           arm_class_prop_set_auto_ofs,
+                           (void *)(uintptr_t)offsetof(ARMCPUClass, has_vfp));
+    }
+    if (arm_class_feature(acc, ARM_FEATURE_NEON)) {
+        class_property_add(oc, "neon", "bool", NULL,
+                           arm_class_prop_get_auto_ofs,
+                           arm_class_prop_set_auto_ofs,
+                           (void *)(uintptr_t)offsetof(ARMCPUClass, has_neon));
+    }
 }
 
 static bool arm_cpu_class_late_init(ObjectClass *oc, Error **errp)
 {
     ARMCPUClass *acc = ARM_CPU_CLASS(oc);
+    uint64_t t;
+    uint32_t u;
 
     if (acc->info->class_late_init) {
         if (!acc->info->class_late_init(acc, errp)) {
@@ -2417,6 +2282,163 @@ static bool arm_cpu_class_late_init(ObjectClass *oc, Error **errp)
     }
 #endif /* !CONFIG_USER_ONLY */
 
+    if (!arm_class_feature(acc, ARM_FEATURE_M)) {
+        if (acc->has_vfp == ON_OFF_AUTO_AUTO) {
+            acc->has_vfp = ((arm_class_feature(acc, ARM_FEATURE_AARCH64)
+                             ? class_isar_feature(aa64_fp_simd, acc)
+                             : class_isar_feature(aa32_vfp, acc))
+                            ? ON_OFF_AUTO_ON : ON_OFF_AUTO_OFF);
+        }
+        switch (acc->has_vfp) {
+        default:
+            g_assert_not_reached();
+        case ON_OFF_AUTO_ON:
+            break;
+        case ON_OFF_AUTO_OFF:
+            /*
+             * Neither KVM nor HVF allow us to lie to the guest about
+             * ID/feature registers, so the guest always sees what
+             * the host has.
+             */
+            if (!tcg_enabled() && !qtest_enabled()) {
+                error_setg(errp,
+                           "Cannot enable %s when guest CPU has VFP disabled",
+                           current_accel_name());
+                return false;
+            }
+
+            t = acc->isar.id_aa64isar1;
+            t = FIELD_DP64(t, ID_AA64ISAR1, JSCVT, 0);
+            acc->isar.id_aa64isar1 = t;
+
+            t = acc->isar.id_aa64pfr0;
+            t = FIELD_DP64(t, ID_AA64PFR0, FP, 0xf);
+            acc->isar.id_aa64pfr0 = t;
+
+            u = acc->isar.id_isar6;
+            u = FIELD_DP32(u, ID_ISAR6, JSCVT, 0);
+            u = FIELD_DP32(u, ID_ISAR6, BF16, 0);
+            acc->isar.id_isar6 = u;
+
+            u = acc->isar.mvfr0;
+            u = FIELD_DP32(u, MVFR0, FPSP, 0);
+            u = FIELD_DP32(u, MVFR0, FPDP, 0);
+            u = FIELD_DP32(u, MVFR0, FPDIVIDE, 0);
+            u = FIELD_DP32(u, MVFR0, FPSQRT, 0);
+            u = FIELD_DP32(u, MVFR0, FPROUND, 0);
+            u = FIELD_DP32(u, MVFR0, FPTRAP, 0);
+            u = FIELD_DP32(u, MVFR0, FPSHVEC, 0);
+            acc->isar.mvfr0 = u;
+
+            u = acc->isar.mvfr1;
+            u = FIELD_DP32(u, MVFR1, FPFTZ, 0);
+            u = FIELD_DP32(u, MVFR1, FPDNAN, 0);
+            u = FIELD_DP32(u, MVFR1, FPHP, 0);
+            acc->isar.mvfr1 = u;
+
+            u = acc->isar.mvfr2;
+            u = FIELD_DP32(u, MVFR2, FPMISC, 0);
+            acc->isar.mvfr2 = u;
+            break;
+        }
+
+        if (acc->has_neon == ON_OFF_AUTO_AUTO) {
+            acc->has_neon = (arm_class_feature(acc, ARM_FEATURE_NEON)
+                             ? ON_OFF_AUTO_ON : ON_OFF_AUTO_OFF);
+        }
+        switch (acc->has_neon) {
+        default:
+            g_assert_not_reached();
+        case ON_OFF_AUTO_ON:
+            break;
+        case ON_OFF_AUTO_OFF:
+            if (!tcg_enabled() && !qtest_enabled()) {
+                error_setg(errp,
+                           "Cannot enable %s when guest CPU has NEON disabled",
+                           current_accel_name());
+                return false;
+            }
+
+            unset_class_feature(acc, ARM_FEATURE_NEON);
+
+            t = acc->isar.id_aa64isar0;
+            t = FIELD_DP64(t, ID_AA64ISAR0, AES, 0);
+            t = FIELD_DP64(t, ID_AA64ISAR0, SHA1, 0);
+            t = FIELD_DP64(t, ID_AA64ISAR0, SHA2, 0);
+            t = FIELD_DP64(t, ID_AA64ISAR0, SHA3, 0);
+            t = FIELD_DP64(t, ID_AA64ISAR0, SM3, 0);
+            t = FIELD_DP64(t, ID_AA64ISAR0, SM4, 0);
+            t = FIELD_DP64(t, ID_AA64ISAR0, DP, 0);
+            acc->isar.id_aa64isar0 = t;
+
+            t = acc->isar.id_aa64isar1;
+            t = FIELD_DP64(t, ID_AA64ISAR1, FCMA, 0);
+            t = FIELD_DP64(t, ID_AA64ISAR1, BF16, 0);
+            t = FIELD_DP64(t, ID_AA64ISAR1, I8MM, 0);
+            acc->isar.id_aa64isar1 = t;
+
+            t = acc->isar.id_aa64pfr0;
+            t = FIELD_DP64(t, ID_AA64PFR0, ADVSIMD, 0xf);
+            acc->isar.id_aa64pfr0 = t;
+
+            u = acc->isar.id_isar5;
+            u = FIELD_DP32(u, ID_ISAR5, AES, 0);
+            u = FIELD_DP32(u, ID_ISAR5, SHA1, 0);
+            u = FIELD_DP32(u, ID_ISAR5, SHA2, 0);
+            u = FIELD_DP32(u, ID_ISAR5, RDM, 0);
+            u = FIELD_DP32(u, ID_ISAR5, VCMA, 0);
+            acc->isar.id_isar5 = u;
+
+            u = acc->isar.id_isar6;
+            u = FIELD_DP32(u, ID_ISAR6, DP, 0);
+            u = FIELD_DP32(u, ID_ISAR6, FHM, 0);
+            u = FIELD_DP32(u, ID_ISAR6, BF16, 0);
+            u = FIELD_DP32(u, ID_ISAR6, I8MM, 0);
+            acc->isar.id_isar6 = u;
+
+            u = acc->isar.mvfr1;
+            u = FIELD_DP32(u, MVFR1, SIMDLS, 0);
+            u = FIELD_DP32(u, MVFR1, SIMDINT, 0);
+            u = FIELD_DP32(u, MVFR1, SIMDSP, 0);
+            u = FIELD_DP32(u, MVFR1, SIMDHP, 0);
+            acc->isar.mvfr1 = u;
+
+            u = acc->isar.mvfr2;
+            u = FIELD_DP32(u, MVFR2, SIMDMISC, 0);
+            acc->isar.mvfr2 = u;
+
+            if (acc->has_vfp == ON_OFF_AUTO_OFF) {
+                t = acc->isar.id_aa64isar0;
+                t = FIELD_DP64(t, ID_AA64ISAR0, FHM, 0);
+                acc->isar.id_aa64isar0 = t;
+
+                t = acc->isar.id_aa64isar1;
+                t = FIELD_DP64(t, ID_AA64ISAR1, FRINTTS, 0);
+                acc->isar.id_aa64isar1 = t;
+
+                u = acc->isar.mvfr0;
+                u = FIELD_DP32(u, MVFR0, SIMDREG, 0);
+                acc->isar.mvfr0 = u;
+
+                /* Despite the name, this field covers both VFP and Neon */
+                u = acc->isar.mvfr1;
+                u = FIELD_DP32(u, MVFR1, SIMDFMAC, 0);
+                acc->isar.mvfr1 = u;
+            }
+            break;
+        }
+        if (acc->has_vfp != acc->has_neon &&
+            arm_class_feature(acc, ARM_FEATURE_AARCH64)) {
+            /*
+             * This is an architectural requirement for AArch64; AArch32 is
+             * more flexible and permits VFP-no-Neon and Neon-no-VFP.
+             */
+            error_setg(errp,
+                       "AArch64 CPUs must have both VFP and Neon or neither");
+            return false;
+        }
+    }
+
     /* Run some consistency checks for TCG. */
     if (tcg_enabled()) {
         bool no_aa32 = arm_class_feature(acc, ARM_FEATURE_AARCH64) &&
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* [RFC PATCH 39/40] target/arm: Move "has-mpu" and "pmsav7-dregion" to class properties
  2023-01-03 18:16 [RFC PATCH 00/40] Toward class init of cpu features Richard Henderson
                   ` (37 preceding siblings ...)
  2023-01-03 18:16 ` [RFC PATCH 38/40] target/arm: Move "vfp" and "neon" to class properties Richard Henderson
@ 2023-01-03 18:16 ` Richard Henderson
  2023-01-03 18:16 ` [RFC PATCH 40/40] target/arm: Move "pmu" to class property Richard Henderson
                   ` (2 subsequent siblings)
  41 siblings, 0 replies; 77+ messages in thread
From: Richard Henderson @ 2023-01-03 18:16 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, berrange, eduardo, armbru, ajones, alex.bennee

With the movement of the properties, we can remove the has_mpu field
from the cpu entirely, using only the class.  The pmsav7_dregion field
must stay in the cpu to handle the usage with VMSTATE_VARRAY_UINT32.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/cpu-qom.h |   3 ++
 target/arm/cpu.h     |   2 -
 target/arm/cpu.c     | 117 ++++++++++++++++++++++++-------------------
 target/arm/helper.c  |   3 +-
 4 files changed, 71 insertions(+), 54 deletions(-)

diff --git a/target/arm/cpu-qom.h b/target/arm/cpu-qom.h
index 0e71569ab5..8f266baa26 100644
--- a/target/arm/cpu-qom.h
+++ b/target/arm/cpu-qom.h
@@ -192,6 +192,9 @@ struct ARMCPUClass {
     OnOffAuto has_vfp;
     /* CPU has Neon */
     OnOffAuto has_neon;
+
+    /* CPU has memory protection unit */
+    bool has_mpu;
 };
 
 static inline int arm_class_feature(ARMCPUClass *acc, int feature)
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index 8d2f78b601..1b181ecde4 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -889,8 +889,6 @@ struct ArchCPU {
     /* CPU has PMU (Performance Monitor Unit) */
     bool has_pmu;
 
-    /* CPU has memory protection unit */
-    bool has_mpu;
     /* PMSAv7 MPU number of supported regions */
     uint32_t pmsav7_dregion;
     /* v8M SAU number of supported regions */
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index e48f62a6fc..b984735793 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -1279,19 +1279,6 @@ static void arm_cpu_initfn(Object *obj)
 static Property arm_cpu_reset_cbar_property =
             DEFINE_PROP_UINT64("reset-cbar", ARMCPU, reset_cbar, 0);
 
-static Property arm_cpu_has_mpu_property =
-            DEFINE_PROP_BOOL("has-mpu", ARMCPU, has_mpu, true);
-
-/* This is like DEFINE_PROP_UINT32 but it doesn't set the default value,
- * because the CPU initfn will have already set cpu->pmsav7_dregion to
- * the right value for that particular CPU type, and we don't want
- * to override that with an incorrect constant value.
- */
-static Property arm_cpu_pmsav7_dregion_property =
-            DEFINE_PROP_UNSIGNED_NODEFAULT("pmsav7-dregion", ARMCPU,
-                                           pmsav7_dregion,
-                                           qdev_prop_uint32, uint32_t);
-
 static bool arm_get_pmu(Object *obj, Error **errp)
 {
     ARMCPU *cpu = ARM_CPU(obj);
@@ -1375,14 +1362,6 @@ static void arm_cpu_post_init(Object *obj)
         object_property_add_bool(obj, "pmu", arm_get_pmu, arm_set_pmu);
     }
 
-    if (arm_feature(&cpu->env, ARM_FEATURE_PMSA)) {
-        qdev_property_add_static(DEVICE(obj), &arm_cpu_has_mpu_property);
-        if (arm_feature(&cpu->env, ARM_FEATURE_V7)) {
-            qdev_property_add_static(DEVICE(obj),
-                                     &arm_cpu_pmsav7_dregion_property);
-        }
-    }
-
     if (arm_feature(&cpu->env, ARM_FEATURE_M_SECURITY)) {
         object_property_add_link(obj, "idau", TYPE_IDAU_INTERFACE, &cpu->idau,
                                  qdev_prop_allow_set_link_before_realize,
@@ -1663,39 +1642,21 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
             FIELD_DP64(cpu->isar.id_aa64dfr0, ID_AA64DFR0, PMSVER, 0);
     }
 
-    /* MPU can be configured out of a PMSA CPU either by setting has-mpu
-     * to false or by setting pmsav7-dregion to 0.
-     */
-    if (!cpu->has_mpu) {
-        cpu->pmsav7_dregion = 0;
-    }
-    if (cpu->pmsav7_dregion == 0) {
-        cpu->has_mpu = false;
-    }
-
-    if (arm_feature(env, ARM_FEATURE_PMSA) &&
-        arm_feature(env, ARM_FEATURE_V7)) {
+    if (cpu->pmsav7_dregion) {
         uint32_t nr = cpu->pmsav7_dregion;
 
-        if (nr > 0xff) {
-            error_setg(errp, "PMSAv7 MPU #regions invalid %" PRIu32, nr);
-            return;
-        }
-
-        if (nr) {
-            if (arm_feature(env, ARM_FEATURE_V8)) {
-                /* PMSAv8 */
-                env->pmsav8.rbar[M_REG_NS] = g_new0(uint32_t, nr);
-                env->pmsav8.rlar[M_REG_NS] = g_new0(uint32_t, nr);
-                if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
-                    env->pmsav8.rbar[M_REG_S] = g_new0(uint32_t, nr);
-                    env->pmsav8.rlar[M_REG_S] = g_new0(uint32_t, nr);
-                }
-            } else {
-                env->pmsav7.drbar = g_new0(uint32_t, nr);
-                env->pmsav7.drsr = g_new0(uint32_t, nr);
-                env->pmsav7.dracr = g_new0(uint32_t, nr);
+        if (arm_feature(env, ARM_FEATURE_V8)) {
+            /* PMSAv8 */
+            env->pmsav8.rbar[M_REG_NS] = g_new0(uint32_t, nr);
+            env->pmsav8.rlar[M_REG_NS] = g_new0(uint32_t, nr);
+            if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
+                env->pmsav8.rbar[M_REG_S] = g_new0(uint32_t, nr);
+                env->pmsav8.rlar[M_REG_S] = g_new0(uint32_t, nr);
             }
+        } else {
+            env->pmsav7.drbar = g_new0(uint32_t, nr);
+            env->pmsav7.drsr = g_new0(uint32_t, nr);
+            env->pmsav7.dracr = g_new0(uint32_t, nr);
         }
     }
 
@@ -1933,6 +1894,28 @@ static const struct TCGCPUOps arm_tcg_ops = {
 };
 #endif /* CONFIG_TCG */
 
+static bool arm_class_prop_bool_ofs(ObjectClass *oc, Visitor *v,
+                                    const char *name, void *opaque,
+                                    Error **errp)
+{
+    ARMCPUClass *acc = ARM_CPU_CLASS(oc);
+    uintptr_t ofs = (uintptr_t)opaque;
+    bool *ptr = (void *)acc + ofs;
+
+    return visit_type_bool(v, name, ptr, errp);
+}
+
+static bool arm_class_prop_uint32_ofs(ObjectClass *oc, Visitor *v,
+                                      const char *name, void *opaque,
+                                      Error **errp)
+{
+    ARMCPUClass *acc = ARM_CPU_CLASS(oc);
+    uintptr_t ofs = (uintptr_t)opaque;
+    uint32_t *ptr = (void *)acc + ofs;
+
+    return visit_type_uint32(v, name, ptr, errp);
+}
+
 static bool arm_class_prop_uint64_ofs(ObjectClass *oc, Visitor *v,
                                       const char *name, void *opaque,
                                       Error **errp)
@@ -2202,6 +2185,22 @@ static void arm_cpu_leaf_class_init(ObjectClass *oc, void *data)
                            arm_class_prop_set_auto_ofs,
                            (void *)(uintptr_t)offsetof(ARMCPUClass, has_neon));
     }
+
+    if (arm_class_feature(acc, ARM_FEATURE_PMSA)) {
+        acc->has_mpu = true;
+        class_property_add(oc, "has-mpu", "bool", NULL,
+                           arm_class_prop_bool_ofs,
+                           arm_class_prop_bool_ofs,
+                           (void *)(uintptr_t)offsetof(ARMCPUClass, has_mpu));
+
+        if (arm_class_feature(acc, ARM_FEATURE_V7)) {
+            class_property_add(oc, "pmsav7-dregion", "uint32", NULL,
+                               arm_class_prop_uint32_ofs,
+                               arm_class_prop_uint32_ofs,
+                               (void *)(uintptr_t)
+                               offsetof(ARMCPUClass, pmsav7_dregion));
+        }
+    }
 }
 
 static bool arm_cpu_class_late_init(ObjectClass *oc, Error **errp)
@@ -2439,6 +2438,22 @@ static bool arm_cpu_class_late_init(ObjectClass *oc, Error **errp)
         }
     }
 
+    /*
+     * MPU can be configured out of a PMSA CPU either by setting has-mpu
+     * to false or by setting pmsav7-dregion to 0.
+     */
+    if (!acc->has_mpu) {
+        acc->pmsav7_dregion = 0;
+    }
+    if (acc->pmsav7_dregion == 0) {
+        acc->has_mpu = false;
+    }
+    if (acc->pmsav7_dregion > 0xff) {
+        error_setg(errp, "PMSAv7 MPU #regions invalid %" PRIu32,
+                   acc->pmsav7_dregion);
+        return false;
+    }
+
     /* Run some consistency checks for TCG. */
     if (tcg_enabled()) {
         bool no_aa32 = arm_class_feature(acc, ARM_FEATURE_AARCH64) &&
diff --git a/target/arm/helper.c b/target/arm/helper.c
index e414fa11dd..90f49108f8 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -4804,8 +4804,9 @@ static void sctlr_write(CPUARMState *env, const ARMCPRegInfo *ri,
                         uint64_t value)
 {
     ARMCPU *cpu = env_archcpu(env);
+    ARMCPUClass *acc = ARM_CPU_GET_CLASS(cpu);
 
-    if (arm_feature(env, ARM_FEATURE_PMSA) && !cpu->has_mpu) {
+    if (arm_feature(env, ARM_FEATURE_PMSA) && !acc->has_mpu) {
         /* M bit is RAZ/WI for PMSA with no MPU implemented */
         value &= ~SCTLR_M;
     }
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* [RFC PATCH 40/40] target/arm: Move "pmu" to class property
  2023-01-03 18:16 [RFC PATCH 00/40] Toward class init of cpu features Richard Henderson
                   ` (38 preceding siblings ...)
  2023-01-03 18:16 ` [RFC PATCH 39/40] target/arm: Move "has-mpu" and "pmsav7-dregion" " Richard Henderson
@ 2023-01-03 18:16 ` Richard Henderson
  2023-01-04  0:01 ` [RFC PATCH 00/40] Toward class init of cpu features Richard Henderson
  2023-01-06 19:12 ` Peter Maydell
  41 siblings, 0 replies; 77+ messages in thread
From: Richard Henderson @ 2023-01-03 18:16 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, berrange, eduardo, armbru, ajones, alex.bennee

With the movement of the property, we can remove the field
from the cpu entirely, using only the class.
Properly detect support in kvm_arm_get_host_cpu_features
rather than adjust much later in kvm_arch_init_vcpu.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/cpu-qom.h |  2 ++
 target/arm/cpu.h     |  3 ---
 target/arm/kvm_arm.h | 13 ----------
 hw/arm/virt.c        | 12 +++++-----
 target/arm/cpu.c     | 57 ++++++++++++++++++++------------------------
 target/arm/kvm.c     | 24 +++++++++++--------
 6 files changed, 48 insertions(+), 63 deletions(-)

diff --git a/target/arm/cpu-qom.h b/target/arm/cpu-qom.h
index 8f266baa26..0272e61c21 100644
--- a/target/arm/cpu-qom.h
+++ b/target/arm/cpu-qom.h
@@ -192,6 +192,8 @@ struct ARMCPUClass {
     OnOffAuto has_vfp;
     /* CPU has Neon */
     OnOffAuto has_neon;
+    /* CPU has PMU (Performance Monitor Unit) */
+    OnOffAuto has_pmu;
 
     /* CPU has memory protection unit */
     bool has_mpu;
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index 1b181ecde4..dac72045d1 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -886,9 +886,6 @@ struct ArchCPU {
     /* Current power state, access guarded by BQL */
     ARMPSCIState power_state;
 
-    /* CPU has PMU (Performance Monitor Unit) */
-    bool has_pmu;
-
     /* PMSAv7 MPU number of supported regions */
     uint32_t pmsav7_dregion;
     /* v8M SAU number of supported regions */
diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h
index d426e24c53..a958e071c1 100644
--- a/target/arm/kvm_arm.h
+++ b/target/arm/kvm_arm.h
@@ -177,14 +177,6 @@ void kvm_arm_steal_time_finalize(ARMCPU *cpu, Error **errp);
  */
 bool kvm_arm_aarch32_supported(void);
 
-/**
- * kvm_arm_pmu_supported:
- *
- * Returns: true if KVM can enable the PMU
- * and false otherwise.
- */
-bool kvm_arm_pmu_supported(void);
-
 /**
  * kvm_arm_sve_supported:
  *
@@ -229,11 +221,6 @@ static inline bool kvm_arm_aarch32_supported(void)
     return false;
 }
 
-static inline bool kvm_arm_pmu_supported(void)
-{
-    return false;
-}
-
 static inline bool kvm_arm_sve_supported(void)
 {
     return false;
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index c1cabe2413..38f89559ed 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -605,7 +605,6 @@ static void fdt_add_pmu_nodes(const VirtMachineState *vms)
     MachineState *ms = MACHINE(vms);
 
     if (!arm_feature(&armcpu->env, ARM_FEATURE_PMU)) {
-        assert(!object_property_get_bool(OBJECT(armcpu), "pmu", NULL));
         return;
     }
 
@@ -1951,9 +1950,11 @@ static void virt_cpu_post_init(VirtMachineState *vms, MemoryRegion *sysmem)
     int max_cpus = MACHINE(vms)->smp.max_cpus;
     bool aarch64, pmu, steal_time;
     CPUState *cpu;
+    ObjectClass *cpu_class;
 
+    cpu_class = object_get_class(OBJECT(first_cpu));
     aarch64 = object_property_get_bool(OBJECT(first_cpu), "aarch64", NULL);
-    pmu = object_property_get_bool(OBJECT(first_cpu), "pmu", NULL);
+    pmu = class_property_get_bool(cpu_class, "pmu", NULL);
     steal_time = object_property_get_bool(OBJECT(first_cpu),
                                           "kvm-steal-time", NULL);
 
@@ -2043,6 +2044,9 @@ static void machvirt_init(MachineState *machine)
     if (!vms->virt) {
         class_property_set_bool(cpu_class, "has_el2", false, &error_abort);
     }
+    if (vmc->no_pmu) {
+        class_property_set_bool(cpu_class, "pmu", false, &error_abort);
+    }
 
     /*
      * In accelerated mode, the memory map is computed earlier in kvm_type()
@@ -2185,10 +2189,6 @@ static void machvirt_init(MachineState *machine)
             object_property_set_bool(cpuobj, "kvm-steal-time", false, NULL);
         }
 
-        if (vmc->no_pmu && object_property_find(cpuobj, "pmu")) {
-            object_property_set_bool(cpuobj, "pmu", false, NULL);
-        }
-
         if (vmc->no_tcg_lpa2 && object_property_find(cpuobj, "lpa2")) {
             object_property_set_bool(cpuobj, "lpa2", false, NULL);
         }
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index b984735793..c287b0bc89 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -1279,29 +1279,6 @@ static void arm_cpu_initfn(Object *obj)
 static Property arm_cpu_reset_cbar_property =
             DEFINE_PROP_UINT64("reset-cbar", ARMCPU, reset_cbar, 0);
 
-static bool arm_get_pmu(Object *obj, Error **errp)
-{
-    ARMCPU *cpu = ARM_CPU(obj);
-
-    return cpu->has_pmu;
-}
-
-static void arm_set_pmu(Object *obj, bool value, Error **errp)
-{
-    ARMCPU *cpu = ARM_CPU(obj);
-
-    if (value) {
-        if (kvm_enabled() && !kvm_arm_pmu_supported()) {
-            error_setg(errp, "'pmu' feature not supported by KVM on this host");
-            return;
-        }
-        set_feature(&cpu->env, ARM_FEATURE_PMU);
-    } else {
-        unset_feature(&cpu->env, ARM_FEATURE_PMU);
-    }
-    cpu->has_pmu = value;
-}
-
 unsigned int gt_cntfrq_period_ns(ARMCPU *cpu)
 {
     ARMCPUClass *acc = ARM_CPU_GET_CLASS(cpu);
@@ -1357,11 +1334,6 @@ static void arm_cpu_post_init(Object *obj)
     }
 #endif
 
-    if (arm_feature(&cpu->env, ARM_FEATURE_PMU)) {
-        cpu->has_pmu = true;
-        object_property_add_bool(obj, "pmu", arm_get_pmu, arm_set_pmu);
-    }
-
     if (arm_feature(&cpu->env, ARM_FEATURE_M_SECURITY)) {
         object_property_add_link(obj, "idau", TYPE_IDAU_INTERFACE, &cpu->idau,
                                  qdev_prop_allow_set_link_before_realize,
@@ -1586,9 +1558,6 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
         return;
     }
 
-    if (!cpu->has_pmu) {
-        unset_feature(env, ARM_FEATURE_PMU);
-    }
     if (arm_feature(env, ARM_FEATURE_PMU)) {
         pmu_init(cpu);
 
@@ -2163,6 +2132,13 @@ static void arm_cpu_leaf_class_init(ObjectClass *oc, void *data)
                            arm_class_prop_set_auto_ofs,
                            (void *)(uintptr_t)offsetof(ARMCPUClass, has_el3));
     }
+
+    if (arm_class_feature(acc, ARM_FEATURE_PMU)) {
+        class_property_add(oc, "pmu", "bool", NULL,
+                           arm_class_prop_get_auto_ofs,
+                           arm_class_prop_set_auto_ofs,
+                           (void *)(uintptr_t)offsetof(ARMCPUClass, has_pmu));
+    }
 #endif /* !CONFIG_USER_ONLY */
 
     /*
@@ -2279,6 +2255,25 @@ static bool arm_cpu_class_late_init(ObjectClass *oc, Error **errp)
     default:
         g_assert_not_reached();
     }
+
+    switch (acc->has_pmu) {
+    case ON_OFF_AUTO_AUTO:
+        acc->has_pmu = (arm_class_feature(acc, ARM_FEATURE_PMU)
+                        ? ON_OFF_AUTO_ON : ON_OFF_AUTO_OFF);
+        break;
+    case ON_OFF_AUTO_OFF:
+        unset_class_feature(acc, ARM_FEATURE_PMU);
+        break;
+    case ON_OFF_AUTO_ON:
+        if (!arm_class_feature(acc, ARM_FEATURE_PMU)) {
+            error_setg(errp, "'pmu' feature not supported by %s on this host",
+                       current_accel_name());
+            return false;
+        }
+        break;
+    default:
+        g_assert_not_reached();
+    }
 #endif /* !CONFIG_USER_ONLY */
 
     if (!arm_class_feature(acc, ARM_FEATURE_M)) {
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index 85971df07c..0ae435addd 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -239,7 +239,13 @@ void kvm_arm_add_vcpu_properties(Object *obj)
                                     "Set off to disable KVM steal time.");
 }
 
-bool kvm_arm_pmu_supported(void)
+/**
+ * kvm_arm_pmu_supported:
+ *
+ * Returns: true if KVM can enable the PMU
+ * and false otherwise.
+ */
+static bool kvm_arm_pmu_supported(void)
 {
     return kvm_check_extension(kvm_state, KVM_CAP_ARM_PMU_V3);
 }
@@ -1463,7 +1469,7 @@ void kvm_arm_pmu_init(CPUState *cs)
         .attr = KVM_ARM_VCPU_PMU_V3_INIT,
     };
 
-    if (!ARM_CPU(cs)->has_pmu) {
+    if (!arm_feature(&ARM_CPU(cs)->env, ARM_FEATURE_PMU)) {
         return;
     }
     if (!kvm_arm_set_device_attr(cs, &attr, "PMU")) {
@@ -1480,7 +1486,7 @@ void kvm_arm_pmu_set_irq(CPUState *cs, int irq)
         .attr = KVM_ARM_VCPU_PMU_V3_IRQ,
     };
 
-    if (!ARM_CPU(cs)->has_pmu) {
+    if (!arm_feature(&ARM_CPU(cs)->env, ARM_FEATURE_PMU)) {
         return;
     }
     if (!kvm_arm_set_device_attr(cs, &attr, "PMU")) {
@@ -1594,6 +1600,9 @@ bool kvm_arm_get_host_cpu_features(ARMCPUClass *acc, Error **errp)
     if (kvm_arm_pmu_supported()) {
         init.features[0] |= 1 << KVM_ARM_VCPU_PMU_V3;
         pmu_supported = true;
+    } else {
+        /* This was optimistically set in aarch64_host_class_init. */
+        unset_class_feature(acc, ARM_FEATURE_PMU);
     }
 
     if (!kvm_arm_create_scratch_host_vcpu(cpus_to_try, fdarray, &init)) {
@@ -1877,7 +1886,6 @@ int kvm_arch_init_vcpu(CPUState *cs)
 {
     int ret;
     ARMCPU *cpu = ARM_CPU(cs);
-    CPUARMState *env = &cpu->env;
     uint64_t psciver;
 
     if (cpu->kvm_target == QEMU_KVM_ARM_TARGET_NONE ||
@@ -1900,13 +1908,9 @@ int kvm_arch_init_vcpu(CPUState *cs)
     if (!arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) {
         cpu->kvm_init_features[0] |= 1 << KVM_ARM_VCPU_EL1_32BIT;
     }
-    if (!kvm_check_extension(cs->kvm_state, KVM_CAP_ARM_PMU_V3)) {
-        cpu->has_pmu = false;
-    }
-    if (cpu->has_pmu) {
+    if (arm_feature(&cpu->env, ARM_FEATURE_PMU)) {
+        assert(kvm_arm_pmu_supported());
         cpu->kvm_init_features[0] |= 1 << KVM_ARM_VCPU_PMU_V3;
-    } else {
-        env->features &= ~(1ULL << ARM_FEATURE_PMU);
     }
     if (cpu_isar_feature(aa64_sve, cpu)) {
         assert(kvm_arm_sve_supported());
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* Re: [RFC PATCH 26/40] target/arm: Rename 'cpu' to 'acc' in class init functions
  2023-01-03 18:16 ` [RFC PATCH 26/40] target/arm: Rename 'cpu' to 'acc' in class init functions Richard Henderson
@ 2023-01-03 19:24   ` Philippe Mathieu-Daudé
  0 siblings, 0 replies; 77+ messages in thread
From: Philippe Mathieu-Daudé @ 2023-01-03 19:24 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel
  Cc: pbonzini, berrange, eduardo, armbru, ajones, alex.bennee

On 3/1/23 19:16, Richard Henderson wrote:
> These were previously left 'misnamed' to minimize the size
> of the patch.  Rename them all in bulk with no other change.
> 
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>   target/arm/cpu64.c   |  858 ++++++++++++++--------------
>   target/arm/cpu_tcg.c | 1260 +++++++++++++++++++++---------------------
>   2 files changed, 1059 insertions(+), 1059 deletions(-)

Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>



^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC PATCH 00/40] Toward class init of cpu features
  2023-01-03 18:16 [RFC PATCH 00/40] Toward class init of cpu features Richard Henderson
                   ` (39 preceding siblings ...)
  2023-01-03 18:16 ` [RFC PATCH 40/40] target/arm: Move "pmu" to class property Richard Henderson
@ 2023-01-04  0:01 ` Richard Henderson
  2023-01-06 19:12 ` Peter Maydell
  41 siblings, 0 replies; 77+ messages in thread
From: Richard Henderson @ 2023-01-04  0:01 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell

On 1/3/23 10:16, Richard Henderson wrote:
> Richard Henderson (40):
>    target/arm: Remove aarch64_cpu_finalizefn
>    target/arm: Create arm_cpu_register_parent
>    target/arm: Remove AArch64CPUClass
>    target/arm: Create TYPE_ARM_V7M_CPU
...
>    target/arm: Utilize arm-cpu instance_post_init hook
...
>    hw/arm/bcm2836: Set mp-affinity property in realize
>    target/arm: Rename arm_cpu_mp_affinity
>    target/arm: Create arm_cpu_mp_affinity
>    target/arm: Represent the entire MPIDR_EL1

I meant to say: Peter, at least this handfull of patches ought to be useful cleanup 
regardless of the rest of the series.


r~



^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC PATCH 13/40] hw/arm/bcm2836: Set mp-affinity property in realize
  2023-01-03 18:16 ` [RFC PATCH 13/40] hw/arm/bcm2836: Set mp-affinity property in realize Richard Henderson
@ 2023-01-05 21:48   ` Philippe Mathieu-Daudé
  2023-01-06  7:51     ` Philippe Mathieu-Daudé
  0 siblings, 1 reply; 77+ messages in thread
From: Philippe Mathieu-Daudé @ 2023-01-05 21:48 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel
  Cc: pbonzini, berrange, eduardo, armbru, ajones, alex.bennee

On 3/1/23 19:16, Richard Henderson wrote:
> There was even a TODO comment that we ought to be using a cpu
> property, but we failed to update when the property was added.
> Use ARM_AFF1_SHIFT instead of the bare constant 8.
> 
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>   hw/arm/bcm2836.c | 7 +++++--
>   1 file changed, 5 insertions(+), 2 deletions(-)
> 
> diff --git a/hw/arm/bcm2836.c b/hw/arm/bcm2836.c
> index 24354338ca..abbb3689d0 100644
> --- a/hw/arm/bcm2836.c
> +++ b/hw/arm/bcm2836.c
> @@ -130,8 +130,11 @@ static void bcm2836_realize(DeviceState *dev, Error **errp)
>           qdev_get_gpio_in_named(DEVICE(&s->control), "gpu-fiq", 0));
>   
>       for (n = 0; n < BCM283X_NCPUS; n++) {
> -        /* TODO: this should be converted to a property of ARM_CPU */
> -        s->cpu[n].core.mp_affinity = (bc->clusterid << 8) | n;
> +        if (!object_property_set_int(OBJECT(&s->cpu[n].core), "mp-affinity",
> +                                     (bc->clusterid << ARM_AFF1_SHIFT) | n,
> +                                     errp)) {
> +            return;
> +        }
>   
>           /* set periphbase/CBAR value for CPU-local registers */
>           if (!object_property_set_int(OBJECT(&s->cpu[n].core), "reset-cbar",

Eh I have almost the same patch locally:

-- >8 --
$ git show 5f675655c844154f3760967296e82adf5d8d7c24
diff --git a/hw/arm/bcm2836.c b/hw/arm/bcm2836.c
index 24354338ca..6f964a3b31 100644
--- a/hw/arm/bcm2836.c
+++ b/hw/arm/bcm2836.c
@@ -130,8 +130,8 @@ static void bcm2836_realize(DeviceState *dev, Error 
**errp)
          qdev_get_gpio_in_named(DEVICE(&s->control), "gpu-fiq", 0));

      for (n = 0; n < BCM283X_NCPUS; n++) {
-        /* TODO: this should be converted to a property of ARM_CPU */
-        s->cpu[n].core.mp_affinity = (bc->clusterid << 8) | n;
+        object_property_set_int(OBJECT(&s->cpu[n].core), "mp-affinity",
+                                (bc->clusterid << 8) | n, &error_abort);

          /* set periphbase/CBAR value for CPU-local registers */
          if (!object_property_set_int(OBJECT(&s->cpu[n].core), 
"reset-cbar",
---

Yours is better (ARM_AFF1_SHIFT & checks return value).

Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* Re: [RFC PATCH 06/40] target/arm: Remove AArch64CPUClass
  2023-01-03 18:16 ` [RFC PATCH 06/40] target/arm: Remove AArch64CPUClass Richard Henderson
@ 2023-01-05 21:50   ` Philippe Mathieu-Daudé
  0 siblings, 0 replies; 77+ messages in thread
From: Philippe Mathieu-Daudé @ 2023-01-05 21:50 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel
  Cc: pbonzini, berrange, eduardo, armbru, ajones, alex.bennee

On 3/1/23 19:16, Richard Henderson wrote:
> The class structure is a plain wrapper around ARMCPUClass.  We really
> only need the QOM class, TYPE_AARCH64_CPU.  The instance init and
> fallback class init functions are identical to the same ones over
> in cpu.c.  Make arm_cpu_post_init static.
> 
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>   target/arm/cpu-qom.h | 19 ++++++-------------
>   target/arm/cpu.h     |  2 --
>   target/arm/cpu.c     |  2 +-
>   target/arm/cpu64.c   | 33 +--------------------------------
>   4 files changed, 8 insertions(+), 48 deletions(-)

Nice!

Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>



^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC PATCH 04/40] target/arm: Remove aarch64_cpu_finalizefn
  2023-01-03 18:16 ` [RFC PATCH 04/40] target/arm: Remove aarch64_cpu_finalizefn Richard Henderson
@ 2023-01-05 21:51   ` Philippe Mathieu-Daudé
  0 siblings, 0 replies; 77+ messages in thread
From: Philippe Mathieu-Daudé @ 2023-01-05 21:51 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel
  Cc: pbonzini, berrange, eduardo, armbru, ajones, alex.bennee

On 3/1/23 19:16, Richard Henderson wrote:
> If the instance_finalize hook is NULL, the hook is not called.
> There is no need to install an empty function.
> 
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>   target/arm/cpu64.c | 5 -----
>   1 file changed, 5 deletions(-)

Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>



^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC PATCH 15/40] target/arm: Create arm_cpu_mp_affinity
  2023-01-03 18:16 ` [RFC PATCH 15/40] target/arm: Create arm_cpu_mp_affinity Richard Henderson
@ 2023-01-05 21:53   ` Philippe Mathieu-Daudé
  0 siblings, 0 replies; 77+ messages in thread
From: Philippe Mathieu-Daudé @ 2023-01-05 21:53 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel
  Cc: pbonzini, berrange, eduardo, armbru, ajones, alex.bennee

On 3/1/23 19:16, Richard Henderson wrote:
> Wrapper to return the mp affinity bits from the cpu.
> 
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>   target/arm/cpu.h          | 5 +++++
>   hw/arm/virt-acpi-build.c  | 2 +-
>   hw/arm/virt.c             | 6 +++---
>   hw/arm/xlnx-versal-virt.c | 3 ++-
>   hw/misc/xlnx-versal-crl.c | 4 ++--
>   target/arm/arm-powerctl.c | 2 +-
>   target/arm/hvf/hvf.c      | 4 ++--
>   target/arm/psci.c         | 2 +-
>   8 files changed, 17 insertions(+), 11 deletions(-)

Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>



^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC PATCH 14/40] target/arm: Rename arm_cpu_mp_affinity
  2023-01-03 18:16 ` [RFC PATCH 14/40] target/arm: Rename arm_cpu_mp_affinity Richard Henderson
@ 2023-01-05 21:55   ` Philippe Mathieu-Daudé
  0 siblings, 0 replies; 77+ messages in thread
From: Philippe Mathieu-Daudé @ 2023-01-05 21:55 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel
  Cc: pbonzini, berrange, eduardo, armbru, ajones, alex.bennee

On 3/1/23 19:16, Richard Henderson wrote:
> Rename to arm_build_mp_affinity.  This frees up the name for
> other usage, and emphasizes that the cpu object is not involved.
> 
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>   target/arm/cpu.h  | 2 +-
>   hw/arm/npcm7xx.c  | 2 +-
>   hw/arm/sbsa-ref.c | 2 +-
>   hw/arm/virt.c     | 2 +-
>   target/arm/cpu.c  | 6 +++---
>   5 files changed, 7 insertions(+), 7 deletions(-)

Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>



^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC PATCH 01/40] qdev: Don't always force the global property array non-null
  2023-01-03 18:16 ` [RFC PATCH 01/40] qdev: Don't always force the global property array non-null Richard Henderson
@ 2023-01-05 21:56   ` Philippe Mathieu-Daudé
  0 siblings, 0 replies; 77+ messages in thread
From: Philippe Mathieu-Daudé @ 2023-01-05 21:56 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel
  Cc: pbonzini, berrange, eduardo, armbru, ajones, alex.bennee

On 3/1/23 19:16, Richard Henderson wrote:
> Only qdev_prop_register_global requires a non-null array.
> The other instances can simply exit early.
> 
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>   hw/core/qdev-properties.c | 43 ++++++++++++++++++++++++---------------
>   1 file changed, 27 insertions(+), 16 deletions(-)

Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>



^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC PATCH 05/40] target/arm: Create arm_cpu_register_parent
  2023-01-03 18:16 ` [RFC PATCH 05/40] target/arm: Create arm_cpu_register_parent Richard Henderson
@ 2023-01-05 21:57   ` Philippe Mathieu-Daudé
  0 siblings, 0 replies; 77+ messages in thread
From: Philippe Mathieu-Daudé @ 2023-01-05 21:57 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel
  Cc: pbonzini, berrange, eduardo, armbru, ajones, alex.bennee

On 3/1/23 19:16, Richard Henderson wrote:
> Create an arm cpu class with a specific abstract parent class.
> 
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>   target/arm/cpu-qom.h | 7 ++++++-
>   target/arm/cpu.c     | 4 ++--
>   2 files changed, 8 insertions(+), 3 deletions(-)

Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>



^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC PATCH 07/40] target/arm: Create TYPE_ARM_V7M_CPU
  2023-01-03 18:16 ` [RFC PATCH 07/40] target/arm: Create TYPE_ARM_V7M_CPU Richard Henderson
@ 2023-01-05 21:58   ` Philippe Mathieu-Daudé
  0 siblings, 0 replies; 77+ messages in thread
From: Philippe Mathieu-Daudé @ 2023-01-05 21:58 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel
  Cc: pbonzini, berrange, eduardo, armbru, ajones, alex.bennee

On 3/1/23 19:16, Richard Henderson wrote:
> Create a new intermediate abstract class for v7m, like we do for
> aarch64. The initialization of ARMCPUClass.info follows the
> concrete class, so remove that init from arm_v7m_class_init.
> 
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>   target/arm/cpu-qom.h |  6 ++++++
>   target/arm/cpu_tcg.c | 36 ++++++++++++++++++++++--------------
>   2 files changed, 28 insertions(+), 14 deletions(-)

Nice again.

Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>



^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC PATCH 08/40] target/arm: Pass ARMCPUClass to ARMCPUInfo.class_init
  2023-01-03 18:16 ` [RFC PATCH 08/40] target/arm: Pass ARMCPUClass to ARMCPUInfo.class_init Richard Henderson
@ 2023-01-05 22:00   ` Philippe Mathieu-Daudé
  0 siblings, 0 replies; 77+ messages in thread
From: Philippe Mathieu-Daudé @ 2023-01-05 22:00 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel
  Cc: pbonzini, berrange, eduardo, armbru, ajones, alex.bennee

On 3/1/23 19:16, Richard Henderson wrote:
> Streamline new instances of this hook, so that we always go
> through arm_cpu_leaf_class_init first, performing common tasks,
> and have resolved the ARMCPUClass.
> 
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>   target/arm/cpu-qom.h |  2 +-
>   target/arm/cpu.c     | 10 +++++++---
>   2 files changed, 8 insertions(+), 4 deletions(-)

Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>



^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC PATCH 11/40] target/arm: Copy features from ARMCPUClass
  2023-01-03 18:16 ` [RFC PATCH 11/40] target/arm: Copy features " Richard Henderson
@ 2023-01-05 22:04   ` Philippe Mathieu-Daudé
  2023-01-06  2:19     ` Richard Henderson
  0 siblings, 1 reply; 77+ messages in thread
From: Philippe Mathieu-Daudé @ 2023-01-05 22:04 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel
  Cc: pbonzini, berrange, eduardo, armbru, ajones, alex.bennee

On 3/1/23 19:16, Richard Henderson wrote:
> Create a features member in ARMCPUClass and copy to the instance in
> arm_cpu_init.  Settings of this value will come in a future patch.
> 
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>   target/arm/cpu-qom.h | 18 ++++++++++++++++++
>   target/arm/cpu.c     |  1 +
>   2 files changed, 19 insertions(+)
> 
> diff --git a/target/arm/cpu-qom.h b/target/arm/cpu-qom.h
> index 5509ef9d85..ac58cc3a87 100644
> --- a/target/arm/cpu-qom.h
> +++ b/target/arm/cpu-qom.h
> @@ -74,8 +74,26 @@ struct ARMCPUClass {
>   
>       /* 'compatible' string for this CPU for Linux device trees */
>       const char *dtb_compatible;
> +
> +    /* Internal CPU feature flags.  */
> +    uint64_t features;
>   };
>   
> +static inline int arm_class_feature(ARMCPUClass *acc, int feature)
> +{
> +    return (acc->features & (1ULL << feature)) != 0;
> +}
> +
> +static inline void set_class_feature(ARMCPUClass *acc, int feature)
> +{
> +    acc->features |= 1ULL << feature;
> +}
> +
> +static inline void unset_class_feature(ARMCPUClass *acc, int feature)
> +{
> +    acc->features &= ~(1ULL << feature);
> +}

These helpers are not used until patch #19 "target/arm: Move most cpu
initialization to the class".

>   void register_cp_regs_for_features(ARMCPU *cpu);
>   void init_cpreg_list(ARMCPU *cpu);
>   
> diff --git a/target/arm/cpu.c b/target/arm/cpu.c
> index 1bc45b2b25..d64b86b6a5 100644
> --- a/target/arm/cpu.c
> +++ b/target/arm/cpu.c
> @@ -1191,6 +1191,7 @@ static void arm_cpu_initfn(Object *obj)
>       QLIST_INIT(&cpu->el_change_hooks);
>   
>       cpu->dtb_compatible = acc->dtb_compatible;
> +    cpu->env.features = acc->features;
>   
>   #ifdef CONFIG_USER_ONLY
>   # ifdef TARGET_AARCH64



^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC PATCH 21/40] target/arm: Remove aarch64 check from aarch64_host_object_init
  2023-01-03 18:16 ` [RFC PATCH 21/40] target/arm: Remove aarch64 check from aarch64_host_object_init Richard Henderson
@ 2023-01-05 22:08   ` Philippe Mathieu-Daudé
  2023-01-06  2:21     ` Richard Henderson
  0 siblings, 1 reply; 77+ messages in thread
From: Philippe Mathieu-Daudé @ 2023-01-05 22:08 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel
  Cc: pbonzini, berrange, eduardo, armbru, ajones, alex.bennee

On 3/1/23 19:16, Richard Henderson wrote:
> Since kvm32 was removed

Maybe add here:

   (see commit 82bf7ae84c: "target/arm: Remove KVM support for 32-bit
   Arm hosts")

> , all kvm hosts support aarch64.
> 
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>   target/arm/cpu64.c | 6 ++----
>   1 file changed, 2 insertions(+), 4 deletions(-)
> 
> diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
> index 28b5a07244..668e979a24 100644
> --- a/target/arm/cpu64.c
> +++ b/target/arm/cpu64.c
> @@ -1095,10 +1095,8 @@ static void aarch64_host_object_init(Object *obj)
>   #if defined(CONFIG_KVM)
>       ARMCPU *cpu = ARM_CPU(obj);
>       kvm_arm_set_cpu_features_from_host(cpu);
> -    if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) {

Worth asserting this feature is enabled? I don't think so, so:
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>

> -        aarch64_add_sve_properties(obj);
> -        aarch64_add_pauth_properties(obj);
> -    }
> +    aarch64_add_sve_properties(obj);
> +    aarch64_add_pauth_properties(obj);
>   #elif defined(CONFIG_HVF)
>       ARMCPU *cpu = ARM_CPU(obj);
>       hvf_arm_set_cpu_features_from_host(cpu);



^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC PATCH 24/40] target/arm/hvf: Probe host into ARMCPUClass
  2023-01-03 18:16 ` [RFC PATCH 24/40] target/arm/hvf: Probe " Richard Henderson
@ 2023-01-05 22:10   ` Philippe Mathieu-Daudé
  0 siblings, 0 replies; 77+ messages in thread
From: Philippe Mathieu-Daudé @ 2023-01-05 22:10 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel
  Cc: pbonzini, berrange, eduardo, armbru, ajones, alex.bennee

On 3/1/23 19:16, Richard Henderson wrote:
> We can now store these values into ARMCPUClass instead of into
> a temporary ARMHostCPUFeatures structure.
> 
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>   target/arm/cpu.h     |  5 ----
>   target/arm/hvf_arm.h |  2 +-
>   target/arm/cpu.c     | 13 ----------
>   target/arm/cpu64.c   |  4 +--
>   target/arm/hvf/hvf.c | 59 +++++++++++---------------------------------
>   5 files changed, 17 insertions(+), 66 deletions(-)

Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>



^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC PATCH 27/40] target/arm: Split out strongarm_class_init
  2023-01-03 18:16 ` [RFC PATCH 27/40] target/arm: Split out strongarm_class_init Richard Henderson
@ 2023-01-05 22:12   ` Philippe Mathieu-Daudé
  0 siblings, 0 replies; 77+ messages in thread
From: Philippe Mathieu-Daudé @ 2023-01-05 22:12 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel
  Cc: pbonzini, berrange, eduardo, armbru, ajones, alex.bennee

On 3/1/23 19:16, Richard Henderson wrote:
> Use an intermediate function to share code between
> sa1100_class_init and sa1110_class_init.
> 
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>   target/arm/cpu_tcg.c | 15 +++++++++------
>   1 file changed, 9 insertions(+), 6 deletions(-)

Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>



^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC PATCH 28/40] target/arm: Split out xscale*_class_init
  2023-01-03 18:16 ` [RFC PATCH 28/40] target/arm: Split out xscale*_class_init Richard Henderson
@ 2023-01-05 22:13   ` Philippe Mathieu-Daudé
  0 siblings, 0 replies; 77+ messages in thread
From: Philippe Mathieu-Daudé @ 2023-01-05 22:13 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel
  Cc: pbonzini, berrange, eduardo, armbru, ajones, alex.bennee

On 3/1/23 19:16, Richard Henderson wrote:
> Use two intermediate functions to share code between
> the 13 variants of pxa*_class_init.
> 
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>   target/arm/cpu_tcg.c | 81 +++++++++++++-------------------------------
>   1 file changed, 23 insertions(+), 58 deletions(-)

Yay :)

Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>



^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC PATCH 32/40] target/arm: Move "midr" to class property
  2023-01-03 18:16 ` [RFC PATCH 32/40] target/arm: Move "midr" to class property Richard Henderson
@ 2023-01-05 22:18   ` Philippe Mathieu-Daudé
  0 siblings, 0 replies; 77+ messages in thread
From: Philippe Mathieu-Daudé @ 2023-01-05 22:18 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel
  Cc: pbonzini, berrange, eduardo, armbru, ajones, alex.bennee

On 3/1/23 19:16, Richard Henderson wrote:
> With the movement of the property, we can remove the field
> from the cpu entirely, using only the class.
> 
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>   target/arm/cpu.h      |  1 -
>   hw/arm/xilinx_zynq.c  |  9 ++++++---
>   hw/intc/armv7m_nvic.c |  2 +-
>   target/arm/cpu.c      | 18 ++++++++++++++++--
>   target/arm/helper.c   | 14 ++++++++------
>   5 files changed, 31 insertions(+), 13 deletions(-)

Lovely.

Perhaps later arm_class_prop_uint64_ofs() can grow into a generic
QOM TYPE macro.

Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>



^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC PATCH 33/40] target/arm: Move "cntfrq" to class property
  2023-01-03 18:16 ` [RFC PATCH 33/40] target/arm: Move "cntfrq" " Richard Henderson
@ 2023-01-05 22:21   ` Philippe Mathieu-Daudé
  0 siblings, 0 replies; 77+ messages in thread
From: Philippe Mathieu-Daudé @ 2023-01-05 22:21 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel
  Cc: pbonzini, berrange, eduardo, armbru, ajones, alex.bennee

On 3/1/23 19:16, Richard Henderson wrote:
> With the movement of the property, we can remove the field
> from the cpu entirely, using only the class.
> 
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>   target/arm/cpu-qom.h    |  3 +++
>   target/arm/cpu.h        |  3 ---
>   hw/arm/aspeed_ast2600.c |  6 +++--
>   target/arm/cpu.c        | 50 +++++++++++++++++++++++------------------
>   target/arm/helper.c     |  3 ++-
>   5 files changed, 37 insertions(+), 28 deletions(-)


> @@ -2320,6 +2318,14 @@ static bool arm_cpu_class_late_init(ObjectClass *oc, Error **errp)
>           }
>       }
>   
> +#ifndef CONFIG_USER_ONLY
> +    /* TODO: Perhaps better to put this check in a property set hook. */

Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>

> +    if (!acc->gt_cntfrq_hz) {
> +        error_setg(errp, "Invalid CNTFRQ: %"PRId64"Hz", acc->gt_cntfrq_hz);
> +        return false;
> +    }
> +#endif /* CONFIG_USER_ONLY */


^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC PATCH 37/40] target/arm: Move "cfgend" to class property
  2023-01-03 18:16 ` [RFC PATCH 37/40] target/arm: Move "cfgend" " Richard Henderson
@ 2023-01-05 22:23   ` Philippe Mathieu-Daudé
  0 siblings, 0 replies; 77+ messages in thread
From: Philippe Mathieu-Daudé @ 2023-01-05 22:23 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel
  Cc: pbonzini, berrange, eduardo, armbru, ajones, alex.bennee

On 3/1/23 19:16, Richard Henderson wrote:
> Remove the cfgend variable entirely and reuse the property
> accessor functions created for reset-hivecs.  This removes
> the last setting of cpu->reset_sctlr, to we can remove that

s/to/so/?

> as well, using only the class value.
> 
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>   target/arm/cpu.h    |  8 --------
>   target/arm/cpu.c    | 26 ++++++++++++--------------
>   target/arm/helper.c |  4 ++--
>   3 files changed, 14 insertions(+), 24 deletions(-)

Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>


^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC PATCH 11/40] target/arm: Copy features from ARMCPUClass
  2023-01-05 22:04   ` Philippe Mathieu-Daudé
@ 2023-01-06  2:19     ` Richard Henderson
  2023-01-06  7:14       ` Philippe Mathieu-Daudé
  0 siblings, 1 reply; 77+ messages in thread
From: Richard Henderson @ 2023-01-06  2:19 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé, qemu-devel
  Cc: pbonzini, berrange, eduardo, armbru, ajones, alex.bennee

On 1/5/23 14:04, Philippe Mathieu-Daudé wrote:
> On 3/1/23 19:16, Richard Henderson wrote:
>> Create a features member in ARMCPUClass and copy to the instance in
>> arm_cpu_init.  Settings of this value will come in a future patch.
>>
>> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
>> ---
>>   target/arm/cpu-qom.h | 18 ++++++++++++++++++
>>   target/arm/cpu.c     |  1 +
>>   2 files changed, 19 insertions(+)
>>
>> diff --git a/target/arm/cpu-qom.h b/target/arm/cpu-qom.h
>> index 5509ef9d85..ac58cc3a87 100644
>> --- a/target/arm/cpu-qom.h
>> +++ b/target/arm/cpu-qom.h
>> @@ -74,8 +74,26 @@ struct ARMCPUClass {
>>       /* 'compatible' string for this CPU for Linux device trees */
>>       const char *dtb_compatible;
>> +
>> +    /* Internal CPU feature flags.  */
>> +    uint64_t features;
>>   };
>> +static inline int arm_class_feature(ARMCPUClass *acc, int feature)
>> +{
>> +    return (acc->features & (1ULL << feature)) != 0;
>> +}
>> +
>> +static inline void set_class_feature(ARMCPUClass *acc, int feature)
>> +{
>> +    acc->features |= 1ULL << feature;
>> +}
>> +
>> +static inline void unset_class_feature(ARMCPUClass *acc, int feature)
>> +{
>> +    acc->features &= ~(1ULL << feature);
>> +}
> 
> These helpers are not used until patch #19 "target/arm: Move most cpu
> initialization to the class".

I know, but I thought it clearer to introduce them with the field.


r~

> 
>>   void register_cp_regs_for_features(ARMCPU *cpu);
>>   void init_cpreg_list(ARMCPU *cpu);
>> diff --git a/target/arm/cpu.c b/target/arm/cpu.c
>> index 1bc45b2b25..d64b86b6a5 100644
>> --- a/target/arm/cpu.c
>> +++ b/target/arm/cpu.c
>> @@ -1191,6 +1191,7 @@ static void arm_cpu_initfn(Object *obj)
>>       QLIST_INIT(&cpu->el_change_hooks);
>>       cpu->dtb_compatible = acc->dtb_compatible;
>> +    cpu->env.features = acc->features;
>>   #ifdef CONFIG_USER_ONLY
>>   # ifdef TARGET_AARCH64
> 



^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC PATCH 21/40] target/arm: Remove aarch64 check from aarch64_host_object_init
  2023-01-05 22:08   ` Philippe Mathieu-Daudé
@ 2023-01-06  2:21     ` Richard Henderson
  0 siblings, 0 replies; 77+ messages in thread
From: Richard Henderson @ 2023-01-06  2:21 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé, qemu-devel
  Cc: pbonzini, berrange, eduardo, armbru, ajones, alex.bennee

On 1/5/23 14:08, Philippe Mathieu-Daudé wrote:
> On 3/1/23 19:16, Richard Henderson wrote:
>> Since kvm32 was removed
> 
> Maybe add here:
> 
>    (see commit 82bf7ae84c: "target/arm: Remove KVM support for 32-bit
>    Arm hosts")
> 
>> , all kvm hosts support aarch64.
>>
>> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
>> ---
>>   target/arm/cpu64.c | 6 ++----
>>   1 file changed, 2 insertions(+), 4 deletions(-)
>>
>> diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
>> index 28b5a07244..668e979a24 100644
>> --- a/target/arm/cpu64.c
>> +++ b/target/arm/cpu64.c
>> @@ -1095,10 +1095,8 @@ static void aarch64_host_object_init(Object *obj)
>>   #if defined(CONFIG_KVM)
>>       ARMCPU *cpu = ARM_CPU(obj);
>>       kvm_arm_set_cpu_features_from_host(cpu);
>> -    if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) {
> 
> Worth asserting this feature is enabled? I don't think so, so:
> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>

Indeed not.  In the next patch we hoist this feature setting out of kvm+hvf to common code 
just above here.


r~

> 
>> -        aarch64_add_sve_properties(obj);
>> -        aarch64_add_pauth_properties(obj);
>> -    }
>> +    aarch64_add_sve_properties(obj);
>> +    aarch64_add_pauth_properties(obj);
>>   #elif defined(CONFIG_HVF)
>>       ARMCPU *cpu = ARM_CPU(obj);
>>       hvf_arm_set_cpu_features_from_host(cpu);
> 



^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC PATCH 11/40] target/arm: Copy features from ARMCPUClass
  2023-01-06  2:19     ` Richard Henderson
@ 2023-01-06  7:14       ` Philippe Mathieu-Daudé
  0 siblings, 0 replies; 77+ messages in thread
From: Philippe Mathieu-Daudé @ 2023-01-06  7:14 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel
  Cc: pbonzini, berrange, eduardo, armbru, ajones, alex.bennee

On 6/1/23 03:19, Richard Henderson wrote:
> On 1/5/23 14:04, Philippe Mathieu-Daudé wrote:
>> On 3/1/23 19:16, Richard Henderson wrote:
>>> Create a features member in ARMCPUClass and copy to the instance in
>>> arm_cpu_init.  Settings of this value will come in a future patch.
>>>
>>> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
>>> ---
>>>   target/arm/cpu-qom.h | 18 ++++++++++++++++++
>>>   target/arm/cpu.c     |  1 +
>>>   2 files changed, 19 insertions(+)


>>> +static inline void unset_class_feature(ARMCPUClass *acc, int feature)
>>> +{
>>> +    acc->features &= ~(1ULL << feature);
>>> +}
>>
>> These helpers are not used until patch #19 "target/arm: Move most cpu
>> initialization to the class".
> 
> I know, but I thought it clearer to introduce them with the field.

Fine.

Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>



^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC PATCH 13/40] hw/arm/bcm2836: Set mp-affinity property in realize
  2023-01-05 21:48   ` Philippe Mathieu-Daudé
@ 2023-01-06  7:51     ` Philippe Mathieu-Daudé
  0 siblings, 0 replies; 77+ messages in thread
From: Philippe Mathieu-Daudé @ 2023-01-06  7:51 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel
  Cc: pbonzini, berrange, eduardo, armbru, ajones, alex.bennee

On 5/1/23 22:48, Philippe Mathieu-Daudé wrote:
> On 3/1/23 19:16, Richard Henderson wrote:
>> There was even a TODO comment that we ought to be using a cpu
>> property, but we failed to update when the property was added.
>> Use ARM_AFF1_SHIFT instead of the bare constant 8.
>>
>> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
>> ---
>>   hw/arm/bcm2836.c | 7 +++++--
>>   1 file changed, 5 insertions(+), 2 deletions(-)
>>
>> diff --git a/hw/arm/bcm2836.c b/hw/arm/bcm2836.c
>> index 24354338ca..abbb3689d0 100644
>> --- a/hw/arm/bcm2836.c
>> +++ b/hw/arm/bcm2836.c
>> @@ -130,8 +130,11 @@ static void bcm2836_realize(DeviceState *dev, 
>> Error **errp)
>>           qdev_get_gpio_in_named(DEVICE(&s->control), "gpu-fiq", 0));
>>       for (n = 0; n < BCM283X_NCPUS; n++) {
>> -        /* TODO: this should be converted to a property of ARM_CPU */
>> -        s->cpu[n].core.mp_affinity = (bc->clusterid << 8) | n;
>> +        if (!object_property_set_int(OBJECT(&s->cpu[n].core), 
>> "mp-affinity",
>> +                                     (bc->clusterid << 
>> ARM_AFF1_SHIFT) | n,
>> +                                     errp)) {
>> +            return;
>> +        }

> Eh I have almost the same patch locally:

> Yours is better (ARM_AFF1_SHIFT & checks return value).

Cherry-picking your patch I had to add "target/arm/cpu-qom.h" to
avoid:

../hw/arm/bcm2836.c:146:56: error: use of undeclared identifier 
'ARM_AFF1_SHIFT'
                                  (bc->clusterid << ARM_AFF1_SHIFT) | n,
                                                    ^

This definition is not QOM related, I guess I'll move it to
"hw/arm/cpu-defs.h" along with ARM_CPU_vIRQ/FIQ and GTIMER* definitions
from "cpu.h".


^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC PATCH 00/40] Toward class init of cpu features
  2023-01-03 18:16 [RFC PATCH 00/40] Toward class init of cpu features Richard Henderson
                   ` (40 preceding siblings ...)
  2023-01-04  0:01 ` [RFC PATCH 00/40] Toward class init of cpu features Richard Henderson
@ 2023-01-06 19:12 ` Peter Maydell
  2023-01-06 19:29   ` Richard Henderson
  41 siblings, 1 reply; 77+ messages in thread
From: Peter Maydell @ 2023-01-06 19:12 UTC (permalink / raw)
  To: Richard Henderson
  Cc: qemu-devel, pbonzini, berrange, eduardo, armbru, ajones, alex.bennee

On Tue, 3 Jan 2023 at 18:27, Richard Henderson
<richard.henderson@linaro.org> wrote:
> The specific problem I'm trying to solve is the location and
> representation of the coprocessor register hash table for ARM cpus,
> but in the process affects how cpu initialization might be done for
> all targets.
>
> At present, each cpu (for all targets) is initialized separately.
> For some, like ARM, we apply QOM properties and then build a hash
> table of all coprocessor regs that are valid for the cpu.  For others,
> like m68k and ppc, we build tables of all valid instructions
> (ppc is slowly moving away from constructed tables to decodetree,
> but the migration is not complete).
>
> Importantly, this happens N times for smp system emulation, for each
> cpu instance, meaning we do N times the work on startup as necessary.
> For system emulation this isn't so bad, as N is generally small-ish,
> but it certainly could be improved.
>
> More importantly, this happens for each thread in user-only emulation.
> This is much more significant because threads can be short-lived, and
> there can be many hundreds of them, each one performing what amounts
> to redundant initialization.
>
> The "obvious" solution is to make better use of the cpu class object.
> Construct data structures once to be shared with all instances.

The trouble with this idea is that not all instances of the same
class are actually necessarily the same. For instance, if you
have a system with both (a) a Cortex-A53 with a PMU, and
(b) a Cortex-A53 without a PMU, then they're both instances of
the same class, but they shouldn't be sharing the coprocessor
register hashtable because they don't have an identical set of
system registers.

This kind of same-CPU-type-heterogenous-configuration system is
not something we're currently using on A-profile, but we do have
it for M-profile (the sse200 has a dual-core setup where only one
of the CPUs has an FPU), so it's not totally outlandish.

thanks
-- PMM


^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC PATCH 16/40] target/arm: Represent the entire MPIDR_EL1
  2023-01-03 18:16 ` [RFC PATCH 16/40] target/arm: Represent the entire MPIDR_EL1 Richard Henderson
@ 2023-01-06 19:16   ` Peter Maydell
  2023-01-06 19:33     ` Richard Henderson
  0 siblings, 1 reply; 77+ messages in thread
From: Peter Maydell @ 2023-01-06 19:16 UTC (permalink / raw)
  To: Richard Henderson
  Cc: qemu-devel, pbonzini, berrange, eduardo, armbru, ajones, alex.bennee

On Tue, 3 Jan 2023 at 18:24, Richard Henderson
<richard.henderson@linaro.org> wrote:
>
> Replace ARMCPU.mp_affinity with CPUARMState.cp15.mpidr_el1,
> setting the additional bits as required.  In particular,
> always set the U bit when there is only one cpu in the system.
> Remove the mp_is_up bit which attempted to do the same thing.
>
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>  target/arm/cpu.h     |  7 ++--
>  target/arm/cpu.c     | 80 +++++++++++++++++++++++++++++++++++++-------
>  target/arm/cpu_tcg.c |  1 -
>  target/arm/helper.c  | 25 ++------------
>  target/arm/hvf/hvf.c |  2 +-
>  target/arm/kvm64.c   |  4 +--
>  6 files changed, 75 insertions(+), 44 deletions(-)

Based purely on the diffstat it's not super-obvious why this
is an improvement. What's the rationale ?

Side note, we don't currently handle the MT bit, where some
CPUs end up putting the cpu number in the Aff1 field rather
than Aff0. We ideally ought to handle that too.

thanks
-- PMM


^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC PATCH 00/40] Toward class init of cpu features
  2023-01-06 19:12 ` Peter Maydell
@ 2023-01-06 19:29   ` Richard Henderson
  2023-01-06 21:59     ` Peter Maydell
  0 siblings, 1 reply; 77+ messages in thread
From: Richard Henderson @ 2023-01-06 19:29 UTC (permalink / raw)
  To: Peter Maydell
  Cc: qemu-devel, pbonzini, berrange, eduardo, armbru, ajones, alex.bennee

On 1/6/23 11:12, Peter Maydell wrote:
> The trouble with this idea is that not all instances of the same
> class are actually necessarily the same. For instance, if you
> have a system with both (a) a Cortex-A53 with a PMU, and
> (b) a Cortex-A53 without a PMU, then they're both instances of
> the same class, but they shouldn't be sharing the coprocessor
> register hashtable because they don't have an identical set of
> system registers.
> 
> This kind of same-CPU-type-heterogenous-configuration system is
> not something we're currently using on A-profile, but we do have
> it for M-profile (the sse200 has a dual-core setup where only one
> of the CPUs has an FPU), so it's not totally outlandish.

Yes, I know.  See patch 29 where I moved the vfp and dsp properties off of the m-profile 
cpus and created new cpu classes instead, specifically for the sse220.

It's not scalable, I'll grant you, but it's hard to design for something we're not using. 
What we use now, apart from the sse200, are common properties set on the command-line.

If we were presented with the class properties early enough, we could create sub-classes 
with the desired properties before instantiating the objects that go with.

Anyway, it seems like we ought to have some solution that does not involve repeating the 
same id register finalization + cpregs hash table construction per cpu -- especially for 
user-only.


r~


^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC PATCH 16/40] target/arm: Represent the entire MPIDR_EL1
  2023-01-06 19:16   ` Peter Maydell
@ 2023-01-06 19:33     ` Richard Henderson
  2023-01-06 22:14       ` Peter Maydell
  0 siblings, 1 reply; 77+ messages in thread
From: Richard Henderson @ 2023-01-06 19:33 UTC (permalink / raw)
  To: Peter Maydell
  Cc: qemu-devel, pbonzini, berrange, eduardo, armbru, ajones, alex.bennee

On 1/6/23 11:16, Peter Maydell wrote:
> On Tue, 3 Jan 2023 at 18:24, Richard Henderson
> <richard.henderson@linaro.org> wrote:
>>
>> Replace ARMCPU.mp_affinity with CPUARMState.cp15.mpidr_el1,
>> setting the additional bits as required.  In particular,
>> always set the U bit when there is only one cpu in the system.
>> Remove the mp_is_up bit which attempted to do the same thing.
>>
>> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
>> ---
>>   target/arm/cpu.h     |  7 ++--
>>   target/arm/cpu.c     | 80 +++++++++++++++++++++++++++++++++++++-------
>>   target/arm/cpu_tcg.c |  1 -
>>   target/arm/helper.c  | 25 ++------------
>>   target/arm/hvf/hvf.c |  2 +-
>>   target/arm/kvm64.c   |  4 +--
>>   6 files changed, 75 insertions(+), 44 deletions(-)
> 
> Based purely on the diffstat it's not super-obvious why this
> is an improvement. What's the rationale ?

It gets rid of cpu->mp_is_up, set only by cortex-r5, and then generalizes.

> Side note, we don't currently handle the MT bit, where some
> CPUs end up putting the cpu number in the Aff1 field rather
> than Aff0. We ideally ought to handle that too.

Would that be set by the board as well?  I don't think we model cpu 
packages/clusters/whatchacallums at that level currently.


r~


^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC PATCH 00/40] Toward class init of cpu features
  2023-01-06 19:29   ` Richard Henderson
@ 2023-01-06 21:59     ` Peter Maydell
  2023-01-06 22:28       ` Richard Henderson
  2023-01-06 23:43       ` Alex Bennée
  0 siblings, 2 replies; 77+ messages in thread
From: Peter Maydell @ 2023-01-06 21:59 UTC (permalink / raw)
  To: Richard Henderson
  Cc: qemu-devel, pbonzini, berrange, eduardo, armbru, ajones, alex.bennee

On Fri, 6 Jan 2023 at 19:29, Richard Henderson
<richard.henderson@linaro.org> wrote:
>
> On 1/6/23 11:12, Peter Maydell wrote:
> > The trouble with this idea is that not all instances of the same
> > class are actually necessarily the same. For instance, if you
> > have a system with both (a) a Cortex-A53 with a PMU, and
> > (b) a Cortex-A53 without a PMU, then they're both instances of
> > the same class, but they shouldn't be sharing the coprocessor
> > register hashtable because they don't have an identical set of
> > system registers.
> >
> > This kind of same-CPU-type-heterogenous-configuration system is
> > not something we're currently using on A-profile, but we do have
> > it for M-profile (the sse200 has a dual-core setup where only one
> > of the CPUs has an FPU), so it's not totally outlandish.
>
> Yes, I know.  See patch 29 where I moved the vfp and dsp properties off of the m-profile
> cpus and created new cpu classes instead, specifically for the sse220.
>
> It's not scalable, I'll grant you, but it's hard to design for something we're not using.
> What we use now, apart from the sse200, are common properties set on the command-line.

We also set some properties in code -- eg aspeed_ast2600.c clears
the 'neon' property on its CPUs, lots of the boards clear
has_el3 and has_el2, etc. I hadn't got as far as patch 29, but
looking at it now that looks like a pretty strong indication
that this is the wrong way to go. It creates 3 extra
cortex-m33 CPU classes, and if we find another thing that
ought to be a CPU property then we'll be up to 8; and the
mess propagates up into the SSE-200 class, which is also
no longer able to be configured in the normal way by setting
properties on it, and it becomes visible in user-facing
command line stuff.

I think our object model pretty strongly wants "create object;
set properties on it that only affect this object you created;
realize it", and having one particular subset of objects that
doesn't work the same way is going to be very confusing.

thanks
-- PMM


^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC PATCH 16/40] target/arm: Represent the entire MPIDR_EL1
  2023-01-06 19:33     ` Richard Henderson
@ 2023-01-06 22:14       ` Peter Maydell
  2023-01-06 22:36         ` Richard Henderson
  0 siblings, 1 reply; 77+ messages in thread
From: Peter Maydell @ 2023-01-06 22:14 UTC (permalink / raw)
  To: Richard Henderson
  Cc: qemu-devel, pbonzini, berrange, eduardo, armbru, ajones, alex.bennee

On Fri, 6 Jan 2023 at 19:33, Richard Henderson
<richard.henderson@linaro.org> wrote:
>
> On 1/6/23 11:16, Peter Maydell wrote:
> > On Tue, 3 Jan 2023 at 18:24, Richard Henderson
> > <richard.henderson@linaro.org> wrote:
> >>
> >> Replace ARMCPU.mp_affinity with CPUARMState.cp15.mpidr_el1,
> >> setting the additional bits as required.  In particular,
> >> always set the U bit when there is only one cpu in the system.
> >> Remove the mp_is_up bit which attempted to do the same thing.
> >>
> >> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> >> ---
> >>   target/arm/cpu.h     |  7 ++--
> >>   target/arm/cpu.c     | 80 +++++++++++++++++++++++++++++++++++++-------
> >>   target/arm/cpu_tcg.c |  1 -
> >>   target/arm/helper.c  | 25 ++------------
> >>   target/arm/hvf/hvf.c |  2 +-
> >>   target/arm/kvm64.c   |  4 +--
> >>   6 files changed, 75 insertions(+), 44 deletions(-)
> >
> > Based purely on the diffstat it's not super-obvious why this
> > is an improvement. What's the rationale ?
>
> It gets rid of cpu->mp_is_up, set only by cortex-r5, and then generalizes.
>
> > Side note, we don't currently handle the MT bit, where some
> > CPUs end up putting the cpu number in the Aff1 field rather
> > than Aff0. We ideally ought to handle that too.
>
> Would that be set by the board as well?  I don't think we model cpu
> packages/clusters/whatchacallums at that level currently.

It's a fixed property of the CPU implementation, same as
mp_is_up. We currently mismodel Cortex-A55, Cortex-A76
and Neoverse-N1, which should all be setting the MT bit in
MPIDR and having the cpu number in Aff1. See this thread:
 https://lore.kernel.org/qemu-devel/CAFEAcA9P2-v94p8H8+ktnf-Yf-rucbGySXE6AGPdwvDxXfP=ZA@mail.gmail.com/

+    if (arm_feature(env, ARM_FEATURE_V7MP)) {
+        cpu->mpidr_el1 |= (1u << 31);   /* M */
+        if (cpu->core_count == 1) {
+            cpu->mpidr_el1 |= 1 << 30;  /* U */
+        }
+    }

This is wrong, incidentally -- a single Cortex A9, A53, etc does
not set the U bit. (It's "a cluster with 1 core in it", not
"a uniprocessor system".) The reason mp_is_up is set only
by the R5 model is because "we implement the MP extensions
but consider ourselves to be not part of a cluster" is a
behaviour of only this CPU. I forget why I didn't implement
it as an ARM_FEATURE_FOO bit.

thanks
-- PMM


^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC PATCH 00/40] Toward class init of cpu features
  2023-01-06 21:59     ` Peter Maydell
@ 2023-01-06 22:28       ` Richard Henderson
  2023-01-07 13:14         ` Peter Maydell
  2023-01-06 23:43       ` Alex Bennée
  1 sibling, 1 reply; 77+ messages in thread
From: Richard Henderson @ 2023-01-06 22:28 UTC (permalink / raw)
  To: Peter Maydell
  Cc: qemu-devel, pbonzini, berrange, eduardo, armbru, ajones, alex.bennee

On 1/6/23 13:59, Peter Maydell wrote:
> We also set some properties in code -- eg aspeed_ast2600.c clears
> the 'neon' property on its CPUs, lots of the boards clear
> has_el3 and has_el2, etc.

Yes indeed, but in all of those cases we want all of the cpus to act identically.  Those 
are all easily handled (patches 35, 36, 38).

> I hadn't got as far as patch 29, but
> looking at it now that looks like a pretty strong indication
> that this is the wrong way to go. It creates 3 extra
> cortex-m33 CPU classes, and if we find another thing that
> ought to be a CPU property then we'll be up to 8;

If we find another thing that needs to be different between cpus, you mean?

> and it becomes visible in user-facing command line stuff.

No it doesn't -- command line is *not* affected, because both before and after, all 
properties are applied identically to all objects.

QMP is affected, which is where I stopped and started asking questions about what QMP is 
actually trying to do.


> I think our object model pretty strongly wants "create object;
> set properties on it that only affect this object you created;
> realize it", and having one particular subset of objects that
> doesn't work the same way is going to be very confusing.

Eh, I didn't think it's particularly confusing as a concept.
The code is rough, buy what one might expect from an RFC.

We really ought to have *some* solution to not repeating property + feature + isar 
interpretation on a per-cpu basis.  I'd be delighted to hear alternatives.


r~


^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC PATCH 16/40] target/arm: Represent the entire MPIDR_EL1
  2023-01-06 22:14       ` Peter Maydell
@ 2023-01-06 22:36         ` Richard Henderson
  0 siblings, 0 replies; 77+ messages in thread
From: Richard Henderson @ 2023-01-06 22:36 UTC (permalink / raw)
  To: Peter Maydell
  Cc: qemu-devel, pbonzini, berrange, eduardo, armbru, ajones, alex.bennee

On 1/6/23 14:14, Peter Maydell wrote:
> +    if (arm_feature(env, ARM_FEATURE_V7MP)) {
> +        cpu->mpidr_el1 |= (1u << 31);   /* M */
> +        if (cpu->core_count == 1) {
> +            cpu->mpidr_el1 |= 1 << 30;  /* U */
> +        }
> +    }
> 
> This is wrong, incidentally -- a single Cortex A9, A53, etc does
> not set the U bit. (It's "a cluster with 1 core in it", not
> "a uniprocessor system".)

Hmph.  It would have been handy to have the "uniprocessor" term defined somewhere in the 
architecture manual, since they appear to be using it in a specialized way.


r~


^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC PATCH 00/40] Toward class init of cpu features
  2023-01-06 21:59     ` Peter Maydell
  2023-01-06 22:28       ` Richard Henderson
@ 2023-01-06 23:43       ` Alex Bennée
  2023-01-06 23:57         ` Richard Henderson
  1 sibling, 1 reply; 77+ messages in thread
From: Alex Bennée @ 2023-01-06 23:43 UTC (permalink / raw)
  To: Peter Maydell
  Cc: Richard Henderson, qemu-devel, pbonzini, berrange, eduardo,
	armbru, ajones


Peter Maydell <peter.maydell@linaro.org> writes:

> On Fri, 6 Jan 2023 at 19:29, Richard Henderson
> <richard.henderson@linaro.org> wrote:
>>
>> On 1/6/23 11:12, Peter Maydell wrote:
>> > The trouble with this idea is that not all instances of the same
>> > class are actually necessarily the same. For instance, if you
>> > have a system with both (a) a Cortex-A53 with a PMU, and
>> > (b) a Cortex-A53 without a PMU, then they're both instances of
>> > the same class, but they shouldn't be sharing the coprocessor
>> > register hashtable because they don't have an identical set of
>> > system registers.
>> >
>> > This kind of same-CPU-type-heterogenous-configuration system is
>> > not something we're currently using on A-profile, but we do have
>> > it for M-profile (the sse200 has a dual-core setup where only one
>> > of the CPUs has an FPU), so it's not totally outlandish.
>>
>> Yes, I know.  See patch 29 where I moved the vfp and dsp properties off of the m-profile
>> cpus and created new cpu classes instead, specifically for the sse220.
>>
>> It's not scalable, I'll grant you, but it's hard to design for something we're not using.
>> What we use now, apart from the sse200, are common properties set on the command-line.
>
> We also set some properties in code -- eg aspeed_ast2600.c clears
> the 'neon' property on its CPUs, lots of the boards clear
> has_el3 and has_el2, etc. I hadn't got as far as patch 29, but
> looking at it now that looks like a pretty strong indication
> that this is the wrong way to go. It creates 3 extra
> cortex-m33 CPU classes, and if we find another thing that
> ought to be a CPU property then we'll be up to 8; and the
> mess propagates up into the SSE-200 class, which is also
> no longer able to be configured in the normal way by setting
> properties on it, and it becomes visible in user-facing
> command line stuff.
>
> I think our object model pretty strongly wants "create object;
> set properties on it that only affect this object you created;
> realize it", and having one particular subset of objects that
> doesn't work the same way is going to be very confusing.

What about cloning objects after they are realised? After all that is
what we do for the core CPUClass in user-mode.

>
> thanks
> -- PMM


-- 
Alex Bennée
Virtualisation Tech Lead @ Linaro


^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC PATCH 00/40] Toward class init of cpu features
  2023-01-06 23:43       ` Alex Bennée
@ 2023-01-06 23:57         ` Richard Henderson
  2023-01-07 10:19           ` Alex Bennée
  0 siblings, 1 reply; 77+ messages in thread
From: Richard Henderson @ 2023-01-06 23:57 UTC (permalink / raw)
  To: Alex Bennée, Peter Maydell
  Cc: qemu-devel, pbonzini, berrange, eduardo, armbru, ajones

On 1/6/23 15:43, Alex Bennée wrote:
> What about cloning objects after they are realised? After all that is
> what we do for the core CPUClass in user-mode.

No we don't.  Where do you get that idea?


r~


^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC PATCH 00/40] Toward class init of cpu features
  2023-01-06 23:57         ` Richard Henderson
@ 2023-01-07 10:19           ` Alex Bennée
  2023-01-07 17:53             ` Richard Henderson
  0 siblings, 1 reply; 77+ messages in thread
From: Alex Bennée @ 2023-01-07 10:19 UTC (permalink / raw)
  To: Richard Henderson
  Cc: Peter Maydell, qemu-devel, pbonzini, berrange, eduardo, armbru, ajones


Richard Henderson <richard.henderson@linaro.org> writes:

> On 1/6/23 15:43, Alex Bennée wrote:
>> What about cloning objects after they are realised? After all that is
>> what we do for the core CPUClass in user-mode.
>
> No we don't.  Where do you get that idea?

Well linux-user does cpu_copy which involves a create step followed by a
reset and then a bunch of copying state across. Can we assume all CPUs
get reset before they are actively used?

Would it be too hacky to defer the creation of those hash tables to the
reset phase and skip it if already defined?

-- 
Alex Bennée
Virtualisation Tech Lead @ Linaro


^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC PATCH 00/40] Toward class init of cpu features
  2023-01-06 22:28       ` Richard Henderson
@ 2023-01-07 13:14         ` Peter Maydell
  0 siblings, 0 replies; 77+ messages in thread
From: Peter Maydell @ 2023-01-07 13:14 UTC (permalink / raw)
  To: Richard Henderson
  Cc: qemu-devel, pbonzini, berrange, eduardo, armbru, ajones, alex.bennee

On Fri, 6 Jan 2023 at 22:28, Richard Henderson
<richard.henderson@linaro.org> wrote:
>
> On 1/6/23 13:59, Peter Maydell wrote:
> > We also set some properties in code -- eg aspeed_ast2600.c clears
> > the 'neon' property on its CPUs, lots of the boards clear
> > has_el3 and has_el2, etc.
>
> Yes indeed, but in all of those cases we want all of the cpus to act identically.  Those
> are all easily handled (patches 35, 36, 38).

That's just a happenstance of how the boards create them.
There's no inherent reason that every CPU of a particular
type in the system has to have identical properties.

> > I hadn't got as far as patch 29, but
> > looking at it now that looks like a pretty strong indication
> > that this is the wrong way to go. It creates 3 extra
> > cortex-m33 CPU classes, and if we find another thing that
> > ought to be a CPU property then we'll be up to 8;
>
> If we find another thing that needs to be different between cpus, you mean?

Yes. But conceptually we already have lots of those, we just
happen not to be using them right this instant.

> > I think our object model pretty strongly wants "create object;
> > set properties on it that only affect this object you created;
> > realize it", and having one particular subset of objects that
> > doesn't work the same way is going to be very confusing.
>
> Eh, I didn't think it's particularly confusing as a concept.
> The code is rough, buy what one might expect from an RFC.
>
> We really ought to have *some* solution to not repeating property + feature + isar
> interpretation on a per-cpu basis.  I'd be delighted to hear alternatives.

Hash "cpu type plus property settings plus ID registers",
and look them up to see if we've already created the
cpregs hashtable for an existing CPU?

-- PMM


^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC PATCH 00/40] Toward class init of cpu features
  2023-01-07 10:19           ` Alex Bennée
@ 2023-01-07 17:53             ` Richard Henderson
  0 siblings, 0 replies; 77+ messages in thread
From: Richard Henderson @ 2023-01-07 17:53 UTC (permalink / raw)
  To: Alex Bennée
  Cc: Peter Maydell, qemu-devel, pbonzini, berrange, eduardo, armbru, ajones

On 1/7/23 02:19, Alex Bennée wrote:
> 
> Richard Henderson <richard.henderson@linaro.org> writes:
> 
>> On 1/6/23 15:43, Alex Bennée wrote:
>>> What about cloning objects after they are realised? After all that is
>>> what we do for the core CPUClass in user-mode.
>>
>> No we don't.  Where do you get that idea?
> 
> Well linux-user does cpu_copy which involves a create step followed by a
> reset and then a bunch of copying state across. Can we assume all CPUs
> get reset before they are actively used?

The hash table creation happens during qdev_realize, there in cpu_create.

> Would it be too hacky to defer the creation of those hash tables to the
> reset phase and skip it if already defined?

Even then you have the copy after the reset, so no, that won't work.


r~


^ permalink raw reply	[flat|nested] 77+ messages in thread

end of thread, other threads:[~2023-01-07 17:54 UTC | newest]

Thread overview: 77+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-01-03 18:16 [RFC PATCH 00/40] Toward class init of cpu features Richard Henderson
2023-01-03 18:16 ` [RFC PATCH 01/40] qdev: Don't always force the global property array non-null Richard Henderson
2023-01-05 21:56   ` Philippe Mathieu-Daudé
2023-01-03 18:16 ` [RFC PATCH 02/40] qom: Introduce class_late_init Richard Henderson
2023-01-03 18:16 ` [RFC PATCH 03/40] qom: Create class properties Richard Henderson
2023-01-03 18:16 ` [RFC PATCH 04/40] target/arm: Remove aarch64_cpu_finalizefn Richard Henderson
2023-01-05 21:51   ` Philippe Mathieu-Daudé
2023-01-03 18:16 ` [RFC PATCH 05/40] target/arm: Create arm_cpu_register_parent Richard Henderson
2023-01-05 21:57   ` Philippe Mathieu-Daudé
2023-01-03 18:16 ` [RFC PATCH 06/40] target/arm: Remove AArch64CPUClass Richard Henderson
2023-01-05 21:50   ` Philippe Mathieu-Daudé
2023-01-03 18:16 ` [RFC PATCH 07/40] target/arm: Create TYPE_ARM_V7M_CPU Richard Henderson
2023-01-05 21:58   ` Philippe Mathieu-Daudé
2023-01-03 18:16 ` [RFC PATCH 08/40] target/arm: Pass ARMCPUClass to ARMCPUInfo.class_init Richard Henderson
2023-01-05 22:00   ` Philippe Mathieu-Daudé
2023-01-03 18:16 ` [RFC PATCH 09/40] target/arm: Utilize arm-cpu instance_post_init hook Richard Henderson
2023-01-03 18:16 ` [RFC PATCH 10/40] target/arm: Copy dtb_compatible from ARMCPUClass Richard Henderson
2023-01-03 18:16 ` [RFC PATCH 11/40] target/arm: Copy features " Richard Henderson
2023-01-05 22:04   ` Philippe Mathieu-Daudé
2023-01-06  2:19     ` Richard Henderson
2023-01-06  7:14       ` Philippe Mathieu-Daudé
2023-01-03 18:16 ` [RFC PATCH 12/40] target/arm: Copy isar and friends " Richard Henderson
2023-01-03 18:16 ` [RFC PATCH 13/40] hw/arm/bcm2836: Set mp-affinity property in realize Richard Henderson
2023-01-05 21:48   ` Philippe Mathieu-Daudé
2023-01-06  7:51     ` Philippe Mathieu-Daudé
2023-01-03 18:16 ` [RFC PATCH 14/40] target/arm: Rename arm_cpu_mp_affinity Richard Henderson
2023-01-05 21:55   ` Philippe Mathieu-Daudé
2023-01-03 18:16 ` [RFC PATCH 15/40] target/arm: Create arm_cpu_mp_affinity Richard Henderson
2023-01-05 21:53   ` Philippe Mathieu-Daudé
2023-01-03 18:16 ` [RFC PATCH 16/40] target/arm: Represent the entire MPIDR_EL1 Richard Henderson
2023-01-06 19:16   ` Peter Maydell
2023-01-06 19:33     ` Richard Henderson
2023-01-06 22:14       ` Peter Maydell
2023-01-06 22:36         ` Richard Henderson
2023-01-03 18:16 ` [RFC PATCH 17/40] target/arm: Copy cp_regs from ARMCPUClass Richard Henderson
2023-01-03 18:16 ` [RFC PATCH 18/40] target/arm: Create cpreg definition functions with GHashTable arg Richard Henderson
2023-01-03 18:16 ` [RFC PATCH 19/40] target/arm: Move most cpu initialization to the class Richard Henderson
2023-01-03 18:16 ` [RFC PATCH 20/40] target/arm: Merge kvm64.c with kvm.c Richard Henderson
2023-01-03 18:16 ` [RFC PATCH 21/40] target/arm: Remove aarch64 check from aarch64_host_object_init Richard Henderson
2023-01-05 22:08   ` Philippe Mathieu-Daudé
2023-01-06  2:21     ` Richard Henderson
2023-01-03 18:16 ` [RFC PATCH 22/40] target/arm: Hoist feature and dtb_compatible from KVM, HVF Richard Henderson
2023-01-03 18:16 ` [RFC PATCH 23/40] target/arm: Probe KVM host into ARMCPUClass Richard Henderson
2023-01-03 18:16 ` [RFC PATCH 24/40] target/arm/hvf: Probe " Richard Henderson
2023-01-05 22:10   ` Philippe Mathieu-Daudé
2023-01-03 18:16 ` [RFC PATCH 25/40] target/arm/hvf: Use offsetof in hvf_arm_get_host_cpu_features Richard Henderson
2023-01-03 18:16 ` [RFC PATCH 26/40] target/arm: Rename 'cpu' to 'acc' in class init functions Richard Henderson
2023-01-03 19:24   ` Philippe Mathieu-Daudé
2023-01-03 18:16 ` [RFC PATCH 27/40] target/arm: Split out strongarm_class_init Richard Henderson
2023-01-05 22:12   ` Philippe Mathieu-Daudé
2023-01-03 18:16 ` [RFC PATCH 28/40] target/arm: Split out xscale*_class_init Richard Henderson
2023-01-05 22:13   ` Philippe Mathieu-Daudé
2023-01-03 18:16 ` [RFC PATCH 29/40] target/arm: Remove m-profile has_vfp and has_dsp properties Richard Henderson
2023-01-03 18:16 ` [RFC PATCH 30/40] target/arm: Move feature bit propagation to class init Richard Henderson
2023-01-03 18:16 ` [RFC PATCH 31/40] target/arm: Get and set class properties in the monitor Richard Henderson
2023-01-03 18:16 ` [RFC PATCH 32/40] target/arm: Move "midr" to class property Richard Henderson
2023-01-05 22:18   ` Philippe Mathieu-Daudé
2023-01-03 18:16 ` [RFC PATCH 33/40] target/arm: Move "cntfrq" " Richard Henderson
2023-01-05 22:21   ` Philippe Mathieu-Daudé
2023-01-03 18:16 ` [RFC PATCH 34/40] target/arm: Move "reset-hivecs" " Richard Henderson
2023-01-03 18:16 ` [RFC PATCH 35/40] target/arm: Move "has_el2" " Richard Henderson
2023-01-03 18:16 ` [RFC PATCH 36/40] target/arm: Move "has_el3" " Richard Henderson
2023-01-03 18:16 ` [RFC PATCH 37/40] target/arm: Move "cfgend" " Richard Henderson
2023-01-05 22:23   ` Philippe Mathieu-Daudé
2023-01-03 18:16 ` [RFC PATCH 38/40] target/arm: Move "vfp" and "neon" to class properties Richard Henderson
2023-01-03 18:16 ` [RFC PATCH 39/40] target/arm: Move "has-mpu" and "pmsav7-dregion" " Richard Henderson
2023-01-03 18:16 ` [RFC PATCH 40/40] target/arm: Move "pmu" to class property Richard Henderson
2023-01-04  0:01 ` [RFC PATCH 00/40] Toward class init of cpu features Richard Henderson
2023-01-06 19:12 ` Peter Maydell
2023-01-06 19:29   ` Richard Henderson
2023-01-06 21:59     ` Peter Maydell
2023-01-06 22:28       ` Richard Henderson
2023-01-07 13:14         ` Peter Maydell
2023-01-06 23:43       ` Alex Bennée
2023-01-06 23:57         ` Richard Henderson
2023-01-07 10:19           ` Alex Bennée
2023-01-07 17:53             ` Richard Henderson

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.