diff mbox series

[v2,4/6] target/riscv: handle custom props in qmp_query_cpu_model_expansion

Message ID 20230926184019.166352-5-dbarboza@ventanamicro.com
State New
Headers show
Series riscv: query-cpu-model-expansion API | expand

Commit Message

Daniel Henrique Barboza Sept. 26, 2023, 6:40 p.m. UTC
Callers can add 'props' when querying for a cpu model expansion to see
if a given CPU model supports a certain criteria, and what's the
resulting CPU object.

If we have 'props' to handle, gather it in a QDict and use the new
riscv_cpuobj_validate_qdict_in() helper to validate it. This helper will
add the custom properties in the CPU object and validate it using
riscv_cpu_finalize_features(). Users will be aware of validation errors
if any occur, if not a CPU object with 'props' will be returned.

Here's an example with the veyron-v1 vendor CPU. Disabling vendor CPU
extensions is allowed, assuming the final config is valid. Disabling
'smstateen' is a valid expansion:

(QEMU) query-cpu-model-expansion type=full model={"name":"veyron-v1","props":{"smstateen":false}}
{"return": {"model": {"name": "veyron-v1", "props": {"zicond": false, ..., "smstateen": false, ...}

But enabling extensions isn't allowed for vendor CPUs. E.g. enabling 'V'
for the veyron-v1 CPU isn't allowed:

(QEMU) query-cpu-model-expansion type=full model={"name":"veyron-v1","props":{"v":true}}
{"error": {"class": "GenericError", "desc": "'veyron-v1' CPU does not allow enabling extensions"}}

Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
---
 target/riscv/riscv-qmp-cmds.c | 65 +++++++++++++++++++++++++++++++++++
 1 file changed, 65 insertions(+)

Comments

Alistair Francis Oct. 16, 2023, 5:26 a.m. UTC | #1
On Wed, Sep 27, 2023 at 4:42 AM Daniel Henrique Barboza
<dbarboza@ventanamicro.com> wrote:
>
> Callers can add 'props' when querying for a cpu model expansion to see
> if a given CPU model supports a certain criteria, and what's the
> resulting CPU object.
>
> If we have 'props' to handle, gather it in a QDict and use the new
> riscv_cpuobj_validate_qdict_in() helper to validate it. This helper will
> add the custom properties in the CPU object and validate it using
> riscv_cpu_finalize_features(). Users will be aware of validation errors
> if any occur, if not a CPU object with 'props' will be returned.
>
> Here's an example with the veyron-v1 vendor CPU. Disabling vendor CPU
> extensions is allowed, assuming the final config is valid. Disabling
> 'smstateen' is a valid expansion:
>
> (QEMU) query-cpu-model-expansion type=full model={"name":"veyron-v1","props":{"smstateen":false}}
> {"return": {"model": {"name": "veyron-v1", "props": {"zicond": false, ..., "smstateen": false, ...}
>
> But enabling extensions isn't allowed for vendor CPUs. E.g. enabling 'V'
> for the veyron-v1 CPU isn't allowed:
>
> (QEMU) query-cpu-model-expansion type=full model={"name":"veyron-v1","props":{"v":true}}
> {"error": {"class": "GenericError", "desc": "'veyron-v1' CPU does not allow enabling extensions"}}
>
> Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>

Reviewed-by: Alistair Francis <alistair.francis@wdc.com>

Alistair

> ---
>  target/riscv/riscv-qmp-cmds.c | 65 +++++++++++++++++++++++++++++++++++
>  1 file changed, 65 insertions(+)
>
> diff --git a/target/riscv/riscv-qmp-cmds.c b/target/riscv/riscv-qmp-cmds.c
> index 2170562e3a..5b2d186c83 100644
> --- a/target/riscv/riscv-qmp-cmds.c
> +++ b/target/riscv/riscv-qmp-cmds.c
> @@ -27,6 +27,9 @@
>  #include "qapi/error.h"
>  #include "qapi/qapi-commands-machine-target.h"
>  #include "qapi/qmp/qdict.h"
> +#include "qapi/qmp/qerror.h"
> +#include "qapi/qobject-input-visitor.h"
> +#include "qapi/visitor.h"
>  #include "qom/qom-qobject.h"
>  #include "cpu-qom.h"
>  #include "cpu.h"
> @@ -83,14 +86,58 @@ static void riscv_obj_add_multiext_props(Object *obj, QDict *qdict_out,
>      }
>  }
>
> +static void riscv_cpuobj_validate_qdict_in(Object *obj, QObject *props,
> +                                           const QDict *qdict_in,
> +                                           Error **errp)
> +{
> +    const QDictEntry *qe;
> +    Visitor *visitor;
> +    Error *local_err = NULL;
> +
> +    visitor = qobject_input_visitor_new(props);
> +    if (!visit_start_struct(visitor, NULL, NULL, 0, &local_err)) {
> +        goto err;
> +    }
> +
> +    for (qe = qdict_first(qdict_in); qe; qe = qdict_next(qdict_in, qe)) {
> +        object_property_find_err(obj, qe->key, &local_err);
> +        if (local_err) {
> +            goto err;
> +        }
> +
> +        object_property_set(obj, qe->key, visitor, &local_err);
> +        if (local_err) {
> +            goto err;
> +        }
> +    }
> +
> +    visit_check_struct(visitor, &local_err);
> +    if (local_err) {
> +        goto err;
> +    }
> +
> +    riscv_cpu_finalize_features(RISCV_CPU(obj), &local_err);
> +    if (local_err) {
> +        goto err;
> +    }
> +
> +    visit_end_struct(visitor, NULL);
> +
> +err:
> +    error_propagate(errp, local_err);
> +    visit_free(visitor);
> +}
> +
>  CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type,
>                                                       CpuModelInfo *model,
>                                                       Error **errp)
>  {
>      CpuModelExpansionInfo *expansion_info;
> +    const QDict *qdict_in = NULL;
>      QDict *qdict_out;
>      ObjectClass *oc;
>      Object *obj;
> +    Error *local_err = NULL;
>
>      if (type != CPU_MODEL_EXPANSION_TYPE_FULL) {
>          error_setg(errp, "The requested expansion type is not supported");
> @@ -104,8 +151,26 @@ CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type,
>          return NULL;
>      }
>
> +    if (model->props) {
> +        qdict_in = qobject_to(QDict, model->props);
> +        if (!qdict_in) {
> +            error_setg(errp, QERR_INVALID_PARAMETER_TYPE, "props", "dict");
> +            return NULL;
> +        }
> +    }
> +
>      obj = object_new(object_class_get_name(oc));
>
> +    if (qdict_in) {
> +        riscv_cpuobj_validate_qdict_in(obj, model->props, qdict_in,
> +                                       &local_err);
> +        if (local_err) {
> +            error_propagate(errp, local_err);
> +            object_unref(obj);
> +            return NULL;
> +        }
> +    }
> +
>      expansion_info = g_new0(CpuModelExpansionInfo, 1);
>      expansion_info->model = g_malloc0(sizeof(*expansion_info->model));
>      expansion_info->model->name = g_strdup(model->name);
> --
> 2.41.0
>
>
diff mbox series

Patch

diff --git a/target/riscv/riscv-qmp-cmds.c b/target/riscv/riscv-qmp-cmds.c
index 2170562e3a..5b2d186c83 100644
--- a/target/riscv/riscv-qmp-cmds.c
+++ b/target/riscv/riscv-qmp-cmds.c
@@ -27,6 +27,9 @@ 
 #include "qapi/error.h"
 #include "qapi/qapi-commands-machine-target.h"
 #include "qapi/qmp/qdict.h"
+#include "qapi/qmp/qerror.h"
+#include "qapi/qobject-input-visitor.h"
+#include "qapi/visitor.h"
 #include "qom/qom-qobject.h"
 #include "cpu-qom.h"
 #include "cpu.h"
@@ -83,14 +86,58 @@  static void riscv_obj_add_multiext_props(Object *obj, QDict *qdict_out,
     }
 }
 
+static void riscv_cpuobj_validate_qdict_in(Object *obj, QObject *props,
+                                           const QDict *qdict_in,
+                                           Error **errp)
+{
+    const QDictEntry *qe;
+    Visitor *visitor;
+    Error *local_err = NULL;
+
+    visitor = qobject_input_visitor_new(props);
+    if (!visit_start_struct(visitor, NULL, NULL, 0, &local_err)) {
+        goto err;
+    }
+
+    for (qe = qdict_first(qdict_in); qe; qe = qdict_next(qdict_in, qe)) {
+        object_property_find_err(obj, qe->key, &local_err);
+        if (local_err) {
+            goto err;
+        }
+
+        object_property_set(obj, qe->key, visitor, &local_err);
+        if (local_err) {
+            goto err;
+        }
+    }
+
+    visit_check_struct(visitor, &local_err);
+    if (local_err) {
+        goto err;
+    }
+
+    riscv_cpu_finalize_features(RISCV_CPU(obj), &local_err);
+    if (local_err) {
+        goto err;
+    }
+
+    visit_end_struct(visitor, NULL);
+
+err:
+    error_propagate(errp, local_err);
+    visit_free(visitor);
+}
+
 CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type,
                                                      CpuModelInfo *model,
                                                      Error **errp)
 {
     CpuModelExpansionInfo *expansion_info;
+    const QDict *qdict_in = NULL;
     QDict *qdict_out;
     ObjectClass *oc;
     Object *obj;
+    Error *local_err = NULL;
 
     if (type != CPU_MODEL_EXPANSION_TYPE_FULL) {
         error_setg(errp, "The requested expansion type is not supported");
@@ -104,8 +151,26 @@  CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type,
         return NULL;
     }
 
+    if (model->props) {
+        qdict_in = qobject_to(QDict, model->props);
+        if (!qdict_in) {
+            error_setg(errp, QERR_INVALID_PARAMETER_TYPE, "props", "dict");
+            return NULL;
+        }
+    }
+
     obj = object_new(object_class_get_name(oc));
 
+    if (qdict_in) {
+        riscv_cpuobj_validate_qdict_in(obj, model->props, qdict_in,
+                                       &local_err);
+        if (local_err) {
+            error_propagate(errp, local_err);
+            object_unref(obj);
+            return NULL;
+        }
+    }
+
     expansion_info = g_new0(CpuModelExpansionInfo, 1);
     expansion_info->model = g_malloc0(sizeof(*expansion_info->model));
     expansion_info->model->name = g_strdup(model->name);