17a9bcaaaSMark Brown // SPDX-License-Identifier: GPL-2.0-only 27a9bcaaaSMark Brown /* 37a9bcaaaSMark Brown * Copyright (C) 2022 ARM Limited. 47a9bcaaaSMark Brown */ 57a9bcaaaSMark Brown 67a9bcaaaSMark Brown #include <errno.h> 77a9bcaaaSMark Brown #include <signal.h> 87a9bcaaaSMark Brown #include <stdbool.h> 97a9bcaaaSMark Brown #include <stddef.h> 107a9bcaaaSMark Brown #include <stdio.h> 117a9bcaaaSMark Brown #include <stdlib.h> 127a9bcaaaSMark Brown #include <string.h> 137a9bcaaaSMark Brown #include <unistd.h> 147a9bcaaaSMark Brown #include <sys/auxv.h> 157a9bcaaaSMark Brown #include <sys/prctl.h> 167a9bcaaaSMark Brown #include <asm/hwcap.h> 177a9bcaaaSMark Brown #include <asm/sigcontext.h> 187a9bcaaaSMark Brown #include <asm/unistd.h> 197a9bcaaaSMark Brown 207a9bcaaaSMark Brown #include "../../kselftest.h" 217a9bcaaaSMark Brown 227a9bcaaaSMark Brown #define TESTS_PER_HWCAP 2 237a9bcaaaSMark Brown 247a9bcaaaSMark Brown /* 257a9bcaaaSMark Brown * Function expected to generate SIGILL when the feature is not 267a9bcaaaSMark Brown * supported and return when it is supported. If SIGILL is generated 277a9bcaaaSMark Brown * then the handler must be able to skip over the instruction safely. 287a9bcaaaSMark Brown * 297a9bcaaaSMark Brown * Note that it is expected that for many architecture extensions 307a9bcaaaSMark Brown * there are no specific traps due to no architecture state being 317a9bcaaaSMark Brown * added so we may not fault if running on a kernel which doesn't know 327a9bcaaaSMark Brown * to add the hwcap. 337a9bcaaaSMark Brown */ 347a9bcaaaSMark Brown typedef void (*sigill_fn)(void); 357a9bcaaaSMark Brown 36b0ab73a5SMark Brown static void cssc_sigill(void) 37b0ab73a5SMark Brown { 38b0ab73a5SMark Brown /* CNT x0, x0 */ 39b0ab73a5SMark Brown asm volatile(".inst 0xdac01c00" : : : "x0"); 40b0ab73a5SMark Brown } 41b0ab73a5SMark Brown 42*d1890517SZeng Heng static void ilrcpc_sigill(void) 43*d1890517SZeng Heng { 44*d1890517SZeng Heng /* LDAPUR W0, [SP, #8] */ 45*d1890517SZeng Heng asm volatile(".inst 0x994083e0" : : : ); 46*d1890517SZeng Heng } 47*d1890517SZeng Heng 48*d1890517SZeng Heng static void lrcpc_sigill(void) 49*d1890517SZeng Heng { 50*d1890517SZeng Heng /* LDAPR W0, [SP, #0] */ 51*d1890517SZeng Heng asm volatile(".inst 0xb8bfc3e0" : : : ); 52*d1890517SZeng Heng } 53*d1890517SZeng Heng 54d8a324f1SKristina Martsenko static void mops_sigill(void) 55d8a324f1SKristina Martsenko { 56d8a324f1SKristina Martsenko char dst[1], src[1]; 57d8a324f1SKristina Martsenko register char *dstp asm ("x0") = dst; 58d8a324f1SKristina Martsenko register char *srcp asm ("x1") = src; 59d8a324f1SKristina Martsenko register long size asm ("x2") = 1; 60d8a324f1SKristina Martsenko 61d8a324f1SKristina Martsenko /* CPYP [x0]!, [x1]!, x2! */ 62d8a324f1SKristina Martsenko asm volatile(".inst 0x1d010440" 63d8a324f1SKristina Martsenko : "+r" (dstp), "+r" (srcp), "+r" (size) 64d8a324f1SKristina Martsenko : 65d8a324f1SKristina Martsenko : "cc", "memory"); 66d8a324f1SKristina Martsenko } 67d8a324f1SKristina Martsenko 68ef939f30SMark Brown static void rng_sigill(void) 69ef939f30SMark Brown { 70ef939f30SMark Brown asm volatile("mrs x0, S3_3_C2_C4_0" : : : "x0"); 71ef939f30SMark Brown } 72ef939f30SMark Brown 737a9bcaaaSMark Brown static void sme_sigill(void) 747a9bcaaaSMark Brown { 757a9bcaaaSMark Brown /* RDSVL x0, #0 */ 767a9bcaaaSMark Brown asm volatile(".inst 0x04bf5800" : : : "x0"); 777a9bcaaaSMark Brown } 787a9bcaaaSMark Brown 793eb1b41fSMark Brown static void sme2_sigill(void) 803eb1b41fSMark Brown { 813eb1b41fSMark Brown /* SMSTART ZA */ 823eb1b41fSMark Brown asm volatile("msr S0_3_C4_C5_3, xzr" : : : ); 833eb1b41fSMark Brown 843eb1b41fSMark Brown /* ZERO ZT0 */ 853eb1b41fSMark Brown asm volatile(".inst 0xc0480001" : : : ); 863eb1b41fSMark Brown 873eb1b41fSMark Brown /* SMSTOP */ 883eb1b41fSMark Brown asm volatile("msr S0_3_C4_C6_3, xzr" : : : ); 893eb1b41fSMark Brown } 903eb1b41fSMark Brown 913eb1b41fSMark Brown static void sme2p1_sigill(void) 923eb1b41fSMark Brown { 933eb1b41fSMark Brown /* SMSTART SM */ 943eb1b41fSMark Brown asm volatile("msr S0_3_C4_C3_3, xzr" : : : ); 953eb1b41fSMark Brown 963eb1b41fSMark Brown /* BFCLAMP { Z0.H - Z1.H }, Z0.H, Z0.H */ 973eb1b41fSMark Brown asm volatile(".inst 0xc120C000" : : : ); 983eb1b41fSMark Brown 993eb1b41fSMark Brown /* SMSTOP */ 1003eb1b41fSMark Brown asm volatile("msr S0_3_C4_C6_3, xzr" : : : ); 1013eb1b41fSMark Brown } 1023eb1b41fSMark Brown 1033eb1b41fSMark Brown static void smei16i32_sigill(void) 1043eb1b41fSMark Brown { 1053eb1b41fSMark Brown /* SMSTART */ 1063eb1b41fSMark Brown asm volatile("msr S0_3_C4_C7_3, xzr" : : : ); 1073eb1b41fSMark Brown 1083eb1b41fSMark Brown /* SMOPA ZA0.S, P0/M, P0/M, Z0.B, Z0.B */ 1093eb1b41fSMark Brown asm volatile(".inst 0xa0800000" : : : ); 1103eb1b41fSMark Brown 1113eb1b41fSMark Brown /* SMSTOP */ 1123eb1b41fSMark Brown asm volatile("msr S0_3_C4_C6_3, xzr" : : : ); 1133eb1b41fSMark Brown } 1143eb1b41fSMark Brown 1153eb1b41fSMark Brown static void smebi32i32_sigill(void) 1163eb1b41fSMark Brown { 1173eb1b41fSMark Brown /* SMSTART */ 1183eb1b41fSMark Brown asm volatile("msr S0_3_C4_C7_3, xzr" : : : ); 1193eb1b41fSMark Brown 1203eb1b41fSMark Brown /* BMOPA ZA0.S, P0/M, P0/M, Z0.B, Z0.B */ 1213eb1b41fSMark Brown asm volatile(".inst 0x80800008" : : : ); 1223eb1b41fSMark Brown 1233eb1b41fSMark Brown /* SMSTOP */ 1243eb1b41fSMark Brown asm volatile("msr S0_3_C4_C6_3, xzr" : : : ); 1253eb1b41fSMark Brown } 1263eb1b41fSMark Brown 1273eb1b41fSMark Brown static void smeb16b16_sigill(void) 1283eb1b41fSMark Brown { 1293eb1b41fSMark Brown /* SMSTART */ 1303eb1b41fSMark Brown asm volatile("msr S0_3_C4_C7_3, xzr" : : : ); 1313eb1b41fSMark Brown 1323eb1b41fSMark Brown /* BFADD ZA.H[W0, 0], {Z0.H-Z1.H} */ 1333eb1b41fSMark Brown asm volatile(".inst 0xC1E41C00" : : : ); 1343eb1b41fSMark Brown 1353eb1b41fSMark Brown /* SMSTOP */ 1363eb1b41fSMark Brown asm volatile("msr S0_3_C4_C6_3, xzr" : : : ); 1373eb1b41fSMark Brown } 1383eb1b41fSMark Brown 1393eb1b41fSMark Brown static void smef16f16_sigill(void) 1403eb1b41fSMark Brown { 1413eb1b41fSMark Brown /* SMSTART */ 1423eb1b41fSMark Brown asm volatile("msr S0_3_C4_C7_3, xzr" : : : ); 1433eb1b41fSMark Brown 1443eb1b41fSMark Brown /* FADD ZA.H[W0, 0], { Z0.H-Z1.H } */ 1453eb1b41fSMark Brown asm volatile(".inst 0xc1a41C00" : : : ); 1463eb1b41fSMark Brown 1473eb1b41fSMark Brown /* SMSTOP */ 1483eb1b41fSMark Brown asm volatile("msr S0_3_C4_C6_3, xzr" : : : ); 1493eb1b41fSMark Brown } 1503eb1b41fSMark Brown 1517a9bcaaaSMark Brown static void sve_sigill(void) 1527a9bcaaaSMark Brown { 1537a9bcaaaSMark Brown /* RDVL x0, #0 */ 1547a9bcaaaSMark Brown asm volatile(".inst 0x04bf5000" : : : "x0"); 1557a9bcaaaSMark Brown } 1567a9bcaaaSMark Brown 157859a9d51SMark Brown static void sve2_sigill(void) 158859a9d51SMark Brown { 159859a9d51SMark Brown /* SQABS Z0.b, P0/M, Z0.B */ 160859a9d51SMark Brown asm volatile(".inst 0x4408A000" : : : "z0"); 161859a9d51SMark Brown } 162859a9d51SMark Brown 163c5195b02SMark Brown static void sve2p1_sigill(void) 164c5195b02SMark Brown { 165c5195b02SMark Brown /* BFADD Z0.H, Z0.H, Z0.H */ 166c5195b02SMark Brown asm volatile(".inst 0x65000000" : : : "z0"); 167c5195b02SMark Brown } 168c5195b02SMark Brown 169859a9d51SMark Brown static void sveaes_sigill(void) 170859a9d51SMark Brown { 171859a9d51SMark Brown /* AESD z0.b, z0.b, z0.b */ 172859a9d51SMark Brown asm volatile(".inst 0x4522e400" : : : "z0"); 173859a9d51SMark Brown } 174859a9d51SMark Brown 175859a9d51SMark Brown static void svepmull_sigill(void) 176859a9d51SMark Brown { 177859a9d51SMark Brown /* PMULLB Z0.Q, Z0.D, Z0.D */ 178859a9d51SMark Brown asm volatile(".inst 0x45006800" : : : "z0"); 179859a9d51SMark Brown } 180859a9d51SMark Brown 181859a9d51SMark Brown static void svebitperm_sigill(void) 182859a9d51SMark Brown { 183859a9d51SMark Brown /* BDEP Z0.B, Z0.B, Z0.B */ 184859a9d51SMark Brown asm volatile(".inst 0x4500b400" : : : "z0"); 185859a9d51SMark Brown } 186859a9d51SMark Brown 187859a9d51SMark Brown static void svesha3_sigill(void) 188859a9d51SMark Brown { 189859a9d51SMark Brown /* EOR3 Z0.D, Z0.D, Z0.D, Z0.D */ 190859a9d51SMark Brown asm volatile(".inst 0x4203800" : : : "z0"); 191859a9d51SMark Brown } 192859a9d51SMark Brown 193859a9d51SMark Brown static void svesm4_sigill(void) 194859a9d51SMark Brown { 195859a9d51SMark Brown /* SM4E Z0.S, Z0.S, Z0.S */ 196859a9d51SMark Brown asm volatile(".inst 0x4523e000" : : : "z0"); 197859a9d51SMark Brown } 198859a9d51SMark Brown 199859a9d51SMark Brown static void svei8mm_sigill(void) 200859a9d51SMark Brown { 201859a9d51SMark Brown /* USDOT Z0.S, Z0.B, Z0.B[0] */ 202859a9d51SMark Brown asm volatile(".inst 0x44a01800" : : : "z0"); 203859a9d51SMark Brown } 204859a9d51SMark Brown 205859a9d51SMark Brown static void svef32mm_sigill(void) 206859a9d51SMark Brown { 207859a9d51SMark Brown /* FMMLA Z0.S, Z0.S, Z0.S */ 208859a9d51SMark Brown asm volatile(".inst 0x64a0e400" : : : "z0"); 209859a9d51SMark Brown } 210859a9d51SMark Brown 211859a9d51SMark Brown static void svef64mm_sigill(void) 212859a9d51SMark Brown { 213859a9d51SMark Brown /* FMMLA Z0.D, Z0.D, Z0.D */ 214859a9d51SMark Brown asm volatile(".inst 0x64e0e400" : : : "z0"); 215859a9d51SMark Brown } 216859a9d51SMark Brown 217859a9d51SMark Brown static void svebf16_sigill(void) 218859a9d51SMark Brown { 219859a9d51SMark Brown /* BFCVT Z0.H, P0/M, Z0.S */ 220859a9d51SMark Brown asm volatile(".inst 0x658aa000" : : : "z0"); 221859a9d51SMark Brown } 222859a9d51SMark Brown 2237a9bcaaaSMark Brown static const struct hwcap_data { 2247a9bcaaaSMark Brown const char *name; 2257a9bcaaaSMark Brown unsigned long at_hwcap; 2267a9bcaaaSMark Brown unsigned long hwcap_bit; 2277a9bcaaaSMark Brown const char *cpuinfo; 2287a9bcaaaSMark Brown sigill_fn sigill_fn; 2297a9bcaaaSMark Brown bool sigill_reliable; 2307a9bcaaaSMark Brown } hwcaps[] = { 2317a9bcaaaSMark Brown { 232b0ab73a5SMark Brown .name = "CSSC", 233b0ab73a5SMark Brown .at_hwcap = AT_HWCAP2, 234b0ab73a5SMark Brown .hwcap_bit = HWCAP2_CSSC, 235b0ab73a5SMark Brown .cpuinfo = "cssc", 236b0ab73a5SMark Brown .sigill_fn = cssc_sigill, 237b0ab73a5SMark Brown }, 238b0ab73a5SMark Brown { 239*d1890517SZeng Heng .name = "LRCPC", 240*d1890517SZeng Heng .at_hwcap = AT_HWCAP, 241*d1890517SZeng Heng .hwcap_bit = HWCAP_LRCPC, 242*d1890517SZeng Heng .cpuinfo = "lrcpc", 243*d1890517SZeng Heng .sigill_fn = lrcpc_sigill, 244*d1890517SZeng Heng }, 245*d1890517SZeng Heng { 246*d1890517SZeng Heng .name = "LRCPC2", 247*d1890517SZeng Heng .at_hwcap = AT_HWCAP, 248*d1890517SZeng Heng .hwcap_bit = HWCAP_ILRCPC, 249*d1890517SZeng Heng .cpuinfo = "ilrcpc", 250*d1890517SZeng Heng .sigill_fn = ilrcpc_sigill, 251*d1890517SZeng Heng }, 252*d1890517SZeng Heng { 253d8a324f1SKristina Martsenko .name = "MOPS", 254d8a324f1SKristina Martsenko .at_hwcap = AT_HWCAP2, 255d8a324f1SKristina Martsenko .hwcap_bit = HWCAP2_MOPS, 256d8a324f1SKristina Martsenko .cpuinfo = "mops", 257d8a324f1SKristina Martsenko .sigill_fn = mops_sigill, 258d8a324f1SKristina Martsenko .sigill_reliable = true, 259d8a324f1SKristina Martsenko }, 260d8a324f1SKristina Martsenko { 261ef939f30SMark Brown .name = "RNG", 262ef939f30SMark Brown .at_hwcap = AT_HWCAP2, 263ef939f30SMark Brown .hwcap_bit = HWCAP2_RNG, 264ef939f30SMark Brown .cpuinfo = "rng", 265ef939f30SMark Brown .sigill_fn = rng_sigill, 266ef939f30SMark Brown }, 267ef939f30SMark Brown { 268989d37fcSMark Brown .name = "RPRFM", 269989d37fcSMark Brown .at_hwcap = AT_HWCAP2, 270989d37fcSMark Brown .hwcap_bit = HWCAP2_RPRFM, 271989d37fcSMark Brown .cpuinfo = "rprfm", 272989d37fcSMark Brown }, 273989d37fcSMark Brown { 2747a9bcaaaSMark Brown .name = "SME", 2757a9bcaaaSMark Brown .at_hwcap = AT_HWCAP2, 2767a9bcaaaSMark Brown .hwcap_bit = HWCAP2_SME, 2777a9bcaaaSMark Brown .cpuinfo = "sme", 2787a9bcaaaSMark Brown .sigill_fn = sme_sigill, 2797a9bcaaaSMark Brown .sigill_reliable = true, 2807a9bcaaaSMark Brown }, 2817a9bcaaaSMark Brown { 2823eb1b41fSMark Brown .name = "SME2", 2833eb1b41fSMark Brown .at_hwcap = AT_HWCAP2, 2843eb1b41fSMark Brown .hwcap_bit = HWCAP2_SME2, 2853eb1b41fSMark Brown .cpuinfo = "sme2", 2863eb1b41fSMark Brown .sigill_fn = sme2_sigill, 2873eb1b41fSMark Brown .sigill_reliable = true, 2883eb1b41fSMark Brown }, 2893eb1b41fSMark Brown { 2903eb1b41fSMark Brown .name = "SME 2.1", 2913eb1b41fSMark Brown .at_hwcap = AT_HWCAP2, 2923eb1b41fSMark Brown .hwcap_bit = HWCAP2_SME2P1, 2933eb1b41fSMark Brown .cpuinfo = "sme2p1", 2943eb1b41fSMark Brown .sigill_fn = sme2p1_sigill, 2953eb1b41fSMark Brown }, 2963eb1b41fSMark Brown { 2973eb1b41fSMark Brown .name = "SME I16I32", 2983eb1b41fSMark Brown .at_hwcap = AT_HWCAP2, 2993eb1b41fSMark Brown .hwcap_bit = HWCAP2_SME_I16I32, 3003eb1b41fSMark Brown .cpuinfo = "smei16i32", 3013eb1b41fSMark Brown .sigill_fn = smei16i32_sigill, 3023eb1b41fSMark Brown }, 3033eb1b41fSMark Brown { 3043eb1b41fSMark Brown .name = "SME BI32I32", 3053eb1b41fSMark Brown .at_hwcap = AT_HWCAP2, 3063eb1b41fSMark Brown .hwcap_bit = HWCAP2_SME_BI32I32, 3073eb1b41fSMark Brown .cpuinfo = "smebi32i32", 3083eb1b41fSMark Brown .sigill_fn = smebi32i32_sigill, 3093eb1b41fSMark Brown }, 3103eb1b41fSMark Brown { 3113eb1b41fSMark Brown .name = "SME B16B16", 3123eb1b41fSMark Brown .at_hwcap = AT_HWCAP2, 3133eb1b41fSMark Brown .hwcap_bit = HWCAP2_SME_B16B16, 3143eb1b41fSMark Brown .cpuinfo = "smeb16b16", 3153eb1b41fSMark Brown .sigill_fn = smeb16b16_sigill, 3163eb1b41fSMark Brown }, 3173eb1b41fSMark Brown { 3183eb1b41fSMark Brown .name = "SME F16F16", 3193eb1b41fSMark Brown .at_hwcap = AT_HWCAP2, 3203eb1b41fSMark Brown .hwcap_bit = HWCAP2_SME_F16F16, 3213eb1b41fSMark Brown .cpuinfo = "smef16f16", 3223eb1b41fSMark Brown .sigill_fn = smef16f16_sigill, 3233eb1b41fSMark Brown }, 3243eb1b41fSMark Brown { 3257a9bcaaaSMark Brown .name = "SVE", 3267a9bcaaaSMark Brown .at_hwcap = AT_HWCAP, 3277a9bcaaaSMark Brown .hwcap_bit = HWCAP_SVE, 3287a9bcaaaSMark Brown .cpuinfo = "sve", 3297a9bcaaaSMark Brown .sigill_fn = sve_sigill, 3307a9bcaaaSMark Brown .sigill_reliable = true, 3317a9bcaaaSMark Brown }, 332859a9d51SMark Brown { 333859a9d51SMark Brown .name = "SVE 2", 334859a9d51SMark Brown .at_hwcap = AT_HWCAP2, 335859a9d51SMark Brown .hwcap_bit = HWCAP2_SVE2, 336859a9d51SMark Brown .cpuinfo = "sve2", 337859a9d51SMark Brown .sigill_fn = sve2_sigill, 338859a9d51SMark Brown }, 339859a9d51SMark Brown { 340c5195b02SMark Brown .name = "SVE 2.1", 341c5195b02SMark Brown .at_hwcap = AT_HWCAP2, 342c5195b02SMark Brown .hwcap_bit = HWCAP2_SVE2P1, 343c5195b02SMark Brown .cpuinfo = "sve2p1", 344c5195b02SMark Brown .sigill_fn = sve2p1_sigill, 345c5195b02SMark Brown }, 346c5195b02SMark Brown { 347859a9d51SMark Brown .name = "SVE AES", 348859a9d51SMark Brown .at_hwcap = AT_HWCAP2, 349859a9d51SMark Brown .hwcap_bit = HWCAP2_SVEAES, 350859a9d51SMark Brown .cpuinfo = "sveaes", 351859a9d51SMark Brown .sigill_fn = sveaes_sigill, 352859a9d51SMark Brown }, 353859a9d51SMark Brown { 354859a9d51SMark Brown .name = "SVE2 PMULL", 355859a9d51SMark Brown .at_hwcap = AT_HWCAP2, 356859a9d51SMark Brown .hwcap_bit = HWCAP2_SVEPMULL, 357859a9d51SMark Brown .cpuinfo = "svepmull", 358859a9d51SMark Brown .sigill_fn = svepmull_sigill, 359859a9d51SMark Brown }, 360859a9d51SMark Brown { 361859a9d51SMark Brown .name = "SVE2 BITPERM", 362859a9d51SMark Brown .at_hwcap = AT_HWCAP2, 363859a9d51SMark Brown .hwcap_bit = HWCAP2_SVEBITPERM, 364859a9d51SMark Brown .cpuinfo = "svebitperm", 365859a9d51SMark Brown .sigill_fn = svebitperm_sigill, 366859a9d51SMark Brown }, 367859a9d51SMark Brown { 368859a9d51SMark Brown .name = "SVE2 SHA3", 369859a9d51SMark Brown .at_hwcap = AT_HWCAP2, 370859a9d51SMark Brown .hwcap_bit = HWCAP2_SVESHA3, 371859a9d51SMark Brown .cpuinfo = "svesha3", 372859a9d51SMark Brown .sigill_fn = svesha3_sigill, 373859a9d51SMark Brown }, 374859a9d51SMark Brown { 375859a9d51SMark Brown .name = "SVE2 SM4", 376859a9d51SMark Brown .at_hwcap = AT_HWCAP2, 377859a9d51SMark Brown .hwcap_bit = HWCAP2_SVESM4, 378859a9d51SMark Brown .cpuinfo = "svesm4", 379859a9d51SMark Brown .sigill_fn = svesm4_sigill, 380859a9d51SMark Brown }, 381859a9d51SMark Brown { 382859a9d51SMark Brown .name = "SVE2 I8MM", 383859a9d51SMark Brown .at_hwcap = AT_HWCAP2, 384859a9d51SMark Brown .hwcap_bit = HWCAP2_SVEI8MM, 385859a9d51SMark Brown .cpuinfo = "svei8mm", 386859a9d51SMark Brown .sigill_fn = svei8mm_sigill, 387859a9d51SMark Brown }, 388859a9d51SMark Brown { 389859a9d51SMark Brown .name = "SVE2 F32MM", 390859a9d51SMark Brown .at_hwcap = AT_HWCAP2, 391859a9d51SMark Brown .hwcap_bit = HWCAP2_SVEF32MM, 392859a9d51SMark Brown .cpuinfo = "svef32mm", 393859a9d51SMark Brown .sigill_fn = svef32mm_sigill, 394859a9d51SMark Brown }, 395859a9d51SMark Brown { 396859a9d51SMark Brown .name = "SVE2 F64MM", 397859a9d51SMark Brown .at_hwcap = AT_HWCAP2, 398859a9d51SMark Brown .hwcap_bit = HWCAP2_SVEF64MM, 399859a9d51SMark Brown .cpuinfo = "svef64mm", 400859a9d51SMark Brown .sigill_fn = svef64mm_sigill, 401859a9d51SMark Brown }, 402859a9d51SMark Brown { 403859a9d51SMark Brown .name = "SVE2 BF16", 404859a9d51SMark Brown .at_hwcap = AT_HWCAP2, 405859a9d51SMark Brown .hwcap_bit = HWCAP2_SVEBF16, 406859a9d51SMark Brown .cpuinfo = "svebf16", 407859a9d51SMark Brown .sigill_fn = svebf16_sigill, 408859a9d51SMark Brown }, 409859a9d51SMark Brown { 410859a9d51SMark Brown .name = "SVE2 EBF16", 411859a9d51SMark Brown .at_hwcap = AT_HWCAP2, 412859a9d51SMark Brown .hwcap_bit = HWCAP2_SVE_EBF16, 413859a9d51SMark Brown .cpuinfo = "sveebf16", 414859a9d51SMark Brown }, 4157a9bcaaaSMark Brown }; 4167a9bcaaaSMark Brown 4177a9bcaaaSMark Brown static bool seen_sigill; 4187a9bcaaaSMark Brown 4197a9bcaaaSMark Brown static void handle_sigill(int sig, siginfo_t *info, void *context) 4207a9bcaaaSMark Brown { 4217a9bcaaaSMark Brown ucontext_t *uc = context; 4227a9bcaaaSMark Brown 4237a9bcaaaSMark Brown seen_sigill = true; 4247a9bcaaaSMark Brown 4257a9bcaaaSMark Brown /* Skip over the offending instruction */ 4267a9bcaaaSMark Brown uc->uc_mcontext.pc += 4; 4277a9bcaaaSMark Brown } 4287a9bcaaaSMark Brown 4297a9bcaaaSMark Brown bool cpuinfo_present(const char *name) 4307a9bcaaaSMark Brown { 4317a9bcaaaSMark Brown FILE *f; 4327a9bcaaaSMark Brown char buf[2048], name_space[30], name_newline[30]; 4337a9bcaaaSMark Brown char *s; 4347a9bcaaaSMark Brown 4357a9bcaaaSMark Brown /* 4367a9bcaaaSMark Brown * The feature should appear with a leading space and either a 4377a9bcaaaSMark Brown * trailing space or a newline. 4387a9bcaaaSMark Brown */ 4397a9bcaaaSMark Brown snprintf(name_space, sizeof(name_space), " %s ", name); 4407a9bcaaaSMark Brown snprintf(name_newline, sizeof(name_newline), " %s\n", name); 4417a9bcaaaSMark Brown 4427a9bcaaaSMark Brown f = fopen("/proc/cpuinfo", "r"); 4437a9bcaaaSMark Brown if (!f) { 4447a9bcaaaSMark Brown ksft_print_msg("Failed to open /proc/cpuinfo\n"); 4457a9bcaaaSMark Brown return false; 4467a9bcaaaSMark Brown } 4477a9bcaaaSMark Brown 4487a9bcaaaSMark Brown while (fgets(buf, sizeof(buf), f)) { 4497a9bcaaaSMark Brown /* Features: line? */ 4507a9bcaaaSMark Brown if (strncmp(buf, "Features\t:", strlen("Features\t:")) != 0) 4517a9bcaaaSMark Brown continue; 4527a9bcaaaSMark Brown 4537a9bcaaaSMark Brown /* All CPUs should be symmetric, don't read any more */ 4547a9bcaaaSMark Brown fclose(f); 4557a9bcaaaSMark Brown 4567a9bcaaaSMark Brown s = strstr(buf, name_space); 4577a9bcaaaSMark Brown if (s) 4587a9bcaaaSMark Brown return true; 4597a9bcaaaSMark Brown s = strstr(buf, name_newline); 4607a9bcaaaSMark Brown if (s) 4617a9bcaaaSMark Brown return true; 4627a9bcaaaSMark Brown 4637a9bcaaaSMark Brown return false; 4647a9bcaaaSMark Brown } 4657a9bcaaaSMark Brown 4667a9bcaaaSMark Brown ksft_print_msg("Failed to find Features in /proc/cpuinfo\n"); 4677a9bcaaaSMark Brown fclose(f); 4687a9bcaaaSMark Brown return false; 4697a9bcaaaSMark Brown } 4707a9bcaaaSMark Brown 4717a9bcaaaSMark Brown int main(void) 4727a9bcaaaSMark Brown { 4737a9bcaaaSMark Brown const struct hwcap_data *hwcap; 4747a9bcaaaSMark Brown int i, ret; 4757a9bcaaaSMark Brown bool have_cpuinfo, have_hwcap; 4767a9bcaaaSMark Brown struct sigaction sa; 4777a9bcaaaSMark Brown 4787a9bcaaaSMark Brown ksft_print_header(); 4797a9bcaaaSMark Brown ksft_set_plan(ARRAY_SIZE(hwcaps) * TESTS_PER_HWCAP); 4807a9bcaaaSMark Brown 4817a9bcaaaSMark Brown memset(&sa, 0, sizeof(sa)); 4827a9bcaaaSMark Brown sa.sa_sigaction = handle_sigill; 4837a9bcaaaSMark Brown sa.sa_flags = SA_RESTART | SA_SIGINFO; 4847a9bcaaaSMark Brown sigemptyset(&sa.sa_mask); 4857a9bcaaaSMark Brown ret = sigaction(SIGILL, &sa, NULL); 4867a9bcaaaSMark Brown if (ret < 0) 4877a9bcaaaSMark Brown ksft_exit_fail_msg("Failed to install SIGILL handler: %s (%d)\n", 4887a9bcaaaSMark Brown strerror(errno), errno); 4897a9bcaaaSMark Brown 4907a9bcaaaSMark Brown for (i = 0; i < ARRAY_SIZE(hwcaps); i++) { 4917a9bcaaaSMark Brown hwcap = &hwcaps[i]; 4927a9bcaaaSMark Brown 49333060a64SMark Brown have_hwcap = getauxval(hwcap->at_hwcap) & hwcap->hwcap_bit; 4947a9bcaaaSMark Brown have_cpuinfo = cpuinfo_present(hwcap->cpuinfo); 4957a9bcaaaSMark Brown 4967a9bcaaaSMark Brown if (have_hwcap) 49778d2b197SMark Brown ksft_print_msg("%s present\n", hwcap->name); 4987a9bcaaaSMark Brown 4997a9bcaaaSMark Brown ksft_test_result(have_hwcap == have_cpuinfo, 5007a9bcaaaSMark Brown "cpuinfo_match_%s\n", hwcap->name); 5017a9bcaaaSMark Brown 5027a9bcaaaSMark Brown if (hwcap->sigill_fn) { 5037a9bcaaaSMark Brown seen_sigill = false; 5047a9bcaaaSMark Brown hwcap->sigill_fn(); 5057a9bcaaaSMark Brown 5067a9bcaaaSMark Brown if (have_hwcap) { 5077a9bcaaaSMark Brown /* Should be able to use the extension */ 5087a9bcaaaSMark Brown ksft_test_result(!seen_sigill, "sigill_%s\n", 5097a9bcaaaSMark Brown hwcap->name); 5107a9bcaaaSMark Brown } else if (hwcap->sigill_reliable) { 5117a9bcaaaSMark Brown /* Guaranteed a SIGILL */ 5127a9bcaaaSMark Brown ksft_test_result(seen_sigill, "sigill_%s\n", 5137a9bcaaaSMark Brown hwcap->name); 5147a9bcaaaSMark Brown } else { 5157a9bcaaaSMark Brown /* Missing SIGILL might be fine */ 5167a9bcaaaSMark Brown ksft_print_msg("SIGILL %sreported for %s\n", 5177a9bcaaaSMark Brown seen_sigill ? "" : "not ", 5187a9bcaaaSMark Brown hwcap->name); 5197a9bcaaaSMark Brown ksft_test_result_skip("sigill_%s\n", 5207a9bcaaaSMark Brown hwcap->name); 5217a9bcaaaSMark Brown } 5227a9bcaaaSMark Brown } else { 5237a9bcaaaSMark Brown ksft_test_result_skip("sigill_%s\n", 5247a9bcaaaSMark Brown hwcap->name); 5257a9bcaaaSMark Brown } 5267a9bcaaaSMark Brown } 5277a9bcaaaSMark Brown 5287a9bcaaaSMark Brown ksft_print_cnts(); 5297a9bcaaaSMark Brown 5307a9bcaaaSMark Brown return 0; 5317a9bcaaaSMark Brown } 532