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