]> git.proxmox.com Git - mirror_qemu.git/blob - target/riscv/riscv-qmp-cmds.c
target/riscv: handle custom props in qmp_query_cpu_model_expansion
[mirror_qemu.git] / target / riscv / riscv-qmp-cmds.c
1 /*
2 * QEMU CPU QMP commands for RISC-V
3 *
4 * Copyright (c) 2023 Ventana Micro Systems Inc.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24
25 #include "qemu/osdep.h"
26
27 #include "qapi/error.h"
28 #include "qapi/qapi-commands-machine-target.h"
29 #include "qapi/qmp/qdict.h"
30 #include "qapi/qmp/qerror.h"
31 #include "qapi/qobject-input-visitor.h"
32 #include "qapi/visitor.h"
33 #include "qom/qom-qobject.h"
34 #include "cpu-qom.h"
35 #include "cpu.h"
36
37 static void riscv_cpu_add_definition(gpointer data, gpointer user_data)
38 {
39 ObjectClass *oc = data;
40 CpuDefinitionInfoList **cpu_list = user_data;
41 CpuDefinitionInfo *info = g_malloc0(sizeof(*info));
42 const char *typename = object_class_get_name(oc);
43 ObjectClass *dyn_class;
44
45 info->name = g_strndup(typename,
46 strlen(typename) - strlen("-" TYPE_RISCV_CPU));
47 info->q_typename = g_strdup(typename);
48
49 dyn_class = object_class_dynamic_cast(oc, TYPE_RISCV_DYNAMIC_CPU);
50 info->q_static = dyn_class == NULL;
51
52 QAPI_LIST_PREPEND(*cpu_list, info);
53 }
54
55 CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
56 {
57 CpuDefinitionInfoList *cpu_list = NULL;
58 GSList *list = object_class_get_list(TYPE_RISCV_CPU, false);
59
60 g_slist_foreach(list, riscv_cpu_add_definition, &cpu_list);
61 g_slist_free(list);
62
63 return cpu_list;
64 }
65
66 static void riscv_obj_add_qdict_prop(Object *obj, QDict *qdict_out,
67 const char *name)
68 {
69 ObjectProperty *prop = object_property_find(obj, name);
70
71 if (prop) {
72 QObject *value;
73
74 assert(prop->get);
75 value = object_property_get_qobject(obj, name, &error_abort);
76
77 qdict_put_obj(qdict_out, name, value);
78 }
79 }
80
81 static void riscv_obj_add_multiext_props(Object *obj, QDict *qdict_out,
82 const RISCVCPUMultiExtConfig *arr)
83 {
84 for (int i = 0; arr[i].name != NULL; i++) {
85 riscv_obj_add_qdict_prop(obj, qdict_out, arr[i].name);
86 }
87 }
88
89 static void riscv_cpuobj_validate_qdict_in(Object *obj, QObject *props,
90 const QDict *qdict_in,
91 Error **errp)
92 {
93 const QDictEntry *qe;
94 Visitor *visitor;
95 Error *local_err = NULL;
96
97 visitor = qobject_input_visitor_new(props);
98 if (!visit_start_struct(visitor, NULL, NULL, 0, &local_err)) {
99 goto err;
100 }
101
102 for (qe = qdict_first(qdict_in); qe; qe = qdict_next(qdict_in, qe)) {
103 object_property_find_err(obj, qe->key, &local_err);
104 if (local_err) {
105 goto err;
106 }
107
108 object_property_set(obj, qe->key, visitor, &local_err);
109 if (local_err) {
110 goto err;
111 }
112 }
113
114 visit_check_struct(visitor, &local_err);
115 if (local_err) {
116 goto err;
117 }
118
119 riscv_cpu_finalize_features(RISCV_CPU(obj), &local_err);
120 if (local_err) {
121 goto err;
122 }
123
124 visit_end_struct(visitor, NULL);
125
126 err:
127 error_propagate(errp, local_err);
128 visit_free(visitor);
129 }
130
131 CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type,
132 CpuModelInfo *model,
133 Error **errp)
134 {
135 CpuModelExpansionInfo *expansion_info;
136 const QDict *qdict_in = NULL;
137 QDict *qdict_out;
138 ObjectClass *oc;
139 Object *obj;
140 Error *local_err = NULL;
141
142 if (type != CPU_MODEL_EXPANSION_TYPE_FULL) {
143 error_setg(errp, "The requested expansion type is not supported");
144 return NULL;
145 }
146
147 oc = cpu_class_by_name(TYPE_RISCV_CPU, model->name);
148 if (!oc) {
149 error_setg(errp, "The CPU type '%s' is not a known RISC-V CPU type",
150 model->name);
151 return NULL;
152 }
153
154 if (model->props) {
155 qdict_in = qobject_to(QDict, model->props);
156 if (!qdict_in) {
157 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, "props", "dict");
158 return NULL;
159 }
160 }
161
162 obj = object_new(object_class_get_name(oc));
163
164 if (qdict_in) {
165 riscv_cpuobj_validate_qdict_in(obj, model->props, qdict_in,
166 &local_err);
167 if (local_err) {
168 error_propagate(errp, local_err);
169 object_unref(obj);
170 return NULL;
171 }
172 }
173
174 expansion_info = g_new0(CpuModelExpansionInfo, 1);
175 expansion_info->model = g_malloc0(sizeof(*expansion_info->model));
176 expansion_info->model->name = g_strdup(model->name);
177
178 qdict_out = qdict_new();
179
180 riscv_obj_add_multiext_props(obj, qdict_out, riscv_cpu_extensions);
181 riscv_obj_add_multiext_props(obj, qdict_out, riscv_cpu_experimental_exts);
182 riscv_obj_add_multiext_props(obj, qdict_out, riscv_cpu_vendor_exts);
183
184 /* Add our CPU boolean options too */
185 riscv_obj_add_qdict_prop(obj, qdict_out, "mmu");
186 riscv_obj_add_qdict_prop(obj, qdict_out, "pmp");
187
188 if (!qdict_size(qdict_out)) {
189 qobject_unref(qdict_out);
190 } else {
191 expansion_info->model->props = QOBJECT(qdict_out);
192 }
193
194 object_unref(obj);
195
196 return expansion_info;
197 }