xref: /qemu/target/riscv/riscv-qmp-cmds.c (revision 6394b67615e1844dd2c0d616f0d2520533e43746)
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/qmp/qerror.h"
321df4f540SDaniel Henrique Barboza #include "qapi/qobject-input-visitor.h"
331df4f540SDaniel Henrique Barboza #include "qapi/visitor.h"
34aeb2bc59SDaniel Henrique Barboza #include "qom/qom-qobject.h"
35a3abecbeSDaniel Henrique Barboza #include "sysemu/kvm.h"
36a3abecbeSDaniel Henrique Barboza #include "sysemu/tcg.h"
37c0177f91SDaniel Henrique Barboza #include "cpu-qom.h"
38aeb2bc59SDaniel Henrique Barboza #include "cpu.h"
39c0177f91SDaniel Henrique Barboza 
40c0177f91SDaniel Henrique Barboza static void riscv_cpu_add_definition(gpointer data, gpointer user_data)
41c0177f91SDaniel Henrique Barboza {
42c0177f91SDaniel Henrique Barboza     ObjectClass *oc = data;
43c0177f91SDaniel Henrique Barboza     CpuDefinitionInfoList **cpu_list = user_data;
44c0177f91SDaniel Henrique Barboza     CpuDefinitionInfo *info = g_malloc0(sizeof(*info));
45c0177f91SDaniel Henrique Barboza     const char *typename = object_class_get_name(oc);
469e1a30d3SDaniel Henrique Barboza     ObjectClass *dyn_class;
47c0177f91SDaniel Henrique Barboza 
484b26aa9fSGavin Shan     info->name = cpu_model_from_type(typename);
49c0177f91SDaniel Henrique Barboza     info->q_typename = g_strdup(typename);
50c0177f91SDaniel Henrique Barboza 
519e1a30d3SDaniel Henrique Barboza     dyn_class = object_class_dynamic_cast(oc, TYPE_RISCV_DYNAMIC_CPU);
529e1a30d3SDaniel Henrique Barboza     info->q_static = dyn_class == NULL;
539e1a30d3SDaniel Henrique Barboza 
54c0177f91SDaniel Henrique Barboza     QAPI_LIST_PREPEND(*cpu_list, info);
55c0177f91SDaniel Henrique Barboza }
56c0177f91SDaniel Henrique Barboza 
57c0177f91SDaniel Henrique Barboza CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
58c0177f91SDaniel Henrique Barboza {
59c0177f91SDaniel Henrique Barboza     CpuDefinitionInfoList *cpu_list = NULL;
60c0177f91SDaniel Henrique Barboza     GSList *list = object_class_get_list(TYPE_RISCV_CPU, false);
61c0177f91SDaniel Henrique Barboza 
62c0177f91SDaniel Henrique Barboza     g_slist_foreach(list, riscv_cpu_add_definition, &cpu_list);
63c0177f91SDaniel Henrique Barboza     g_slist_free(list);
64c0177f91SDaniel Henrique Barboza 
65c0177f91SDaniel Henrique Barboza     return cpu_list;
66c0177f91SDaniel Henrique Barboza }
67aeb2bc59SDaniel Henrique Barboza 
68a3abecbeSDaniel Henrique Barboza static void riscv_check_if_cpu_available(RISCVCPU *cpu, Error **errp)
69a3abecbeSDaniel Henrique Barboza {
70a3abecbeSDaniel Henrique Barboza     if (!riscv_cpu_accelerator_compatible(cpu)) {
71a3abecbeSDaniel Henrique Barboza         g_autofree char *name = riscv_cpu_get_name(cpu);
72a3abecbeSDaniel Henrique Barboza         const char *accel = kvm_enabled() ? "kvm" : "tcg";
73a3abecbeSDaniel Henrique Barboza 
74a3abecbeSDaniel Henrique Barboza         error_setg(errp, "'%s' CPU not available with %s", name, accel);
75a3abecbeSDaniel Henrique Barboza         return;
76a3abecbeSDaniel Henrique Barboza     }
77a3abecbeSDaniel Henrique Barboza }
78a3abecbeSDaniel Henrique Barboza 
79aeb2bc59SDaniel Henrique Barboza static void riscv_obj_add_qdict_prop(Object *obj, QDict *qdict_out,
80aeb2bc59SDaniel Henrique Barboza                                      const char *name)
81aeb2bc59SDaniel Henrique Barboza {
82aeb2bc59SDaniel Henrique Barboza     ObjectProperty *prop = object_property_find(obj, name);
83aeb2bc59SDaniel Henrique Barboza 
84aeb2bc59SDaniel Henrique Barboza     if (prop) {
85aeb2bc59SDaniel Henrique Barboza         QObject *value;
86aeb2bc59SDaniel Henrique Barboza 
87aeb2bc59SDaniel Henrique Barboza         assert(prop->get);
88aeb2bc59SDaniel Henrique Barboza         value = object_property_get_qobject(obj, name, &error_abort);
89aeb2bc59SDaniel Henrique Barboza 
90aeb2bc59SDaniel Henrique Barboza         qdict_put_obj(qdict_out, name, value);
91aeb2bc59SDaniel Henrique Barboza     }
92aeb2bc59SDaniel Henrique Barboza }
93aeb2bc59SDaniel Henrique Barboza 
94aeb2bc59SDaniel Henrique Barboza static void riscv_obj_add_multiext_props(Object *obj, QDict *qdict_out,
95aeb2bc59SDaniel Henrique Barboza                                          const RISCVCPUMultiExtConfig *arr)
96aeb2bc59SDaniel Henrique Barboza {
97aeb2bc59SDaniel Henrique Barboza     for (int i = 0; arr[i].name != NULL; i++) {
98aeb2bc59SDaniel Henrique Barboza         riscv_obj_add_qdict_prop(obj, qdict_out, arr[i].name);
99aeb2bc59SDaniel Henrique Barboza     }
100aeb2bc59SDaniel Henrique Barboza }
101aeb2bc59SDaniel Henrique Barboza 
102a8815483SDaniel Henrique Barboza static void riscv_obj_add_named_feats_qdict(Object *obj, QDict *qdict_out)
103a8815483SDaniel Henrique Barboza {
104a8815483SDaniel Henrique Barboza     const RISCVCPUMultiExtConfig *named_cfg;
105a8815483SDaniel Henrique Barboza     RISCVCPU *cpu = RISCV_CPU(obj);
106a8815483SDaniel Henrique Barboza     QObject *value;
107a8815483SDaniel Henrique Barboza     bool flag_val;
108a8815483SDaniel Henrique Barboza 
109a8815483SDaniel Henrique Barboza     for (int i = 0; riscv_cpu_named_features[i].name != NULL; i++) {
110a8815483SDaniel Henrique Barboza         named_cfg = &riscv_cpu_named_features[i];
111a8815483SDaniel Henrique Barboza         flag_val = isa_ext_is_enabled(cpu, named_cfg->offset);
112a8815483SDaniel Henrique Barboza         value = QOBJECT(qbool_from_bool(flag_val));
113a8815483SDaniel Henrique Barboza 
114a8815483SDaniel Henrique Barboza         qdict_put_obj(qdict_out, named_cfg->name, value);
115a8815483SDaniel Henrique Barboza     }
116a8815483SDaniel Henrique Barboza }
117a8815483SDaniel Henrique Barboza 
118*6394b676SDaniel Henrique Barboza static void riscv_obj_add_profiles_qdict(Object *obj, QDict *qdict_out)
119*6394b676SDaniel Henrique Barboza {
120*6394b676SDaniel Henrique Barboza     RISCVCPUProfile *profile;
121*6394b676SDaniel Henrique Barboza     QObject *value;
122*6394b676SDaniel Henrique Barboza 
123*6394b676SDaniel Henrique Barboza     for (int i = 0; riscv_profiles[i] != NULL; i++) {
124*6394b676SDaniel Henrique Barboza         profile = riscv_profiles[i];
125*6394b676SDaniel Henrique Barboza         value = QOBJECT(qbool_from_bool(profile->enabled));
126*6394b676SDaniel Henrique Barboza 
127*6394b676SDaniel Henrique Barboza         qdict_put_obj(qdict_out, profile->name, value);
128*6394b676SDaniel Henrique Barboza     }
129*6394b676SDaniel Henrique Barboza }
130*6394b676SDaniel Henrique Barboza 
1311df4f540SDaniel Henrique Barboza static void riscv_cpuobj_validate_qdict_in(Object *obj, QObject *props,
1321df4f540SDaniel Henrique Barboza                                            const QDict *qdict_in,
1331df4f540SDaniel Henrique Barboza                                            Error **errp)
1341df4f540SDaniel Henrique Barboza {
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);
1401df4f540SDaniel Henrique Barboza     if (!visit_start_struct(visitor, NULL, NULL, 0, &local_err)) {
1411df4f540SDaniel Henrique Barboza         goto err;
1421df4f540SDaniel Henrique Barboza     }
1431df4f540SDaniel Henrique Barboza 
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;
1731df4f540SDaniel Henrique Barboza     const QDict *qdict_in = NULL;
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 
1911df4f540SDaniel Henrique Barboza     if (model->props) {
1921df4f540SDaniel Henrique Barboza         qdict_in = qobject_to(QDict, model->props);
1931df4f540SDaniel Henrique Barboza         if (!qdict_in) {
1941df4f540SDaniel Henrique Barboza             error_setg(errp, QERR_INVALID_PARAMETER_TYPE, "props", "dict");
1951df4f540SDaniel Henrique Barboza             return NULL;
1961df4f540SDaniel Henrique Barboza         }
1971df4f540SDaniel Henrique Barboza     }
1981df4f540SDaniel Henrique Barboza 
199aeb2bc59SDaniel Henrique Barboza     obj = object_new(object_class_get_name(oc));
200aeb2bc59SDaniel Henrique Barboza 
201a3abecbeSDaniel Henrique Barboza     riscv_check_if_cpu_available(RISCV_CPU(obj), &local_err);
202a3abecbeSDaniel Henrique Barboza     if (local_err != NULL) {
203a3abecbeSDaniel Henrique Barboza         error_propagate(errp, local_err);
204a3abecbeSDaniel Henrique Barboza         object_unref(obj);
205a3abecbeSDaniel Henrique Barboza         return NULL;
206a3abecbeSDaniel Henrique Barboza     }
207a3abecbeSDaniel Henrique Barboza 
2081df4f540SDaniel Henrique Barboza     if (qdict_in) {
2091df4f540SDaniel Henrique Barboza         riscv_cpuobj_validate_qdict_in(obj, model->props, qdict_in,
2101df4f540SDaniel Henrique Barboza                                        &local_err);
2111df4f540SDaniel Henrique Barboza         if (local_err) {
2121df4f540SDaniel Henrique Barboza             error_propagate(errp, local_err);
2131df4f540SDaniel Henrique Barboza             object_unref(obj);
2141df4f540SDaniel Henrique Barboza             return NULL;
2151df4f540SDaniel Henrique Barboza         }
2161df4f540SDaniel Henrique Barboza     }
2171df4f540SDaniel Henrique Barboza 
218a8815483SDaniel Henrique Barboza     riscv_cpu_finalize_features(RISCV_CPU(obj), &local_err);
219a8815483SDaniel Henrique Barboza     if (local_err) {
220a8815483SDaniel Henrique Barboza         error_propagate(errp, local_err);
221a8815483SDaniel Henrique Barboza         object_unref(obj);
222a8815483SDaniel Henrique Barboza         return NULL;
223a8815483SDaniel Henrique Barboza     }
224a8815483SDaniel Henrique Barboza 
225aeb2bc59SDaniel Henrique Barboza     expansion_info = g_new0(CpuModelExpansionInfo, 1);
226aeb2bc59SDaniel Henrique Barboza     expansion_info->model = g_malloc0(sizeof(*expansion_info->model));
227aeb2bc59SDaniel Henrique Barboza     expansion_info->model->name = g_strdup(model->name);
228aeb2bc59SDaniel Henrique Barboza 
229aeb2bc59SDaniel Henrique Barboza     qdict_out = qdict_new();
230aeb2bc59SDaniel Henrique Barboza 
231aeb2bc59SDaniel Henrique Barboza     riscv_obj_add_multiext_props(obj, qdict_out, riscv_cpu_extensions);
232aeb2bc59SDaniel Henrique Barboza     riscv_obj_add_multiext_props(obj, qdict_out, riscv_cpu_experimental_exts);
233aeb2bc59SDaniel Henrique Barboza     riscv_obj_add_multiext_props(obj, qdict_out, riscv_cpu_vendor_exts);
234a8815483SDaniel Henrique Barboza     riscv_obj_add_named_feats_qdict(obj, qdict_out);
235*6394b676SDaniel Henrique Barboza     riscv_obj_add_profiles_qdict(obj, qdict_out);
236aeb2bc59SDaniel Henrique Barboza 
237aeb2bc59SDaniel Henrique Barboza     /* Add our CPU boolean options too */
238aeb2bc59SDaniel Henrique Barboza     riscv_obj_add_qdict_prop(obj, qdict_out, "mmu");
239aeb2bc59SDaniel Henrique Barboza     riscv_obj_add_qdict_prop(obj, qdict_out, "pmp");
240aeb2bc59SDaniel Henrique Barboza 
241aeb2bc59SDaniel Henrique Barboza     if (!qdict_size(qdict_out)) {
242aeb2bc59SDaniel Henrique Barboza         qobject_unref(qdict_out);
243aeb2bc59SDaniel Henrique Barboza     } else {
244aeb2bc59SDaniel Henrique Barboza         expansion_info->model->props = QOBJECT(qdict_out);
245aeb2bc59SDaniel Henrique Barboza     }
246aeb2bc59SDaniel Henrique Barboza 
247aeb2bc59SDaniel Henrique Barboza     object_unref(obj);
248aeb2bc59SDaniel Henrique Barboza 
249aeb2bc59SDaniel Henrique Barboza     return expansion_info;
250aeb2bc59SDaniel Henrique Barboza }
251