]>
Commit | Line | Data |
---|---|---|
ae50a770 PX |
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 | */ | |
112ed241 | 22 | |
ae50a770 | 23 | #include "qemu/osdep.h" |
e19afd56 | 24 | #include "hw/boards.h" |
db31e49a | 25 | #include "kvm_arm.h" |
e19afd56 AJ |
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" | |
b0227cdb | 30 | #include "qapi/qapi-commands-misc-target.h" |
e19afd56 AJ |
31 | #include "qapi/qmp/qdict.h" |
32 | #include "qom/qom-qobject.h" | |
db31e49a PX |
33 | |
34 | static GICCapability *gic_cap_new(int version) | |
35 | { | |
36 | GICCapability *cap = g_new0(GICCapability, 1); | |
37 | cap->version = version; | |
38 | /* by default, support none */ | |
39 | cap->emulated = false; | |
40 | cap->kernel = false; | |
41 | return cap; | |
42 | } | |
43 | ||
db31e49a PX |
44 | static inline void gic_cap_kvm_probe(GICCapability *v2, GICCapability *v3) |
45 | { | |
46 | #ifdef CONFIG_KVM | |
47 | int fdarray[3]; | |
48 | ||
49 | if (!kvm_arm_create_scratch_host_vcpu(NULL, fdarray, NULL)) { | |
50 | return; | |
51 | } | |
52 | ||
53 | /* Test KVM GICv2 */ | |
54 | if (kvm_device_supported(fdarray[1], KVM_DEV_TYPE_ARM_VGIC_V2)) { | |
55 | v2->kernel = true; | |
56 | } | |
57 | ||
58 | /* Test KVM GICv3 */ | |
59 | if (kvm_device_supported(fdarray[1], KVM_DEV_TYPE_ARM_VGIC_V3)) { | |
60 | v3->kernel = true; | |
61 | } | |
62 | ||
63 | kvm_arm_destroy_scratch_host_vcpu(fdarray); | |
64 | #endif | |
65 | } | |
ae50a770 PX |
66 | |
67 | GICCapabilityList *qmp_query_gic_capabilities(Error **errp) | |
68 | { | |
db31e49a PX |
69 | GICCapabilityList *head = NULL; |
70 | GICCapability *v2 = gic_cap_new(2), *v3 = gic_cap_new(3); | |
71 | ||
72 | v2->emulated = true; | |
3b1a2225 | 73 | v3->emulated = true; |
db31e49a PX |
74 | |
75 | gic_cap_kvm_probe(v2, v3); | |
76 | ||
54aa3de7 EB |
77 | QAPI_LIST_PREPEND(head, v2); |
78 | QAPI_LIST_PREPEND(head, v3); | |
db31e49a PX |
79 | |
80 | return head; | |
ae50a770 | 81 | } |
e19afd56 | 82 | |
0df9142d AJ |
83 | QEMU_BUILD_BUG_ON(ARM_MAX_VQ > 16); |
84 | ||
e19afd56 AJ |
85 | /* |
86 | * These are cpu model features we want to advertise. The order here | |
87 | * matters as this is the order in which qmp_query_cpu_model_expansion | |
88 | * will attempt to set them. If there are dependencies between features, | |
89 | * then the order that considers those dependencies must be used. | |
90 | */ | |
91 | static const char *cpu_model_advertised_features[] = { | |
73234775 | 92 | "aarch64", "pmu", "sve", |
0df9142d AJ |
93 | "sve128", "sve256", "sve384", "sve512", |
94 | "sve640", "sve768", "sve896", "sve1024", "sve1152", "sve1280", | |
95 | "sve1408", "sve1536", "sve1664", "sve1792", "sve1920", "sve2048", | |
68970d1e | 96 | "kvm-no-adjvtime", "kvm-steal-time", |
399e5e71 | 97 | "pauth", "pauth-impdef", "pauth-qarma3", |
e19afd56 AJ |
98 | NULL |
99 | }; | |
100 | ||
101 | CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type, | |
102 | CpuModelInfo *model, | |
103 | Error **errp) | |
104 | { | |
105 | CpuModelExpansionInfo *expansion_info; | |
ef6783d3 | 106 | const QDict *qdict_in; |
e19afd56 AJ |
107 | QDict *qdict_out; |
108 | ObjectClass *oc; | |
109 | Object *obj; | |
110 | const char *name; | |
111 | int i; | |
112 | ||
113 | if (type != CPU_MODEL_EXPANSION_TYPE_FULL) { | |
114 | error_setg(errp, "The requested expansion type is not supported"); | |
115 | return NULL; | |
116 | } | |
117 | ||
118 | if (!kvm_enabled() && !strcmp(model->name, "host")) { | |
119 | error_setg(errp, "The CPU type '%s' requires KVM", model->name); | |
120 | return NULL; | |
121 | } | |
122 | ||
123 | oc = cpu_class_by_name(TYPE_ARM_CPU, model->name); | |
124 | if (!oc) { | |
125 | error_setg(errp, "The CPU type '%s' is not a recognized ARM CPU type", | |
126 | model->name); | |
127 | return NULL; | |
128 | } | |
129 | ||
130 | if (kvm_enabled()) { | |
e19afd56 AJ |
131 | bool supported = false; |
132 | ||
133 | if (!strcmp(model->name, "host") || !strcmp(model->name, "max")) { | |
134 | /* These are kvmarm's recommended cpu types */ | |
135 | supported = true; | |
0999a4ba LY |
136 | } else if (current_machine->cpu_type) { |
137 | const char *cpu_type = current_machine->cpu_type; | |
138 | int len = strlen(cpu_type) - strlen(ARM_CPU_TYPE_SUFFIX); | |
139 | ||
140 | if (strlen(model->name) == len && | |
141 | !strncmp(model->name, cpu_type, len)) { | |
142 | /* KVM is enabled and we're using this type, so it works. */ | |
143 | supported = true; | |
144 | } | |
e19afd56 AJ |
145 | } |
146 | if (!supported) { | |
147 | error_setg(errp, "We cannot guarantee the CPU type '%s' works " | |
148 | "with KVM on this host", model->name); | |
149 | return NULL; | |
150 | } | |
151 | } | |
152 | ||
e19afd56 AJ |
153 | obj = object_new(object_class_get_name(oc)); |
154 | ||
ef6783d3 | 155 | if (model->props) { |
e19afd56 AJ |
156 | Visitor *visitor; |
157 | Error *err = NULL; | |
158 | ||
159 | visitor = qobject_input_visitor_new(model->props); | |
8934643a | 160 | if (!visit_start_struct(visitor, "model.props", NULL, 0, errp)) { |
e19afd56 AJ |
161 | visit_free(visitor); |
162 | object_unref(obj); | |
e19afd56 AJ |
163 | return NULL; |
164 | } | |
165 | ||
ef6783d3 | 166 | qdict_in = qobject_to(QDict, model->props); |
e19afd56 AJ |
167 | i = 0; |
168 | while ((name = cpu_model_advertised_features[i++]) != NULL) { | |
169 | if (qdict_get(qdict_in, name)) { | |
778a2dc5 | 170 | if (!object_property_set(obj, name, visitor, &err)) { |
e19afd56 AJ |
171 | break; |
172 | } | |
173 | } | |
174 | } | |
175 | ||
176 | if (!err) { | |
177 | visit_check_struct(visitor, &err); | |
178 | } | |
0df9142d AJ |
179 | if (!err) { |
180 | arm_cpu_finalize_features(ARM_CPU(obj), &err); | |
181 | } | |
e19afd56 AJ |
182 | visit_end_struct(visitor, NULL); |
183 | visit_free(visitor); | |
184 | if (err) { | |
185 | object_unref(obj); | |
186 | error_propagate(errp, err); | |
187 | return NULL; | |
188 | } | |
0df9142d | 189 | } else { |
20ac582d | 190 | arm_cpu_finalize_features(ARM_CPU(obj), &error_abort); |
e19afd56 AJ |
191 | } |
192 | ||
193 | expansion_info = g_new0(CpuModelExpansionInfo, 1); | |
194 | expansion_info->model = g_malloc0(sizeof(*expansion_info->model)); | |
195 | expansion_info->model->name = g_strdup(model->name); | |
196 | ||
197 | qdict_out = qdict_new(); | |
198 | ||
199 | i = 0; | |
200 | while ((name = cpu_model_advertised_features[i++]) != NULL) { | |
efba1595 | 201 | ObjectProperty *prop = object_property_find(obj, name); |
e19afd56 | 202 | if (prop) { |
e19afd56 AJ |
203 | QObject *value; |
204 | ||
205 | assert(prop->get); | |
20ac582d | 206 | value = object_property_get_qobject(obj, name, &error_abort); |
e19afd56 AJ |
207 | |
208 | qdict_put_obj(qdict_out, name, value); | |
209 | } | |
210 | } | |
211 | ||
212 | if (!qdict_size(qdict_out)) { | |
213 | qobject_unref(qdict_out); | |
214 | } else { | |
215 | expansion_info->model->props = QOBJECT(qdict_out); | |
e19afd56 AJ |
216 | } |
217 | ||
218 | object_unref(obj); | |
219 | ||
220 | return expansion_info; | |
221 | } | |
3362f04d PMD |
222 | |
223 | static void arm_cpu_add_definition(gpointer data, gpointer user_data) | |
224 | { | |
225 | ObjectClass *oc = data; | |
226 | CpuDefinitionInfoList **cpu_list = user_data; | |
227 | CpuDefinitionInfo *info; | |
228 | const char *typename; | |
229 | ||
230 | typename = object_class_get_name(oc); | |
231 | info = g_malloc0(sizeof(*info)); | |
4b26aa9f | 232 | info->name = cpu_model_from_type(typename); |
3362f04d PMD |
233 | info->q_typename = g_strdup(typename); |
234 | ||
235 | QAPI_LIST_PREPEND(*cpu_list, info); | |
236 | } | |
237 | ||
238 | CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp) | |
239 | { | |
240 | CpuDefinitionInfoList *cpu_list = NULL; | |
241 | GSList *list; | |
242 | ||
243 | list = object_class_get_list(TYPE_ARM_CPU, false); | |
244 | g_slist_foreach(list, arm_cpu_add_definition, &cpu_list); | |
245 | g_slist_free(list); | |
246 | ||
247 | return cpu_list; | |
248 | } |