master
c 227 lines 6.66 KB
Raw
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.h"
29 #include "qobject/qbool.h"
30 #include "qobject/qdict.h"
31 #include "qapi/qobject-input-visitor.h"
32 #include "qapi/visitor.h"
33 #include "qom/qom-qobject.h"
34 #include "system/kvm.h"
35 #include "system/tcg.h"
36 #include "cpu-qom.h"
37 #include "cpu.h"
38 #include "target/riscv/tcg/csr.h"
39
40 static void riscv_cpu_add_definition(gpointer data, gpointer user_data)
41 {
42 ObjectClass *oc = data;
43 CpuDefinitionInfoList **cpu_list = user_data;
44 CpuDefinitionInfo *info = g_malloc0(sizeof(*info));
45 const char *typename = object_class_get_name(oc);
46 ObjectClass *dyn_class;
47
48 info->name = cpu_model_from_type(typename);
49 info->q_typename = g_strdup(typename);
50
51 dyn_class = object_class_dynamic_cast(oc, TYPE_RISCV_DYNAMIC_CPU);
52 info->q_static = dyn_class == NULL;
53
54 QAPI_LIST_PREPEND(*cpu_list, info);
55 }
56
57 CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
58 {
59 CpuDefinitionInfoList *cpu_list = NULL;
60 GSList *list = object_class_get_list(TYPE_RISCV_CPU, false);
61
62 g_slist_foreach(list, riscv_cpu_add_definition, &cpu_list);
63 g_slist_free(list);
64
65 return cpu_list;
66 }
67
68 static void riscv_check_if_cpu_available(RISCVCPU *cpu, Error **errp)
69 {
70 if (!riscv_cpu_accelerator_compatible(cpu)) {
71 g_autofree char *name = riscv_cpu_get_name(cpu);
72 const char *accel = kvm_enabled() ? "kvm" : "tcg";
73
74 error_setg(errp, "'%s' CPU not available with %s", name, accel);
75 return;
76 }
77 }
78
79 static void riscv_obj_add_qdict_prop(Object *obj, QDict *qdict_out,
80 const char *name)
81 {
82 ObjectProperty *prop = object_property_find(obj, name);
83
84 if (prop) {
85 QObject *value;
86
87 assert(prop->get);
88 value = object_property_get_qobject(obj, name, &error_abort);
89
90 qdict_put_obj(qdict_out, name, value);
91 }
92 }
93
94 static void riscv_obj_add_multiext_props(Object *obj, QDict *qdict_out)
95 {
96 const RISCVIsaExtData *edata;
97
98 for (edata = isa_edata_arr; edata && edata->name; edata++) {
99 if (edata->prop_name) {
100 riscv_obj_add_qdict_prop(obj, qdict_out, edata->prop_name);
101 }
102 }
103 }
104
105 static void riscv_obj_add_profiles_qdict(Object *obj, QDict *qdict_out)
106 {
107 RISCVCPUProfile *profile;
108 QObject *value;
109
110 for (int i = 0; riscv_profiles[i] != NULL; i++) {
111 profile = riscv_profiles[i];
112 value = QOBJECT(qbool_from_bool(profile->present));
113
114 qdict_put_obj(qdict_out, profile->name, value);
115 }
116 }
117
118 static void riscv_cpuobj_validate_qdict_in(Object *obj, QObject *props,
119 const char *props_arg_name,
120 Error **errp)
121 {
122 const QDict *qdict_in;
123 const QDictEntry *qe;
124 Visitor *visitor;
125 Error *local_err = NULL;
126
127 visitor = qobject_input_visitor_new(props);
128 if (!visit_start_struct(visitor, props_arg_name, NULL, 0, &local_err)) {
129 goto err;
130 }
131
132 qdict_in = qobject_to(QDict, props);
133 for (qe = qdict_first(qdict_in); qe; qe = qdict_next(qdict_in, qe)) {
134 object_property_find_err(obj, qe->key, &local_err);
135 if (local_err) {
136 goto err;
137 }
138
139 object_property_set(obj, qe->key, visitor, &local_err);
140 if (local_err) {
141 goto err;
142 }
143 }
144
145 visit_check_struct(visitor, &local_err);
146 if (local_err) {
147 goto err;
148 }
149
150 visit_end_struct(visitor, NULL);
151
152 err:
153 error_propagate(errp, local_err);
154 visit_free(visitor);
155 }
156
157 CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type,
158 CpuModelInfo *model,
159 Error **errp)
160 {
161 CpuModelExpansionInfo *expansion_info;
162 QDict *qdict_out;
163 ObjectClass *oc;
164 Object *obj;
165 Error *local_err = NULL;
166
167 if (type != CPU_MODEL_EXPANSION_TYPE_FULL) {
168 error_setg(errp, "The requested expansion type is not supported");
169 return NULL;
170 }
171
172 oc = cpu_class_by_name(TYPE_RISCV_CPU, model->name);
173 if (!oc) {
174 error_setg(errp, "The CPU type '%s' is not a known RISC-V CPU type",
175 model->name);
176 return NULL;
177 }
178
179 obj = object_new(object_class_get_name(oc));
180
181 riscv_check_if_cpu_available(RISCV_CPU(obj), &local_err);
182 if (local_err != NULL) {
183 error_propagate(errp, local_err);
184 object_unref(obj);
185 return NULL;
186 }
187
188 if (model->props) {
189 riscv_cpuobj_validate_qdict_in(obj, model->props, "model.props",
190 &local_err);
191 if (local_err) {
192 error_propagate(errp, local_err);
193 object_unref(obj);
194 return NULL;
195 }
196 }
197
198 riscv_cpu_finalize_features(RISCV_CPU(obj), &local_err);
199 if (local_err) {
200 error_propagate(errp, local_err);
201 object_unref(obj);
202 return NULL;
203 }
204
205 expansion_info = g_new0(CpuModelExpansionInfo, 1);
206 expansion_info->model = g_malloc0(sizeof(*expansion_info->model));
207 expansion_info->model->name = g_strdup(model->name);
208
209 qdict_out = qdict_new();
210
211 riscv_obj_add_multiext_props(obj, qdict_out);
212 riscv_obj_add_profiles_qdict(obj, qdict_out);
213
214 /* Add our CPU boolean options too */
215 riscv_obj_add_qdict_prop(obj, qdict_out, "mmu");
216 riscv_obj_add_qdict_prop(obj, qdict_out, "pmp");
217
218 if (!qdict_size(qdict_out)) {
219 qobject_unref(qdict_out);
220 } else {
221 expansion_info->model->props = QOBJECT(qdict_out);
222 }
223
224 object_unref(obj);
225
226 return expansion_info;
227 }