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 bool supported = false; 141 142 if (!strcmp(model->name, "host") || !strcmp(model->name, "max")) { 143 /* These are kvmarm's recommended cpu types */ 144 supported = true; 145 } else if (current_machine->cpu_type) { 146 const char *cpu_type = current_machine->cpu_type; 147 int len = strlen(cpu_type) - strlen(ARM_CPU_TYPE_SUFFIX); 148 149 if (strlen(model->name) == len && 150 !strncmp(model->name, cpu_type, len)) { 151 /* KVM is enabled and we're using this type, so it works. */ 152 supported = true; 153 } 154 } 155 if (!supported) { 156 error_setg(errp, "We cannot guarantee the CPU type '%s' works " 157 "with KVM on this host", model->name); 158 return NULL; 159 } 160 } 161 162 if (model->props) { 163 qdict_in = qobject_to(QDict, model->props); 164 if (!qdict_in) { 165 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, "props", "dict"); 166 return NULL; 167 } 168 } 169 170 obj = object_new(object_class_get_name(oc)); 171 172 if (qdict_in) { 173 Visitor *visitor; 174 Error *err = NULL; 175 176 visitor = qobject_input_visitor_new(model->props); 177 if (!visit_start_struct(visitor, NULL, NULL, 0, &err)) { 178 visit_free(visitor); 179 object_unref(obj); 180 error_propagate(errp, err); 181 return NULL; 182 } 183 184 i = 0; 185 while ((name = cpu_model_advertised_features[i++]) != NULL) { 186 if (qdict_get(qdict_in, name)) { 187 object_property_set(obj, visitor, name, &err); 188 if (err) { 189 break; 190 } 191 } 192 } 193 194 if (!err) { 195 visit_check_struct(visitor, &err); 196 } 197 if (!err) { 198 arm_cpu_finalize_features(ARM_CPU(obj), &err); 199 } 200 visit_end_struct(visitor, NULL); 201 visit_free(visitor); 202 if (err) { 203 object_unref(obj); 204 error_propagate(errp, err); 205 return NULL; 206 } 207 } else { 208 arm_cpu_finalize_features(ARM_CPU(obj), &error_abort); 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 QObject *value; 222 223 assert(prop->get); 224 value = object_property_get_qobject(obj, name, &error_abort); 225 226 qdict_put_obj(qdict_out, name, value); 227 } 228 } 229 230 if (!qdict_size(qdict_out)) { 231 qobject_unref(qdict_out); 232 } else { 233 expansion_info->model->props = QOBJECT(qdict_out); 234 expansion_info->model->has_props = true; 235 } 236 237 object_unref(obj); 238 239 return expansion_info; 240 } 241