1 /*
2 * Copyright (c) 2020 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29 #include <cpu_capabilities_public.h>
30 #include <darwintest.h>
31 #include <machine/cpu_capabilities.h>
32 #include <stdlib.h>
33 #include <sys/sysctl.h>
34
35 #include "exc_helpers.h"
36
37 T_GLOBAL_META(
38 T_META_NAMESPACE("xnu.arm"),
39 T_META_RADAR_COMPONENT_NAME("xnu"),
40 T_META_RADAR_COMPONENT_VERSION("arm"),
41 T_META_OWNER("ghackmann"),
42 T_META_RUN_CONCURRENTLY(true),
43 T_META_TAG("SoCSpecific")
44 );
45
46 static volatile bool cap_usable;
47
48 static size_t
bad_instruction_handler(mach_port_t task __unused,mach_port_t thread __unused,exception_type_t type __unused,mach_exception_data_t codes __unused,uint64_t exception_pc __unused)49 bad_instruction_handler(mach_port_t task __unused, mach_port_t thread __unused,
50 exception_type_t type __unused, mach_exception_data_t codes __unused,
51 uint64_t exception_pc __unused)
52 {
53 cap_usable = false;
54 return 4;
55 }
56
57 static void
try_fp16(void)58 try_fp16(void)
59 {
60 asm volatile (
61 "fmov h0, #0" "\n"
62 :
63 :
64 : "v0"
65 );
66 }
67
68 static void
try_atomics(void)69 try_atomics(void)
70 {
71 uint64_t dword;
72 asm volatile (
73 "swp xzr, xzr, [%[dword]]"
74 :
75 : [dword]"r"(&dword)
76 );
77 }
78
79 static void
try_crc32(void)80 try_crc32(void)
81 {
82 asm volatile ( "crc32b wzr, wzr, wzr");
83 }
84
85 static void
try_fhm(void)86 try_fhm(void)
87 {
88 asm volatile (
89 "fmov d0, #0" "\n"
90 "fmlal v0.2s, v0.2h, v0.2h" "\n"
91 :
92 :
93 : "v0"
94 );
95 }
96
97 static void
try_sha512(void)98 try_sha512(void)
99 {
100 asm volatile (
101 "fmov d0, #0" "\n"
102 "fmov d1, #0" "\n"
103 "sha512h q0, q0, v0.2d" "\n"
104 :
105 :
106 : "v0"
107 );
108 }
109
110 static void
try_sha3(void)111 try_sha3(void)
112 {
113 asm volatile (
114 "fmov d0, #0" "\n"
115 "fmov d1, #0" "\n"
116 "eor3 v0.16b, v0.16b, v0.16b, v0.16b" "\n"
117 :
118 :
119 : "v0"
120 );
121 }
122
123 static void
try_sha1(void)124 try_sha1(void)
125 {
126 asm volatile (
127 "fmov s0, #0" "\n"
128 "sha1h s0, s0" "\n"
129 :
130 :
131 : "v0"
132 );
133 }
134
135 static void
try_pmull(void)136 try_pmull(void)
137 {
138 asm volatile (
139 "fmov d0, #0" "\n"
140 "pmull v0.1q, v0.1d, v0.1d" "\n"
141 :
142 :
143 : "v0"
144 );
145 }
146
147 static void
try_aes(void)148 try_aes(void)
149 {
150 asm volatile (
151 "fmov d0, #0" "\n"
152 "fmov d1, #0" "\n"
153 "aesd v0.16B, v0.16B" "\n"
154 :
155 :
156 : "v0"
157 );
158 }
159
160
161 static void
try_sha256(void)162 try_sha256(void)
163 {
164 asm volatile (
165 "fmov d0, #0" "\n"
166 "fmov d1, #0" "\n"
167 "sha256h q0, q0, v0.4s" "\n"
168 :
169 :
170 : "v0"
171 );
172 }
173
174
175 static void
try_compnum(void)176 try_compnum(void)
177 {
178 asm volatile (
179 "fmov d0, #0" "\n"
180 "fcadd v0.2s, v0.2s, v0.2s, #90" "\n"
181 :
182 :
183 : "v0"
184 );
185 }
186
187
188 static void
try_flagm(void)189 try_flagm(void)
190 {
191 asm volatile (
192 "cfinv" "\n"
193 "cfinv" "\n"
194 );
195 }
196
197 static void
try_flagm2(void)198 try_flagm2(void)
199 {
200 asm volatile (
201 "axflag" "\n"
202 "xaflag" "\n"
203 );
204 }
205
206 static void
try_dotprod(void)207 try_dotprod(void)
208 {
209 asm volatile (
210 "udot v0.4S,v1.16B,v2.16B"
211 :
212 :
213 : "v0"
214 );
215 }
216
217 static void
try_rdm(void)218 try_rdm(void)
219 {
220 asm volatile (
221 "sqrdmlah s0, s1, s2"
222 :
223 :
224 : "s0"
225 );
226 }
227
228 static void
try_sb(void)229 try_sb(void)
230 {
231 asm volatile (
232 "sb"
233 );
234 }
235
236 static void
try_frintts(void)237 try_frintts(void)
238 {
239 asm volatile (
240 "frint32x s0, s0"
241 :
242 :
243 : "s0"
244 );
245 }
246
247 static void
try_jscvt(void)248 try_jscvt(void)
249 {
250 asm volatile (
251 "fmov d0, #0" "\n"
252 "fjcvtzs w1, d0" "\n"
253 :
254 :
255 : "w1", "d0"
256 );
257 }
258
259 static void
try_pauth(void)260 try_pauth(void)
261 {
262 asm volatile (
263 "pacga x0, x0, x0"
264 :
265 :
266 : "x0"
267 );
268 }
269
270 static void
try_dpb(void)271 try_dpb(void)
272 {
273 int x;
274 asm volatile (
275 "dc cvap, %0"
276 :
277 : "r" (&x)
278 );
279 }
280
281 static void
try_dpb2(void)282 try_dpb2(void)
283 {
284 int x;
285 asm volatile (
286 "dc cvadp, %0"
287 :
288 : "r" (&x)
289 );
290 }
291
292 static void
try_lrcpc(void)293 try_lrcpc(void)
294 {
295 int x;
296 asm volatile (
297 "ldaprb w0, [%0]"
298 :
299 : "r" (&x)
300 : "w0"
301 );
302 }
303
304 static void
try_lrcpc2(void)305 try_lrcpc2(void)
306 {
307 int x;
308 asm volatile (
309 "ldapurb w0, [%0]"
310 :
311 : "r" (&x)
312 : "w0"
313 );
314 }
315
316
317 static void
try_specres(void)318 try_specres(void)
319 {
320 int x;
321 asm volatile (
322 "cfp rctx, %0"
323 :
324 : "r" (&x)
325 );
326 }
327
328 static void
try_bf16(void)329 try_bf16(void)
330 {
331 asm volatile (
332 "bfdot v0.4S,v1.8H,v2.8H"
333 :
334 :
335 : "v0"
336 );
337 }
338
339 static void
try_i8mm(void)340 try_i8mm(void)
341 {
342 asm volatile (
343 "sudot v0.4S,v1.16B,v2.4B[0]"
344 :
345 :
346 : "v0"
347 );
348 }
349
350 static void
try_ecv(void)351 try_ecv(void)
352 {
353 /*
354 * These registers are present only when FEAT_ECV is implemented.
355 * Otherwise, direct accesses to CNTPCTSS_EL0 or CNTVCTSS_EL0 are UNDEFINED.
356 */
357 (void)__builtin_arm_rsr64("CNTPCTSS_EL0");
358 (void)__builtin_arm_rsr64("CNTVCTSS_EL0");
359 }
360
361 static void
try_afp(void)362 try_afp(void)
363 {
364 /*
365 * FEAT_AFP can be detected via three new FPCR bits which were
366 * previously marked read-as-zero.
367 */
368 const uint64_t FPCR_AFP_FLAGS = (1 << 0) | (1 << 1) | (1 << 2);
369
370 uint64_t old_fpcr = __builtin_arm_rsr64("FPCR");
371 __builtin_arm_wsr64("FPCR", old_fpcr | FPCR_AFP_FLAGS);
372 uint64_t new_fpcr = __builtin_arm_rsr64("FPCR");
373 __builtin_arm_wsr64("FPCR", old_fpcr);
374
375 if ((new_fpcr & FPCR_AFP_FLAGS) != FPCR_AFP_FLAGS) {
376 cap_usable = false;
377 }
378 }
379
380 static void
try_rpres(void)381 try_rpres(void)
382 {
383 /*
384 * When FEAT_RPRES is enabled via FPCR.AH, floating-point reciprocal
385 * estimate instructions increase precision from 8 mantissa bits to 12
386 * mantissa bits. This can be detected by estimating 1/10.0 (which has
387 * no exact floating-point representation) and checking bits 11-14.
388 */
389 const uint64_t FPCR_AH = (1 << 1);
390 const uint32_t EXTRA_MANTISSA_BITS = (0xf << 11);
391
392 uint32_t recip;
393 uint64_t old_fpcr = __builtin_arm_rsr64("FPCR");
394 __builtin_arm_wsr64("FPCR", old_fpcr | FPCR_AH);
395 asm volatile (
396 "fmov s0, #10.0" "\n"
397 "frecpe s0, s0" "\n"
398 "fmov %w0, s0" "\n"
399 : "=r"(recip)
400 :
401 : "s0"
402 );
403 __builtin_arm_wsr64("FPCR", old_fpcr);
404
405 if ((recip & EXTRA_MANTISSA_BITS) == 0) {
406 cap_usable = false;
407 }
408 }
409
410 __attribute__((target("wfxt")))
411 static void
try_wfxt(void)412 try_wfxt(void)
413 {
414 asm volatile ("wfet xzr");
415 }
416
417 static void
try_sme(void)418 try_sme(void)
419 {
420 asm volatile (
421 "rdsvl x0, #1"
422 :
423 :
424 : "x0"
425 );
426 }
427
428 static void
try_sme2(void)429 try_sme2(void)
430 {
431 asm volatile (
432 "smstart za" "\n"
433 "zero { zt0 }" "\n"
434 "smstop za" "\n"
435 );
436 }
437
438 static void
try_sme_f32f32(void)439 try_sme_f32f32(void)
440 {
441 asm volatile (
442 "smstart" "\n"
443 "fmopa za0.s, p0/m, p0/m, z0.s, z0.s" "\n"
444 "smstop" "\n"
445 );
446 }
447
448 static void
try_sme_bi32i32(void)449 try_sme_bi32i32(void)
450 {
451 asm volatile (
452 "smstart" "\n"
453 "bmopa za0.s, p0/m, p0/m, z0.s, z0.s" "\n"
454 "smstop" "\n"
455 );
456 }
457
458 static void
try_sme_b16f32(void)459 try_sme_b16f32(void)
460 {
461 asm volatile (
462 "smstart" "\n"
463 "bfmopa za0.s, p0/m, p0/m, z0.h, z0.h" "\n"
464 "smstop" "\n"
465 );
466 }
467
468 static void
try_sme_f16f32(void)469 try_sme_f16f32(void)
470 {
471 asm volatile (
472 "smstart" "\n"
473 "fmopa za0.s, p0/m, p0/m, z0.h, z0.h" "\n"
474 "smstop" "\n"
475 );
476 }
477
478 static void
try_sme_i8i32(void)479 try_sme_i8i32(void)
480 {
481 asm volatile (
482 "smstart" "\n"
483 "smopa za0.s, p0/m, p0/m, z0.b, z0.b" "\n"
484 "smstop" "\n"
485 );
486 }
487
488 static void
try_sme_i16i32(void)489 try_sme_i16i32(void)
490 {
491 asm volatile (
492 "smstart" "\n"
493 "smopa za0.s, p0/m, p0/m, z0.h, z0.h" "\n"
494 "smstop" "\n"
495 );
496 }
497
498 __attribute__((target("sme-f64f64")))
499 static void
try_sme_f64f64(void)500 try_sme_f64f64(void)
501 {
502 asm volatile (
503 "smstart" "\n"
504 "fmopa za0.d, p0/m, p0/m, z0.d, z0.d" "\n"
505 "smstop" "\n"
506 );
507 }
508
509 __attribute__((target("sme-i16i64")))
510 static void
try_sme_i16i64(void)511 try_sme_i16i64(void)
512 {
513 asm volatile (
514 "smstart" "\n"
515 "smopa za0.d, p0/m, p0/m, z0.h, z0.h" "\n"
516 "smstop" "\n"
517 );
518 }
519
520 __attribute__((target("sme2p1")))
521 static void
try_sme2p1(void)522 try_sme2p1(void)
523 {
524 asm volatile (
525 "mov x8, #0" "\n"
526 "smstart" "\n"
527 "zero za.d[w8, #0, VGx2]" "\n"
528 "smstop" "\n"
529 :
530 :
531 : "x8"
532 );
533 }
534
535 __attribute__((target("sme2p1,sme-f16f16")))
536 static void
try_sme_f16f16(void)537 try_sme_f16f16(void)
538 {
539 asm volatile (
540 "smstart" "\n"
541 "fmopa za0.h, p0/m, p0/m, z0.h, z0.h" "\n"
542 "smstop" "\n"
543 );
544 }
545
546 __attribute__((target("sme2p1,b16b16,sme-b16b16")))
547 static void
try_sme_b16b16(void)548 try_sme_b16b16(void)
549 {
550 asm volatile (
551 "smstart" "\n"
552 "bfmopa za0.h, p0/m, p0/m, z0.h, z0.h" "\n"
553 "smstop" "\n"
554 );
555 }
556
557
558 static void
try_fpexcp(void)559 try_fpexcp(void)
560 {
561 /* FP Exceptions are supported if all exceptions bit can be set. */
562 const uint64_t flags = (1 << 8) | (1 << 9) | (1 << 10) | (1 << 11) | (1 << 12) | (1 << 15);
563
564 uint64_t old_fpcr = __builtin_arm_rsr64("FPCR");
565 __builtin_arm_wsr64("FPCR", old_fpcr | flags);
566 uint64_t new_fpcr = __builtin_arm_rsr64("FPCR");
567 __builtin_arm_wsr64("FPCR", old_fpcr);
568
569 if ((new_fpcr & flags) != flags) {
570 cap_usable = false;
571 }
572 }
573
574 static void
try_dit(void)575 try_dit(void)
576 {
577 asm volatile (
578 "msr DIT, x0"
579 :
580 :
581 : "x0"
582 );
583 }
584
585 static mach_port_t exc_port;
586
587 static uint8_t hw_optional_arm_caps[(CAP_BIT_NB + 7) / 8];
588
589 static void
test_cpu_capability(const char * cap_name,uint64_t commpage_flag,const char * cap_sysctl,int cap_bit,void (* try_cpu_capability)(void))590 test_cpu_capability(const char *cap_name, uint64_t commpage_flag, const char *cap_sysctl, int cap_bit, void (*try_cpu_capability)(void))
591 {
592 bool has_commpage_flag = commpage_flag != 0;
593 uint64_t commpage_caps = _get_cpu_capabilities();
594 bool commpage_flag_set = false;
595 if (has_commpage_flag) {
596 commpage_flag_set = (commpage_caps & commpage_flag);
597 }
598
599 bool has_sysctl = cap_sysctl != NULL;
600 int sysctl_val;
601 bool sysctl_flag_set = false;
602 if (has_sysctl) {
603 size_t sysctl_size = sizeof(sysctl_val);
604 int err = sysctlbyname(cap_sysctl, &sysctl_val, &sysctl_size, NULL, 0);
605 sysctl_flag_set = (err == 0 && sysctl_val > 0);
606 }
607
608 bool has_cap_bit = (cap_bit != -1);
609 bool cap_bit_set = false;
610 if (has_cap_bit) {
611 size_t idx = (unsigned int)cap_bit / 8;
612 unsigned int bit = 1U << (cap_bit % 8);
613 cap_bit_set = (hw_optional_arm_caps[idx] & bit);
614 }
615
616 bool has_capability = has_commpage_flag ? commpage_flag_set : sysctl_flag_set;
617
618 if (!has_commpage_flag && !has_sysctl) {
619 T_FAIL("Tested capability must have either sysctl or commpage flag");
620 return;
621 }
622
623 if (has_commpage_flag && has_sysctl) {
624 T_EXPECT_EQ(commpage_flag_set, sysctl_flag_set, "%s commpage flag matches sysctl flag", cap_name);
625 }
626 if (has_commpage_flag && has_cap_bit) {
627 T_EXPECT_EQ(commpage_flag_set, cap_bit_set, "%s commpage flag matches hw.optional.arm.caps bit", cap_name);
628 }
629 if (has_sysctl && has_cap_bit) {
630 T_EXPECT_EQ(sysctl_flag_set, cap_bit_set, "%s sysctl flag matches hw.optional.arm.caps bit", cap_name);
631 }
632
633 if (try_cpu_capability != NULL) {
634 cap_usable = true;
635 try_cpu_capability();
636 T_EXPECT_EQ(has_capability, cap_usable, "%s capability matches actual usability", cap_name);
637 }
638 }
639
640 static inline void
test_deprecated_sysctl(const char * cap_name,uint64_t commpage_flag,const char * deprecated_sysctl)641 test_deprecated_sysctl(const char *cap_name, uint64_t commpage_flag, const char *deprecated_sysctl)
642 {
643 char *deprecated_cap_name;
644 int err = asprintf(&deprecated_cap_name, "%s (deprecated sysctl)", cap_name);
645 T_QUIET; T_ASSERT_NE(err, -1, "asprintf");
646 test_cpu_capability(deprecated_cap_name, commpage_flag, deprecated_sysctl, -1, NULL);
647 free(deprecated_cap_name);
648 }
649
650 T_DECL(cpu_capabilities, "Verify ARM CPU capabilities", T_META_TAG_VM_NOT_ELIGIBLE) {
651 T_SETUPBEGIN;
652 size_t hw_optional_arm_caps_size = sizeof(hw_optional_arm_caps);
653 int err = sysctlbyname("hw.optional.arm.caps", hw_optional_arm_caps, &hw_optional_arm_caps_size, NULL, 0);
654 T_QUIET; T_ASSERT_POSIX_SUCCESS(err, "sysctlbyname(\"hw.optional.arm.caps\")");
655
656 exc_port = create_exception_port(EXC_MASK_BAD_INSTRUCTION);
657 T_SETUPEND;
658
659 repeat_exception_handler(exc_port, bad_instruction_handler);
660
661 test_deprecated_sysctl("FP16", kHasFeatFP16, "hw.optional.neon_fp16");
662 test_cpu_capability("FP16", kHasFeatFP16, "hw.optional.arm.FEAT_FP16", CAP_BIT_FEAT_FP16, try_fp16);
663 test_deprecated_sysctl("LSE", kHasFeatLSE, "hw.optional.armv8_1_atomics");
664 test_cpu_capability("LSE", kHasFeatLSE, "hw.optional.arm.FEAT_LSE", CAP_BIT_FEAT_LSE, try_atomics);
665 test_deprecated_sysctl("CRC32", kHasARMv8Crc32, "hw.optional.armv8_crc32");
666 test_cpu_capability("CRC32", kHasARMv8Crc32, "hw.optional.arm.FEAT_CRC32", CAP_BIT_FEAT_CRC32, try_crc32);
667 test_deprecated_sysctl("FHM", kHasFeatFHM, "hw.optional.armv8_2_fhm");
668 test_cpu_capability("FHM", kHasFeatFHM, "hw.optional.arm.FEAT_FHM", CAP_BIT_FEAT_FHM, try_fhm);
669 test_deprecated_sysctl("SHA512", kHasFeatSHA512, "hw.optional.armv8_2_sha512");
670 test_cpu_capability("SHA512", kHasFeatSHA512, "hw.optional.arm.FEAT_SHA512", CAP_BIT_FEAT_SHA512, try_sha512);
671 test_deprecated_sysctl("SHA3", kHasFeatSHA3, "hw.optional.armv8_2_sha3");
672 test_cpu_capability("SHA3", kHasFeatSHA3, "hw.optional.arm.FEAT_SHA3", CAP_BIT_FEAT_SHA3, try_sha3);
673 test_cpu_capability("AES", kHasFeatAES, "hw.optional.arm.FEAT_AES", CAP_BIT_FEAT_AES, try_aes);
674 test_cpu_capability("SHA1", kHasFeatSHA1, "hw.optional.arm.FEAT_SHA1", CAP_BIT_FEAT_SHA1, try_sha1);
675 test_cpu_capability("SHA256", kHasFeatSHA256, "hw.optional.arm.FEAT_SHA256", CAP_BIT_FEAT_SHA256, try_sha256);
676 test_cpu_capability("PMULL", kHasFeatPMULL, "hw.optional.arm.FEAT_PMULL", CAP_BIT_FEAT_PMULL, try_pmull);
677 test_deprecated_sysctl("FCMA", kHasFeatFCMA, "hw.optional.armv8_3_compnum");
678 test_cpu_capability("FCMA", kHasFeatFCMA, "hw.optional.arm.FEAT_FCMA", CAP_BIT_FEAT_FCMA, try_compnum);
679 test_cpu_capability("FlagM", kHasFEATFlagM, "hw.optional.arm.FEAT_FlagM", CAP_BIT_FEAT_FlagM, try_flagm);
680 test_cpu_capability("FlagM2", kHasFEATFlagM2, "hw.optional.arm.FEAT_FlagM2", CAP_BIT_FEAT_FlagM2, try_flagm2);
681 test_cpu_capability("DotProd", kHasFeatDotProd, "hw.optional.arm.FEAT_DotProd", CAP_BIT_FEAT_DotProd, try_dotprod);
682 test_cpu_capability("RDM", kHasFeatRDM, "hw.optional.arm.FEAT_RDM", CAP_BIT_FEAT_RDM, try_rdm);
683 test_cpu_capability("SB", kHasFeatSB, "hw.optional.arm.FEAT_SB", CAP_BIT_FEAT_SB, try_sb);
684 test_cpu_capability("FRINTTS", kHasFeatFRINTTS, "hw.optional.arm.FEAT_FRINTTS", CAP_BIT_FEAT_FRINTTS, try_frintts);
685 test_cpu_capability("JSCVT", kHasFeatJSCVT, "hw.optional.arm.FEAT_JSCVT", CAP_BIT_FEAT_JSCVT, try_jscvt);
686 test_cpu_capability("PAuth", kHasFeatPAuth, "hw.optional.arm.FEAT_PAuth", CAP_BIT_FEAT_PAuth, try_pauth);
687 test_cpu_capability("DBP", kHasFeatDPB, "hw.optional.arm.FEAT_DPB", CAP_BIT_FEAT_DPB, try_dpb);
688 test_cpu_capability("DBP2", kHasFeatDPB2, "hw.optional.arm.FEAT_DPB2", CAP_BIT_FEAT_DPB2, try_dpb2);
689 test_cpu_capability("SPECRES", kHasFeatSPECRES, "hw.optional.arm.FEAT_SPECRES", CAP_BIT_FEAT_SPECRES, try_specres);
690 test_cpu_capability("LRCPC", kHasFeatLRCPC, "hw.optional.arm.FEAT_LRCPC", CAP_BIT_FEAT_LRCPC, try_lrcpc);
691 test_cpu_capability("LRCPC2", kHasFeatLRCPC2, "hw.optional.arm.FEAT_LRCPC2", CAP_BIT_FEAT_LRCPC2, try_lrcpc2);
692 test_cpu_capability("AFP", kHasFeatAFP, "hw.optional.arm.FEAT_AFP", CAP_BIT_FEAT_AFP, try_afp);
693 test_cpu_capability("DIT", kHasFeatDIT, "hw.optional.arm.FEAT_DIT", CAP_BIT_FEAT_DIT, try_dit);
694 test_cpu_capability("FP16", kHasFP_SyncExceptions, "hw.optional.arm.FP_SyncExceptions", -1, try_fpexcp);
695 test_cpu_capability("SME", kHasFeatSME, "hw.optional.arm.FEAT_SME", CAP_BIT_FEAT_SME, try_sme);
696 test_cpu_capability("SME2", kHasFeatSME2, "hw.optional.arm.FEAT_SME2", CAP_BIT_FEAT_SME2, try_sme2);
697 test_cpu_capability("SME2.1", kHasFeatSME2p1, "hw.optional.arm.FEAT_SME2p1", CAP_BIT_FEAT_SME2p1, try_sme2p1);
698
699 // The following features do not have a commpage entry
700 test_cpu_capability("BF16", 0, "hw.optional.arm.FEAT_BF16", CAP_BIT_FEAT_BF16, try_bf16);
701 test_cpu_capability("I8MM", 0, "hw.optional.arm.FEAT_I8MM", CAP_BIT_FEAT_I8MM, try_i8mm);
702 test_cpu_capability("ECV", 0, "hw.optional.arm.FEAT_ECV", CAP_BIT_FEAT_ECV, try_ecv);
703 test_cpu_capability("RPRES", 0, "hw.optional.arm.FEAT_RPRES", CAP_BIT_FEAT_RPRES, try_rpres);
704 test_cpu_capability("WFxT", 0, "hw.optional.arm.FEAT_WFxT", CAP_BIT_FEAT_WFxT, try_wfxt);
705 test_cpu_capability("SME_F32F32", 0, "hw.optional.arm.SME_F32F32", CAP_BIT_SME_F32F32, try_sme_f32f32);
706 test_cpu_capability("SME_BI32I32", 0, "hw.optional.arm.SME_BI32I32", CAP_BIT_SME_BI32I32, try_sme_bi32i32);
707 test_cpu_capability("SME_B16F32", 0, "hw.optional.arm.SME_B16F32", CAP_BIT_SME_B16F32, try_sme_b16f32);
708 test_cpu_capability("SME_F16F32", 0, "hw.optional.arm.SME_F16F32", CAP_BIT_SME_F16F32, try_sme_f16f32);
709 test_cpu_capability("SME_I8I32", 0, "hw.optional.arm.SME_I8I32", CAP_BIT_SME_I8I32, try_sme_i8i32);
710 test_cpu_capability("SME_I16I32", 0, "hw.optional.arm.SME_I16I32", CAP_BIT_SME_I16I32, try_sme_i16i32);
711 test_cpu_capability("SME_F64F64", 0, "hw.optional.arm.FEAT_SME_F64F64", CAP_BIT_FEAT_SME_F64F64, try_sme_f64f64);
712 test_cpu_capability("SME_I16I64", 0, "hw.optional.arm.FEAT_SME_I16I64", CAP_BIT_FEAT_SME_I16I64, try_sme_i16i64);
713 test_cpu_capability("SME_F16F16", 0, "hw.optional.arm.FEAT_SME_F16F16", CAP_BIT_FEAT_SME_F16F16, try_sme_f16f16);
714 test_cpu_capability("SME_B16B16", 0, "hw.optional.arm.FEAT_SME_B16B16", CAP_BIT_FEAT_SME_B16B16, try_sme_b16b16);
715
716 // The following features do not add instructions or registers to test for the presence of
717 test_deprecated_sysctl("PACIMP", kHasArmv8GPI, "hw.optional.armv8_gpi");
718 test_cpu_capability("PACIMP", kHasArmv8GPI, "hw.optional.arm.FEAT_PACIMP", CAP_BIT_FEAT_PACIMP, NULL);
719 test_cpu_capability("LSE2", kHasFeatLSE2, "hw.optional.arm.FEAT_LSE2", CAP_BIT_FEAT_LSE2, NULL);
720 test_cpu_capability("CSV2", kHasFeatCSV2, "hw.optional.arm.FEAT_CSV2", CAP_BIT_FEAT_CSV2, NULL);
721 test_cpu_capability("CSV3", kHasFeatCSV3, "hw.optional.arm.FEAT_CSV3", CAP_BIT_FEAT_CSV3, NULL);
722 }
723