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