]>
Commit | Line | Data |
---|---|---|
d14d42f1 PM |
1 | /* |
2 | * QEMU AArch64 CPU | |
3 | * | |
4 | * Copyright (c) 2013 Linaro Ltd | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or | |
7 | * modify it under the terms of the GNU General Public License | |
8 | * as published by the Free Software Foundation; either version 2 | |
9 | * of the License, or (at your option) any later version. | |
10 | * | |
11 | * This program is distributed in the hope that it will be useful, | |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | * GNU General Public License for more details. | |
15 | * | |
16 | * You should have received a copy of the GNU General Public License | |
17 | * along with this program; if not, see | |
18 | * <http://www.gnu.org/licenses/gpl-2.0.html> | |
19 | */ | |
20 | ||
74c21bd0 | 21 | #include "qemu/osdep.h" |
da34e65c | 22 | #include "qapi/error.h" |
d14d42f1 | 23 | #include "cpu.h" |
0b903369 | 24 | #include "cpregs.h" |
0b8fa32f | 25 | #include "qemu/module.h" |
d14d42f1 | 26 | #include "sysemu/kvm.h" |
6ee609b7 | 27 | #include "sysemu/hvf.h" |
fcab465e FR |
28 | #include "sysemu/qtest.h" |
29 | #include "sysemu/tcg.h" | |
bab52d4b | 30 | #include "kvm_arm.h" |
dcfb1d04 | 31 | #include "hvf_arm.h" |
adf92eab | 32 | #include "qapi/visitor.h" |
eb94284d | 33 | #include "hw/qdev-properties.h" |
7c1aaf98 | 34 | #include "internals.h" |
5a534314 | 35 | #include "cpu-features.h" |
34bfe467 | 36 | #include "cpregs.h" |
eb94284d | 37 | |
0df9142d AJ |
38 | void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp) |
39 | { | |
40 | /* | |
41 | * If any vector lengths are explicitly enabled with sve<N> properties, | |
42 | * then all other lengths are implicitly disabled. If sve-max-vq is | |
43 | * specified then it is the same as explicitly enabling all lengths | |
44 | * up to and including the specified maximum, which means all larger | |
45 | * lengths will be implicitly disabled. If no sve<N> properties | |
46 | * are enabled and sve-max-vq is not specified, then all lengths not | |
47 | * explicitly disabled will be enabled. Additionally, all power-of-two | |
48 | * vector lengths less than the maximum enabled length will be | |
49 | * automatically enabled and all vector lengths larger than the largest | |
50 | * disabled power-of-two vector length will be automatically disabled. | |
51 | * Errors are generated if the user provided input that interferes with | |
52 | * any of the above. Finally, if SVE is not disabled, then at least one | |
53 | * vector length must be enabled. | |
54 | */ | |
7f9e25a6 RH |
55 | uint32_t vq_map = cpu->sve_vq.map; |
56 | uint32_t vq_init = cpu->sve_vq.init; | |
886902ec RH |
57 | uint32_t vq_supported; |
58 | uint32_t vq_mask = 0; | |
59 | uint32_t tmp, vq, max_vq = 0; | |
0df9142d | 60 | |
5b65e5ab AJ |
61 | /* |
62 | * CPU models specify a set of supported vector lengths which are | |
63 | * enabled by default. Attempting to enable any vector length not set | |
64 | * in the supported bitmap results in an error. When KVM is enabled we | |
65 | * fetch the supported bitmap from the host. | |
66 | */ | |
886902ec RH |
67 | if (kvm_enabled()) { |
68 | if (kvm_arm_sve_supported()) { | |
7f9e25a6 RH |
69 | cpu->sve_vq.supported = kvm_arm_sve_get_vls(CPU(cpu)); |
70 | vq_supported = cpu->sve_vq.supported; | |
886902ec RH |
71 | } else { |
72 | assert(!cpu_isar_feature(aa64_sve, cpu)); | |
73 | vq_supported = 0; | |
74 | } | |
75 | } else { | |
7f9e25a6 | 76 | vq_supported = cpu->sve_vq.supported; |
6fa8a379 AJ |
77 | } |
78 | ||
0df9142d AJ |
79 | /* |
80 | * Process explicit sve<N> properties. | |
81 | * From the properties, sve_vq_map<N> implies sve_vq_init<N>. | |
82 | * Check first for any sve<N> enabled. | |
83 | */ | |
886902ec RH |
84 | if (vq_map != 0) { |
85 | max_vq = 32 - clz32(vq_map); | |
86 | vq_mask = MAKE_64BIT_MASK(0, max_vq); | |
0df9142d AJ |
87 | |
88 | if (cpu->sve_max_vq && max_vq > cpu->sve_max_vq) { | |
89 | error_setg(errp, "cannot enable sve%d", max_vq * 128); | |
90 | error_append_hint(errp, "sve%d is larger than the maximum vector " | |
91 | "length, sve-max-vq=%d (%d bits)\n", | |
92 | max_vq * 128, cpu->sve_max_vq, | |
93 | cpu->sve_max_vq * 128); | |
94 | return; | |
95 | } | |
96 | ||
6fa8a379 AJ |
97 | if (kvm_enabled()) { |
98 | /* | |
673d8215 | 99 | * For KVM we have to automatically enable all supported uninitialized |
6fa8a379 AJ |
100 | * lengths, even when the smaller lengths are not all powers-of-two. |
101 | */ | |
886902ec | 102 | vq_map |= vq_supported & ~vq_init & vq_mask; |
6fa8a379 AJ |
103 | } else { |
104 | /* Propagate enabled bits down through required powers-of-two. */ | |
886902ec | 105 | vq_map |= SVE_VQ_POW2_MAP & ~vq_init & vq_mask; |
0df9142d AJ |
106 | } |
107 | } else if (cpu->sve_max_vq == 0) { | |
108 | /* | |
109 | * No explicit bits enabled, and no implicit bits from sve-max-vq. | |
110 | */ | |
111 | if (!cpu_isar_feature(aa64_sve, cpu)) { | |
112 | /* SVE is disabled and so are all vector lengths. Good. */ | |
113 | return; | |
114 | } | |
115 | ||
6fa8a379 AJ |
116 | if (kvm_enabled()) { |
117 | /* Disabling a supported length disables all larger lengths. */ | |
886902ec | 118 | tmp = vq_init & vq_supported; |
6fa8a379 AJ |
119 | } else { |
120 | /* Disabling a power-of-two disables all larger lengths. */ | |
886902ec | 121 | tmp = vq_init & SVE_VQ_POW2_MAP; |
022707e5 | 122 | } |
886902ec | 123 | vq = ctz32(tmp) + 1; |
022707e5 AJ |
124 | |
125 | max_vq = vq <= ARM_MAX_VQ ? vq - 1 : ARM_MAX_VQ; | |
c4107723 | 126 | vq_mask = max_vq > 0 ? MAKE_64BIT_MASK(0, max_vq) : 0; |
886902ec RH |
127 | vq_map = vq_supported & ~vq_init & vq_mask; |
128 | ||
c4107723 | 129 | if (vq_map == 0) { |
022707e5 AJ |
130 | error_setg(errp, "cannot disable sve%d", vq * 128); |
131 | error_append_hint(errp, "Disabling sve%d results in all " | |
132 | "vector lengths being disabled.\n", | |
133 | vq * 128); | |
134 | error_append_hint(errp, "With SVE enabled, at least one " | |
135 | "vector length must be enabled.\n"); | |
136 | return; | |
0df9142d | 137 | } |
0df9142d | 138 | |
886902ec RH |
139 | max_vq = 32 - clz32(vq_map); |
140 | vq_mask = MAKE_64BIT_MASK(0, max_vq); | |
0df9142d AJ |
141 | } |
142 | ||
143 | /* | |
144 | * Process the sve-max-vq property. | |
145 | * Note that we know from the above that no bit above | |
146 | * sve-max-vq is currently set. | |
147 | */ | |
148 | if (cpu->sve_max_vq != 0) { | |
149 | max_vq = cpu->sve_max_vq; | |
886902ec | 150 | vq_mask = MAKE_64BIT_MASK(0, max_vq); |
0df9142d | 151 | |
886902ec | 152 | if (vq_init & ~vq_map & (1 << (max_vq - 1))) { |
0df9142d AJ |
153 | error_setg(errp, "cannot disable sve%d", max_vq * 128); |
154 | error_append_hint(errp, "The maximum vector length must be " | |
155 | "enabled, sve-max-vq=%d (%d bits)\n", | |
156 | max_vq, max_vq * 128); | |
157 | return; | |
158 | } | |
159 | ||
160 | /* Set all bits not explicitly set within sve-max-vq. */ | |
886902ec | 161 | vq_map |= ~vq_init & vq_mask; |
0df9142d AJ |
162 | } |
163 | ||
164 | /* | |
165 | * We should know what max-vq is now. Also, as we're done | |
166 | * manipulating sve-vq-map, we ensure any bits above max-vq | |
167 | * are clear, just in case anybody looks. | |
168 | */ | |
169 | assert(max_vq != 0); | |
886902ec RH |
170 | assert(vq_mask != 0); |
171 | vq_map &= vq_mask; | |
0df9142d | 172 | |
022707e5 | 173 | /* Ensure the set of lengths matches what is supported. */ |
886902ec RH |
174 | tmp = vq_map ^ (vq_supported & vq_mask); |
175 | if (tmp) { | |
176 | vq = 32 - clz32(tmp); | |
177 | if (vq_map & (1 << (vq - 1))) { | |
022707e5 AJ |
178 | if (cpu->sve_max_vq) { |
179 | error_setg(errp, "cannot set sve-max-vq=%d", cpu->sve_max_vq); | |
180 | error_append_hint(errp, "This CPU does not support " | |
181 | "the vector length %d-bits.\n", vq * 128); | |
182 | error_append_hint(errp, "It may not be possible to use " | |
183 | "sve-max-vq with this CPU. Try " | |
184 | "using only sve<N> properties.\n"); | |
6fa8a379 | 185 | } else { |
022707e5 | 186 | error_setg(errp, "cannot enable sve%d", vq * 128); |
531cc510 RH |
187 | if (vq_supported) { |
188 | error_append_hint(errp, "This CPU does not support " | |
189 | "the vector length %d-bits.\n", vq * 128); | |
190 | } else { | |
191 | error_append_hint(errp, "SVE not supported by KVM " | |
192 | "on this host\n"); | |
193 | } | |
022707e5 AJ |
194 | } |
195 | return; | |
196 | } else { | |
197 | if (kvm_enabled()) { | |
6fa8a379 AJ |
198 | error_setg(errp, "cannot disable sve%d", vq * 128); |
199 | error_append_hint(errp, "The KVM host requires all " | |
200 | "supported vector lengths smaller " | |
201 | "than %d bits to also be enabled.\n", | |
202 | max_vq * 128); | |
6fa8a379 | 203 | return; |
022707e5 AJ |
204 | } else { |
205 | /* Ensure all required powers-of-two are enabled. */ | |
886902ec RH |
206 | tmp = SVE_VQ_POW2_MAP & vq_mask & ~vq_map; |
207 | if (tmp) { | |
208 | vq = 32 - clz32(tmp); | |
209 | error_setg(errp, "cannot disable sve%d", vq * 128); | |
210 | error_append_hint(errp, "sve%d is required as it " | |
211 | "is a power-of-two length smaller " | |
212 | "than the maximum, sve%d\n", | |
213 | vq * 128, max_vq * 128); | |
214 | return; | |
022707e5 | 215 | } |
6fa8a379 AJ |
216 | } |
217 | } | |
0df9142d AJ |
218 | } |
219 | ||
220 | /* | |
221 | * Now that we validated all our vector lengths, the only question | |
222 | * left to answer is if we even want SVE at all. | |
223 | */ | |
224 | if (!cpu_isar_feature(aa64_sve, cpu)) { | |
225 | error_setg(errp, "cannot enable sve%d", max_vq * 128); | |
226 | error_append_hint(errp, "SVE must be enabled to enable vector " | |
227 | "lengths.\n"); | |
228 | error_append_hint(errp, "Add sve=on to the CPU property list.\n"); | |
229 | return; | |
230 | } | |
231 | ||
232 | /* From now on sve_max_vq is the actual maximum supported length. */ | |
233 | cpu->sve_max_vq = max_vq; | |
7f9e25a6 | 234 | cpu->sve_vq.map = vq_map; |
0df9142d AJ |
235 | } |
236 | ||
8073b871 | 237 | /* |
0f40784e RH |
238 | * Note that cpu_arm_{get,set}_vq cannot use the simpler |
239 | * object_property_add_bool interface because they make use of the | |
240 | * contents of "name" to determine which bit on which to operate. | |
8073b871 | 241 | */ |
0f40784e RH |
242 | static void cpu_arm_get_vq(Object *obj, Visitor *v, const char *name, |
243 | void *opaque, Error **errp) | |
0df9142d AJ |
244 | { |
245 | ARMCPU *cpu = ARM_CPU(obj); | |
0f40784e | 246 | ARMVQMap *vq_map = opaque; |
0df9142d | 247 | uint32_t vq = atoi(&name[3]) / 128; |
e74c0976 | 248 | bool sve = vq_map == &cpu->sve_vq; |
0df9142d AJ |
249 | bool value; |
250 | ||
e74c0976 RH |
251 | /* All vector lengths are disabled when feature is off. */ |
252 | if (sve | |
253 | ? !cpu_isar_feature(aa64_sve, cpu) | |
254 | : !cpu_isar_feature(aa64_sme, cpu)) { | |
0df9142d AJ |
255 | value = false; |
256 | } else { | |
0f40784e | 257 | value = extract32(vq_map->map, vq - 1, 1); |
0df9142d AJ |
258 | } |
259 | visit_type_bool(v, name, &value, errp); | |
260 | } | |
261 | ||
0f40784e RH |
262 | static void cpu_arm_set_vq(Object *obj, Visitor *v, const char *name, |
263 | void *opaque, Error **errp) | |
0df9142d | 264 | { |
0f40784e | 265 | ARMVQMap *vq_map = opaque; |
0df9142d | 266 | uint32_t vq = atoi(&name[3]) / 128; |
0df9142d AJ |
267 | bool value; |
268 | ||
668f62ec | 269 | if (!visit_type_bool(v, name, &value, errp)) { |
0df9142d AJ |
270 | return; |
271 | } | |
272 | ||
0f40784e RH |
273 | vq_map->map = deposit32(vq_map->map, vq - 1, 1, value); |
274 | vq_map->init |= 1 << (vq - 1); | |
0df9142d AJ |
275 | } |
276 | ||
8073b871 | 277 | static bool cpu_arm_get_sve(Object *obj, Error **errp) |
73234775 AJ |
278 | { |
279 | ARMCPU *cpu = ARM_CPU(obj); | |
8073b871 | 280 | return cpu_isar_feature(aa64_sve, cpu); |
73234775 AJ |
281 | } |
282 | ||
8073b871 | 283 | static void cpu_arm_set_sve(Object *obj, bool value, Error **errp) |
73234775 AJ |
284 | { |
285 | ARMCPU *cpu = ARM_CPU(obj); | |
73234775 AJ |
286 | uint64_t t; |
287 | ||
7d20e681 | 288 | if (value && kvm_enabled() && !kvm_arm_sve_supported()) { |
14e99e0f AJ |
289 | error_setg(errp, "'sve' feature not supported by KVM on this host"); |
290 | return; | |
291 | } | |
292 | ||
73234775 AJ |
293 | t = cpu->isar.id_aa64pfr0; |
294 | t = FIELD_DP64(t, ID_AA64PFR0, SVE, value); | |
295 | cpu->isar.id_aa64pfr0 = t; | |
296 | } | |
297 | ||
e74c0976 RH |
298 | void arm_cpu_sme_finalize(ARMCPU *cpu, Error **errp) |
299 | { | |
300 | uint32_t vq_map = cpu->sme_vq.map; | |
301 | uint32_t vq_init = cpu->sme_vq.init; | |
302 | uint32_t vq_supported = cpu->sme_vq.supported; | |
303 | uint32_t vq; | |
304 | ||
305 | if (vq_map == 0) { | |
306 | if (!cpu_isar_feature(aa64_sme, cpu)) { | |
307 | cpu->isar.id_aa64smfr0 = 0; | |
308 | return; | |
309 | } | |
310 | ||
311 | /* TODO: KVM will require limitations via SMCR_EL2. */ | |
312 | vq_map = vq_supported & ~vq_init; | |
313 | ||
314 | if (vq_map == 0) { | |
315 | vq = ctz32(vq_supported) + 1; | |
316 | error_setg(errp, "cannot disable sme%d", vq * 128); | |
317 | error_append_hint(errp, "All SME vector lengths are disabled.\n"); | |
318 | error_append_hint(errp, "With SME enabled, at least one " | |
319 | "vector length must be enabled.\n"); | |
320 | return; | |
321 | } | |
322 | } else { | |
323 | if (!cpu_isar_feature(aa64_sme, cpu)) { | |
324 | vq = 32 - clz32(vq_map); | |
325 | error_setg(errp, "cannot enable sme%d", vq * 128); | |
326 | error_append_hint(errp, "SME must be enabled to enable " | |
327 | "vector lengths.\n"); | |
328 | error_append_hint(errp, "Add sme=on to the CPU property list.\n"); | |
329 | return; | |
330 | } | |
331 | /* TODO: KVM will require limitations via SMCR_EL2. */ | |
332 | } | |
333 | ||
334 | cpu->sme_vq.map = vq_map; | |
335 | } | |
336 | ||
337 | static bool cpu_arm_get_sme(Object *obj, Error **errp) | |
338 | { | |
339 | ARMCPU *cpu = ARM_CPU(obj); | |
340 | return cpu_isar_feature(aa64_sme, cpu); | |
341 | } | |
342 | ||
343 | static void cpu_arm_set_sme(Object *obj, bool value, Error **errp) | |
344 | { | |
345 | ARMCPU *cpu = ARM_CPU(obj); | |
346 | uint64_t t; | |
347 | ||
348 | t = cpu->isar.id_aa64pfr1; | |
349 | t = FIELD_DP64(t, ID_AA64PFR1, SME, value); | |
350 | cpu->isar.id_aa64pfr1 = t; | |
351 | } | |
352 | ||
353 | static bool cpu_arm_get_sme_fa64(Object *obj, Error **errp) | |
354 | { | |
355 | ARMCPU *cpu = ARM_CPU(obj); | |
356 | return cpu_isar_feature(aa64_sme, cpu) && | |
357 | cpu_isar_feature(aa64_sme_fa64, cpu); | |
358 | } | |
359 | ||
360 | static void cpu_arm_set_sme_fa64(Object *obj, bool value, Error **errp) | |
361 | { | |
362 | ARMCPU *cpu = ARM_CPU(obj); | |
363 | uint64_t t; | |
364 | ||
365 | t = cpu->isar.id_aa64smfr0; | |
366 | t = FIELD_DP64(t, ID_AA64SMFR0, FA64, value); | |
367 | cpu->isar.id_aa64smfr0 = t; | |
368 | } | |
369 | ||
b3d52804 | 370 | #ifdef CONFIG_USER_ONLY |
e74c0976 | 371 | /* Mirror linux /proc/sys/abi/{sve,sme}_default_vector_length. */ |
515816a8 RH |
372 | static void cpu_arm_set_default_vec_len(Object *obj, Visitor *v, |
373 | const char *name, void *opaque, | |
374 | Error **errp) | |
b3d52804 | 375 | { |
515816a8 | 376 | uint32_t *ptr_default_vq = opaque; |
b3d52804 RH |
377 | int32_t default_len, default_vq, remainder; |
378 | ||
379 | if (!visit_type_int32(v, name, &default_len, errp)) { | |
380 | return; | |
381 | } | |
382 | ||
383 | /* Undocumented, but the kernel allows -1 to indicate "maximum". */ | |
384 | if (default_len == -1) { | |
515816a8 | 385 | *ptr_default_vq = ARM_MAX_VQ; |
b3d52804 RH |
386 | return; |
387 | } | |
388 | ||
389 | default_vq = default_len / 16; | |
390 | remainder = default_len % 16; | |
391 | ||
392 | /* | |
042e85d1 PM |
393 | * Note that the 512 max comes from include/uapi/asm/sve_context.h |
394 | * and is the maximum architectural width of ZCR_ELx.LEN. | |
395 | */ | |
396 | if (remainder || default_vq < 1 || default_vq > 512) { | |
397 | ARMCPU *cpu = ARM_CPU(obj); | |
398 | const char *which = | |
399 | (ptr_default_vq == &cpu->sve_default_vq ? "sve" : "sme"); | |
400 | ||
401 | error_setg(errp, "cannot set %s-default-vector-length", which); | |
402 | if (remainder) { | |
403 | error_append_hint(errp, "Vector length not a multiple of 16\n"); | |
404 | } else if (default_vq < 1) { | |
405 | error_append_hint(errp, "Vector length smaller than 16\n"); | |
406 | } else { | |
407 | error_append_hint(errp, "Vector length larger than %d\n", | |
408 | 512 * 16); | |
409 | } | |
410 | return; | |
411 | } | |
412 | ||
413 | *ptr_default_vq = default_vq; | |
414 | } | |
415 | ||
416 | static void cpu_arm_get_default_vec_len(Object *obj, Visitor *v, | |
417 | const char *name, void *opaque, | |
418 | Error **errp) | |
419 | { | |
420 | uint32_t *ptr_default_vq = opaque; | |
421 | int32_t value = *ptr_default_vq * 16; | |
422 | ||
423 | visit_type_int32(v, name, &value, errp); | |
424 | } | |
425 | #endif | |
426 | ||
39920a04 | 427 | void aarch64_add_sve_properties(Object *obj) |
042e85d1 PM |
428 | { |
429 | ARMCPU *cpu = ARM_CPU(obj); | |
430 | uint32_t vq; | |
431 | ||
432 | object_property_add_bool(obj, "sve", cpu_arm_get_sve, cpu_arm_set_sve); | |
433 | ||
434 | for (vq = 1; vq <= ARM_MAX_VQ; ++vq) { | |
435 | char name[8]; | |
436 | sprintf(name, "sve%d", vq * 128); | |
437 | object_property_add(obj, name, "bool", cpu_arm_get_vq, | |
438 | cpu_arm_set_vq, NULL, &cpu->sve_vq); | |
439 | } | |
440 | ||
441 | #ifdef CONFIG_USER_ONLY | |
442 | /* Mirror linux /proc/sys/abi/sve_default_vector_length. */ | |
443 | object_property_add(obj, "sve-default-vector-length", "int32", | |
444 | cpu_arm_get_default_vec_len, | |
445 | cpu_arm_set_default_vec_len, NULL, | |
446 | &cpu->sve_default_vq); | |
447 | #endif | |
448 | } | |
449 | ||
39920a04 | 450 | void aarch64_add_sme_properties(Object *obj) |
042e85d1 PM |
451 | { |
452 | ARMCPU *cpu = ARM_CPU(obj); | |
453 | uint32_t vq; | |
454 | ||
455 | object_property_add_bool(obj, "sme", cpu_arm_get_sme, cpu_arm_set_sme); | |
456 | object_property_add_bool(obj, "sme_fa64", cpu_arm_get_sme_fa64, | |
457 | cpu_arm_set_sme_fa64); | |
458 | ||
459 | for (vq = 1; vq <= ARM_MAX_VQ; vq <<= 1) { | |
460 | char name[8]; | |
461 | sprintf(name, "sme%d", vq * 128); | |
462 | object_property_add(obj, name, "bool", cpu_arm_get_vq, | |
463 | cpu_arm_set_vq, NULL, &cpu->sme_vq); | |
464 | } | |
465 | ||
466 | #ifdef CONFIG_USER_ONLY | |
467 | /* Mirror linux /proc/sys/abi/sme_default_vector_length. */ | |
468 | object_property_add(obj, "sme-default-vector-length", "int32", | |
469 | cpu_arm_get_default_vec_len, | |
470 | cpu_arm_set_default_vec_len, NULL, | |
471 | &cpu->sme_default_vq); | |
472 | #endif | |
473 | } | |
474 | ||
475 | void arm_cpu_pauth_finalize(ARMCPU *cpu, Error **errp) | |
476 | { | |
6c3427ee | 477 | ARMPauthFeature features = cpu_isar_feature(pauth_feature, cpu); |
399e5e71 | 478 | uint64_t isar1, isar2; |
042e85d1 | 479 | |
6c3427ee RH |
480 | /* |
481 | * These properties enable or disable Pauth as a whole, or change | |
482 | * the pauth algorithm, but do not change the set of features that | |
483 | * are present. We have saved a copy of those features above and | |
484 | * will now place it into the field that chooses the algorithm. | |
485 | * | |
486 | * Begin by disabling all fields. | |
487 | */ | |
488 | isar1 = cpu->isar.id_aa64isar1; | |
489 | isar1 = FIELD_DP64(isar1, ID_AA64ISAR1, APA, 0); | |
490 | isar1 = FIELD_DP64(isar1, ID_AA64ISAR1, GPA, 0); | |
491 | isar1 = FIELD_DP64(isar1, ID_AA64ISAR1, API, 0); | |
492 | isar1 = FIELD_DP64(isar1, ID_AA64ISAR1, GPI, 0); | |
042e85d1 | 493 | |
399e5e71 RH |
494 | isar2 = cpu->isar.id_aa64isar2; |
495 | isar2 = FIELD_DP64(isar2, ID_AA64ISAR2, APA3, 0); | |
496 | isar2 = FIELD_DP64(isar2, ID_AA64ISAR2, GPA3, 0); | |
497 | ||
6c3427ee RH |
498 | if (kvm_enabled() || hvf_enabled()) { |
499 | /* | |
500 | * Exit early if PAuth is enabled and fall through to disable it. | |
501 | * The algorithm selection properties are not present. | |
502 | */ | |
503 | if (cpu->prop_pauth) { | |
504 | if (features == 0) { | |
505 | error_setg(errp, "'pauth' feature not supported by " | |
506 | "%s on this host", current_accel_name()); | |
507 | } | |
508 | return; | |
509 | } | |
510 | } else { | |
511 | /* Pauth properties are only present when the model supports it. */ | |
512 | if (features == 0) { | |
513 | assert(!cpu->prop_pauth); | |
514 | return; | |
515 | } | |
042e85d1 | 516 | |
6c3427ee | 517 | if (cpu->prop_pauth) { |
399e5e71 RH |
518 | if (cpu->prop_pauth_impdef && cpu->prop_pauth_qarma3) { |
519 | error_setg(errp, | |
520 | "cannot enable both pauth-impdef and pauth-qarma3"); | |
521 | return; | |
522 | } | |
523 | ||
6c3427ee RH |
524 | if (cpu->prop_pauth_impdef) { |
525 | isar1 = FIELD_DP64(isar1, ID_AA64ISAR1, API, features); | |
526 | isar1 = FIELD_DP64(isar1, ID_AA64ISAR1, GPI, 1); | |
399e5e71 RH |
527 | } else if (cpu->prop_pauth_qarma3) { |
528 | isar2 = FIELD_DP64(isar2, ID_AA64ISAR2, APA3, features); | |
529 | isar2 = FIELD_DP64(isar2, ID_AA64ISAR2, GPA3, 1); | |
6c3427ee RH |
530 | } else { |
531 | isar1 = FIELD_DP64(isar1, ID_AA64ISAR1, APA, features); | |
532 | isar1 = FIELD_DP64(isar1, ID_AA64ISAR1, GPA, 1); | |
533 | } | |
399e5e71 RH |
534 | } else if (cpu->prop_pauth_impdef || cpu->prop_pauth_qarma3) { |
535 | error_setg(errp, "cannot enable pauth-impdef or " | |
536 | "pauth-qarma3 without pauth"); | |
6c3427ee | 537 | error_append_hint(errp, "Add pauth=on to the CPU property list.\n"); |
042e85d1 | 538 | } |
042e85d1 PM |
539 | } |
540 | ||
6c3427ee | 541 | cpu->isar.id_aa64isar1 = isar1; |
399e5e71 | 542 | cpu->isar.id_aa64isar2 = isar2; |
042e85d1 PM |
543 | } |
544 | ||
545 | static Property arm_cpu_pauth_property = | |
546 | DEFINE_PROP_BOOL("pauth", ARMCPU, prop_pauth, true); | |
547 | static Property arm_cpu_pauth_impdef_property = | |
548 | DEFINE_PROP_BOOL("pauth-impdef", ARMCPU, prop_pauth_impdef, false); | |
399e5e71 RH |
549 | static Property arm_cpu_pauth_qarma3_property = |
550 | DEFINE_PROP_BOOL("pauth-qarma3", ARMCPU, prop_pauth_qarma3, false); | |
042e85d1 | 551 | |
39920a04 | 552 | void aarch64_add_pauth_properties(Object *obj) |
042e85d1 PM |
553 | { |
554 | ARMCPU *cpu = ARM_CPU(obj); | |
555 | ||
556 | /* Default to PAUTH on, with the architected algorithm on TCG. */ | |
557 | qdev_property_add_static(DEVICE(obj), &arm_cpu_pauth_property); | |
558 | if (kvm_enabled() || hvf_enabled()) { | |
559 | /* | |
560 | * Mirror PAuth support from the probed sysregs back into the | |
561 | * property for KVM or hvf. Is it just a bit backward? Yes it is! | |
562 | * Note that prop_pauth is true whether the host CPU supports the | |
563 | * architected QARMA5 algorithm or the IMPDEF one. We don't | |
564 | * provide the separate pauth-impdef property for KVM or hvf, | |
565 | * only for TCG. | |
566 | */ | |
567 | cpu->prop_pauth = cpu_isar_feature(aa64_pauth, cpu); | |
568 | } else { | |
569 | qdev_property_add_static(DEVICE(obj), &arm_cpu_pauth_impdef_property); | |
399e5e71 | 570 | qdev_property_add_static(DEVICE(obj), &arm_cpu_pauth_qarma3_property); |
042e85d1 PM |
571 | } |
572 | } | |
573 | ||
042e85d1 PM |
574 | void arm_cpu_lpa2_finalize(ARMCPU *cpu, Error **errp) |
575 | { | |
576 | uint64_t t; | |
577 | ||
578 | /* | |
579 | * We only install the property for tcg -cpu max; this is the | |
580 | * only situation in which the cpu field can be true. | |
b3d52804 | 581 | */ |
042e85d1 | 582 | if (!cpu->prop_lpa2) { |
b3d52804 RH |
583 | return; |
584 | } | |
585 | ||
042e85d1 PM |
586 | t = cpu->isar.id_aa64mmfr0; |
587 | t = FIELD_DP64(t, ID_AA64MMFR0, TGRAN16, 2); /* 16k pages w/ LPA2 */ | |
588 | t = FIELD_DP64(t, ID_AA64MMFR0, TGRAN4, 1); /* 4k pages w/ LPA2 */ | |
589 | t = FIELD_DP64(t, ID_AA64MMFR0, TGRAN16_2, 3); /* 16k stage2 w/ LPA2 */ | |
590 | t = FIELD_DP64(t, ID_AA64MMFR0, TGRAN4_2, 3); /* 4k stage2 w/ LPA2 */ | |
591 | cpu->isar.id_aa64mmfr0 = t; | |
b3d52804 RH |
592 | } |
593 | ||
042e85d1 | 594 | static void aarch64_a57_initfn(Object *obj) |
b3d52804 | 595 | { |
042e85d1 | 596 | ARMCPU *cpu = ARM_CPU(obj); |
b3d52804 | 597 | |
042e85d1 PM |
598 | cpu->dtb_compatible = "arm,cortex-a57"; |
599 | set_feature(&cpu->env, ARM_FEATURE_V8); | |
600 | set_feature(&cpu->env, ARM_FEATURE_NEON); | |
601 | set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER); | |
602 | set_feature(&cpu->env, ARM_FEATURE_AARCH64); | |
603 | set_feature(&cpu->env, ARM_FEATURE_CBAR_RO); | |
604 | set_feature(&cpu->env, ARM_FEATURE_EL2); | |
605 | set_feature(&cpu->env, ARM_FEATURE_EL3); | |
606 | set_feature(&cpu->env, ARM_FEATURE_PMU); | |
607 | cpu->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A57; | |
608 | cpu->midr = 0x411fd070; | |
609 | cpu->revidr = 0x00000000; | |
610 | cpu->reset_fpsid = 0x41034070; | |
611 | cpu->isar.mvfr0 = 0x10110222; | |
612 | cpu->isar.mvfr1 = 0x12111111; | |
613 | cpu->isar.mvfr2 = 0x00000043; | |
614 | cpu->ctr = 0x8444c004; | |
615 | cpu->reset_sctlr = 0x00c50838; | |
616 | cpu->isar.id_pfr0 = 0x00000131; | |
617 | cpu->isar.id_pfr1 = 0x00011011; | |
618 | cpu->isar.id_dfr0 = 0x03010066; | |
619 | cpu->id_afr0 = 0x00000000; | |
620 | cpu->isar.id_mmfr0 = 0x10101105; | |
621 | cpu->isar.id_mmfr1 = 0x40000000; | |
622 | cpu->isar.id_mmfr2 = 0x01260000; | |
623 | cpu->isar.id_mmfr3 = 0x02102211; | |
624 | cpu->isar.id_isar0 = 0x02101110; | |
625 | cpu->isar.id_isar1 = 0x13112111; | |
626 | cpu->isar.id_isar2 = 0x21232042; | |
627 | cpu->isar.id_isar3 = 0x01112131; | |
628 | cpu->isar.id_isar4 = 0x00011142; | |
629 | cpu->isar.id_isar5 = 0x00011121; | |
630 | cpu->isar.id_isar6 = 0; | |
631 | cpu->isar.id_aa64pfr0 = 0x00002222; | |
632 | cpu->isar.id_aa64dfr0 = 0x10305106; | |
633 | cpu->isar.id_aa64isar0 = 0x00011120; | |
634 | cpu->isar.id_aa64mmfr0 = 0x00001124; | |
635 | cpu->isar.dbgdidr = 0x3516d000; | |
636 | cpu->isar.dbgdevid = 0x01110f13; | |
637 | cpu->isar.dbgdevid1 = 0x2; | |
638 | cpu->isar.reset_pmcr_el0 = 0x41013000; | |
639 | cpu->clidr = 0x0a200023; | |
640 | cpu->ccsidr[0] = 0x701fe00a; /* 32KB L1 dcache */ | |
641 | cpu->ccsidr[1] = 0x201fe012; /* 48KB L1 icache */ | |
642 | cpu->ccsidr[2] = 0x70ffe07a; /* 2048KB L2 cache */ | |
643 | cpu->dcz_blocksize = 4; /* 64 bytes */ | |
644 | cpu->gic_num_lrs = 4; | |
645 | cpu->gic_vpribits = 5; | |
646 | cpu->gic_vprebits = 5; | |
647 | cpu->gic_pribits = 5; | |
648 | define_cortex_a72_a57_a53_cp_reginfo(cpu); | |
b3d52804 | 649 | } |
b3d52804 | 650 | |
042e85d1 | 651 | static void aarch64_a53_initfn(Object *obj) |
87014c6b | 652 | { |
0f40784e | 653 | ARMCPU *cpu = ARM_CPU(obj); |
87014c6b | 654 | |
042e85d1 PM |
655 | cpu->dtb_compatible = "arm,cortex-a53"; |
656 | set_feature(&cpu->env, ARM_FEATURE_V8); | |
657 | set_feature(&cpu->env, ARM_FEATURE_NEON); | |
658 | set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER); | |
659 | set_feature(&cpu->env, ARM_FEATURE_AARCH64); | |
660 | set_feature(&cpu->env, ARM_FEATURE_CBAR_RO); | |
661 | set_feature(&cpu->env, ARM_FEATURE_EL2); | |
662 | set_feature(&cpu->env, ARM_FEATURE_EL3); | |
663 | set_feature(&cpu->env, ARM_FEATURE_PMU); | |
664 | cpu->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A53; | |
665 | cpu->midr = 0x410fd034; | |
666 | cpu->revidr = 0x00000000; | |
667 | cpu->reset_fpsid = 0x41034070; | |
668 | cpu->isar.mvfr0 = 0x10110222; | |
669 | cpu->isar.mvfr1 = 0x12111111; | |
670 | cpu->isar.mvfr2 = 0x00000043; | |
671 | cpu->ctr = 0x84448004; /* L1Ip = VIPT */ | |
672 | cpu->reset_sctlr = 0x00c50838; | |
673 | cpu->isar.id_pfr0 = 0x00000131; | |
674 | cpu->isar.id_pfr1 = 0x00011011; | |
675 | cpu->isar.id_dfr0 = 0x03010066; | |
676 | cpu->id_afr0 = 0x00000000; | |
677 | cpu->isar.id_mmfr0 = 0x10101105; | |
678 | cpu->isar.id_mmfr1 = 0x40000000; | |
679 | cpu->isar.id_mmfr2 = 0x01260000; | |
680 | cpu->isar.id_mmfr3 = 0x02102211; | |
681 | cpu->isar.id_isar0 = 0x02101110; | |
682 | cpu->isar.id_isar1 = 0x13112111; | |
683 | cpu->isar.id_isar2 = 0x21232042; | |
684 | cpu->isar.id_isar3 = 0x01112131; | |
685 | cpu->isar.id_isar4 = 0x00011142; | |
686 | cpu->isar.id_isar5 = 0x00011121; | |
687 | cpu->isar.id_isar6 = 0; | |
688 | cpu->isar.id_aa64pfr0 = 0x00002222; | |
689 | cpu->isar.id_aa64dfr0 = 0x10305106; | |
690 | cpu->isar.id_aa64isar0 = 0x00011120; | |
691 | cpu->isar.id_aa64mmfr0 = 0x00001122; /* 40 bit physical addr */ | |
692 | cpu->isar.dbgdidr = 0x3516d000; | |
693 | cpu->isar.dbgdevid = 0x00110f13; | |
694 | cpu->isar.dbgdevid1 = 0x1; | |
695 | cpu->isar.reset_pmcr_el0 = 0x41033000; | |
696 | cpu->clidr = 0x0a200023; | |
697 | cpu->ccsidr[0] = 0x700fe01a; /* 32KB L1 dcache */ | |
698 | cpu->ccsidr[1] = 0x201fe00a; /* 32KB L1 icache */ | |
699 | cpu->ccsidr[2] = 0x707fe07a; /* 1024KB L2 cache */ | |
700 | cpu->dcz_blocksize = 4; /* 64 bytes */ | |
701 | cpu->gic_num_lrs = 4; | |
702 | cpu->gic_vpribits = 5; | |
703 | cpu->gic_vprebits = 5; | |
704 | cpu->gic_pribits = 5; | |
705 | define_cortex_a72_a57_a53_cp_reginfo(cpu); | |
706 | } | |
87014c6b | 707 | |
73cc9ee6 | 708 | static void aarch64_host_initfn(Object *obj) |
dcfb1d04 | 709 | { |
0baa21be | 710 | #if defined(CONFIG_KVM) |
dcfb1d04 | 711 | ARMCPU *cpu = ARM_CPU(obj); |
dcfb1d04 PM |
712 | kvm_arm_set_cpu_features_from_host(cpu); |
713 | if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) { | |
714 | aarch64_add_sve_properties(obj); | |
715 | aarch64_add_pauth_properties(obj); | |
716 | } | |
0baa21be PM |
717 | #elif defined(CONFIG_HVF) |
718 | ARMCPU *cpu = ARM_CPU(obj); | |
dcfb1d04 | 719 | hvf_arm_set_cpu_features_from_host(cpu); |
92d6528d | 720 | aarch64_add_pauth_properties(obj); |
0baa21be PM |
721 | #else |
722 | g_assert_not_reached(); | |
dcfb1d04 | 723 | #endif |
dcfb1d04 | 724 | } |
dcfb1d04 | 725 | |
25be2105 FR |
726 | static void aarch64_max_initfn(Object *obj) |
727 | { | |
728 | if (kvm_enabled() || hvf_enabled()) { | |
729 | /* With KVM or HVF, '-cpu max' is identical to '-cpu host' */ | |
730 | aarch64_host_initfn(obj); | |
731 | return; | |
732 | } | |
733 | ||
fcab465e FR |
734 | if (tcg_enabled() || qtest_enabled()) { |
735 | aarch64_a57_initfn(obj); | |
736 | } | |
25be2105 | 737 | |
fcab465e FR |
738 | /* '-cpu max' for TCG: we currently do this as "A57 with extra things" */ |
739 | if (tcg_enabled()) { | |
740 | aarch64_max_tcg_initfn(obj); | |
741 | } | |
25be2105 FR |
742 | } |
743 | ||
d14d42f1 | 744 | static const ARMCPUInfo aarch64_cpus[] = { |
cb1fa941 | 745 | { .name = "cortex-a57", .initfn = aarch64_a57_initfn }, |
e3531026 | 746 | { .name = "cortex-a53", .initfn = aarch64_a53_initfn }, |
bab52d4b | 747 | { .name = "max", .initfn = aarch64_max_initfn }, |
73cc9ee6 PM |
748 | #if defined(CONFIG_KVM) || defined(CONFIG_HVF) |
749 | { .name = "host", .initfn = aarch64_host_initfn }, | |
750 | #endif | |
d14d42f1 PM |
751 | }; |
752 | ||
fb8d6c24 GB |
753 | static bool aarch64_cpu_get_aarch64(Object *obj, Error **errp) |
754 | { | |
755 | ARMCPU *cpu = ARM_CPU(obj); | |
756 | ||
757 | return arm_feature(&cpu->env, ARM_FEATURE_AARCH64); | |
758 | } | |
759 | ||
760 | static void aarch64_cpu_set_aarch64(Object *obj, bool value, Error **errp) | |
761 | { | |
762 | ARMCPU *cpu = ARM_CPU(obj); | |
763 | ||
764 | /* At this time, this property is only allowed if KVM is enabled. This | |
765 | * restriction allows us to avoid fixing up functionality that assumes a | |
766 | * uniform execution state like do_interrupt. | |
767 | */ | |
fb8d6c24 | 768 | if (value == false) { |
7d20e681 | 769 | if (!kvm_enabled() || !kvm_arm_aarch32_supported()) { |
b9e758f0 AJ |
770 | error_setg(errp, "'aarch64' feature cannot be disabled " |
771 | "unless KVM is enabled and 32-bit EL1 " | |
772 | "is supported"); | |
773 | return; | |
774 | } | |
fb8d6c24 GB |
775 | unset_feature(&cpu->env, ARM_FEATURE_AARCH64); |
776 | } else { | |
777 | set_feature(&cpu->env, ARM_FEATURE_AARCH64); | |
778 | } | |
779 | } | |
780 | ||
d14d42f1 PM |
781 | static void aarch64_cpu_finalizefn(Object *obj) |
782 | { | |
783 | } | |
784 | ||
a6506838 | 785 | static const gchar *aarch64_gdb_arch_name(CPUState *cs) |
b3820e6c | 786 | { |
a6506838 | 787 | return "aarch64"; |
b3820e6c DH |
788 | } |
789 | ||
d14d42f1 PM |
790 | static void aarch64_cpu_class_init(ObjectClass *oc, void *data) |
791 | { | |
14ade10f AG |
792 | CPUClass *cc = CPU_CLASS(oc); |
793 | ||
96c04212 AG |
794 | cc->gdb_read_register = aarch64_cpu_gdb_read_register; |
795 | cc->gdb_write_register = aarch64_cpu_gdb_write_register; | |
796 | cc->gdb_num_core_regs = 34; | |
797 | cc->gdb_core_xml_file = "aarch64-core.xml"; | |
b3820e6c | 798 | cc->gdb_arch_name = aarch64_gdb_arch_name; |
85cc807c EH |
799 | |
800 | object_class_property_add_bool(oc, "aarch64", aarch64_cpu_get_aarch64, | |
801 | aarch64_cpu_set_aarch64); | |
802 | object_class_property_set_description(oc, "aarch64", | |
803 | "Set on/off to enable/disable aarch64 " | |
804 | "execution state "); | |
d14d42f1 PM |
805 | } |
806 | ||
51e5ef45 MAL |
807 | static void aarch64_cpu_instance_init(Object *obj) |
808 | { | |
809 | ARMCPUClass *acc = ARM_CPU_GET_CLASS(obj); | |
810 | ||
811 | acc->info->initfn(obj); | |
812 | arm_cpu_post_init(obj); | |
813 | } | |
814 | ||
815 | static void cpu_register_class_init(ObjectClass *oc, void *data) | |
816 | { | |
817 | ARMCPUClass *acc = ARM_CPU_CLASS(oc); | |
818 | ||
819 | acc->info = data; | |
820 | } | |
821 | ||
37bcf244 | 822 | void aarch64_cpu_register(const ARMCPUInfo *info) |
d14d42f1 PM |
823 | { |
824 | TypeInfo type_info = { | |
825 | .parent = TYPE_AARCH64_CPU, | |
51e5ef45 | 826 | .instance_init = aarch64_cpu_instance_init, |
51e5ef45 MAL |
827 | .class_init = info->class_init ?: cpu_register_class_init, |
828 | .class_data = (void *)info, | |
d14d42f1 PM |
829 | }; |
830 | ||
831 | type_info.name = g_strdup_printf("%s-" TYPE_ARM_CPU, info->name); | |
832 | type_register(&type_info); | |
833 | g_free((void *)type_info.name); | |
834 | } | |
835 | ||
836 | static const TypeInfo aarch64_cpu_type_info = { | |
837 | .name = TYPE_AARCH64_CPU, | |
838 | .parent = TYPE_ARM_CPU, | |
d14d42f1 PM |
839 | .instance_finalize = aarch64_cpu_finalizefn, |
840 | .abstract = true, | |
d14d42f1 PM |
841 | .class_init = aarch64_cpu_class_init, |
842 | }; | |
843 | ||
844 | static void aarch64_cpu_register_types(void) | |
845 | { | |
92b6a659 | 846 | size_t i; |
d14d42f1 PM |
847 | |
848 | type_register_static(&aarch64_cpu_type_info); | |
83e6813a | 849 | |
92b6a659 PMD |
850 | for (i = 0; i < ARRAY_SIZE(aarch64_cpus); ++i) { |
851 | aarch64_cpu_register(&aarch64_cpus[i]); | |
d14d42f1 PM |
852 | } |
853 | } | |
854 | ||
855 | type_init(aarch64_cpu_register_types) |