xref: /qemu/target/riscv/riscv-qmp-cmds.c (revision ef6783d3f7d06cf185971afbb30ff35209e9db49)
1c0177f91SDaniel Henrique Barboza /*
2c0177f91SDaniel Henrique Barboza  * QEMU CPU QMP commands for RISC-V
3c0177f91SDaniel Henrique Barboza  *
4c0177f91SDaniel Henrique Barboza  * Copyright (c) 2023 Ventana Micro Systems Inc.
5c0177f91SDaniel Henrique Barboza  *
6c0177f91SDaniel Henrique Barboza  * Permission is hereby granted, free of charge, to any person obtaining a copy
7c0177f91SDaniel Henrique Barboza  * of this software and associated documentation files (the "Software"), to deal
8c0177f91SDaniel Henrique Barboza  * in the Software without restriction, including without limitation the rights
9c0177f91SDaniel Henrique Barboza  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10c0177f91SDaniel Henrique Barboza  * copies of the Software, and to permit persons to whom the Software is
11c0177f91SDaniel Henrique Barboza  * furnished to do so, subject to the following conditions:
12c0177f91SDaniel Henrique Barboza  *
13c0177f91SDaniel Henrique Barboza  * The above copyright notice and this permission notice shall be included in
14c0177f91SDaniel Henrique Barboza  * all copies or substantial portions of the Software.
15c0177f91SDaniel Henrique Barboza  *
16c0177f91SDaniel Henrique Barboza  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17c0177f91SDaniel Henrique Barboza  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18c0177f91SDaniel Henrique Barboza  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19c0177f91SDaniel Henrique Barboza  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20c0177f91SDaniel Henrique Barboza  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21c0177f91SDaniel Henrique Barboza  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22c0177f91SDaniel Henrique Barboza  * THE SOFTWARE.
23c0177f91SDaniel Henrique Barboza  */
24c0177f91SDaniel Henrique Barboza 
25c0177f91SDaniel Henrique Barboza #include "qemu/osdep.h"
26c0177f91SDaniel Henrique Barboza 
27aeb2bc59SDaniel Henrique Barboza #include "qapi/error.h"
28c0177f91SDaniel Henrique Barboza #include "qapi/qapi-commands-machine-target.h"
29a8815483SDaniel Henrique Barboza #include "qapi/qmp/qbool.h"
30aeb2bc59SDaniel Henrique Barboza #include "qapi/qmp/qdict.h"
311df4f540SDaniel Henrique Barboza #include "qapi/qobject-input-visitor.h"
321df4f540SDaniel Henrique Barboza #include "qapi/visitor.h"
33aeb2bc59SDaniel Henrique Barboza #include "qom/qom-qobject.h"
34a3abecbeSDaniel Henrique Barboza #include "sysemu/kvm.h"
35a3abecbeSDaniel Henrique Barboza #include "sysemu/tcg.h"
36c0177f91SDaniel Henrique Barboza #include "cpu-qom.h"
37aeb2bc59SDaniel Henrique Barboza #include "cpu.h"
38c0177f91SDaniel Henrique Barboza 
39c0177f91SDaniel Henrique Barboza static void riscv_cpu_add_definition(gpointer data, gpointer user_data)
40c0177f91SDaniel Henrique Barboza {
41c0177f91SDaniel Henrique Barboza     ObjectClass *oc = data;
42c0177f91SDaniel Henrique Barboza     CpuDefinitionInfoList **cpu_list = user_data;
43c0177f91SDaniel Henrique Barboza     CpuDefinitionInfo *info = g_malloc0(sizeof(*info));
44c0177f91SDaniel Henrique Barboza     const char *typename = object_class_get_name(oc);
459e1a30d3SDaniel Henrique Barboza     ObjectClass *dyn_class;
46c0177f91SDaniel Henrique Barboza 
474b26aa9fSGavin Shan     info->name = cpu_model_from_type(typename);
48c0177f91SDaniel Henrique Barboza     info->q_typename = g_strdup(typename);
49c0177f91SDaniel Henrique Barboza 
509e1a30d3SDaniel Henrique Barboza     dyn_class = object_class_dynamic_cast(oc, TYPE_RISCV_DYNAMIC_CPU);
519e1a30d3SDaniel Henrique Barboza     info->q_static = dyn_class == NULL;
529e1a30d3SDaniel Henrique Barboza 
53c0177f91SDaniel Henrique Barboza     QAPI_LIST_PREPEND(*cpu_list, info);
54c0177f91SDaniel Henrique Barboza }
55c0177f91SDaniel Henrique Barboza 
56c0177f91SDaniel Henrique Barboza CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
57c0177f91SDaniel Henrique Barboza {
58c0177f91SDaniel Henrique Barboza     CpuDefinitionInfoList *cpu_list = NULL;
59c0177f91SDaniel Henrique Barboza     GSList *list = object_class_get_list(TYPE_RISCV_CPU, false);
60c0177f91SDaniel Henrique Barboza 
61c0177f91SDaniel Henrique Barboza     g_slist_foreach(list, riscv_cpu_add_definition, &cpu_list);
62c0177f91SDaniel Henrique Barboza     g_slist_free(list);
63c0177f91SDaniel Henrique Barboza 
64c0177f91SDaniel Henrique Barboza     return cpu_list;
65c0177f91SDaniel Henrique Barboza }
66aeb2bc59SDaniel Henrique Barboza 
67a3abecbeSDaniel Henrique Barboza static void riscv_check_if_cpu_available(RISCVCPU *cpu, Error **errp)
68a3abecbeSDaniel Henrique Barboza {
69a3abecbeSDaniel Henrique Barboza     if (!riscv_cpu_accelerator_compatible(cpu)) {
70a3abecbeSDaniel Henrique Barboza         g_autofree char *name = riscv_cpu_get_name(cpu);
71a3abecbeSDaniel Henrique Barboza         const char *accel = kvm_enabled() ? "kvm" : "tcg";
72a3abecbeSDaniel Henrique Barboza 
73a3abecbeSDaniel Henrique Barboza         error_setg(errp, "'%s' CPU not available with %s", name, accel);
74a3abecbeSDaniel Henrique Barboza         return;
75a3abecbeSDaniel Henrique Barboza     }
76a3abecbeSDaniel Henrique Barboza }
77a3abecbeSDaniel Henrique Barboza 
78aeb2bc59SDaniel Henrique Barboza static void riscv_obj_add_qdict_prop(Object *obj, QDict *qdict_out,
79aeb2bc59SDaniel Henrique Barboza                                      const char *name)
80aeb2bc59SDaniel Henrique Barboza {
81aeb2bc59SDaniel Henrique Barboza     ObjectProperty *prop = object_property_find(obj, name);
82aeb2bc59SDaniel Henrique Barboza 
83aeb2bc59SDaniel Henrique Barboza     if (prop) {
84aeb2bc59SDaniel Henrique Barboza         QObject *value;
85aeb2bc59SDaniel Henrique Barboza 
86aeb2bc59SDaniel Henrique Barboza         assert(prop->get);
87aeb2bc59SDaniel Henrique Barboza         value = object_property_get_qobject(obj, name, &error_abort);
88aeb2bc59SDaniel Henrique Barboza 
89aeb2bc59SDaniel Henrique Barboza         qdict_put_obj(qdict_out, name, value);
90aeb2bc59SDaniel Henrique Barboza     }
91aeb2bc59SDaniel Henrique Barboza }
92aeb2bc59SDaniel Henrique Barboza 
93aeb2bc59SDaniel Henrique Barboza static void riscv_obj_add_multiext_props(Object *obj, QDict *qdict_out,
94aeb2bc59SDaniel Henrique Barboza                                          const RISCVCPUMultiExtConfig *arr)
95aeb2bc59SDaniel Henrique Barboza {
96aeb2bc59SDaniel Henrique Barboza     for (int i = 0; arr[i].name != NULL; i++) {
97aeb2bc59SDaniel Henrique Barboza         riscv_obj_add_qdict_prop(obj, qdict_out, arr[i].name);
98aeb2bc59SDaniel Henrique Barboza     }
99aeb2bc59SDaniel Henrique Barboza }
100aeb2bc59SDaniel Henrique Barboza 
101a8815483SDaniel Henrique Barboza static void riscv_obj_add_named_feats_qdict(Object *obj, QDict *qdict_out)
102a8815483SDaniel Henrique Barboza {
103a8815483SDaniel Henrique Barboza     const RISCVCPUMultiExtConfig *named_cfg;
104a8815483SDaniel Henrique Barboza     RISCVCPU *cpu = RISCV_CPU(obj);
105a8815483SDaniel Henrique Barboza     QObject *value;
106a8815483SDaniel Henrique Barboza     bool flag_val;
107a8815483SDaniel Henrique Barboza 
108a8815483SDaniel Henrique Barboza     for (int i = 0; riscv_cpu_named_features[i].name != NULL; i++) {
109a8815483SDaniel Henrique Barboza         named_cfg = &riscv_cpu_named_features[i];
110a8815483SDaniel Henrique Barboza         flag_val = isa_ext_is_enabled(cpu, named_cfg->offset);
111a8815483SDaniel Henrique Barboza         value = QOBJECT(qbool_from_bool(flag_val));
112a8815483SDaniel Henrique Barboza 
113a8815483SDaniel Henrique Barboza         qdict_put_obj(qdict_out, named_cfg->name, value);
114a8815483SDaniel Henrique Barboza     }
115a8815483SDaniel Henrique Barboza }
116a8815483SDaniel Henrique Barboza 
1176394b676SDaniel Henrique Barboza static void riscv_obj_add_profiles_qdict(Object *obj, QDict *qdict_out)
1186394b676SDaniel Henrique Barboza {
1196394b676SDaniel Henrique Barboza     RISCVCPUProfile *profile;
1206394b676SDaniel Henrique Barboza     QObject *value;
1216394b676SDaniel Henrique Barboza 
1226394b676SDaniel Henrique Barboza     for (int i = 0; riscv_profiles[i] != NULL; i++) {
1236394b676SDaniel Henrique Barboza         profile = riscv_profiles[i];
1246394b676SDaniel Henrique Barboza         value = QOBJECT(qbool_from_bool(profile->enabled));
1256394b676SDaniel Henrique Barboza 
1266394b676SDaniel Henrique Barboza         qdict_put_obj(qdict_out, profile->name, value);
1276394b676SDaniel Henrique Barboza     }
1286394b676SDaniel Henrique Barboza }
1296394b676SDaniel Henrique Barboza 
1301df4f540SDaniel Henrique Barboza static void riscv_cpuobj_validate_qdict_in(Object *obj, QObject *props,
1311df4f540SDaniel Henrique Barboza                                            Error **errp)
1321df4f540SDaniel Henrique Barboza {
133*ef6783d3SMarkus Armbruster     const QDict *qdict_in;
1341df4f540SDaniel Henrique Barboza     const QDictEntry *qe;
1351df4f540SDaniel Henrique Barboza     Visitor *visitor;
1361df4f540SDaniel Henrique Barboza     Error *local_err = NULL;
1371df4f540SDaniel Henrique Barboza 
1381df4f540SDaniel Henrique Barboza     visitor = qobject_input_visitor_new(props);
139*ef6783d3SMarkus Armbruster     if (!visit_start_struct(visitor, "props", NULL, 0, &local_err)) {
1401df4f540SDaniel Henrique Barboza         goto err;
1411df4f540SDaniel Henrique Barboza     }
1421df4f540SDaniel Henrique Barboza 
143*ef6783d3SMarkus Armbruster     qdict_in = qobject_to(QDict, props);
1441df4f540SDaniel Henrique Barboza     for (qe = qdict_first(qdict_in); qe; qe = qdict_next(qdict_in, qe)) {
1451df4f540SDaniel Henrique Barboza         object_property_find_err(obj, qe->key, &local_err);
1461df4f540SDaniel Henrique Barboza         if (local_err) {
1471df4f540SDaniel Henrique Barboza             goto err;
1481df4f540SDaniel Henrique Barboza         }
1491df4f540SDaniel Henrique Barboza 
1501df4f540SDaniel Henrique Barboza         object_property_set(obj, qe->key, visitor, &local_err);
1511df4f540SDaniel Henrique Barboza         if (local_err) {
1521df4f540SDaniel Henrique Barboza             goto err;
1531df4f540SDaniel Henrique Barboza         }
1541df4f540SDaniel Henrique Barboza     }
1551df4f540SDaniel Henrique Barboza 
1561df4f540SDaniel Henrique Barboza     visit_check_struct(visitor, &local_err);
1571df4f540SDaniel Henrique Barboza     if (local_err) {
1581df4f540SDaniel Henrique Barboza         goto err;
1591df4f540SDaniel Henrique Barboza     }
1601df4f540SDaniel Henrique Barboza 
1611df4f540SDaniel Henrique Barboza     visit_end_struct(visitor, NULL);
1621df4f540SDaniel Henrique Barboza 
1631df4f540SDaniel Henrique Barboza err:
1641df4f540SDaniel Henrique Barboza     error_propagate(errp, local_err);
1651df4f540SDaniel Henrique Barboza     visit_free(visitor);
1661df4f540SDaniel Henrique Barboza }
1671df4f540SDaniel Henrique Barboza 
168aeb2bc59SDaniel Henrique Barboza CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type,
169aeb2bc59SDaniel Henrique Barboza                                                      CpuModelInfo *model,
170aeb2bc59SDaniel Henrique Barboza                                                      Error **errp)
171aeb2bc59SDaniel Henrique Barboza {
172aeb2bc59SDaniel Henrique Barboza     CpuModelExpansionInfo *expansion_info;
173aeb2bc59SDaniel Henrique Barboza     QDict *qdict_out;
174aeb2bc59SDaniel Henrique Barboza     ObjectClass *oc;
175aeb2bc59SDaniel Henrique Barboza     Object *obj;
1761df4f540SDaniel Henrique Barboza     Error *local_err = NULL;
177aeb2bc59SDaniel Henrique Barboza 
178aeb2bc59SDaniel Henrique Barboza     if (type != CPU_MODEL_EXPANSION_TYPE_FULL) {
179aeb2bc59SDaniel Henrique Barboza         error_setg(errp, "The requested expansion type is not supported");
180aeb2bc59SDaniel Henrique Barboza         return NULL;
181aeb2bc59SDaniel Henrique Barboza     }
182aeb2bc59SDaniel Henrique Barboza 
183aeb2bc59SDaniel Henrique Barboza     oc = cpu_class_by_name(TYPE_RISCV_CPU, model->name);
184aeb2bc59SDaniel Henrique Barboza     if (!oc) {
185aeb2bc59SDaniel Henrique Barboza         error_setg(errp, "The CPU type '%s' is not a known RISC-V CPU type",
186aeb2bc59SDaniel Henrique Barboza                    model->name);
187aeb2bc59SDaniel Henrique Barboza         return NULL;
188aeb2bc59SDaniel Henrique Barboza     }
189aeb2bc59SDaniel Henrique Barboza 
190aeb2bc59SDaniel Henrique Barboza     obj = object_new(object_class_get_name(oc));
191aeb2bc59SDaniel Henrique Barboza 
192a3abecbeSDaniel Henrique Barboza     riscv_check_if_cpu_available(RISCV_CPU(obj), &local_err);
193a3abecbeSDaniel Henrique Barboza     if (local_err != NULL) {
194a3abecbeSDaniel Henrique Barboza         error_propagate(errp, local_err);
195a3abecbeSDaniel Henrique Barboza         object_unref(obj);
196a3abecbeSDaniel Henrique Barboza         return NULL;
197a3abecbeSDaniel Henrique Barboza     }
198a3abecbeSDaniel Henrique Barboza 
199*ef6783d3SMarkus Armbruster     if (model->props) {
200*ef6783d3SMarkus Armbruster         riscv_cpuobj_validate_qdict_in(obj, model->props, &local_err);
2011df4f540SDaniel Henrique Barboza         if (local_err) {
2021df4f540SDaniel Henrique Barboza             error_propagate(errp, local_err);
2031df4f540SDaniel Henrique Barboza             object_unref(obj);
2041df4f540SDaniel Henrique Barboza             return NULL;
2051df4f540SDaniel Henrique Barboza         }
2061df4f540SDaniel Henrique Barboza     }
2071df4f540SDaniel Henrique Barboza 
208a8815483SDaniel Henrique Barboza     riscv_cpu_finalize_features(RISCV_CPU(obj), &local_err);
209a8815483SDaniel Henrique Barboza     if (local_err) {
210a8815483SDaniel Henrique Barboza         error_propagate(errp, local_err);
211a8815483SDaniel Henrique Barboza         object_unref(obj);
212a8815483SDaniel Henrique Barboza         return NULL;
213a8815483SDaniel Henrique Barboza     }
214a8815483SDaniel Henrique Barboza 
215aeb2bc59SDaniel Henrique Barboza     expansion_info = g_new0(CpuModelExpansionInfo, 1);
216aeb2bc59SDaniel Henrique Barboza     expansion_info->model = g_malloc0(sizeof(*expansion_info->model));
217aeb2bc59SDaniel Henrique Barboza     expansion_info->model->name = g_strdup(model->name);
218aeb2bc59SDaniel Henrique Barboza 
219aeb2bc59SDaniel Henrique Barboza     qdict_out = qdict_new();
220aeb2bc59SDaniel Henrique Barboza 
221aeb2bc59SDaniel Henrique Barboza     riscv_obj_add_multiext_props(obj, qdict_out, riscv_cpu_extensions);
222aeb2bc59SDaniel Henrique Barboza     riscv_obj_add_multiext_props(obj, qdict_out, riscv_cpu_experimental_exts);
223aeb2bc59SDaniel Henrique Barboza     riscv_obj_add_multiext_props(obj, qdict_out, riscv_cpu_vendor_exts);
224a8815483SDaniel Henrique Barboza     riscv_obj_add_named_feats_qdict(obj, qdict_out);
2256394b676SDaniel Henrique Barboza     riscv_obj_add_profiles_qdict(obj, qdict_out);
226aeb2bc59SDaniel Henrique Barboza 
227aeb2bc59SDaniel Henrique Barboza     /* Add our CPU boolean options too */
228aeb2bc59SDaniel Henrique Barboza     riscv_obj_add_qdict_prop(obj, qdict_out, "mmu");
229aeb2bc59SDaniel Henrique Barboza     riscv_obj_add_qdict_prop(obj, qdict_out, "pmp");
230aeb2bc59SDaniel Henrique Barboza 
231aeb2bc59SDaniel Henrique Barboza     if (!qdict_size(qdict_out)) {
232aeb2bc59SDaniel Henrique Barboza         qobject_unref(qdict_out);
233aeb2bc59SDaniel Henrique Barboza     } else {
234aeb2bc59SDaniel Henrique Barboza         expansion_info->model->props = QOBJECT(qdict_out);
235aeb2bc59SDaniel Henrique Barboza     }
236aeb2bc59SDaniel Henrique Barboza 
237aeb2bc59SDaniel Henrique Barboza     object_unref(obj);
238aeb2bc59SDaniel Henrique Barboza 
239aeb2bc59SDaniel Henrique Barboza     return expansion_info;
240aeb2bc59SDaniel Henrique Barboza }
241