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