xref: /openbmc/qemu/target/riscv/riscv-qmp-cmds.c (revision aeb2bc59)
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-target.h"
29 #include "qapi/qmp/qdict.h"
30 #include "qom/qom-qobject.h"
31 #include "cpu-qom.h"
32 #include "cpu.h"
33 
34 static void riscv_cpu_add_definition(gpointer data, gpointer user_data)
35 {
36     ObjectClass *oc = data;
37     CpuDefinitionInfoList **cpu_list = user_data;
38     CpuDefinitionInfo *info = g_malloc0(sizeof(*info));
39     const char *typename = object_class_get_name(oc);
40     ObjectClass *dyn_class;
41 
42     info->name = g_strndup(typename,
43                            strlen(typename) - strlen("-" TYPE_RISCV_CPU));
44     info->q_typename = g_strdup(typename);
45 
46     dyn_class = object_class_dynamic_cast(oc, TYPE_RISCV_DYNAMIC_CPU);
47     info->q_static = dyn_class == NULL;
48 
49     QAPI_LIST_PREPEND(*cpu_list, info);
50 }
51 
52 CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
53 {
54     CpuDefinitionInfoList *cpu_list = NULL;
55     GSList *list = object_class_get_list(TYPE_RISCV_CPU, false);
56 
57     g_slist_foreach(list, riscv_cpu_add_definition, &cpu_list);
58     g_slist_free(list);
59 
60     return cpu_list;
61 }
62 
63 static void riscv_obj_add_qdict_prop(Object *obj, QDict *qdict_out,
64                                      const char *name)
65 {
66     ObjectProperty *prop = object_property_find(obj, name);
67 
68     if (prop) {
69         QObject *value;
70 
71         assert(prop->get);
72         value = object_property_get_qobject(obj, name, &error_abort);
73 
74         qdict_put_obj(qdict_out, name, value);
75     }
76 }
77 
78 static void riscv_obj_add_multiext_props(Object *obj, QDict *qdict_out,
79                                          const RISCVCPUMultiExtConfig *arr)
80 {
81     for (int i = 0; arr[i].name != NULL; i++) {
82         riscv_obj_add_qdict_prop(obj, qdict_out, arr[i].name);
83     }
84 }
85 
86 CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type,
87                                                      CpuModelInfo *model,
88                                                      Error **errp)
89 {
90     CpuModelExpansionInfo *expansion_info;
91     QDict *qdict_out;
92     ObjectClass *oc;
93     Object *obj;
94 
95     if (type != CPU_MODEL_EXPANSION_TYPE_FULL) {
96         error_setg(errp, "The requested expansion type is not supported");
97         return NULL;
98     }
99 
100     oc = cpu_class_by_name(TYPE_RISCV_CPU, model->name);
101     if (!oc) {
102         error_setg(errp, "The CPU type '%s' is not a known RISC-V CPU type",
103                    model->name);
104         return NULL;
105     }
106 
107     obj = object_new(object_class_get_name(oc));
108 
109     expansion_info = g_new0(CpuModelExpansionInfo, 1);
110     expansion_info->model = g_malloc0(sizeof(*expansion_info->model));
111     expansion_info->model->name = g_strdup(model->name);
112 
113     qdict_out = qdict_new();
114 
115     riscv_obj_add_multiext_props(obj, qdict_out, riscv_cpu_extensions);
116     riscv_obj_add_multiext_props(obj, qdict_out, riscv_cpu_experimental_exts);
117     riscv_obj_add_multiext_props(obj, qdict_out, riscv_cpu_vendor_exts);
118 
119     /* Add our CPU boolean options too */
120     riscv_obj_add_qdict_prop(obj, qdict_out, "mmu");
121     riscv_obj_add_qdict_prop(obj, qdict_out, "pmp");
122 
123     if (!qdict_size(qdict_out)) {
124         qobject_unref(qdict_out);
125     } else {
126         expansion_info->model->props = QOBJECT(qdict_out);
127     }
128 
129     object_unref(obj);
130 
131     return expansion_info;
132 }
133