xref: /qemu/target/riscv/riscv-qmp-cmds.c (revision 3b916140043e2757dd8d51ec641a6885e960e6ca)
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/qbool.h"
30  #include "qapi/qmp/qdict.h"
31  #include "qapi/qmp/qerror.h"
32  #include "qapi/qobject-input-visitor.h"
33  #include "qapi/visitor.h"
34  #include "qom/qom-qobject.h"
35  #include "sysemu/kvm.h"
36  #include "sysemu/tcg.h"
37  #include "cpu-qom.h"
38  #include "cpu.h"
39  
40  static void riscv_cpu_add_definition(gpointer data, gpointer user_data)
41  {
42      ObjectClass *oc = data;
43      CpuDefinitionInfoList **cpu_list = user_data;
44      CpuDefinitionInfo *info = g_malloc0(sizeof(*info));
45      const char *typename = object_class_get_name(oc);
46      ObjectClass *dyn_class;
47  
48      info->name = cpu_model_from_type(typename);
49      info->q_typename = g_strdup(typename);
50  
51      dyn_class = object_class_dynamic_cast(oc, TYPE_RISCV_DYNAMIC_CPU);
52      info->q_static = dyn_class == NULL;
53  
54      QAPI_LIST_PREPEND(*cpu_list, info);
55  }
56  
57  CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
58  {
59      CpuDefinitionInfoList *cpu_list = NULL;
60      GSList *list = object_class_get_list(TYPE_RISCV_CPU, false);
61  
62      g_slist_foreach(list, riscv_cpu_add_definition, &cpu_list);
63      g_slist_free(list);
64  
65      return cpu_list;
66  }
67  
68  static void riscv_check_if_cpu_available(RISCVCPU *cpu, Error **errp)
69  {
70      if (!riscv_cpu_accelerator_compatible(cpu)) {
71          g_autofree char *name = riscv_cpu_get_name(cpu);
72          const char *accel = kvm_enabled() ? "kvm" : "tcg";
73  
74          error_setg(errp, "'%s' CPU not available with %s", name, accel);
75          return;
76      }
77  }
78  
79  static void riscv_obj_add_qdict_prop(Object *obj, QDict *qdict_out,
80                                       const char *name)
81  {
82      ObjectProperty *prop = object_property_find(obj, name);
83  
84      if (prop) {
85          QObject *value;
86  
87          assert(prop->get);
88          value = object_property_get_qobject(obj, name, &error_abort);
89  
90          qdict_put_obj(qdict_out, name, value);
91      }
92  }
93  
94  static void riscv_obj_add_multiext_props(Object *obj, QDict *qdict_out,
95                                           const RISCVCPUMultiExtConfig *arr)
96  {
97      for (int i = 0; arr[i].name != NULL; i++) {
98          riscv_obj_add_qdict_prop(obj, qdict_out, arr[i].name);
99      }
100  }
101  
102  static void riscv_obj_add_named_feats_qdict(Object *obj, QDict *qdict_out)
103  {
104      const RISCVCPUMultiExtConfig *named_cfg;
105      RISCVCPU *cpu = RISCV_CPU(obj);
106      QObject *value;
107      bool flag_val;
108  
109      for (int i = 0; riscv_cpu_named_features[i].name != NULL; i++) {
110          named_cfg = &riscv_cpu_named_features[i];
111          flag_val = isa_ext_is_enabled(cpu, named_cfg->offset);
112          value = QOBJECT(qbool_from_bool(flag_val));
113  
114          qdict_put_obj(qdict_out, named_cfg->name, value);
115      }
116  }
117  
118  static void riscv_obj_add_profiles_qdict(Object *obj, QDict *qdict_out)
119  {
120      RISCVCPUProfile *profile;
121      QObject *value;
122  
123      for (int i = 0; riscv_profiles[i] != NULL; i++) {
124          profile = riscv_profiles[i];
125          value = QOBJECT(qbool_from_bool(profile->enabled));
126  
127          qdict_put_obj(qdict_out, profile->name, value);
128      }
129  }
130  
131  static void riscv_cpuobj_validate_qdict_in(Object *obj, QObject *props,
132                                             const QDict *qdict_in,
133                                             Error **errp)
134  {
135      const QDictEntry *qe;
136      Visitor *visitor;
137      Error *local_err = NULL;
138  
139      visitor = qobject_input_visitor_new(props);
140      if (!visit_start_struct(visitor, NULL, NULL, 0, &local_err)) {
141          goto err;
142      }
143  
144      for (qe = qdict_first(qdict_in); qe; qe = qdict_next(qdict_in, qe)) {
145          object_property_find_err(obj, qe->key, &local_err);
146          if (local_err) {
147              goto err;
148          }
149  
150          object_property_set(obj, qe->key, visitor, &local_err);
151          if (local_err) {
152              goto err;
153          }
154      }
155  
156      visit_check_struct(visitor, &local_err);
157      if (local_err) {
158          goto err;
159      }
160  
161      visit_end_struct(visitor, NULL);
162  
163  err:
164      error_propagate(errp, local_err);
165      visit_free(visitor);
166  }
167  
168  CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type,
169                                                       CpuModelInfo *model,
170                                                       Error **errp)
171  {
172      CpuModelExpansionInfo *expansion_info;
173      const QDict *qdict_in = NULL;
174      QDict *qdict_out;
175      ObjectClass *oc;
176      Object *obj;
177      Error *local_err = NULL;
178  
179      if (type != CPU_MODEL_EXPANSION_TYPE_FULL) {
180          error_setg(errp, "The requested expansion type is not supported");
181          return NULL;
182      }
183  
184      oc = cpu_class_by_name(TYPE_RISCV_CPU, model->name);
185      if (!oc) {
186          error_setg(errp, "The CPU type '%s' is not a known RISC-V CPU type",
187                     model->name);
188          return NULL;
189      }
190  
191      if (model->props) {
192          qdict_in = qobject_to(QDict, model->props);
193          if (!qdict_in) {
194              error_setg(errp, QERR_INVALID_PARAMETER_TYPE, "props", "dict");
195              return NULL;
196          }
197      }
198  
199      obj = object_new(object_class_get_name(oc));
200  
201      riscv_check_if_cpu_available(RISCV_CPU(obj), &local_err);
202      if (local_err != NULL) {
203          error_propagate(errp, local_err);
204          object_unref(obj);
205          return NULL;
206      }
207  
208      if (qdict_in) {
209          riscv_cpuobj_validate_qdict_in(obj, model->props, qdict_in,
210                                         &local_err);
211          if (local_err) {
212              error_propagate(errp, local_err);
213              object_unref(obj);
214              return NULL;
215          }
216      }
217  
218      riscv_cpu_finalize_features(RISCV_CPU(obj), &local_err);
219      if (local_err) {
220          error_propagate(errp, local_err);
221          object_unref(obj);
222          return NULL;
223      }
224  
225      expansion_info = g_new0(CpuModelExpansionInfo, 1);
226      expansion_info->model = g_malloc0(sizeof(*expansion_info->model));
227      expansion_info->model->name = g_strdup(model->name);
228  
229      qdict_out = qdict_new();
230  
231      riscv_obj_add_multiext_props(obj, qdict_out, riscv_cpu_extensions);
232      riscv_obj_add_multiext_props(obj, qdict_out, riscv_cpu_experimental_exts);
233      riscv_obj_add_multiext_props(obj, qdict_out, riscv_cpu_vendor_exts);
234      riscv_obj_add_named_feats_qdict(obj, qdict_out);
235      riscv_obj_add_profiles_qdict(obj, qdict_out);
236  
237      /* Add our CPU boolean options too */
238      riscv_obj_add_qdict_prop(obj, qdict_out, "mmu");
239      riscv_obj_add_qdict_prop(obj, qdict_out, "pmp");
240  
241      if (!qdict_size(qdict_out)) {
242          qobject_unref(qdict_out);
243      } else {
244          expansion_info->model->props = QOBJECT(qdict_out);
245      }
246  
247      object_unref(obj);
248  
249      return expansion_info;
250  }
251