xref: /qemu/target/riscv/riscv-qmp-cmds.c (revision 1df4f540d6352131cefa7ca48b637ccb774ce9e0)
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"
29aeb2bc59SDaniel Henrique Barboza #include "qapi/qmp/qdict.h"
30*1df4f540SDaniel Henrique Barboza #include "qapi/qmp/qerror.h"
31*1df4f540SDaniel Henrique Barboza #include "qapi/qobject-input-visitor.h"
32*1df4f540SDaniel Henrique Barboza #include "qapi/visitor.h"
33aeb2bc59SDaniel Henrique Barboza #include "qom/qom-qobject.h"
34c0177f91SDaniel Henrique Barboza #include "cpu-qom.h"
35aeb2bc59SDaniel Henrique Barboza #include "cpu.h"
36c0177f91SDaniel Henrique Barboza 
37c0177f91SDaniel Henrique Barboza static void riscv_cpu_add_definition(gpointer data, gpointer user_data)
38c0177f91SDaniel Henrique Barboza {
39c0177f91SDaniel Henrique Barboza     ObjectClass *oc = data;
40c0177f91SDaniel Henrique Barboza     CpuDefinitionInfoList **cpu_list = user_data;
41c0177f91SDaniel Henrique Barboza     CpuDefinitionInfo *info = g_malloc0(sizeof(*info));
42c0177f91SDaniel Henrique Barboza     const char *typename = object_class_get_name(oc);
439e1a30d3SDaniel Henrique Barboza     ObjectClass *dyn_class;
44c0177f91SDaniel Henrique Barboza 
45c0177f91SDaniel Henrique Barboza     info->name = g_strndup(typename,
46c0177f91SDaniel Henrique Barboza                            strlen(typename) - strlen("-" TYPE_RISCV_CPU));
47c0177f91SDaniel Henrique Barboza     info->q_typename = g_strdup(typename);
48c0177f91SDaniel Henrique Barboza 
499e1a30d3SDaniel Henrique Barboza     dyn_class = object_class_dynamic_cast(oc, TYPE_RISCV_DYNAMIC_CPU);
509e1a30d3SDaniel Henrique Barboza     info->q_static = dyn_class == NULL;
519e1a30d3SDaniel Henrique Barboza 
52c0177f91SDaniel Henrique Barboza     QAPI_LIST_PREPEND(*cpu_list, info);
53c0177f91SDaniel Henrique Barboza }
54c0177f91SDaniel Henrique Barboza 
55c0177f91SDaniel Henrique Barboza CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
56c0177f91SDaniel Henrique Barboza {
57c0177f91SDaniel Henrique Barboza     CpuDefinitionInfoList *cpu_list = NULL;
58c0177f91SDaniel Henrique Barboza     GSList *list = object_class_get_list(TYPE_RISCV_CPU, false);
59c0177f91SDaniel Henrique Barboza 
60c0177f91SDaniel Henrique Barboza     g_slist_foreach(list, riscv_cpu_add_definition, &cpu_list);
61c0177f91SDaniel Henrique Barboza     g_slist_free(list);
62c0177f91SDaniel Henrique Barboza 
63c0177f91SDaniel Henrique Barboza     return cpu_list;
64c0177f91SDaniel Henrique Barboza }
65aeb2bc59SDaniel Henrique Barboza 
66aeb2bc59SDaniel Henrique Barboza static void riscv_obj_add_qdict_prop(Object *obj, QDict *qdict_out,
67aeb2bc59SDaniel Henrique Barboza                                      const char *name)
68aeb2bc59SDaniel Henrique Barboza {
69aeb2bc59SDaniel Henrique Barboza     ObjectProperty *prop = object_property_find(obj, name);
70aeb2bc59SDaniel Henrique Barboza 
71aeb2bc59SDaniel Henrique Barboza     if (prop) {
72aeb2bc59SDaniel Henrique Barboza         QObject *value;
73aeb2bc59SDaniel Henrique Barboza 
74aeb2bc59SDaniel Henrique Barboza         assert(prop->get);
75aeb2bc59SDaniel Henrique Barboza         value = object_property_get_qobject(obj, name, &error_abort);
76aeb2bc59SDaniel Henrique Barboza 
77aeb2bc59SDaniel Henrique Barboza         qdict_put_obj(qdict_out, name, value);
78aeb2bc59SDaniel Henrique Barboza     }
79aeb2bc59SDaniel Henrique Barboza }
80aeb2bc59SDaniel Henrique Barboza 
81aeb2bc59SDaniel Henrique Barboza static void riscv_obj_add_multiext_props(Object *obj, QDict *qdict_out,
82aeb2bc59SDaniel Henrique Barboza                                          const RISCVCPUMultiExtConfig *arr)
83aeb2bc59SDaniel Henrique Barboza {
84aeb2bc59SDaniel Henrique Barboza     for (int i = 0; arr[i].name != NULL; i++) {
85aeb2bc59SDaniel Henrique Barboza         riscv_obj_add_qdict_prop(obj, qdict_out, arr[i].name);
86aeb2bc59SDaniel Henrique Barboza     }
87aeb2bc59SDaniel Henrique Barboza }
88aeb2bc59SDaniel Henrique Barboza 
89*1df4f540SDaniel Henrique Barboza static void riscv_cpuobj_validate_qdict_in(Object *obj, QObject *props,
90*1df4f540SDaniel Henrique Barboza                                            const QDict *qdict_in,
91*1df4f540SDaniel Henrique Barboza                                            Error **errp)
92*1df4f540SDaniel Henrique Barboza {
93*1df4f540SDaniel Henrique Barboza     const QDictEntry *qe;
94*1df4f540SDaniel Henrique Barboza     Visitor *visitor;
95*1df4f540SDaniel Henrique Barboza     Error *local_err = NULL;
96*1df4f540SDaniel Henrique Barboza 
97*1df4f540SDaniel Henrique Barboza     visitor = qobject_input_visitor_new(props);
98*1df4f540SDaniel Henrique Barboza     if (!visit_start_struct(visitor, NULL, NULL, 0, &local_err)) {
99*1df4f540SDaniel Henrique Barboza         goto err;
100*1df4f540SDaniel Henrique Barboza     }
101*1df4f540SDaniel Henrique Barboza 
102*1df4f540SDaniel Henrique Barboza     for (qe = qdict_first(qdict_in); qe; qe = qdict_next(qdict_in, qe)) {
103*1df4f540SDaniel Henrique Barboza         object_property_find_err(obj, qe->key, &local_err);
104*1df4f540SDaniel Henrique Barboza         if (local_err) {
105*1df4f540SDaniel Henrique Barboza             goto err;
106*1df4f540SDaniel Henrique Barboza         }
107*1df4f540SDaniel Henrique Barboza 
108*1df4f540SDaniel Henrique Barboza         object_property_set(obj, qe->key, visitor, &local_err);
109*1df4f540SDaniel Henrique Barboza         if (local_err) {
110*1df4f540SDaniel Henrique Barboza             goto err;
111*1df4f540SDaniel Henrique Barboza         }
112*1df4f540SDaniel Henrique Barboza     }
113*1df4f540SDaniel Henrique Barboza 
114*1df4f540SDaniel Henrique Barboza     visit_check_struct(visitor, &local_err);
115*1df4f540SDaniel Henrique Barboza     if (local_err) {
116*1df4f540SDaniel Henrique Barboza         goto err;
117*1df4f540SDaniel Henrique Barboza     }
118*1df4f540SDaniel Henrique Barboza 
119*1df4f540SDaniel Henrique Barboza     riscv_cpu_finalize_features(RISCV_CPU(obj), &local_err);
120*1df4f540SDaniel Henrique Barboza     if (local_err) {
121*1df4f540SDaniel Henrique Barboza         goto err;
122*1df4f540SDaniel Henrique Barboza     }
123*1df4f540SDaniel Henrique Barboza 
124*1df4f540SDaniel Henrique Barboza     visit_end_struct(visitor, NULL);
125*1df4f540SDaniel Henrique Barboza 
126*1df4f540SDaniel Henrique Barboza err:
127*1df4f540SDaniel Henrique Barboza     error_propagate(errp, local_err);
128*1df4f540SDaniel Henrique Barboza     visit_free(visitor);
129*1df4f540SDaniel Henrique Barboza }
130*1df4f540SDaniel Henrique Barboza 
131aeb2bc59SDaniel Henrique Barboza CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type,
132aeb2bc59SDaniel Henrique Barboza                                                      CpuModelInfo *model,
133aeb2bc59SDaniel Henrique Barboza                                                      Error **errp)
134aeb2bc59SDaniel Henrique Barboza {
135aeb2bc59SDaniel Henrique Barboza     CpuModelExpansionInfo *expansion_info;
136*1df4f540SDaniel Henrique Barboza     const QDict *qdict_in = NULL;
137aeb2bc59SDaniel Henrique Barboza     QDict *qdict_out;
138aeb2bc59SDaniel Henrique Barboza     ObjectClass *oc;
139aeb2bc59SDaniel Henrique Barboza     Object *obj;
140*1df4f540SDaniel Henrique Barboza     Error *local_err = NULL;
141aeb2bc59SDaniel Henrique Barboza 
142aeb2bc59SDaniel Henrique Barboza     if (type != CPU_MODEL_EXPANSION_TYPE_FULL) {
143aeb2bc59SDaniel Henrique Barboza         error_setg(errp, "The requested expansion type is not supported");
144aeb2bc59SDaniel Henrique Barboza         return NULL;
145aeb2bc59SDaniel Henrique Barboza     }
146aeb2bc59SDaniel Henrique Barboza 
147aeb2bc59SDaniel Henrique Barboza     oc = cpu_class_by_name(TYPE_RISCV_CPU, model->name);
148aeb2bc59SDaniel Henrique Barboza     if (!oc) {
149aeb2bc59SDaniel Henrique Barboza         error_setg(errp, "The CPU type '%s' is not a known RISC-V CPU type",
150aeb2bc59SDaniel Henrique Barboza                    model->name);
151aeb2bc59SDaniel Henrique Barboza         return NULL;
152aeb2bc59SDaniel Henrique Barboza     }
153aeb2bc59SDaniel Henrique Barboza 
154*1df4f540SDaniel Henrique Barboza     if (model->props) {
155*1df4f540SDaniel Henrique Barboza         qdict_in = qobject_to(QDict, model->props);
156*1df4f540SDaniel Henrique Barboza         if (!qdict_in) {
157*1df4f540SDaniel Henrique Barboza             error_setg(errp, QERR_INVALID_PARAMETER_TYPE, "props", "dict");
158*1df4f540SDaniel Henrique Barboza             return NULL;
159*1df4f540SDaniel Henrique Barboza         }
160*1df4f540SDaniel Henrique Barboza     }
161*1df4f540SDaniel Henrique Barboza 
162aeb2bc59SDaniel Henrique Barboza     obj = object_new(object_class_get_name(oc));
163aeb2bc59SDaniel Henrique Barboza 
164*1df4f540SDaniel Henrique Barboza     if (qdict_in) {
165*1df4f540SDaniel Henrique Barboza         riscv_cpuobj_validate_qdict_in(obj, model->props, qdict_in,
166*1df4f540SDaniel Henrique Barboza                                        &local_err);
167*1df4f540SDaniel Henrique Barboza         if (local_err) {
168*1df4f540SDaniel Henrique Barboza             error_propagate(errp, local_err);
169*1df4f540SDaniel Henrique Barboza             object_unref(obj);
170*1df4f540SDaniel Henrique Barboza             return NULL;
171*1df4f540SDaniel Henrique Barboza         }
172*1df4f540SDaniel Henrique Barboza     }
173*1df4f540SDaniel Henrique Barboza 
174aeb2bc59SDaniel Henrique Barboza     expansion_info = g_new0(CpuModelExpansionInfo, 1);
175aeb2bc59SDaniel Henrique Barboza     expansion_info->model = g_malloc0(sizeof(*expansion_info->model));
176aeb2bc59SDaniel Henrique Barboza     expansion_info->model->name = g_strdup(model->name);
177aeb2bc59SDaniel Henrique Barboza 
178aeb2bc59SDaniel Henrique Barboza     qdict_out = qdict_new();
179aeb2bc59SDaniel Henrique Barboza 
180aeb2bc59SDaniel Henrique Barboza     riscv_obj_add_multiext_props(obj, qdict_out, riscv_cpu_extensions);
181aeb2bc59SDaniel Henrique Barboza     riscv_obj_add_multiext_props(obj, qdict_out, riscv_cpu_experimental_exts);
182aeb2bc59SDaniel Henrique Barboza     riscv_obj_add_multiext_props(obj, qdict_out, riscv_cpu_vendor_exts);
183aeb2bc59SDaniel Henrique Barboza 
184aeb2bc59SDaniel Henrique Barboza     /* Add our CPU boolean options too */
185aeb2bc59SDaniel Henrique Barboza     riscv_obj_add_qdict_prop(obj, qdict_out, "mmu");
186aeb2bc59SDaniel Henrique Barboza     riscv_obj_add_qdict_prop(obj, qdict_out, "pmp");
187aeb2bc59SDaniel Henrique Barboza 
188aeb2bc59SDaniel Henrique Barboza     if (!qdict_size(qdict_out)) {
189aeb2bc59SDaniel Henrique Barboza         qobject_unref(qdict_out);
190aeb2bc59SDaniel Henrique Barboza     } else {
191aeb2bc59SDaniel Henrique Barboza         expansion_info->model->props = QOBJECT(qdict_out);
192aeb2bc59SDaniel Henrique Barboza     }
193aeb2bc59SDaniel Henrique Barboza 
194aeb2bc59SDaniel Henrique Barboza     object_unref(obj);
195aeb2bc59SDaniel Henrique Barboza 
196aeb2bc59SDaniel Henrique Barboza     return expansion_info;
197aeb2bc59SDaniel Henrique Barboza }
198