xref: /openbmc/qemu/target/arm/cpu-features.h (revision d0f0cd5b)
1 /*
2  * QEMU Arm CPU -- feature test functions
3  *
4  *  Copyright (c) 2023 Linaro Ltd
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library 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 GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #ifndef TARGET_ARM_FEATURES_H
21 #define TARGET_ARM_FEATURES_H
22 
23 #include "hw/registerfields.h"
24 #include "qemu/host-utils.h"
25 
26 /*
27  * Naming convention for isar_feature functions:
28  * Functions which test 32-bit ID registers should have _aa32_ in
29  * their name. Functions which test 64-bit ID registers should have
30  * _aa64_ in their name. These must only be used in code where we
31  * know for certain that the CPU has AArch32 or AArch64 respectively
32  * or where the correct answer for a CPU which doesn't implement that
33  * CPU state is "false" (eg when generating A32 or A64 code, if adding
34  * system registers that are specific to that CPU state, for "should
35  * we let this system register bit be set" tests where the 32-bit
36  * flavour of the register doesn't have the bit, and so on).
37  * Functions which simply ask "does this feature exist at all" have
38  * _any_ in their name, and always return the logical OR of the _aa64_
39  * and the _aa32_ function.
40  */
41 
42 /*
43  * 32-bit feature tests via id registers.
44  */
45 static inline bool isar_feature_aa32_thumb_div(const ARMISARegisters *id)
46 {
47     return FIELD_EX32(id->id_isar0, ID_ISAR0, DIVIDE) != 0;
48 }
49 
50 static inline bool isar_feature_aa32_arm_div(const ARMISARegisters *id)
51 {
52     return FIELD_EX32(id->id_isar0, ID_ISAR0, DIVIDE) > 1;
53 }
54 
55 static inline bool isar_feature_aa32_lob(const ARMISARegisters *id)
56 {
57     /* (M-profile) low-overhead loops and branch future */
58     return FIELD_EX32(id->id_isar0, ID_ISAR0, CMPBRANCH) >= 3;
59 }
60 
61 static inline bool isar_feature_aa32_jazelle(const ARMISARegisters *id)
62 {
63     return FIELD_EX32(id->id_isar1, ID_ISAR1, JAZELLE) != 0;
64 }
65 
66 static inline bool isar_feature_aa32_aes(const ARMISARegisters *id)
67 {
68     return FIELD_EX32(id->id_isar5, ID_ISAR5, AES) != 0;
69 }
70 
71 static inline bool isar_feature_aa32_pmull(const ARMISARegisters *id)
72 {
73     return FIELD_EX32(id->id_isar5, ID_ISAR5, AES) > 1;
74 }
75 
76 static inline bool isar_feature_aa32_sha1(const ARMISARegisters *id)
77 {
78     return FIELD_EX32(id->id_isar5, ID_ISAR5, SHA1) != 0;
79 }
80 
81 static inline bool isar_feature_aa32_sha2(const ARMISARegisters *id)
82 {
83     return FIELD_EX32(id->id_isar5, ID_ISAR5, SHA2) != 0;
84 }
85 
86 static inline bool isar_feature_aa32_crc32(const ARMISARegisters *id)
87 {
88     return FIELD_EX32(id->id_isar5, ID_ISAR5, CRC32) != 0;
89 }
90 
91 static inline bool isar_feature_aa32_rdm(const ARMISARegisters *id)
92 {
93     return FIELD_EX32(id->id_isar5, ID_ISAR5, RDM) != 0;
94 }
95 
96 static inline bool isar_feature_aa32_vcma(const ARMISARegisters *id)
97 {
98     return FIELD_EX32(id->id_isar5, ID_ISAR5, VCMA) != 0;
99 }
100 
101 static inline bool isar_feature_aa32_jscvt(const ARMISARegisters *id)
102 {
103     return FIELD_EX32(id->id_isar6, ID_ISAR6, JSCVT) != 0;
104 }
105 
106 static inline bool isar_feature_aa32_dp(const ARMISARegisters *id)
107 {
108     return FIELD_EX32(id->id_isar6, ID_ISAR6, DP) != 0;
109 }
110 
111 static inline bool isar_feature_aa32_fhm(const ARMISARegisters *id)
112 {
113     return FIELD_EX32(id->id_isar6, ID_ISAR6, FHM) != 0;
114 }
115 
116 static inline bool isar_feature_aa32_sb(const ARMISARegisters *id)
117 {
118     return FIELD_EX32(id->id_isar6, ID_ISAR6, SB) != 0;
119 }
120 
121 static inline bool isar_feature_aa32_predinv(const ARMISARegisters *id)
122 {
123     return FIELD_EX32(id->id_isar6, ID_ISAR6, SPECRES) != 0;
124 }
125 
126 static inline bool isar_feature_aa32_bf16(const ARMISARegisters *id)
127 {
128     return FIELD_EX32(id->id_isar6, ID_ISAR6, BF16) != 0;
129 }
130 
131 static inline bool isar_feature_aa32_i8mm(const ARMISARegisters *id)
132 {
133     return FIELD_EX32(id->id_isar6, ID_ISAR6, I8MM) != 0;
134 }
135 
136 static inline bool isar_feature_aa32_ras(const ARMISARegisters *id)
137 {
138     return FIELD_EX32(id->id_pfr0, ID_PFR0, RAS) != 0;
139 }
140 
141 static inline bool isar_feature_aa32_mprofile(const ARMISARegisters *id)
142 {
143     return FIELD_EX32(id->id_pfr1, ID_PFR1, MPROGMOD) != 0;
144 }
145 
146 static inline bool isar_feature_aa32_m_sec_state(const ARMISARegisters *id)
147 {
148     /*
149      * Return true if M-profile state handling insns
150      * (VSCCLRM, CLRM, FPCTX access insns) are implemented
151      */
152     return FIELD_EX32(id->id_pfr1, ID_PFR1, SECURITY) >= 3;
153 }
154 
155 static inline bool isar_feature_aa32_fp16_arith(const ARMISARegisters *id)
156 {
157     /* Sadly this is encoded differently for A-profile and M-profile */
158     if (isar_feature_aa32_mprofile(id)) {
159         return FIELD_EX32(id->mvfr1, MVFR1, FP16) > 0;
160     } else {
161         return FIELD_EX32(id->mvfr1, MVFR1, FPHP) >= 3;
162     }
163 }
164 
165 static inline bool isar_feature_aa32_mve(const ARMISARegisters *id)
166 {
167     /*
168      * Return true if MVE is supported (either integer or floating point).
169      * We must check for M-profile as the MVFR1 field means something
170      * else for A-profile.
171      */
172     return isar_feature_aa32_mprofile(id) &&
173         FIELD_EX32(id->mvfr1, MVFR1, MVE) > 0;
174 }
175 
176 static inline bool isar_feature_aa32_mve_fp(const ARMISARegisters *id)
177 {
178     /*
179      * Return true if MVE is supported (either integer or floating point).
180      * We must check for M-profile as the MVFR1 field means something
181      * else for A-profile.
182      */
183     return isar_feature_aa32_mprofile(id) &&
184         FIELD_EX32(id->mvfr1, MVFR1, MVE) >= 2;
185 }
186 
187 static inline bool isar_feature_aa32_vfp_simd(const ARMISARegisters *id)
188 {
189     /*
190      * Return true if either VFP or SIMD is implemented.
191      * In this case, a minimum of VFP w/ D0-D15.
192      */
193     return FIELD_EX32(id->mvfr0, MVFR0, SIMDREG) > 0;
194 }
195 
196 static inline bool isar_feature_aa32_simd_r32(const ARMISARegisters *id)
197 {
198     /* Return true if D16-D31 are implemented */
199     return FIELD_EX32(id->mvfr0, MVFR0, SIMDREG) >= 2;
200 }
201 
202 static inline bool isar_feature_aa32_fpshvec(const ARMISARegisters *id)
203 {
204     return FIELD_EX32(id->mvfr0, MVFR0, FPSHVEC) > 0;
205 }
206 
207 static inline bool isar_feature_aa32_fpsp_v2(const ARMISARegisters *id)
208 {
209     /* Return true if CPU supports single precision floating point, VFPv2 */
210     return FIELD_EX32(id->mvfr0, MVFR0, FPSP) > 0;
211 }
212 
213 static inline bool isar_feature_aa32_fpsp_v3(const ARMISARegisters *id)
214 {
215     /* Return true if CPU supports single precision floating point, VFPv3 */
216     return FIELD_EX32(id->mvfr0, MVFR0, FPSP) >= 2;
217 }
218 
219 static inline bool isar_feature_aa32_fpdp_v2(const ARMISARegisters *id)
220 {
221     /* Return true if CPU supports double precision floating point, VFPv2 */
222     return FIELD_EX32(id->mvfr0, MVFR0, FPDP) > 0;
223 }
224 
225 static inline bool isar_feature_aa32_fpdp_v3(const ARMISARegisters *id)
226 {
227     /* Return true if CPU supports double precision floating point, VFPv3 */
228     return FIELD_EX32(id->mvfr0, MVFR0, FPDP) >= 2;
229 }
230 
231 static inline bool isar_feature_aa32_vfp(const ARMISARegisters *id)
232 {
233     return isar_feature_aa32_fpsp_v2(id) || isar_feature_aa32_fpdp_v2(id);
234 }
235 
236 /*
237  * We always set the FP and SIMD FP16 fields to indicate identical
238  * levels of support (assuming SIMD is implemented at all), so
239  * we only need one set of accessors.
240  */
241 static inline bool isar_feature_aa32_fp16_spconv(const ARMISARegisters *id)
242 {
243     return FIELD_EX32(id->mvfr1, MVFR1, FPHP) > 0;
244 }
245 
246 static inline bool isar_feature_aa32_fp16_dpconv(const ARMISARegisters *id)
247 {
248     return FIELD_EX32(id->mvfr1, MVFR1, FPHP) > 1;
249 }
250 
251 /*
252  * Note that this ID register field covers both VFP and Neon FMAC,
253  * so should usually be tested in combination with some other
254  * check that confirms the presence of whichever of VFP or Neon is
255  * relevant, to avoid accidentally enabling a Neon feature on
256  * a VFP-no-Neon core or vice-versa.
257  */
258 static inline bool isar_feature_aa32_simdfmac(const ARMISARegisters *id)
259 {
260     return FIELD_EX32(id->mvfr1, MVFR1, SIMDFMAC) != 0;
261 }
262 
263 static inline bool isar_feature_aa32_vsel(const ARMISARegisters *id)
264 {
265     return FIELD_EX32(id->mvfr2, MVFR2, FPMISC) >= 1;
266 }
267 
268 static inline bool isar_feature_aa32_vcvt_dr(const ARMISARegisters *id)
269 {
270     return FIELD_EX32(id->mvfr2, MVFR2, FPMISC) >= 2;
271 }
272 
273 static inline bool isar_feature_aa32_vrint(const ARMISARegisters *id)
274 {
275     return FIELD_EX32(id->mvfr2, MVFR2, FPMISC) >= 3;
276 }
277 
278 static inline bool isar_feature_aa32_vminmaxnm(const ARMISARegisters *id)
279 {
280     return FIELD_EX32(id->mvfr2, MVFR2, FPMISC) >= 4;
281 }
282 
283 static inline bool isar_feature_aa32_pxn(const ARMISARegisters *id)
284 {
285     return FIELD_EX32(id->id_mmfr0, ID_MMFR0, VMSA) >= 4;
286 }
287 
288 static inline bool isar_feature_aa32_pan(const ARMISARegisters *id)
289 {
290     return FIELD_EX32(id->id_mmfr3, ID_MMFR3, PAN) != 0;
291 }
292 
293 static inline bool isar_feature_aa32_ats1e1(const ARMISARegisters *id)
294 {
295     return FIELD_EX32(id->id_mmfr3, ID_MMFR3, PAN) >= 2;
296 }
297 
298 static inline bool isar_feature_aa32_pmuv3p1(const ARMISARegisters *id)
299 {
300     /* 0xf means "non-standard IMPDEF PMU" */
301     return FIELD_EX32(id->id_dfr0, ID_DFR0, PERFMON) >= 4 &&
302         FIELD_EX32(id->id_dfr0, ID_DFR0, PERFMON) != 0xf;
303 }
304 
305 static inline bool isar_feature_aa32_pmuv3p4(const ARMISARegisters *id)
306 {
307     /* 0xf means "non-standard IMPDEF PMU" */
308     return FIELD_EX32(id->id_dfr0, ID_DFR0, PERFMON) >= 5 &&
309         FIELD_EX32(id->id_dfr0, ID_DFR0, PERFMON) != 0xf;
310 }
311 
312 static inline bool isar_feature_aa32_pmuv3p5(const ARMISARegisters *id)
313 {
314     /* 0xf means "non-standard IMPDEF PMU" */
315     return FIELD_EX32(id->id_dfr0, ID_DFR0, PERFMON) >= 6 &&
316         FIELD_EX32(id->id_dfr0, ID_DFR0, PERFMON) != 0xf;
317 }
318 
319 static inline bool isar_feature_aa32_hpd(const ARMISARegisters *id)
320 {
321     return FIELD_EX32(id->id_mmfr4, ID_MMFR4, HPDS) != 0;
322 }
323 
324 static inline bool isar_feature_aa32_ac2(const ARMISARegisters *id)
325 {
326     return FIELD_EX32(id->id_mmfr4, ID_MMFR4, AC2) != 0;
327 }
328 
329 static inline bool isar_feature_aa32_ccidx(const ARMISARegisters *id)
330 {
331     return FIELD_EX32(id->id_mmfr4, ID_MMFR4, CCIDX) != 0;
332 }
333 
334 static inline bool isar_feature_aa32_tts2uxn(const ARMISARegisters *id)
335 {
336     return FIELD_EX32(id->id_mmfr4, ID_MMFR4, XNX) != 0;
337 }
338 
339 static inline bool isar_feature_aa32_half_evt(const ARMISARegisters *id)
340 {
341     return FIELD_EX32(id->id_mmfr4, ID_MMFR4, EVT) >= 1;
342 }
343 
344 static inline bool isar_feature_aa32_evt(const ARMISARegisters *id)
345 {
346     return FIELD_EX32(id->id_mmfr4, ID_MMFR4, EVT) >= 2;
347 }
348 
349 static inline bool isar_feature_aa32_dit(const ARMISARegisters *id)
350 {
351     return FIELD_EX32(id->id_pfr0, ID_PFR0, DIT) != 0;
352 }
353 
354 static inline bool isar_feature_aa32_ssbs(const ARMISARegisters *id)
355 {
356     return FIELD_EX32(id->id_pfr2, ID_PFR2, SSBS) != 0;
357 }
358 
359 static inline bool isar_feature_aa32_debugv7p1(const ARMISARegisters *id)
360 {
361     return FIELD_EX32(id->id_dfr0, ID_DFR0, COPDBG) >= 5;
362 }
363 
364 static inline bool isar_feature_aa32_debugv8p2(const ARMISARegisters *id)
365 {
366     return FIELD_EX32(id->id_dfr0, ID_DFR0, COPDBG) >= 8;
367 }
368 
369 static inline bool isar_feature_aa32_doublelock(const ARMISARegisters *id)
370 {
371     return FIELD_EX32(id->dbgdevid, DBGDEVID, DOUBLELOCK) > 0;
372 }
373 
374 /*
375  * 64-bit feature tests via id registers.
376  */
377 static inline bool isar_feature_aa64_aes(const ARMISARegisters *id)
378 {
379     return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, AES) != 0;
380 }
381 
382 static inline bool isar_feature_aa64_pmull(const ARMISARegisters *id)
383 {
384     return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, AES) > 1;
385 }
386 
387 static inline bool isar_feature_aa64_sha1(const ARMISARegisters *id)
388 {
389     return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, SHA1) != 0;
390 }
391 
392 static inline bool isar_feature_aa64_sha256(const ARMISARegisters *id)
393 {
394     return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, SHA2) != 0;
395 }
396 
397 static inline bool isar_feature_aa64_sha512(const ARMISARegisters *id)
398 {
399     return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, SHA2) > 1;
400 }
401 
402 static inline bool isar_feature_aa64_crc32(const ARMISARegisters *id)
403 {
404     return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, CRC32) != 0;
405 }
406 
407 static inline bool isar_feature_aa64_atomics(const ARMISARegisters *id)
408 {
409     return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, ATOMIC) != 0;
410 }
411 
412 static inline bool isar_feature_aa64_rdm(const ARMISARegisters *id)
413 {
414     return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, RDM) != 0;
415 }
416 
417 static inline bool isar_feature_aa64_sha3(const ARMISARegisters *id)
418 {
419     return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, SHA3) != 0;
420 }
421 
422 static inline bool isar_feature_aa64_sm3(const ARMISARegisters *id)
423 {
424     return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, SM3) != 0;
425 }
426 
427 static inline bool isar_feature_aa64_sm4(const ARMISARegisters *id)
428 {
429     return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, SM4) != 0;
430 }
431 
432 static inline bool isar_feature_aa64_dp(const ARMISARegisters *id)
433 {
434     return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, DP) != 0;
435 }
436 
437 static inline bool isar_feature_aa64_fhm(const ARMISARegisters *id)
438 {
439     return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, FHM) != 0;
440 }
441 
442 static inline bool isar_feature_aa64_condm_4(const ARMISARegisters *id)
443 {
444     return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, TS) != 0;
445 }
446 
447 static inline bool isar_feature_aa64_condm_5(const ARMISARegisters *id)
448 {
449     return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, TS) >= 2;
450 }
451 
452 static inline bool isar_feature_aa64_rndr(const ARMISARegisters *id)
453 {
454     return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, RNDR) != 0;
455 }
456 
457 static inline bool isar_feature_aa64_tlbirange(const ARMISARegisters *id)
458 {
459     return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, TLB) == 2;
460 }
461 
462 static inline bool isar_feature_aa64_tlbios(const ARMISARegisters *id)
463 {
464     return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, TLB) != 0;
465 }
466 
467 static inline bool isar_feature_aa64_jscvt(const ARMISARegisters *id)
468 {
469     return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, JSCVT) != 0;
470 }
471 
472 static inline bool isar_feature_aa64_fcma(const ARMISARegisters *id)
473 {
474     return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, FCMA) != 0;
475 }
476 
477 /*
478  * These are the values from APA/API/APA3.
479  * In general these must be compared '>=', per the normal Arm ARM
480  * treatment of fields in ID registers.
481  */
482 typedef enum {
483     PauthFeat_None         = 0,
484     PauthFeat_1            = 1,
485     PauthFeat_EPAC         = 2,
486     PauthFeat_2            = 3,
487     PauthFeat_FPAC         = 4,
488     PauthFeat_FPACCOMBINED = 5,
489 } ARMPauthFeature;
490 
491 static inline ARMPauthFeature
492 isar_feature_pauth_feature(const ARMISARegisters *id)
493 {
494     /*
495      * Architecturally, only one of {APA,API,APA3} may be active (non-zero)
496      * and the other two must be zero.  Thus we may avoid conditionals.
497      */
498     return (FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, APA) |
499             FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, API) |
500             FIELD_EX64(id->id_aa64isar2, ID_AA64ISAR2, APA3));
501 }
502 
503 static inline bool isar_feature_aa64_pauth(const ARMISARegisters *id)
504 {
505     /*
506      * Return true if any form of pauth is enabled, as this
507      * predicate controls migration of the 128-bit keys.
508      */
509     return isar_feature_pauth_feature(id) != PauthFeat_None;
510 }
511 
512 static inline bool isar_feature_aa64_pauth_qarma5(const ARMISARegisters *id)
513 {
514     /*
515      * Return true if pauth is enabled with the architected QARMA5 algorithm.
516      * QEMU will always enable or disable both APA and GPA.
517      */
518     return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, APA) != 0;
519 }
520 
521 static inline bool isar_feature_aa64_pauth_qarma3(const ARMISARegisters *id)
522 {
523     /*
524      * Return true if pauth is enabled with the architected QARMA3 algorithm.
525      * QEMU will always enable or disable both APA3 and GPA3.
526      */
527     return FIELD_EX64(id->id_aa64isar2, ID_AA64ISAR2, APA3) != 0;
528 }
529 
530 static inline bool isar_feature_aa64_sb(const ARMISARegisters *id)
531 {
532     return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, SB) != 0;
533 }
534 
535 static inline bool isar_feature_aa64_predinv(const ARMISARegisters *id)
536 {
537     return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, SPECRES) != 0;
538 }
539 
540 static inline bool isar_feature_aa64_frint(const ARMISARegisters *id)
541 {
542     return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, FRINTTS) != 0;
543 }
544 
545 static inline bool isar_feature_aa64_dcpop(const ARMISARegisters *id)
546 {
547     return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, DPB) != 0;
548 }
549 
550 static inline bool isar_feature_aa64_dcpodp(const ARMISARegisters *id)
551 {
552     return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, DPB) >= 2;
553 }
554 
555 static inline bool isar_feature_aa64_bf16(const ARMISARegisters *id)
556 {
557     return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, BF16) != 0;
558 }
559 
560 static inline bool isar_feature_aa64_ebf16(const ARMISARegisters *id)
561 {
562     return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, BF16) > 1;
563 }
564 
565 static inline bool isar_feature_aa64_rcpc_8_3(const ARMISARegisters *id)
566 {
567     return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, LRCPC) != 0;
568 }
569 
570 static inline bool isar_feature_aa64_rcpc_8_4(const ARMISARegisters *id)
571 {
572     return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, LRCPC) >= 2;
573 }
574 
575 static inline bool isar_feature_aa64_i8mm(const ARMISARegisters *id)
576 {
577     return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, I8MM) != 0;
578 }
579 
580 static inline bool isar_feature_aa64_wfxt(const ARMISARegisters *id)
581 {
582     return FIELD_EX64(id->id_aa64isar2, ID_AA64ISAR2, WFXT) >= 2;
583 }
584 
585 static inline bool isar_feature_aa64_hbc(const ARMISARegisters *id)
586 {
587     return FIELD_EX64(id->id_aa64isar2, ID_AA64ISAR2, BC) != 0;
588 }
589 
590 static inline bool isar_feature_aa64_mops(const ARMISARegisters *id)
591 {
592     return FIELD_EX64(id->id_aa64isar2, ID_AA64ISAR2, MOPS);
593 }
594 
595 static inline bool isar_feature_aa64_fp_simd(const ARMISARegisters *id)
596 {
597     /* We always set the AdvSIMD and FP fields identically.  */
598     return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, FP) != 0xf;
599 }
600 
601 static inline bool isar_feature_aa64_fp16(const ARMISARegisters *id)
602 {
603     /* We always set the AdvSIMD and FP fields identically wrt FP16.  */
604     return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, FP) == 1;
605 }
606 
607 static inline bool isar_feature_aa64_aa32(const ARMISARegisters *id)
608 {
609     return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, EL0) >= 2;
610 }
611 
612 static inline bool isar_feature_aa64_aa32_el1(const ARMISARegisters *id)
613 {
614     return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, EL1) >= 2;
615 }
616 
617 static inline bool isar_feature_aa64_aa32_el2(const ARMISARegisters *id)
618 {
619     return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, EL2) >= 2;
620 }
621 
622 static inline bool isar_feature_aa64_ras(const ARMISARegisters *id)
623 {
624     return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, RAS) != 0;
625 }
626 
627 static inline bool isar_feature_aa64_doublefault(const ARMISARegisters *id)
628 {
629     return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, RAS) >= 2;
630 }
631 
632 static inline bool isar_feature_aa64_sve(const ARMISARegisters *id)
633 {
634     return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, SVE) != 0;
635 }
636 
637 static inline bool isar_feature_aa64_sel2(const ARMISARegisters *id)
638 {
639     return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, SEL2) != 0;
640 }
641 
642 static inline bool isar_feature_aa64_rme(const ARMISARegisters *id)
643 {
644     return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, RME) != 0;
645 }
646 
647 static inline bool isar_feature_aa64_dit(const ARMISARegisters *id)
648 {
649     return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, DIT) != 0;
650 }
651 
652 static inline bool isar_feature_aa64_scxtnum(const ARMISARegisters *id)
653 {
654     int key = FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, CSV2);
655     if (key >= 2) {
656         return true;      /* FEAT_CSV2_2 */
657     }
658     if (key == 1) {
659         key = FIELD_EX64(id->id_aa64pfr1, ID_AA64PFR1, CSV2_FRAC);
660         return key >= 2;  /* FEAT_CSV2_1p2 */
661     }
662     return false;
663 }
664 
665 static inline bool isar_feature_aa64_ssbs(const ARMISARegisters *id)
666 {
667     return FIELD_EX64(id->id_aa64pfr1, ID_AA64PFR1, SSBS) != 0;
668 }
669 
670 static inline bool isar_feature_aa64_bti(const ARMISARegisters *id)
671 {
672     return FIELD_EX64(id->id_aa64pfr1, ID_AA64PFR1, BT) != 0;
673 }
674 
675 static inline bool isar_feature_aa64_mte_insn_reg(const ARMISARegisters *id)
676 {
677     return FIELD_EX64(id->id_aa64pfr1, ID_AA64PFR1, MTE) != 0;
678 }
679 
680 static inline bool isar_feature_aa64_mte(const ARMISARegisters *id)
681 {
682     return FIELD_EX64(id->id_aa64pfr1, ID_AA64PFR1, MTE) >= 2;
683 }
684 
685 static inline bool isar_feature_aa64_mte3(const ARMISARegisters *id)
686 {
687     return FIELD_EX64(id->id_aa64pfr1, ID_AA64PFR1, MTE) >= 3;
688 }
689 
690 static inline bool isar_feature_aa64_sme(const ARMISARegisters *id)
691 {
692     return FIELD_EX64(id->id_aa64pfr1, ID_AA64PFR1, SME) != 0;
693 }
694 
695 static inline bool isar_feature_aa64_nmi(const ARMISARegisters *id)
696 {
697     return FIELD_EX64(id->id_aa64pfr1, ID_AA64PFR1, NMI) != 0;
698 }
699 
700 static inline bool isar_feature_aa64_tgran4_lpa2(const ARMISARegisters *id)
701 {
702     return FIELD_SEX64(id->id_aa64mmfr0, ID_AA64MMFR0, TGRAN4) >= 1;
703 }
704 
705 static inline bool isar_feature_aa64_tgran4_2_lpa2(const ARMISARegisters *id)
706 {
707     unsigned t = FIELD_EX64(id->id_aa64mmfr0, ID_AA64MMFR0, TGRAN4_2);
708     return t >= 3 || (t == 0 && isar_feature_aa64_tgran4_lpa2(id));
709 }
710 
711 static inline bool isar_feature_aa64_tgran16_lpa2(const ARMISARegisters *id)
712 {
713     return FIELD_EX64(id->id_aa64mmfr0, ID_AA64MMFR0, TGRAN16) >= 2;
714 }
715 
716 static inline bool isar_feature_aa64_tgran16_2_lpa2(const ARMISARegisters *id)
717 {
718     unsigned t = FIELD_EX64(id->id_aa64mmfr0, ID_AA64MMFR0, TGRAN16_2);
719     return t >= 3 || (t == 0 && isar_feature_aa64_tgran16_lpa2(id));
720 }
721 
722 static inline bool isar_feature_aa64_tgran4(const ARMISARegisters *id)
723 {
724     return FIELD_SEX64(id->id_aa64mmfr0, ID_AA64MMFR0, TGRAN4) >= 0;
725 }
726 
727 static inline bool isar_feature_aa64_tgran16(const ARMISARegisters *id)
728 {
729     return FIELD_EX64(id->id_aa64mmfr0, ID_AA64MMFR0, TGRAN16) >= 1;
730 }
731 
732 static inline bool isar_feature_aa64_tgran64(const ARMISARegisters *id)
733 {
734     return FIELD_SEX64(id->id_aa64mmfr0, ID_AA64MMFR0, TGRAN64) >= 0;
735 }
736 
737 static inline bool isar_feature_aa64_tgran4_2(const ARMISARegisters *id)
738 {
739     unsigned t = FIELD_EX64(id->id_aa64mmfr0, ID_AA64MMFR0, TGRAN4_2);
740     return t >= 2 || (t == 0 && isar_feature_aa64_tgran4(id));
741 }
742 
743 static inline bool isar_feature_aa64_tgran16_2(const ARMISARegisters *id)
744 {
745     unsigned t = FIELD_EX64(id->id_aa64mmfr0, ID_AA64MMFR0, TGRAN16_2);
746     return t >= 2 || (t == 0 && isar_feature_aa64_tgran16(id));
747 }
748 
749 static inline bool isar_feature_aa64_tgran64_2(const ARMISARegisters *id)
750 {
751     unsigned t = FIELD_EX64(id->id_aa64mmfr0, ID_AA64MMFR0, TGRAN64_2);
752     return t >= 2 || (t == 0 && isar_feature_aa64_tgran64(id));
753 }
754 
755 static inline bool isar_feature_aa64_fgt(const ARMISARegisters *id)
756 {
757     return FIELD_EX64(id->id_aa64mmfr0, ID_AA64MMFR0, FGT) != 0;
758 }
759 
760 static inline bool isar_feature_aa64_ecv_traps(const ARMISARegisters *id)
761 {
762     return FIELD_EX64(id->id_aa64mmfr0, ID_AA64MMFR0, ECV) > 0;
763 }
764 
765 static inline bool isar_feature_aa64_ecv(const ARMISARegisters *id)
766 {
767     return FIELD_EX64(id->id_aa64mmfr0, ID_AA64MMFR0, ECV) > 1;
768 }
769 
770 static inline bool isar_feature_aa64_vh(const ARMISARegisters *id)
771 {
772     return FIELD_EX64(id->id_aa64mmfr1, ID_AA64MMFR1, VH) != 0;
773 }
774 
775 static inline bool isar_feature_aa64_lor(const ARMISARegisters *id)
776 {
777     return FIELD_EX64(id->id_aa64mmfr1, ID_AA64MMFR1, LO) != 0;
778 }
779 
780 static inline bool isar_feature_aa64_pan(const ARMISARegisters *id)
781 {
782     return FIELD_EX64(id->id_aa64mmfr1, ID_AA64MMFR1, PAN) != 0;
783 }
784 
785 static inline bool isar_feature_aa64_ats1e1(const ARMISARegisters *id)
786 {
787     return FIELD_EX64(id->id_aa64mmfr1, ID_AA64MMFR1, PAN) >= 2;
788 }
789 
790 static inline bool isar_feature_aa64_pan3(const ARMISARegisters *id)
791 {
792     return FIELD_EX64(id->id_aa64mmfr1, ID_AA64MMFR1, PAN) >= 3;
793 }
794 
795 static inline bool isar_feature_aa64_hcx(const ARMISARegisters *id)
796 {
797     return FIELD_EX64(id->id_aa64mmfr1, ID_AA64MMFR1, HCX) != 0;
798 }
799 
800 static inline bool isar_feature_aa64_tidcp1(const ARMISARegisters *id)
801 {
802     return FIELD_EX64(id->id_aa64mmfr1, ID_AA64MMFR1, TIDCP1) != 0;
803 }
804 
805 static inline bool isar_feature_aa64_hafs(const ARMISARegisters *id)
806 {
807     return FIELD_EX64(id->id_aa64mmfr1, ID_AA64MMFR1, HAFDBS) != 0;
808 }
809 
810 static inline bool isar_feature_aa64_hdbs(const ARMISARegisters *id)
811 {
812     return FIELD_EX64(id->id_aa64mmfr1, ID_AA64MMFR1, HAFDBS) >= 2;
813 }
814 
815 static inline bool isar_feature_aa64_tts2uxn(const ARMISARegisters *id)
816 {
817     return FIELD_EX64(id->id_aa64mmfr1, ID_AA64MMFR1, XNX) != 0;
818 }
819 
820 static inline bool isar_feature_aa64_uao(const ARMISARegisters *id)
821 {
822     return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, UAO) != 0;
823 }
824 
825 static inline bool isar_feature_aa64_st(const ARMISARegisters *id)
826 {
827     return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, ST) != 0;
828 }
829 
830 static inline bool isar_feature_aa64_lse2(const ARMISARegisters *id)
831 {
832     return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, AT) != 0;
833 }
834 
835 static inline bool isar_feature_aa64_fwb(const ARMISARegisters *id)
836 {
837     return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, FWB) != 0;
838 }
839 
840 static inline bool isar_feature_aa64_ids(const ARMISARegisters *id)
841 {
842     return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, IDS) != 0;
843 }
844 
845 static inline bool isar_feature_aa64_half_evt(const ARMISARegisters *id)
846 {
847     return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, EVT) >= 1;
848 }
849 
850 static inline bool isar_feature_aa64_evt(const ARMISARegisters *id)
851 {
852     return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, EVT) >= 2;
853 }
854 
855 static inline bool isar_feature_aa64_ccidx(const ARMISARegisters *id)
856 {
857     return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, CCIDX) != 0;
858 }
859 
860 static inline bool isar_feature_aa64_lva(const ARMISARegisters *id)
861 {
862     return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, VARANGE) != 0;
863 }
864 
865 static inline bool isar_feature_aa64_e0pd(const ARMISARegisters *id)
866 {
867     return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, E0PD) != 0;
868 }
869 
870 static inline bool isar_feature_aa64_nv(const ARMISARegisters *id)
871 {
872     return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, NV) != 0;
873 }
874 
875 static inline bool isar_feature_aa64_nv2(const ARMISARegisters *id)
876 {
877     return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, NV) >= 2;
878 }
879 
880 static inline bool isar_feature_aa64_pmuv3p1(const ARMISARegisters *id)
881 {
882     return FIELD_EX64(id->id_aa64dfr0, ID_AA64DFR0, PMUVER) >= 4 &&
883         FIELD_EX64(id->id_aa64dfr0, ID_AA64DFR0, PMUVER) != 0xf;
884 }
885 
886 static inline bool isar_feature_aa64_pmuv3p4(const ARMISARegisters *id)
887 {
888     return FIELD_EX64(id->id_aa64dfr0, ID_AA64DFR0, PMUVER) >= 5 &&
889         FIELD_EX64(id->id_aa64dfr0, ID_AA64DFR0, PMUVER) != 0xf;
890 }
891 
892 static inline bool isar_feature_aa64_pmuv3p5(const ARMISARegisters *id)
893 {
894     return FIELD_EX64(id->id_aa64dfr0, ID_AA64DFR0, PMUVER) >= 6 &&
895         FIELD_EX64(id->id_aa64dfr0, ID_AA64DFR0, PMUVER) != 0xf;
896 }
897 
898 static inline bool isar_feature_aa64_debugv8p2(const ARMISARegisters *id)
899 {
900     return FIELD_EX64(id->id_aa64dfr0, ID_AA64DFR0, DEBUGVER) >= 8;
901 }
902 
903 static inline bool isar_feature_aa64_doublelock(const ARMISARegisters *id)
904 {
905     return FIELD_SEX64(id->id_aa64dfr0, ID_AA64DFR0, DOUBLELOCK) >= 0;
906 }
907 
908 static inline bool isar_feature_aa64_sve2(const ARMISARegisters *id)
909 {
910     return FIELD_EX64(id->id_aa64zfr0, ID_AA64ZFR0, SVEVER) != 0;
911 }
912 
913 static inline bool isar_feature_aa64_sve2_aes(const ARMISARegisters *id)
914 {
915     return FIELD_EX64(id->id_aa64zfr0, ID_AA64ZFR0, AES) != 0;
916 }
917 
918 static inline bool isar_feature_aa64_sve2_pmull128(const ARMISARegisters *id)
919 {
920     return FIELD_EX64(id->id_aa64zfr0, ID_AA64ZFR0, AES) >= 2;
921 }
922 
923 static inline bool isar_feature_aa64_sve2_bitperm(const ARMISARegisters *id)
924 {
925     return FIELD_EX64(id->id_aa64zfr0, ID_AA64ZFR0, BITPERM) != 0;
926 }
927 
928 static inline bool isar_feature_aa64_sve_bf16(const ARMISARegisters *id)
929 {
930     return FIELD_EX64(id->id_aa64zfr0, ID_AA64ZFR0, BFLOAT16) != 0;
931 }
932 
933 static inline bool isar_feature_aa64_sve2_sha3(const ARMISARegisters *id)
934 {
935     return FIELD_EX64(id->id_aa64zfr0, ID_AA64ZFR0, SHA3) != 0;
936 }
937 
938 static inline bool isar_feature_aa64_sve2_sm4(const ARMISARegisters *id)
939 {
940     return FIELD_EX64(id->id_aa64zfr0, ID_AA64ZFR0, SM4) != 0;
941 }
942 
943 static inline bool isar_feature_aa64_sve_i8mm(const ARMISARegisters *id)
944 {
945     return FIELD_EX64(id->id_aa64zfr0, ID_AA64ZFR0, I8MM) != 0;
946 }
947 
948 static inline bool isar_feature_aa64_sve_f32mm(const ARMISARegisters *id)
949 {
950     return FIELD_EX64(id->id_aa64zfr0, ID_AA64ZFR0, F32MM) != 0;
951 }
952 
953 static inline bool isar_feature_aa64_sve_f64mm(const ARMISARegisters *id)
954 {
955     return FIELD_EX64(id->id_aa64zfr0, ID_AA64ZFR0, F64MM) != 0;
956 }
957 
958 static inline bool isar_feature_aa64_sme_f64f64(const ARMISARegisters *id)
959 {
960     return FIELD_EX64(id->id_aa64smfr0, ID_AA64SMFR0, F64F64);
961 }
962 
963 static inline bool isar_feature_aa64_sme_i16i64(const ARMISARegisters *id)
964 {
965     return FIELD_EX64(id->id_aa64smfr0, ID_AA64SMFR0, I16I64) == 0xf;
966 }
967 
968 static inline bool isar_feature_aa64_sme_fa64(const ARMISARegisters *id)
969 {
970     return FIELD_EX64(id->id_aa64smfr0, ID_AA64SMFR0, FA64);
971 }
972 
973 /*
974  * Feature tests for "does this exist in either 32-bit or 64-bit?"
975  */
976 static inline bool isar_feature_any_fp16(const ARMISARegisters *id)
977 {
978     return isar_feature_aa64_fp16(id) || isar_feature_aa32_fp16_arith(id);
979 }
980 
981 static inline bool isar_feature_any_predinv(const ARMISARegisters *id)
982 {
983     return isar_feature_aa64_predinv(id) || isar_feature_aa32_predinv(id);
984 }
985 
986 static inline bool isar_feature_any_pmuv3p1(const ARMISARegisters *id)
987 {
988     return isar_feature_aa64_pmuv3p1(id) || isar_feature_aa32_pmuv3p1(id);
989 }
990 
991 static inline bool isar_feature_any_pmuv3p4(const ARMISARegisters *id)
992 {
993     return isar_feature_aa64_pmuv3p4(id) || isar_feature_aa32_pmuv3p4(id);
994 }
995 
996 static inline bool isar_feature_any_pmuv3p5(const ARMISARegisters *id)
997 {
998     return isar_feature_aa64_pmuv3p5(id) || isar_feature_aa32_pmuv3p5(id);
999 }
1000 
1001 static inline bool isar_feature_any_ccidx(const ARMISARegisters *id)
1002 {
1003     return isar_feature_aa64_ccidx(id) || isar_feature_aa32_ccidx(id);
1004 }
1005 
1006 static inline bool isar_feature_any_tts2uxn(const ARMISARegisters *id)
1007 {
1008     return isar_feature_aa64_tts2uxn(id) || isar_feature_aa32_tts2uxn(id);
1009 }
1010 
1011 static inline bool isar_feature_any_debugv8p2(const ARMISARegisters *id)
1012 {
1013     return isar_feature_aa64_debugv8p2(id) || isar_feature_aa32_debugv8p2(id);
1014 }
1015 
1016 static inline bool isar_feature_any_ras(const ARMISARegisters *id)
1017 {
1018     return isar_feature_aa64_ras(id) || isar_feature_aa32_ras(id);
1019 }
1020 
1021 static inline bool isar_feature_any_half_evt(const ARMISARegisters *id)
1022 {
1023     return isar_feature_aa64_half_evt(id) || isar_feature_aa32_half_evt(id);
1024 }
1025 
1026 static inline bool isar_feature_any_evt(const ARMISARegisters *id)
1027 {
1028     return isar_feature_aa64_evt(id) || isar_feature_aa32_evt(id);
1029 }
1030 
1031 typedef enum {
1032     CCSIDR_FORMAT_LEGACY,
1033     CCSIDR_FORMAT_CCIDX,
1034 } CCSIDRFormat;
1035 
1036 static inline uint64_t make_ccsidr(CCSIDRFormat format, unsigned assoc,
1037                                    unsigned linesize, unsigned cachesize,
1038                                    uint8_t flags)
1039 {
1040     unsigned lg_linesize = ctz32(linesize);
1041     unsigned sets;
1042     uint64_t ccsidr = 0;
1043 
1044     assert(assoc != 0);
1045     assert(is_power_of_2(linesize));
1046     assert(lg_linesize >= 4 && lg_linesize <= 7 + 4);
1047 
1048     /* sets * associativity * linesize == cachesize. */
1049     sets = cachesize / (assoc * linesize);
1050     assert(cachesize % (assoc * linesize) == 0);
1051 
1052     if (format == CCSIDR_FORMAT_LEGACY) {
1053         /*
1054          * The 32-bit CCSIDR format is:
1055          *   [27:13] number of sets - 1
1056          *   [12:3]  associativity - 1
1057          *   [2:0]   log2(linesize) - 4
1058          *           so 0 == 16 bytes, 1 == 32 bytes, 2 == 64 bytes, etc
1059          */
1060         ccsidr = deposit32(ccsidr, 28,  4, flags);
1061         ccsidr = deposit32(ccsidr, 13, 15, sets - 1);
1062         ccsidr = deposit32(ccsidr,  3, 10, assoc - 1);
1063         ccsidr = deposit32(ccsidr,  0,  3, lg_linesize - 4);
1064     } else {
1065         /*
1066          * The 64-bit CCSIDR_EL1 format is:
1067          *   [55:32] number of sets - 1
1068          *   [23:3]  associativity - 1
1069          *   [2:0]   log2(linesize) - 4
1070          *           so 0 == 16 bytes, 1 == 32 bytes, 2 == 64 bytes, etc
1071          */
1072         ccsidr = deposit64(ccsidr, 32, 24, sets - 1);
1073         ccsidr = deposit64(ccsidr,  3, 21, assoc - 1);
1074         ccsidr = deposit64(ccsidr,  0,  3, lg_linesize - 4);
1075     }
1076 
1077     return ccsidr;
1078 }
1079 
1080 /*
1081  * Forward to the above feature tests given an ARMCPU pointer.
1082  */
1083 #define cpu_isar_feature(name, cpu) \
1084     ({ ARMCPU *cpu_ = (cpu); isar_feature_##name(&cpu_->isar); })
1085 
1086 #endif
1087