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