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/qobject-input-visitor.h" 321df4f540SDaniel Henrique Barboza #include "qapi/visitor.h" 33aeb2bc59SDaniel Henrique Barboza #include "qom/qom-qobject.h" 34*32cad1ffSPhilippe Mathieu-Daudé #include "system/kvm.h" 35*32cad1ffSPhilippe Mathieu-Daudé #include "system/tcg.h" 36c0177f91SDaniel Henrique Barboza #include "cpu-qom.h" 37aeb2bc59SDaniel Henrique Barboza #include "cpu.h" 38c0177f91SDaniel Henrique Barboza 39c0177f91SDaniel Henrique Barboza static void riscv_cpu_add_definition(gpointer data, gpointer user_data) 40c0177f91SDaniel Henrique Barboza { 41c0177f91SDaniel Henrique Barboza ObjectClass *oc = data; 42c0177f91SDaniel Henrique Barboza CpuDefinitionInfoList **cpu_list = user_data; 43c0177f91SDaniel Henrique Barboza CpuDefinitionInfo *info = g_malloc0(sizeof(*info)); 44c0177f91SDaniel Henrique Barboza const char *typename = object_class_get_name(oc); 459e1a30d3SDaniel Henrique Barboza ObjectClass *dyn_class; 46c0177f91SDaniel Henrique Barboza 474b26aa9fSGavin Shan info->name = cpu_model_from_type(typename); 48c0177f91SDaniel Henrique Barboza info->q_typename = g_strdup(typename); 49c0177f91SDaniel Henrique Barboza 509e1a30d3SDaniel Henrique Barboza dyn_class = object_class_dynamic_cast(oc, TYPE_RISCV_DYNAMIC_CPU); 519e1a30d3SDaniel Henrique Barboza info->q_static = dyn_class == NULL; 529e1a30d3SDaniel Henrique Barboza 53c0177f91SDaniel Henrique Barboza QAPI_LIST_PREPEND(*cpu_list, info); 54c0177f91SDaniel Henrique Barboza } 55c0177f91SDaniel Henrique Barboza 56c0177f91SDaniel Henrique Barboza CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp) 57c0177f91SDaniel Henrique Barboza { 58c0177f91SDaniel Henrique Barboza CpuDefinitionInfoList *cpu_list = NULL; 59c0177f91SDaniel Henrique Barboza GSList *list = object_class_get_list(TYPE_RISCV_CPU, false); 60c0177f91SDaniel Henrique Barboza 61c0177f91SDaniel Henrique Barboza g_slist_foreach(list, riscv_cpu_add_definition, &cpu_list); 62c0177f91SDaniel Henrique Barboza g_slist_free(list); 63c0177f91SDaniel Henrique Barboza 64c0177f91SDaniel Henrique Barboza return cpu_list; 65c0177f91SDaniel Henrique Barboza } 66aeb2bc59SDaniel Henrique Barboza 67a3abecbeSDaniel Henrique Barboza static void riscv_check_if_cpu_available(RISCVCPU *cpu, Error **errp) 68a3abecbeSDaniel Henrique Barboza { 69a3abecbeSDaniel Henrique Barboza if (!riscv_cpu_accelerator_compatible(cpu)) { 70a3abecbeSDaniel Henrique Barboza g_autofree char *name = riscv_cpu_get_name(cpu); 71a3abecbeSDaniel Henrique Barboza const char *accel = kvm_enabled() ? "kvm" : "tcg"; 72a3abecbeSDaniel Henrique Barboza 73a3abecbeSDaniel Henrique Barboza error_setg(errp, "'%s' CPU not available with %s", name, accel); 74a3abecbeSDaniel Henrique Barboza return; 75a3abecbeSDaniel Henrique Barboza } 76a3abecbeSDaniel Henrique Barboza } 77a3abecbeSDaniel Henrique Barboza 78aeb2bc59SDaniel Henrique Barboza static void riscv_obj_add_qdict_prop(Object *obj, QDict *qdict_out, 79aeb2bc59SDaniel Henrique Barboza const char *name) 80aeb2bc59SDaniel Henrique Barboza { 81aeb2bc59SDaniel Henrique Barboza ObjectProperty *prop = object_property_find(obj, name); 82aeb2bc59SDaniel Henrique Barboza 83aeb2bc59SDaniel Henrique Barboza if (prop) { 84aeb2bc59SDaniel Henrique Barboza QObject *value; 85aeb2bc59SDaniel Henrique Barboza 86aeb2bc59SDaniel Henrique Barboza assert(prop->get); 87aeb2bc59SDaniel Henrique Barboza value = object_property_get_qobject(obj, name, &error_abort); 88aeb2bc59SDaniel Henrique Barboza 89aeb2bc59SDaniel Henrique Barboza qdict_put_obj(qdict_out, name, value); 90aeb2bc59SDaniel Henrique Barboza } 91aeb2bc59SDaniel Henrique Barboza } 92aeb2bc59SDaniel Henrique Barboza 93aeb2bc59SDaniel Henrique Barboza static void riscv_obj_add_multiext_props(Object *obj, QDict *qdict_out, 94aeb2bc59SDaniel Henrique Barboza const RISCVCPUMultiExtConfig *arr) 95aeb2bc59SDaniel Henrique Barboza { 96aeb2bc59SDaniel Henrique Barboza for (int i = 0; arr[i].name != NULL; i++) { 97aeb2bc59SDaniel Henrique Barboza riscv_obj_add_qdict_prop(obj, qdict_out, arr[i].name); 98aeb2bc59SDaniel Henrique Barboza } 99aeb2bc59SDaniel Henrique Barboza } 100aeb2bc59SDaniel Henrique Barboza 101a8815483SDaniel Henrique Barboza static void riscv_obj_add_named_feats_qdict(Object *obj, QDict *qdict_out) 102a8815483SDaniel Henrique Barboza { 103a8815483SDaniel Henrique Barboza const RISCVCPUMultiExtConfig *named_cfg; 104a8815483SDaniel Henrique Barboza RISCVCPU *cpu = RISCV_CPU(obj); 105a8815483SDaniel Henrique Barboza QObject *value; 106a8815483SDaniel Henrique Barboza bool flag_val; 107a8815483SDaniel Henrique Barboza 108a8815483SDaniel Henrique Barboza for (int i = 0; riscv_cpu_named_features[i].name != NULL; i++) { 109a8815483SDaniel Henrique Barboza named_cfg = &riscv_cpu_named_features[i]; 110a8815483SDaniel Henrique Barboza flag_val = isa_ext_is_enabled(cpu, named_cfg->offset); 111a8815483SDaniel Henrique Barboza value = QOBJECT(qbool_from_bool(flag_val)); 112a8815483SDaniel Henrique Barboza 113a8815483SDaniel Henrique Barboza qdict_put_obj(qdict_out, named_cfg->name, value); 114a8815483SDaniel Henrique Barboza } 115a8815483SDaniel Henrique Barboza } 116a8815483SDaniel Henrique Barboza 1176394b676SDaniel Henrique Barboza static void riscv_obj_add_profiles_qdict(Object *obj, QDict *qdict_out) 1186394b676SDaniel Henrique Barboza { 1196394b676SDaniel Henrique Barboza RISCVCPUProfile *profile; 1206394b676SDaniel Henrique Barboza QObject *value; 1216394b676SDaniel Henrique Barboza 1226394b676SDaniel Henrique Barboza for (int i = 0; riscv_profiles[i] != NULL; i++) { 1236394b676SDaniel Henrique Barboza profile = riscv_profiles[i]; 1246394b676SDaniel Henrique Barboza value = QOBJECT(qbool_from_bool(profile->enabled)); 1256394b676SDaniel Henrique Barboza 1266394b676SDaniel Henrique Barboza qdict_put_obj(qdict_out, profile->name, value); 1276394b676SDaniel Henrique Barboza } 1286394b676SDaniel Henrique Barboza } 1296394b676SDaniel Henrique Barboza 1301df4f540SDaniel Henrique Barboza static void riscv_cpuobj_validate_qdict_in(Object *obj, QObject *props, 1318934643aSMarkus Armbruster const char *props_arg_name, 1321df4f540SDaniel Henrique Barboza Error **errp) 1331df4f540SDaniel Henrique Barboza { 134ef6783d3SMarkus Armbruster const QDict *qdict_in; 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); 1408934643aSMarkus Armbruster if (!visit_start_struct(visitor, props_arg_name, NULL, 0, &local_err)) { 1411df4f540SDaniel Henrique Barboza goto err; 1421df4f540SDaniel Henrique Barboza } 1431df4f540SDaniel Henrique Barboza 144ef6783d3SMarkus Armbruster qdict_in = qobject_to(QDict, props); 1451df4f540SDaniel Henrique Barboza for (qe = qdict_first(qdict_in); qe; qe = qdict_next(qdict_in, qe)) { 1461df4f540SDaniel Henrique Barboza object_property_find_err(obj, qe->key, &local_err); 1471df4f540SDaniel Henrique Barboza if (local_err) { 1481df4f540SDaniel Henrique Barboza goto err; 1491df4f540SDaniel Henrique Barboza } 1501df4f540SDaniel Henrique Barboza 1511df4f540SDaniel Henrique Barboza object_property_set(obj, qe->key, visitor, &local_err); 1521df4f540SDaniel Henrique Barboza if (local_err) { 1531df4f540SDaniel Henrique Barboza goto err; 1541df4f540SDaniel Henrique Barboza } 1551df4f540SDaniel Henrique Barboza } 1561df4f540SDaniel Henrique Barboza 1571df4f540SDaniel Henrique Barboza visit_check_struct(visitor, &local_err); 1581df4f540SDaniel Henrique Barboza if (local_err) { 1591df4f540SDaniel Henrique Barboza goto err; 1601df4f540SDaniel Henrique Barboza } 1611df4f540SDaniel Henrique Barboza 1621df4f540SDaniel Henrique Barboza visit_end_struct(visitor, NULL); 1631df4f540SDaniel Henrique Barboza 1641df4f540SDaniel Henrique Barboza err: 1651df4f540SDaniel Henrique Barboza error_propagate(errp, local_err); 1661df4f540SDaniel Henrique Barboza visit_free(visitor); 1671df4f540SDaniel Henrique Barboza } 1681df4f540SDaniel Henrique Barboza 169aeb2bc59SDaniel Henrique Barboza CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type, 170aeb2bc59SDaniel Henrique Barboza CpuModelInfo *model, 171aeb2bc59SDaniel Henrique Barboza Error **errp) 172aeb2bc59SDaniel Henrique Barboza { 173aeb2bc59SDaniel Henrique Barboza CpuModelExpansionInfo *expansion_info; 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 191aeb2bc59SDaniel Henrique Barboza obj = object_new(object_class_get_name(oc)); 192aeb2bc59SDaniel Henrique Barboza 193a3abecbeSDaniel Henrique Barboza riscv_check_if_cpu_available(RISCV_CPU(obj), &local_err); 194a3abecbeSDaniel Henrique Barboza if (local_err != NULL) { 195a3abecbeSDaniel Henrique Barboza error_propagate(errp, local_err); 196a3abecbeSDaniel Henrique Barboza object_unref(obj); 197a3abecbeSDaniel Henrique Barboza return NULL; 198a3abecbeSDaniel Henrique Barboza } 199a3abecbeSDaniel Henrique Barboza 200ef6783d3SMarkus Armbruster if (model->props) { 2018934643aSMarkus Armbruster riscv_cpuobj_validate_qdict_in(obj, model->props, "model.props", 2028934643aSMarkus Armbruster &local_err); 2031df4f540SDaniel Henrique Barboza if (local_err) { 2041df4f540SDaniel Henrique Barboza error_propagate(errp, local_err); 2051df4f540SDaniel Henrique Barboza object_unref(obj); 2061df4f540SDaniel Henrique Barboza return NULL; 2071df4f540SDaniel Henrique Barboza } 2081df4f540SDaniel Henrique Barboza } 2091df4f540SDaniel Henrique Barboza 210a8815483SDaniel Henrique Barboza riscv_cpu_finalize_features(RISCV_CPU(obj), &local_err); 211a8815483SDaniel Henrique Barboza if (local_err) { 212a8815483SDaniel Henrique Barboza error_propagate(errp, local_err); 213a8815483SDaniel Henrique Barboza object_unref(obj); 214a8815483SDaniel Henrique Barboza return NULL; 215a8815483SDaniel Henrique Barboza } 216a8815483SDaniel Henrique Barboza 217aeb2bc59SDaniel Henrique Barboza expansion_info = g_new0(CpuModelExpansionInfo, 1); 218aeb2bc59SDaniel Henrique Barboza expansion_info->model = g_malloc0(sizeof(*expansion_info->model)); 219aeb2bc59SDaniel Henrique Barboza expansion_info->model->name = g_strdup(model->name); 220aeb2bc59SDaniel Henrique Barboza 221aeb2bc59SDaniel Henrique Barboza qdict_out = qdict_new(); 222aeb2bc59SDaniel Henrique Barboza 223aeb2bc59SDaniel Henrique Barboza riscv_obj_add_multiext_props(obj, qdict_out, riscv_cpu_extensions); 224aeb2bc59SDaniel Henrique Barboza riscv_obj_add_multiext_props(obj, qdict_out, riscv_cpu_experimental_exts); 225aeb2bc59SDaniel Henrique Barboza riscv_obj_add_multiext_props(obj, qdict_out, riscv_cpu_vendor_exts); 226a8815483SDaniel Henrique Barboza riscv_obj_add_named_feats_qdict(obj, qdict_out); 2276394b676SDaniel Henrique Barboza riscv_obj_add_profiles_qdict(obj, qdict_out); 228aeb2bc59SDaniel Henrique Barboza 229aeb2bc59SDaniel Henrique Barboza /* Add our CPU boolean options too */ 230aeb2bc59SDaniel Henrique Barboza riscv_obj_add_qdict_prop(obj, qdict_out, "mmu"); 231aeb2bc59SDaniel Henrique Barboza riscv_obj_add_qdict_prop(obj, qdict_out, "pmp"); 232aeb2bc59SDaniel Henrique Barboza 233aeb2bc59SDaniel Henrique Barboza if (!qdict_size(qdict_out)) { 234aeb2bc59SDaniel Henrique Barboza qobject_unref(qdict_out); 235aeb2bc59SDaniel Henrique Barboza } else { 236aeb2bc59SDaniel Henrique Barboza expansion_info->model->props = QOBJECT(qdict_out); 237aeb2bc59SDaniel Henrique Barboza } 238aeb2bc59SDaniel Henrique Barboza 239aeb2bc59SDaniel Henrique Barboza object_unref(obj); 240aeb2bc59SDaniel Henrique Barboza 241aeb2bc59SDaniel Henrique Barboza return expansion_info; 242aeb2bc59SDaniel Henrique Barboza } 243