xref: /openbmc/qemu/target/riscv/riscv-qmp-cmds.c (revision 441e0eefabbb6283223237a26f2a48c6a61db40a)
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 
riscv_cpu_add_definition(gpointer data,gpointer user_data)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 
qmp_query_cpu_definitions(Error ** errp)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 
riscv_check_if_cpu_available(RISCVCPU * cpu,Error ** errp)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 
riscv_obj_add_qdict_prop(Object * obj,QDict * qdict_out,const char * name)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 
riscv_obj_add_multiext_props(Object * obj,QDict * qdict_out,const RISCVCPUMultiExtConfig * arr)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 
riscv_obj_add_named_feats_qdict(Object * obj,QDict * qdict_out)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 
riscv_obj_add_profiles_qdict(Object * obj,QDict * qdict_out)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 
riscv_cpuobj_validate_qdict_in(Object * obj,QObject * props,const char * props_arg_name,Error ** errp)1301df4f540SDaniel Henrique Barboza static void riscv_cpuobj_validate_qdict_in(Object *obj, QObject *props,
131*8934643aSMarkus Armbruster                                            const char *props_arg_name,
1321df4f540SDaniel Henrique Barboza                                            Error **errp)
1331df4f540SDaniel Henrique Barboza {
134ef6783d3SMarkus Armbruster     const QDict *qdict_in;
1351df4f540SDaniel Henrique Barboza     const QDictEntry *qe;
1361df4f540SDaniel Henrique Barboza     Visitor *visitor;
1371df4f540SDaniel Henrique Barboza     Error *local_err = NULL;
1381df4f540SDaniel Henrique Barboza 
1391df4f540SDaniel Henrique Barboza     visitor = qobject_input_visitor_new(props);
140*8934643aSMarkus Armbruster     if (!visit_start_struct(visitor, props_arg_name, NULL, 0, &local_err)) {
1411df4f540SDaniel Henrique Barboza         goto err;
1421df4f540SDaniel Henrique Barboza     }
1431df4f540SDaniel Henrique Barboza 
144ef6783d3SMarkus Armbruster     qdict_in = qobject_to(QDict, props);
1451df4f540SDaniel Henrique Barboza     for (qe = qdict_first(qdict_in); qe; qe = qdict_next(qdict_in, qe)) {
1461df4f540SDaniel Henrique Barboza         object_property_find_err(obj, qe->key, &local_err);
1471df4f540SDaniel Henrique Barboza         if (local_err) {
1481df4f540SDaniel Henrique Barboza             goto err;
1491df4f540SDaniel Henrique Barboza         }
1501df4f540SDaniel Henrique Barboza 
1511df4f540SDaniel Henrique Barboza         object_property_set(obj, qe->key, visitor, &local_err);
1521df4f540SDaniel Henrique Barboza         if (local_err) {
1531df4f540SDaniel Henrique Barboza             goto err;
1541df4f540SDaniel Henrique Barboza         }
1551df4f540SDaniel Henrique Barboza     }
1561df4f540SDaniel Henrique Barboza 
1571df4f540SDaniel Henrique Barboza     visit_check_struct(visitor, &local_err);
1581df4f540SDaniel Henrique Barboza     if (local_err) {
1591df4f540SDaniel Henrique Barboza         goto err;
1601df4f540SDaniel Henrique Barboza     }
1611df4f540SDaniel Henrique Barboza 
1621df4f540SDaniel Henrique Barboza     visit_end_struct(visitor, NULL);
1631df4f540SDaniel Henrique Barboza 
1641df4f540SDaniel Henrique Barboza err:
1651df4f540SDaniel Henrique Barboza     error_propagate(errp, local_err);
1661df4f540SDaniel Henrique Barboza     visit_free(visitor);
1671df4f540SDaniel Henrique Barboza }
1681df4f540SDaniel Henrique Barboza 
qmp_query_cpu_model_expansion(CpuModelExpansionType type,CpuModelInfo * model,Error ** errp)169aeb2bc59SDaniel Henrique Barboza CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type,
170aeb2bc59SDaniel Henrique Barboza                                                      CpuModelInfo *model,
171aeb2bc59SDaniel Henrique Barboza                                                      Error **errp)
172aeb2bc59SDaniel Henrique Barboza {
173aeb2bc59SDaniel Henrique Barboza     CpuModelExpansionInfo *expansion_info;
174aeb2bc59SDaniel Henrique Barboza     QDict *qdict_out;
175aeb2bc59SDaniel Henrique Barboza     ObjectClass *oc;
176aeb2bc59SDaniel Henrique Barboza     Object *obj;
1771df4f540SDaniel Henrique Barboza     Error *local_err = NULL;
178aeb2bc59SDaniel Henrique Barboza 
179aeb2bc59SDaniel Henrique Barboza     if (type != CPU_MODEL_EXPANSION_TYPE_FULL) {
180aeb2bc59SDaniel Henrique Barboza         error_setg(errp, "The requested expansion type is not supported");
181aeb2bc59SDaniel Henrique Barboza         return NULL;
182aeb2bc59SDaniel Henrique Barboza     }
183aeb2bc59SDaniel Henrique Barboza 
184aeb2bc59SDaniel Henrique Barboza     oc = cpu_class_by_name(TYPE_RISCV_CPU, model->name);
185aeb2bc59SDaniel Henrique Barboza     if (!oc) {
186aeb2bc59SDaniel Henrique Barboza         error_setg(errp, "The CPU type '%s' is not a known RISC-V CPU type",
187aeb2bc59SDaniel Henrique Barboza                    model->name);
188aeb2bc59SDaniel Henrique Barboza         return NULL;
189aeb2bc59SDaniel Henrique Barboza     }
190aeb2bc59SDaniel Henrique Barboza 
191aeb2bc59SDaniel Henrique Barboza     obj = object_new(object_class_get_name(oc));
192aeb2bc59SDaniel Henrique Barboza 
193a3abecbeSDaniel Henrique Barboza     riscv_check_if_cpu_available(RISCV_CPU(obj), &local_err);
194a3abecbeSDaniel Henrique Barboza     if (local_err != NULL) {
195a3abecbeSDaniel Henrique Barboza         error_propagate(errp, local_err);
196a3abecbeSDaniel Henrique Barboza         object_unref(obj);
197a3abecbeSDaniel Henrique Barboza         return NULL;
198a3abecbeSDaniel Henrique Barboza     }
199a3abecbeSDaniel Henrique Barboza 
200ef6783d3SMarkus Armbruster     if (model->props) {
201*8934643aSMarkus Armbruster         riscv_cpuobj_validate_qdict_in(obj, model->props, "model.props",
202*8934643aSMarkus Armbruster                                        &local_err);
2031df4f540SDaniel Henrique Barboza         if (local_err) {
2041df4f540SDaniel Henrique Barboza             error_propagate(errp, local_err);
2051df4f540SDaniel Henrique Barboza             object_unref(obj);
2061df4f540SDaniel Henrique Barboza             return NULL;
2071df4f540SDaniel Henrique Barboza         }
2081df4f540SDaniel Henrique Barboza     }
2091df4f540SDaniel Henrique Barboza 
210a8815483SDaniel Henrique Barboza     riscv_cpu_finalize_features(RISCV_CPU(obj), &local_err);
211a8815483SDaniel Henrique Barboza     if (local_err) {
212a8815483SDaniel Henrique Barboza         error_propagate(errp, local_err);
213a8815483SDaniel Henrique Barboza         object_unref(obj);
214a8815483SDaniel Henrique Barboza         return NULL;
215a8815483SDaniel Henrique Barboza     }
216a8815483SDaniel Henrique Barboza 
217aeb2bc59SDaniel Henrique Barboza     expansion_info = g_new0(CpuModelExpansionInfo, 1);
218aeb2bc59SDaniel Henrique Barboza     expansion_info->model = g_malloc0(sizeof(*expansion_info->model));
219aeb2bc59SDaniel Henrique Barboza     expansion_info->model->name = g_strdup(model->name);
220aeb2bc59SDaniel Henrique Barboza 
221aeb2bc59SDaniel Henrique Barboza     qdict_out = qdict_new();
222aeb2bc59SDaniel Henrique Barboza 
223aeb2bc59SDaniel Henrique Barboza     riscv_obj_add_multiext_props(obj, qdict_out, riscv_cpu_extensions);
224aeb2bc59SDaniel Henrique Barboza     riscv_obj_add_multiext_props(obj, qdict_out, riscv_cpu_experimental_exts);
225aeb2bc59SDaniel Henrique Barboza     riscv_obj_add_multiext_props(obj, qdict_out, riscv_cpu_vendor_exts);
226a8815483SDaniel Henrique Barboza     riscv_obj_add_named_feats_qdict(obj, qdict_out);
2276394b676SDaniel Henrique Barboza     riscv_obj_add_profiles_qdict(obj, qdict_out);
228aeb2bc59SDaniel Henrique Barboza 
229aeb2bc59SDaniel Henrique Barboza     /* Add our CPU boolean options too */
230aeb2bc59SDaniel Henrique Barboza     riscv_obj_add_qdict_prop(obj, qdict_out, "mmu");
231aeb2bc59SDaniel Henrique Barboza     riscv_obj_add_qdict_prop(obj, qdict_out, "pmp");
232aeb2bc59SDaniel Henrique Barboza 
233aeb2bc59SDaniel Henrique Barboza     if (!qdict_size(qdict_out)) {
234aeb2bc59SDaniel Henrique Barboza         qobject_unref(qdict_out);
235aeb2bc59SDaniel Henrique Barboza     } else {
236aeb2bc59SDaniel Henrique Barboza         expansion_info->model->props = QOBJECT(qdict_out);
237aeb2bc59SDaniel Henrique Barboza     }
238aeb2bc59SDaniel Henrique Barboza 
239aeb2bc59SDaniel Henrique Barboza     object_unref(obj);
240aeb2bc59SDaniel Henrique Barboza 
241aeb2bc59SDaniel Henrique Barboza     return expansion_info;
242aeb2bc59SDaniel Henrique Barboza }
243