1 /* 2 * QEMU monitor.c for ARM. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a copy 5 * of this software and associated documentation files (the "Software"), to deal 6 * in the Software without restriction, including without limitation the rights 7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 * copies of the Software, and to permit persons to whom the Software is 9 * furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included in 12 * all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 * THE SOFTWARE. 21 */ 22 23 #include "qemu/osdep.h" 24 #include "hw/boards.h" 25 #include "kvm_arm.h" 26 #include "qapi/error.h" 27 #include "qapi/visitor.h" 28 #include "qapi/qobject-input-visitor.h" 29 #include "qapi/qapi-commands-machine-target.h" 30 #include "qapi/qapi-commands-misc-target.h" 31 #include "qapi/qmp/qerror.h" 32 #include "qapi/qmp/qdict.h" 33 #include "qom/qom-qobject.h" 34 35 static GICCapability *gic_cap_new(int version) 36 { 37 GICCapability *cap = g_new0(GICCapability, 1); 38 cap->version = version; 39 /* by default, support none */ 40 cap->emulated = false; 41 cap->kernel = false; 42 return cap; 43 } 44 45 static GICCapabilityList *gic_cap_list_add(GICCapabilityList *head, 46 GICCapability *cap) 47 { 48 GICCapabilityList *item = g_new0(GICCapabilityList, 1); 49 item->value = cap; 50 item->next = head; 51 return item; 52 } 53 54 static inline void gic_cap_kvm_probe(GICCapability *v2, GICCapability *v3) 55 { 56 #ifdef CONFIG_KVM 57 int fdarray[3]; 58 59 if (!kvm_arm_create_scratch_host_vcpu(NULL, fdarray, NULL)) { 60 return; 61 } 62 63 /* Test KVM GICv2 */ 64 if (kvm_device_supported(fdarray[1], KVM_DEV_TYPE_ARM_VGIC_V2)) { 65 v2->kernel = true; 66 } 67 68 /* Test KVM GICv3 */ 69 if (kvm_device_supported(fdarray[1], KVM_DEV_TYPE_ARM_VGIC_V3)) { 70 v3->kernel = true; 71 } 72 73 kvm_arm_destroy_scratch_host_vcpu(fdarray); 74 #endif 75 } 76 77 GICCapabilityList *qmp_query_gic_capabilities(Error **errp) 78 { 79 GICCapabilityList *head = NULL; 80 GICCapability *v2 = gic_cap_new(2), *v3 = gic_cap_new(3); 81 82 v2->emulated = true; 83 v3->emulated = true; 84 85 gic_cap_kvm_probe(v2, v3); 86 87 head = gic_cap_list_add(head, v2); 88 head = gic_cap_list_add(head, v3); 89 90 return head; 91 } 92 93 QEMU_BUILD_BUG_ON(ARM_MAX_VQ > 16); 94 95 /* 96 * These are cpu model features we want to advertise. The order here 97 * matters as this is the order in which qmp_query_cpu_model_expansion 98 * will attempt to set them. If there are dependencies between features, 99 * then the order that considers those dependencies must be used. 100 */ 101 static const char *cpu_model_advertised_features[] = { 102 "aarch64", "pmu", "sve", 103 "sve128", "sve256", "sve384", "sve512", 104 "sve640", "sve768", "sve896", "sve1024", "sve1152", "sve1280", 105 "sve1408", "sve1536", "sve1664", "sve1792", "sve1920", "sve2048", 106 "kvm-no-adjvtime", 107 NULL 108 }; 109 110 CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type, 111 CpuModelInfo *model, 112 Error **errp) 113 { 114 CpuModelExpansionInfo *expansion_info; 115 const QDict *qdict_in = NULL; 116 QDict *qdict_out; 117 ObjectClass *oc; 118 Object *obj; 119 const char *name; 120 int i; 121 122 if (type != CPU_MODEL_EXPANSION_TYPE_FULL) { 123 error_setg(errp, "The requested expansion type is not supported"); 124 return NULL; 125 } 126 127 if (!kvm_enabled() && !strcmp(model->name, "host")) { 128 error_setg(errp, "The CPU type '%s' requires KVM", model->name); 129 return NULL; 130 } 131 132 oc = cpu_class_by_name(TYPE_ARM_CPU, model->name); 133 if (!oc) { 134 error_setg(errp, "The CPU type '%s' is not a recognized ARM CPU type", 135 model->name); 136 return NULL; 137 } 138 139 if (kvm_enabled()) { 140 const char *cpu_type = current_machine->cpu_type; 141 int len = strlen(cpu_type) - strlen(ARM_CPU_TYPE_SUFFIX); 142 bool supported = false; 143 144 if (!strcmp(model->name, "host") || !strcmp(model->name, "max")) { 145 /* These are kvmarm's recommended cpu types */ 146 supported = true; 147 } else if (strlen(model->name) == len && 148 !strncmp(model->name, cpu_type, len)) { 149 /* KVM is enabled and we're using this type, so it works. */ 150 supported = true; 151 } 152 if (!supported) { 153 error_setg(errp, "We cannot guarantee the CPU type '%s' works " 154 "with KVM on this host", model->name); 155 return NULL; 156 } 157 } 158 159 if (model->props) { 160 qdict_in = qobject_to(QDict, model->props); 161 if (!qdict_in) { 162 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, "props", "dict"); 163 return NULL; 164 } 165 } 166 167 obj = object_new(object_class_get_name(oc)); 168 169 if (qdict_in) { 170 Visitor *visitor; 171 Error *err = NULL; 172 173 visitor = qobject_input_visitor_new(model->props); 174 visit_start_struct(visitor, NULL, NULL, 0, &err); 175 if (err) { 176 visit_free(visitor); 177 object_unref(obj); 178 error_propagate(errp, err); 179 return NULL; 180 } 181 182 i = 0; 183 while ((name = cpu_model_advertised_features[i++]) != NULL) { 184 if (qdict_get(qdict_in, name)) { 185 object_property_set(obj, visitor, name, &err); 186 if (err) { 187 break; 188 } 189 } 190 } 191 192 if (!err) { 193 visit_check_struct(visitor, &err); 194 } 195 if (!err) { 196 arm_cpu_finalize_features(ARM_CPU(obj), &err); 197 } 198 visit_end_struct(visitor, NULL); 199 visit_free(visitor); 200 if (err) { 201 object_unref(obj); 202 error_propagate(errp, err); 203 return NULL; 204 } 205 } else { 206 Error *err = NULL; 207 arm_cpu_finalize_features(ARM_CPU(obj), &err); 208 assert(err == NULL); 209 } 210 211 expansion_info = g_new0(CpuModelExpansionInfo, 1); 212 expansion_info->model = g_malloc0(sizeof(*expansion_info->model)); 213 expansion_info->model->name = g_strdup(model->name); 214 215 qdict_out = qdict_new(); 216 217 i = 0; 218 while ((name = cpu_model_advertised_features[i++]) != NULL) { 219 ObjectProperty *prop = object_property_find(obj, name, NULL); 220 if (prop) { 221 Error *err = NULL; 222 QObject *value; 223 224 assert(prop->get); 225 value = object_property_get_qobject(obj, name, &err); 226 assert(!err); 227 228 qdict_put_obj(qdict_out, name, value); 229 } 230 } 231 232 if (!qdict_size(qdict_out)) { 233 qobject_unref(qdict_out); 234 } else { 235 expansion_info->model->props = QOBJECT(qdict_out); 236 expansion_info->model->has_props = true; 237 } 238 239 object_unref(obj); 240 241 return expansion_info; 242 } 243