Register all the defined Arm properties to the host model if CONFIG_KVM is
enabled. Add property finder, getter/setter functions, and wire up the
property registration in the CPU initialization path.

Co-authored-by: Khushit Shah <[email protected]>
Signed-off-by: Shaju Abraham <[email protected]>
---
 target/arm/arm-cpu-props.c | 216 +++++++++++++++++++++++++++++++++++++
 target/arm/arm-cpu-props.h |   2 +-
 target/arm/cpu64.c         |   3 +-
 3 files changed, 219 insertions(+), 2 deletions(-)

diff --git a/target/arm/arm-cpu-props.c b/target/arm/arm-cpu-props.c
index f22fe7f08b..1a34428c00 100644
--- a/target/arm/arm-cpu-props.c
+++ b/target/arm/arm-cpu-props.c
@@ -41,3 +41,219 @@ const ArmCpuPropDesc arm_cpu_props[] = {
 #include "arm-cpu-props.inc.h"
     { .name = NULL },
 };
+
+static const ArmCpuPropDesc *arm_find_prop(const char *name)
+{
+    const ArmCpuPropDesc *p;
+    for (p = arm_cpu_props; p->name; p++) {
+        if (g_str_equal(p->name, name)) {
+            return p;
+        }
+    }
+    return NULL;
+}
+
+static void arm_single_field_get(ARMCPU *cpu, const ArmCpuPropDesc *p,
+                                 Visitor *v, const char *name, Error **errp)
+{
+    uint64_t value;
+    char *s;
+    bool b;
+
+    arm_idreg_field_read(cpu, p->base_field, &value);
+
+    switch (p->type) {
+    case ARM_PROP_STRING: {
+        s = g_strdup(arm_arch_val_name(p->base_field, value));
+
+        if (!s) {
+            error_setg(errp, "Property '%s': unknown value %" PRIu64,
+                       name, value);
+            return;
+        }
+        visit_type_str(v, name, &s, errp);
+        g_free(s);
+        break;
+    }
+    case ARM_PROP_BOOLEAN: {
+        b = value != 0;
+        visit_type_bool(v, name, &b, errp);
+        break;
+    }
+    case ARM_PROP_NUMERIC:
+        visit_type_uint64(v, name, &value, errp);
+        break;
+    default:
+        g_assert_not_reached();
+    }
+}
+
+static void arm_fractional_get(ARMCPU *cpu, const ArmCpuPropDesc *p,
+                               Visitor *v, const char *name, Error **errp)
+{
+    uint64_t base_val, frac_val;
+    const ArmFracVal *val;
+    char *s;
+
+    arm_idreg_field_read(cpu, p->base_field, &base_val);
+    arm_idreg_field_read(cpu, p->frac_field, &frac_val);
+
+    for (val = p->vals; val->name; val++) {
+        if (val->base_val == base_val && val->frac_val == frac_val) {
+            s = g_strdup(val->name);
+            visit_type_str(v, name, &s, errp);
+            g_free(s);
+            return;
+        }
+    }
+
+    error_setg(errp,
+               "Property '%s': unknown fractional value %" PRIu64
+               ".%" PRIu64, name, base_val, frac_val);
+}
+
+static void arm_cpu_prop_get(Object *obj, Visitor *v, const char *name,
+                             void *opaque, Error **errp)
+{
+    ARMCPU *cpu = ARM_CPU(obj);
+    const ArmCpuPropDesc *p = arm_find_prop(name);
+
+    if (!p) {
+        error_setg(errp, "Property %s not found", name);
+        return;
+    }
+
+    switch (p->type) {
+    case ARM_PROP_STRING:
+    case ARM_PROP_BOOLEAN:
+    case ARM_PROP_NUMERIC:
+        arm_single_field_get(cpu, p, v, name, errp);
+        break;
+    case ARM_PROP_FRACTIONAL:
+        arm_fractional_get(cpu, p, v, name, errp);
+        break;
+    }
+}
+
+static void arm_single_field_set(ARMCPU *cpu, const ArmCpuPropDesc *p,
+                                 Visitor *v, const char *name, Error **errp)
+{
+    uint64_t value;
+    char *str = NULL;
+    bool b;
+
+    switch (p->type) {
+    case ARM_PROP_STRING: {
+
+        if (!visit_type_str(v, name, &str, errp)) {
+            return;
+        }
+        if (!arm_arch_val_from_name(p->base_field, str, &value)) {
+            error_setg(errp, "Property '%s': invalid value '%s'", name, str);
+            g_free(str);
+            return;
+        }
+        g_free(str);
+        break;
+    }
+    case ARM_PROP_BOOLEAN: {
+
+        if (!visit_type_bool(v, name, &b, errp)) {
+            return;
+        }
+        value = b ? 1 : 0;
+        break;
+    }
+    case ARM_PROP_NUMERIC:
+        if (!visit_type_uint64(v, name, &value, errp)) {
+            return;
+        }
+        break;
+    default:
+        g_assert_not_reached();
+    }
+
+    if (!arm_idreg_field_write(cpu, p->base_field, value, errp)) {
+        error_prepend(errp, "Property '%s': ", name);
+    }
+}
+
+static void arm_fractional_set(ARMCPU *cpu, const ArmCpuPropDesc *p,
+                               Visitor *v, const char *name, Error **errp)
+{
+    char *str = NULL;
+    const ArmFracVal *val;
+
+    if (!visit_type_str(v, name, &str, errp)) {
+        return;
+    }
+
+    for (val = p->vals; val->name; val++) {
+        if (g_str_equal(val->name, str)) {
+            if (!arm_idreg_field_write(cpu, p->base_field,
+                                       val->base_val, errp)) {
+                error_prepend(errp, "Property '%s': ", name);
+                g_free(str);
+                return;
+            }
+            if (!arm_idreg_field_write(cpu, p->frac_field,
+                                       val->frac_val, errp)) {
+                error_prepend(errp, "Property '%s': ", name);
+            }
+            g_free(str);
+            return;
+        }
+    }
+
+    error_setg(errp, "Property '%s': invalid fractional value '%s'",
+               name, str);
+    g_free(str);
+}
+
+static void arm_cpu_prop_set(Object *obj, Visitor *v, const char *name,
+                             void *opaque, Error **errp)
+{
+    ARMCPU *cpu = ARM_CPU(obj);
+    const ArmCpuPropDesc *p = arm_find_prop(name);
+
+    if (!p) {
+        error_setg(errp, "Property %s not found", name);
+        return;
+    }
+
+    switch (p->type) {
+    case ARM_PROP_STRING:
+    case ARM_PROP_BOOLEAN:
+    case ARM_PROP_NUMERIC:
+        arm_single_field_set(cpu, p, v, name, errp);
+        break;
+    case ARM_PROP_FRACTIONAL:
+        arm_fractional_set(cpu, p, v, name, errp);
+        break;
+    }
+}
+
+void arm_add_cpu_props(Object *obj)
+{
+    const char *type;
+    const ArmCpuPropDesc *p;
+
+    for (p = arm_cpu_props; p->name; p++) {
+        switch (p->type) {
+        case ARM_PROP_STRING:
+        case ARM_PROP_FRACTIONAL:
+            type = "string";
+            break;
+        case ARM_PROP_BOOLEAN:
+            type = "bool";
+            break;
+        case ARM_PROP_NUMERIC:
+            type = "number";
+            break;
+        default:
+            g_assert_not_reached();
+        }
+        object_property_add(obj, p->name, type,
+                            arm_cpu_prop_get, arm_cpu_prop_set, NULL, NULL);
+    }
+}
diff --git a/target/arm/arm-cpu-props.h b/target/arm/arm-cpu-props.h
index 1dc3786ea9..48f9c46ccb 100644
--- a/target/arm/arm-cpu-props.h
+++ b/target/arm/arm-cpu-props.h
@@ -32,5 +32,5 @@ typedef struct ArmCpuPropDesc {
     ArmFieldIdx frac_field;
     const ArmFracVal *vals;
 } ArmCpuPropDesc;
-
+void arm_add_cpu_props(Object *obj);
 #endif
diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
index a93ad2da5a..0300f8677f 100644
--- a/target/arm/cpu64.c
+++ b/target/arm/cpu64.c
@@ -37,7 +37,7 @@
 #include "hw/core/qdev-properties.h"
 #include "internals.h"
 #include "cpu-features.h"
-
+#include "arm-cpu-props.h"
 /* convert between <register>_IDX and SYS_<register> */
 #define DEF(NAME, OP0, OP1, CRN, CRM, OP2)      \
     [NAME##_IDX] = SYS_##NAME,
@@ -863,6 +863,7 @@ static void aarch64_host_initfn(Object *obj)
     kvm_arm_set_cpreg_mig_tolerances(cpu);
     kvm_arm_set_cpu_features_from_host(cpu);
     aarch64_add_sve_properties(obj);
+    arm_add_cpu_props(obj);
 #elif defined(CONFIG_HVF)
     hvf_arm_set_cpu_features_from_host(cpu);
 #elif defined(CONFIG_WHPX)
-- 
2.52.0


Reply via email to