162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2022 ARM Limited. 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <errno.h> 762306a36Sopenharmony_ci#include <signal.h> 862306a36Sopenharmony_ci#include <stdbool.h> 962306a36Sopenharmony_ci#include <stddef.h> 1062306a36Sopenharmony_ci#include <stdio.h> 1162306a36Sopenharmony_ci#include <stdlib.h> 1262306a36Sopenharmony_ci#include <string.h> 1362306a36Sopenharmony_ci#include <unistd.h> 1462306a36Sopenharmony_ci#include <sys/auxv.h> 1562306a36Sopenharmony_ci#include <sys/prctl.h> 1662306a36Sopenharmony_ci#include <asm/hwcap.h> 1762306a36Sopenharmony_ci#include <asm/sigcontext.h> 1862306a36Sopenharmony_ci#include <asm/unistd.h> 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#include "../../kselftest.h" 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#define TESTS_PER_HWCAP 3 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci/* 2562306a36Sopenharmony_ci * Function expected to generate exception when the feature is not 2662306a36Sopenharmony_ci * supported and return when it is supported. If the specific exception 2762306a36Sopenharmony_ci * is generated then the handler must be able to skip over the 2862306a36Sopenharmony_ci * instruction safely. 2962306a36Sopenharmony_ci * 3062306a36Sopenharmony_ci * Note that it is expected that for many architecture extensions 3162306a36Sopenharmony_ci * there are no specific traps due to no architecture state being 3262306a36Sopenharmony_ci * added so we may not fault if running on a kernel which doesn't know 3362306a36Sopenharmony_ci * to add the hwcap. 3462306a36Sopenharmony_ci */ 3562306a36Sopenharmony_citypedef void (*sig_fn)(void); 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_cistatic void aes_sigill(void) 3862306a36Sopenharmony_ci{ 3962306a36Sopenharmony_ci /* AESE V0.16B, V0.16B */ 4062306a36Sopenharmony_ci asm volatile(".inst 0x4e284800" : : : ); 4162306a36Sopenharmony_ci} 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_cistatic void atomics_sigill(void) 4462306a36Sopenharmony_ci{ 4562306a36Sopenharmony_ci /* STADD W0, [SP] */ 4662306a36Sopenharmony_ci asm volatile(".inst 0xb82003ff" : : : ); 4762306a36Sopenharmony_ci} 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_cistatic void crc32_sigill(void) 5062306a36Sopenharmony_ci{ 5162306a36Sopenharmony_ci /* CRC32W W0, W0, W1 */ 5262306a36Sopenharmony_ci asm volatile(".inst 0x1ac14800" : : : ); 5362306a36Sopenharmony_ci} 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_cistatic void cssc_sigill(void) 5662306a36Sopenharmony_ci{ 5762306a36Sopenharmony_ci /* CNT x0, x0 */ 5862306a36Sopenharmony_ci asm volatile(".inst 0xdac01c00" : : : "x0"); 5962306a36Sopenharmony_ci} 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_cistatic void fp_sigill(void) 6262306a36Sopenharmony_ci{ 6362306a36Sopenharmony_ci asm volatile("fmov s0, #1"); 6462306a36Sopenharmony_ci} 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_cistatic void ilrcpc_sigill(void) 6762306a36Sopenharmony_ci{ 6862306a36Sopenharmony_ci /* LDAPUR W0, [SP, #8] */ 6962306a36Sopenharmony_ci asm volatile(".inst 0x994083e0" : : : ); 7062306a36Sopenharmony_ci} 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_cistatic void jscvt_sigill(void) 7362306a36Sopenharmony_ci{ 7462306a36Sopenharmony_ci /* FJCVTZS W0, D0 */ 7562306a36Sopenharmony_ci asm volatile(".inst 0x1e7e0000" : : : ); 7662306a36Sopenharmony_ci} 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_cistatic void lrcpc_sigill(void) 7962306a36Sopenharmony_ci{ 8062306a36Sopenharmony_ci /* LDAPR W0, [SP, #0] */ 8162306a36Sopenharmony_ci asm volatile(".inst 0xb8bfc3e0" : : : ); 8262306a36Sopenharmony_ci} 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_cistatic void mops_sigill(void) 8562306a36Sopenharmony_ci{ 8662306a36Sopenharmony_ci char dst[1], src[1]; 8762306a36Sopenharmony_ci register char *dstp asm ("x0") = dst; 8862306a36Sopenharmony_ci register char *srcp asm ("x1") = src; 8962306a36Sopenharmony_ci register long size asm ("x2") = 1; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci /* CPYP [x0]!, [x1]!, x2! */ 9262306a36Sopenharmony_ci asm volatile(".inst 0x1d010440" 9362306a36Sopenharmony_ci : "+r" (dstp), "+r" (srcp), "+r" (size) 9462306a36Sopenharmony_ci : 9562306a36Sopenharmony_ci : "cc", "memory"); 9662306a36Sopenharmony_ci} 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_cistatic void pmull_sigill(void) 9962306a36Sopenharmony_ci{ 10062306a36Sopenharmony_ci /* PMULL V0.1Q, V0.1D, V0.1D */ 10162306a36Sopenharmony_ci asm volatile(".inst 0x0ee0e000" : : : ); 10262306a36Sopenharmony_ci} 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_cistatic void rng_sigill(void) 10562306a36Sopenharmony_ci{ 10662306a36Sopenharmony_ci asm volatile("mrs x0, S3_3_C2_C4_0" : : : "x0"); 10762306a36Sopenharmony_ci} 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_cistatic void sha1_sigill(void) 11062306a36Sopenharmony_ci{ 11162306a36Sopenharmony_ci /* SHA1H S0, S0 */ 11262306a36Sopenharmony_ci asm volatile(".inst 0x5e280800" : : : ); 11362306a36Sopenharmony_ci} 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_cistatic void sha2_sigill(void) 11662306a36Sopenharmony_ci{ 11762306a36Sopenharmony_ci /* SHA256H Q0, Q0, V0.4S */ 11862306a36Sopenharmony_ci asm volatile(".inst 0x5e004000" : : : ); 11962306a36Sopenharmony_ci} 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_cistatic void sha512_sigill(void) 12262306a36Sopenharmony_ci{ 12362306a36Sopenharmony_ci /* SHA512H Q0, Q0, V0.2D */ 12462306a36Sopenharmony_ci asm volatile(".inst 0xce608000" : : : ); 12562306a36Sopenharmony_ci} 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_cistatic void sme_sigill(void) 12862306a36Sopenharmony_ci{ 12962306a36Sopenharmony_ci /* RDSVL x0, #0 */ 13062306a36Sopenharmony_ci asm volatile(".inst 0x04bf5800" : : : "x0"); 13162306a36Sopenharmony_ci} 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_cistatic void sme2_sigill(void) 13462306a36Sopenharmony_ci{ 13562306a36Sopenharmony_ci /* SMSTART ZA */ 13662306a36Sopenharmony_ci asm volatile("msr S0_3_C4_C5_3, xzr" : : : ); 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci /* ZERO ZT0 */ 13962306a36Sopenharmony_ci asm volatile(".inst 0xc0480001" : : : ); 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci /* SMSTOP */ 14262306a36Sopenharmony_ci asm volatile("msr S0_3_C4_C6_3, xzr" : : : ); 14362306a36Sopenharmony_ci} 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_cistatic void sme2p1_sigill(void) 14662306a36Sopenharmony_ci{ 14762306a36Sopenharmony_ci /* SMSTART SM */ 14862306a36Sopenharmony_ci asm volatile("msr S0_3_C4_C3_3, xzr" : : : ); 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci /* BFCLAMP { Z0.H - Z1.H }, Z0.H, Z0.H */ 15162306a36Sopenharmony_ci asm volatile(".inst 0xc120C000" : : : ); 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci /* SMSTOP */ 15462306a36Sopenharmony_ci asm volatile("msr S0_3_C4_C6_3, xzr" : : : ); 15562306a36Sopenharmony_ci} 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_cistatic void smei16i32_sigill(void) 15862306a36Sopenharmony_ci{ 15962306a36Sopenharmony_ci /* SMSTART */ 16062306a36Sopenharmony_ci asm volatile("msr S0_3_C4_C7_3, xzr" : : : ); 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci /* SMOPA ZA0.S, P0/M, P0/M, Z0.B, Z0.B */ 16362306a36Sopenharmony_ci asm volatile(".inst 0xa0800000" : : : ); 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci /* SMSTOP */ 16662306a36Sopenharmony_ci asm volatile("msr S0_3_C4_C6_3, xzr" : : : ); 16762306a36Sopenharmony_ci} 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_cistatic void smebi32i32_sigill(void) 17062306a36Sopenharmony_ci{ 17162306a36Sopenharmony_ci /* SMSTART */ 17262306a36Sopenharmony_ci asm volatile("msr S0_3_C4_C7_3, xzr" : : : ); 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci /* BMOPA ZA0.S, P0/M, P0/M, Z0.B, Z0.B */ 17562306a36Sopenharmony_ci asm volatile(".inst 0x80800008" : : : ); 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci /* SMSTOP */ 17862306a36Sopenharmony_ci asm volatile("msr S0_3_C4_C6_3, xzr" : : : ); 17962306a36Sopenharmony_ci} 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_cistatic void smeb16b16_sigill(void) 18262306a36Sopenharmony_ci{ 18362306a36Sopenharmony_ci /* SMSTART */ 18462306a36Sopenharmony_ci asm volatile("msr S0_3_C4_C7_3, xzr" : : : ); 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci /* BFADD ZA.H[W0, 0], {Z0.H-Z1.H} */ 18762306a36Sopenharmony_ci asm volatile(".inst 0xC1E41C00" : : : ); 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci /* SMSTOP */ 19062306a36Sopenharmony_ci asm volatile("msr S0_3_C4_C6_3, xzr" : : : ); 19162306a36Sopenharmony_ci} 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_cistatic void smef16f16_sigill(void) 19462306a36Sopenharmony_ci{ 19562306a36Sopenharmony_ci /* SMSTART */ 19662306a36Sopenharmony_ci asm volatile("msr S0_3_C4_C7_3, xzr" : : : ); 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci /* FADD ZA.H[W0, 0], { Z0.H-Z1.H } */ 19962306a36Sopenharmony_ci asm volatile(".inst 0xc1a41C00" : : : ); 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci /* SMSTOP */ 20262306a36Sopenharmony_ci asm volatile("msr S0_3_C4_C6_3, xzr" : : : ); 20362306a36Sopenharmony_ci} 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_cistatic void sve_sigill(void) 20662306a36Sopenharmony_ci{ 20762306a36Sopenharmony_ci /* RDVL x0, #0 */ 20862306a36Sopenharmony_ci asm volatile(".inst 0x04bf5000" : : : "x0"); 20962306a36Sopenharmony_ci} 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_cistatic void sve2_sigill(void) 21262306a36Sopenharmony_ci{ 21362306a36Sopenharmony_ci /* SQABS Z0.b, P0/M, Z0.B */ 21462306a36Sopenharmony_ci asm volatile(".inst 0x4408A000" : : : "z0"); 21562306a36Sopenharmony_ci} 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_cistatic void sve2p1_sigill(void) 21862306a36Sopenharmony_ci{ 21962306a36Sopenharmony_ci /* BFADD Z0.H, Z0.H, Z0.H */ 22062306a36Sopenharmony_ci asm volatile(".inst 0x65000000" : : : "z0"); 22162306a36Sopenharmony_ci} 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_cistatic void sveaes_sigill(void) 22462306a36Sopenharmony_ci{ 22562306a36Sopenharmony_ci /* AESD z0.b, z0.b, z0.b */ 22662306a36Sopenharmony_ci asm volatile(".inst 0x4522e400" : : : "z0"); 22762306a36Sopenharmony_ci} 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_cistatic void svepmull_sigill(void) 23062306a36Sopenharmony_ci{ 23162306a36Sopenharmony_ci /* PMULLB Z0.Q, Z0.D, Z0.D */ 23262306a36Sopenharmony_ci asm volatile(".inst 0x45006800" : : : "z0"); 23362306a36Sopenharmony_ci} 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_cistatic void svebitperm_sigill(void) 23662306a36Sopenharmony_ci{ 23762306a36Sopenharmony_ci /* BDEP Z0.B, Z0.B, Z0.B */ 23862306a36Sopenharmony_ci asm volatile(".inst 0x4500b400" : : : "z0"); 23962306a36Sopenharmony_ci} 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_cistatic void svesha3_sigill(void) 24262306a36Sopenharmony_ci{ 24362306a36Sopenharmony_ci /* EOR3 Z0.D, Z0.D, Z0.D, Z0.D */ 24462306a36Sopenharmony_ci asm volatile(".inst 0x4203800" : : : "z0"); 24562306a36Sopenharmony_ci} 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_cistatic void svesm4_sigill(void) 24862306a36Sopenharmony_ci{ 24962306a36Sopenharmony_ci /* SM4E Z0.S, Z0.S, Z0.S */ 25062306a36Sopenharmony_ci asm volatile(".inst 0x4523e000" : : : "z0"); 25162306a36Sopenharmony_ci} 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_cistatic void svei8mm_sigill(void) 25462306a36Sopenharmony_ci{ 25562306a36Sopenharmony_ci /* USDOT Z0.S, Z0.B, Z0.B[0] */ 25662306a36Sopenharmony_ci asm volatile(".inst 0x44a01800" : : : "z0"); 25762306a36Sopenharmony_ci} 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_cistatic void svef32mm_sigill(void) 26062306a36Sopenharmony_ci{ 26162306a36Sopenharmony_ci /* FMMLA Z0.S, Z0.S, Z0.S */ 26262306a36Sopenharmony_ci asm volatile(".inst 0x64a0e400" : : : "z0"); 26362306a36Sopenharmony_ci} 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_cistatic void svef64mm_sigill(void) 26662306a36Sopenharmony_ci{ 26762306a36Sopenharmony_ci /* FMMLA Z0.D, Z0.D, Z0.D */ 26862306a36Sopenharmony_ci asm volatile(".inst 0x64e0e400" : : : "z0"); 26962306a36Sopenharmony_ci} 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_cistatic void svebf16_sigill(void) 27262306a36Sopenharmony_ci{ 27362306a36Sopenharmony_ci /* BFCVT Z0.H, P0/M, Z0.S */ 27462306a36Sopenharmony_ci asm volatile(".inst 0x658aa000" : : : "z0"); 27562306a36Sopenharmony_ci} 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_cistatic void hbc_sigill(void) 27862306a36Sopenharmony_ci{ 27962306a36Sopenharmony_ci /* BC.EQ +4 */ 28062306a36Sopenharmony_ci asm volatile("cmp xzr, xzr\n" 28162306a36Sopenharmony_ci ".inst 0x54000030" : : : "cc"); 28262306a36Sopenharmony_ci} 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_cistatic void uscat_sigbus(void) 28562306a36Sopenharmony_ci{ 28662306a36Sopenharmony_ci /* unaligned atomic access */ 28762306a36Sopenharmony_ci asm volatile("ADD x1, sp, #2" : : : ); 28862306a36Sopenharmony_ci /* STADD W0, [X1] */ 28962306a36Sopenharmony_ci asm volatile(".inst 0xb820003f" : : : ); 29062306a36Sopenharmony_ci} 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_cistatic const struct hwcap_data { 29362306a36Sopenharmony_ci const char *name; 29462306a36Sopenharmony_ci unsigned long at_hwcap; 29562306a36Sopenharmony_ci unsigned long hwcap_bit; 29662306a36Sopenharmony_ci const char *cpuinfo; 29762306a36Sopenharmony_ci sig_fn sigill_fn; 29862306a36Sopenharmony_ci bool sigill_reliable; 29962306a36Sopenharmony_ci sig_fn sigbus_fn; 30062306a36Sopenharmony_ci bool sigbus_reliable; 30162306a36Sopenharmony_ci} hwcaps[] = { 30262306a36Sopenharmony_ci { 30362306a36Sopenharmony_ci .name = "AES", 30462306a36Sopenharmony_ci .at_hwcap = AT_HWCAP, 30562306a36Sopenharmony_ci .hwcap_bit = HWCAP_AES, 30662306a36Sopenharmony_ci .cpuinfo = "aes", 30762306a36Sopenharmony_ci .sigill_fn = aes_sigill, 30862306a36Sopenharmony_ci }, 30962306a36Sopenharmony_ci { 31062306a36Sopenharmony_ci .name = "CRC32", 31162306a36Sopenharmony_ci .at_hwcap = AT_HWCAP, 31262306a36Sopenharmony_ci .hwcap_bit = HWCAP_CRC32, 31362306a36Sopenharmony_ci .cpuinfo = "crc32", 31462306a36Sopenharmony_ci .sigill_fn = crc32_sigill, 31562306a36Sopenharmony_ci }, 31662306a36Sopenharmony_ci { 31762306a36Sopenharmony_ci .name = "CSSC", 31862306a36Sopenharmony_ci .at_hwcap = AT_HWCAP2, 31962306a36Sopenharmony_ci .hwcap_bit = HWCAP2_CSSC, 32062306a36Sopenharmony_ci .cpuinfo = "cssc", 32162306a36Sopenharmony_ci .sigill_fn = cssc_sigill, 32262306a36Sopenharmony_ci }, 32362306a36Sopenharmony_ci { 32462306a36Sopenharmony_ci .name = "FP", 32562306a36Sopenharmony_ci .at_hwcap = AT_HWCAP, 32662306a36Sopenharmony_ci .hwcap_bit = HWCAP_FP, 32762306a36Sopenharmony_ci .cpuinfo = "fp", 32862306a36Sopenharmony_ci .sigill_fn = fp_sigill, 32962306a36Sopenharmony_ci }, 33062306a36Sopenharmony_ci { 33162306a36Sopenharmony_ci .name = "JSCVT", 33262306a36Sopenharmony_ci .at_hwcap = AT_HWCAP, 33362306a36Sopenharmony_ci .hwcap_bit = HWCAP_JSCVT, 33462306a36Sopenharmony_ci .cpuinfo = "jscvt", 33562306a36Sopenharmony_ci .sigill_fn = jscvt_sigill, 33662306a36Sopenharmony_ci }, 33762306a36Sopenharmony_ci { 33862306a36Sopenharmony_ci .name = "LRCPC", 33962306a36Sopenharmony_ci .at_hwcap = AT_HWCAP, 34062306a36Sopenharmony_ci .hwcap_bit = HWCAP_LRCPC, 34162306a36Sopenharmony_ci .cpuinfo = "lrcpc", 34262306a36Sopenharmony_ci .sigill_fn = lrcpc_sigill, 34362306a36Sopenharmony_ci }, 34462306a36Sopenharmony_ci { 34562306a36Sopenharmony_ci .name = "LRCPC2", 34662306a36Sopenharmony_ci .at_hwcap = AT_HWCAP, 34762306a36Sopenharmony_ci .hwcap_bit = HWCAP_ILRCPC, 34862306a36Sopenharmony_ci .cpuinfo = "ilrcpc", 34962306a36Sopenharmony_ci .sigill_fn = ilrcpc_sigill, 35062306a36Sopenharmony_ci }, 35162306a36Sopenharmony_ci { 35262306a36Sopenharmony_ci .name = "LSE", 35362306a36Sopenharmony_ci .at_hwcap = AT_HWCAP, 35462306a36Sopenharmony_ci .hwcap_bit = HWCAP_ATOMICS, 35562306a36Sopenharmony_ci .cpuinfo = "atomics", 35662306a36Sopenharmony_ci .sigill_fn = atomics_sigill, 35762306a36Sopenharmony_ci }, 35862306a36Sopenharmony_ci { 35962306a36Sopenharmony_ci .name = "LSE2", 36062306a36Sopenharmony_ci .at_hwcap = AT_HWCAP, 36162306a36Sopenharmony_ci .hwcap_bit = HWCAP_USCAT, 36262306a36Sopenharmony_ci .cpuinfo = "uscat", 36362306a36Sopenharmony_ci .sigill_fn = atomics_sigill, 36462306a36Sopenharmony_ci .sigbus_fn = uscat_sigbus, 36562306a36Sopenharmony_ci .sigbus_reliable = true, 36662306a36Sopenharmony_ci }, 36762306a36Sopenharmony_ci { 36862306a36Sopenharmony_ci .name = "MOPS", 36962306a36Sopenharmony_ci .at_hwcap = AT_HWCAP2, 37062306a36Sopenharmony_ci .hwcap_bit = HWCAP2_MOPS, 37162306a36Sopenharmony_ci .cpuinfo = "mops", 37262306a36Sopenharmony_ci .sigill_fn = mops_sigill, 37362306a36Sopenharmony_ci .sigill_reliable = true, 37462306a36Sopenharmony_ci }, 37562306a36Sopenharmony_ci { 37662306a36Sopenharmony_ci .name = "PMULL", 37762306a36Sopenharmony_ci .at_hwcap = AT_HWCAP, 37862306a36Sopenharmony_ci .hwcap_bit = HWCAP_PMULL, 37962306a36Sopenharmony_ci .cpuinfo = "pmull", 38062306a36Sopenharmony_ci .sigill_fn = pmull_sigill, 38162306a36Sopenharmony_ci }, 38262306a36Sopenharmony_ci { 38362306a36Sopenharmony_ci .name = "RNG", 38462306a36Sopenharmony_ci .at_hwcap = AT_HWCAP2, 38562306a36Sopenharmony_ci .hwcap_bit = HWCAP2_RNG, 38662306a36Sopenharmony_ci .cpuinfo = "rng", 38762306a36Sopenharmony_ci .sigill_fn = rng_sigill, 38862306a36Sopenharmony_ci }, 38962306a36Sopenharmony_ci { 39062306a36Sopenharmony_ci .name = "RPRFM", 39162306a36Sopenharmony_ci .at_hwcap = AT_HWCAP2, 39262306a36Sopenharmony_ci .hwcap_bit = HWCAP2_RPRFM, 39362306a36Sopenharmony_ci .cpuinfo = "rprfm", 39462306a36Sopenharmony_ci }, 39562306a36Sopenharmony_ci { 39662306a36Sopenharmony_ci .name = "SHA1", 39762306a36Sopenharmony_ci .at_hwcap = AT_HWCAP, 39862306a36Sopenharmony_ci .hwcap_bit = HWCAP_SHA1, 39962306a36Sopenharmony_ci .cpuinfo = "sha1", 40062306a36Sopenharmony_ci .sigill_fn = sha1_sigill, 40162306a36Sopenharmony_ci }, 40262306a36Sopenharmony_ci { 40362306a36Sopenharmony_ci .name = "SHA2", 40462306a36Sopenharmony_ci .at_hwcap = AT_HWCAP, 40562306a36Sopenharmony_ci .hwcap_bit = HWCAP_SHA2, 40662306a36Sopenharmony_ci .cpuinfo = "sha2", 40762306a36Sopenharmony_ci .sigill_fn = sha2_sigill, 40862306a36Sopenharmony_ci }, 40962306a36Sopenharmony_ci { 41062306a36Sopenharmony_ci .name = "SHA512", 41162306a36Sopenharmony_ci .at_hwcap = AT_HWCAP, 41262306a36Sopenharmony_ci .hwcap_bit = HWCAP_SHA512, 41362306a36Sopenharmony_ci .cpuinfo = "sha512", 41462306a36Sopenharmony_ci .sigill_fn = sha512_sigill, 41562306a36Sopenharmony_ci }, 41662306a36Sopenharmony_ci { 41762306a36Sopenharmony_ci .name = "SME", 41862306a36Sopenharmony_ci .at_hwcap = AT_HWCAP2, 41962306a36Sopenharmony_ci .hwcap_bit = HWCAP2_SME, 42062306a36Sopenharmony_ci .cpuinfo = "sme", 42162306a36Sopenharmony_ci .sigill_fn = sme_sigill, 42262306a36Sopenharmony_ci .sigill_reliable = true, 42362306a36Sopenharmony_ci }, 42462306a36Sopenharmony_ci { 42562306a36Sopenharmony_ci .name = "SME2", 42662306a36Sopenharmony_ci .at_hwcap = AT_HWCAP2, 42762306a36Sopenharmony_ci .hwcap_bit = HWCAP2_SME2, 42862306a36Sopenharmony_ci .cpuinfo = "sme2", 42962306a36Sopenharmony_ci .sigill_fn = sme2_sigill, 43062306a36Sopenharmony_ci .sigill_reliable = true, 43162306a36Sopenharmony_ci }, 43262306a36Sopenharmony_ci { 43362306a36Sopenharmony_ci .name = "SME 2.1", 43462306a36Sopenharmony_ci .at_hwcap = AT_HWCAP2, 43562306a36Sopenharmony_ci .hwcap_bit = HWCAP2_SME2P1, 43662306a36Sopenharmony_ci .cpuinfo = "sme2p1", 43762306a36Sopenharmony_ci .sigill_fn = sme2p1_sigill, 43862306a36Sopenharmony_ci }, 43962306a36Sopenharmony_ci { 44062306a36Sopenharmony_ci .name = "SME I16I32", 44162306a36Sopenharmony_ci .at_hwcap = AT_HWCAP2, 44262306a36Sopenharmony_ci .hwcap_bit = HWCAP2_SME_I16I32, 44362306a36Sopenharmony_ci .cpuinfo = "smei16i32", 44462306a36Sopenharmony_ci .sigill_fn = smei16i32_sigill, 44562306a36Sopenharmony_ci }, 44662306a36Sopenharmony_ci { 44762306a36Sopenharmony_ci .name = "SME BI32I32", 44862306a36Sopenharmony_ci .at_hwcap = AT_HWCAP2, 44962306a36Sopenharmony_ci .hwcap_bit = HWCAP2_SME_BI32I32, 45062306a36Sopenharmony_ci .cpuinfo = "smebi32i32", 45162306a36Sopenharmony_ci .sigill_fn = smebi32i32_sigill, 45262306a36Sopenharmony_ci }, 45362306a36Sopenharmony_ci { 45462306a36Sopenharmony_ci .name = "SME B16B16", 45562306a36Sopenharmony_ci .at_hwcap = AT_HWCAP2, 45662306a36Sopenharmony_ci .hwcap_bit = HWCAP2_SME_B16B16, 45762306a36Sopenharmony_ci .cpuinfo = "smeb16b16", 45862306a36Sopenharmony_ci .sigill_fn = smeb16b16_sigill, 45962306a36Sopenharmony_ci }, 46062306a36Sopenharmony_ci { 46162306a36Sopenharmony_ci .name = "SME F16F16", 46262306a36Sopenharmony_ci .at_hwcap = AT_HWCAP2, 46362306a36Sopenharmony_ci .hwcap_bit = HWCAP2_SME_F16F16, 46462306a36Sopenharmony_ci .cpuinfo = "smef16f16", 46562306a36Sopenharmony_ci .sigill_fn = smef16f16_sigill, 46662306a36Sopenharmony_ci }, 46762306a36Sopenharmony_ci { 46862306a36Sopenharmony_ci .name = "SVE", 46962306a36Sopenharmony_ci .at_hwcap = AT_HWCAP, 47062306a36Sopenharmony_ci .hwcap_bit = HWCAP_SVE, 47162306a36Sopenharmony_ci .cpuinfo = "sve", 47262306a36Sopenharmony_ci .sigill_fn = sve_sigill, 47362306a36Sopenharmony_ci .sigill_reliable = true, 47462306a36Sopenharmony_ci }, 47562306a36Sopenharmony_ci { 47662306a36Sopenharmony_ci .name = "SVE 2", 47762306a36Sopenharmony_ci .at_hwcap = AT_HWCAP2, 47862306a36Sopenharmony_ci .hwcap_bit = HWCAP2_SVE2, 47962306a36Sopenharmony_ci .cpuinfo = "sve2", 48062306a36Sopenharmony_ci .sigill_fn = sve2_sigill, 48162306a36Sopenharmony_ci }, 48262306a36Sopenharmony_ci { 48362306a36Sopenharmony_ci .name = "SVE 2.1", 48462306a36Sopenharmony_ci .at_hwcap = AT_HWCAP2, 48562306a36Sopenharmony_ci .hwcap_bit = HWCAP2_SVE2P1, 48662306a36Sopenharmony_ci .cpuinfo = "sve2p1", 48762306a36Sopenharmony_ci .sigill_fn = sve2p1_sigill, 48862306a36Sopenharmony_ci }, 48962306a36Sopenharmony_ci { 49062306a36Sopenharmony_ci .name = "SVE AES", 49162306a36Sopenharmony_ci .at_hwcap = AT_HWCAP2, 49262306a36Sopenharmony_ci .hwcap_bit = HWCAP2_SVEAES, 49362306a36Sopenharmony_ci .cpuinfo = "sveaes", 49462306a36Sopenharmony_ci .sigill_fn = sveaes_sigill, 49562306a36Sopenharmony_ci }, 49662306a36Sopenharmony_ci { 49762306a36Sopenharmony_ci .name = "SVE2 PMULL", 49862306a36Sopenharmony_ci .at_hwcap = AT_HWCAP2, 49962306a36Sopenharmony_ci .hwcap_bit = HWCAP2_SVEPMULL, 50062306a36Sopenharmony_ci .cpuinfo = "svepmull", 50162306a36Sopenharmony_ci .sigill_fn = svepmull_sigill, 50262306a36Sopenharmony_ci }, 50362306a36Sopenharmony_ci { 50462306a36Sopenharmony_ci .name = "SVE2 BITPERM", 50562306a36Sopenharmony_ci .at_hwcap = AT_HWCAP2, 50662306a36Sopenharmony_ci .hwcap_bit = HWCAP2_SVEBITPERM, 50762306a36Sopenharmony_ci .cpuinfo = "svebitperm", 50862306a36Sopenharmony_ci .sigill_fn = svebitperm_sigill, 50962306a36Sopenharmony_ci }, 51062306a36Sopenharmony_ci { 51162306a36Sopenharmony_ci .name = "SVE2 SHA3", 51262306a36Sopenharmony_ci .at_hwcap = AT_HWCAP2, 51362306a36Sopenharmony_ci .hwcap_bit = HWCAP2_SVESHA3, 51462306a36Sopenharmony_ci .cpuinfo = "svesha3", 51562306a36Sopenharmony_ci .sigill_fn = svesha3_sigill, 51662306a36Sopenharmony_ci }, 51762306a36Sopenharmony_ci { 51862306a36Sopenharmony_ci .name = "SVE2 SM4", 51962306a36Sopenharmony_ci .at_hwcap = AT_HWCAP2, 52062306a36Sopenharmony_ci .hwcap_bit = HWCAP2_SVESM4, 52162306a36Sopenharmony_ci .cpuinfo = "svesm4", 52262306a36Sopenharmony_ci .sigill_fn = svesm4_sigill, 52362306a36Sopenharmony_ci }, 52462306a36Sopenharmony_ci { 52562306a36Sopenharmony_ci .name = "SVE2 I8MM", 52662306a36Sopenharmony_ci .at_hwcap = AT_HWCAP2, 52762306a36Sopenharmony_ci .hwcap_bit = HWCAP2_SVEI8MM, 52862306a36Sopenharmony_ci .cpuinfo = "svei8mm", 52962306a36Sopenharmony_ci .sigill_fn = svei8mm_sigill, 53062306a36Sopenharmony_ci }, 53162306a36Sopenharmony_ci { 53262306a36Sopenharmony_ci .name = "SVE2 F32MM", 53362306a36Sopenharmony_ci .at_hwcap = AT_HWCAP2, 53462306a36Sopenharmony_ci .hwcap_bit = HWCAP2_SVEF32MM, 53562306a36Sopenharmony_ci .cpuinfo = "svef32mm", 53662306a36Sopenharmony_ci .sigill_fn = svef32mm_sigill, 53762306a36Sopenharmony_ci }, 53862306a36Sopenharmony_ci { 53962306a36Sopenharmony_ci .name = "SVE2 F64MM", 54062306a36Sopenharmony_ci .at_hwcap = AT_HWCAP2, 54162306a36Sopenharmony_ci .hwcap_bit = HWCAP2_SVEF64MM, 54262306a36Sopenharmony_ci .cpuinfo = "svef64mm", 54362306a36Sopenharmony_ci .sigill_fn = svef64mm_sigill, 54462306a36Sopenharmony_ci }, 54562306a36Sopenharmony_ci { 54662306a36Sopenharmony_ci .name = "SVE2 BF16", 54762306a36Sopenharmony_ci .at_hwcap = AT_HWCAP2, 54862306a36Sopenharmony_ci .hwcap_bit = HWCAP2_SVEBF16, 54962306a36Sopenharmony_ci .cpuinfo = "svebf16", 55062306a36Sopenharmony_ci .sigill_fn = svebf16_sigill, 55162306a36Sopenharmony_ci }, 55262306a36Sopenharmony_ci { 55362306a36Sopenharmony_ci .name = "SVE2 EBF16", 55462306a36Sopenharmony_ci .at_hwcap = AT_HWCAP2, 55562306a36Sopenharmony_ci .hwcap_bit = HWCAP2_SVE_EBF16, 55662306a36Sopenharmony_ci .cpuinfo = "sveebf16", 55762306a36Sopenharmony_ci }, 55862306a36Sopenharmony_ci { 55962306a36Sopenharmony_ci .name = "HBC", 56062306a36Sopenharmony_ci .at_hwcap = AT_HWCAP2, 56162306a36Sopenharmony_ci .hwcap_bit = HWCAP2_HBC, 56262306a36Sopenharmony_ci .cpuinfo = "hbc", 56362306a36Sopenharmony_ci .sigill_fn = hbc_sigill, 56462306a36Sopenharmony_ci .sigill_reliable = true, 56562306a36Sopenharmony_ci }, 56662306a36Sopenharmony_ci}; 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_citypedef void (*sighandler_fn)(int, siginfo_t *, void *); 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci#define DEF_SIGHANDLER_FUNC(SIG, NUM) \ 57162306a36Sopenharmony_cistatic bool seen_##SIG; \ 57262306a36Sopenharmony_cistatic void handle_##SIG(int sig, siginfo_t *info, void *context) \ 57362306a36Sopenharmony_ci{ \ 57462306a36Sopenharmony_ci ucontext_t *uc = context; \ 57562306a36Sopenharmony_ci \ 57662306a36Sopenharmony_ci seen_##SIG = true; \ 57762306a36Sopenharmony_ci /* Skip over the offending instruction */ \ 57862306a36Sopenharmony_ci uc->uc_mcontext.pc += 4; \ 57962306a36Sopenharmony_ci} 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ciDEF_SIGHANDLER_FUNC(sigill, SIGILL); 58262306a36Sopenharmony_ciDEF_SIGHANDLER_FUNC(sigbus, SIGBUS); 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_cibool cpuinfo_present(const char *name) 58562306a36Sopenharmony_ci{ 58662306a36Sopenharmony_ci FILE *f; 58762306a36Sopenharmony_ci char buf[2048], name_space[30], name_newline[30]; 58862306a36Sopenharmony_ci char *s; 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci /* 59162306a36Sopenharmony_ci * The feature should appear with a leading space and either a 59262306a36Sopenharmony_ci * trailing space or a newline. 59362306a36Sopenharmony_ci */ 59462306a36Sopenharmony_ci snprintf(name_space, sizeof(name_space), " %s ", name); 59562306a36Sopenharmony_ci snprintf(name_newline, sizeof(name_newline), " %s\n", name); 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci f = fopen("/proc/cpuinfo", "r"); 59862306a36Sopenharmony_ci if (!f) { 59962306a36Sopenharmony_ci ksft_print_msg("Failed to open /proc/cpuinfo\n"); 60062306a36Sopenharmony_ci return false; 60162306a36Sopenharmony_ci } 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci while (fgets(buf, sizeof(buf), f)) { 60462306a36Sopenharmony_ci /* Features: line? */ 60562306a36Sopenharmony_ci if (strncmp(buf, "Features\t:", strlen("Features\t:")) != 0) 60662306a36Sopenharmony_ci continue; 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci /* All CPUs should be symmetric, don't read any more */ 60962306a36Sopenharmony_ci fclose(f); 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci s = strstr(buf, name_space); 61262306a36Sopenharmony_ci if (s) 61362306a36Sopenharmony_ci return true; 61462306a36Sopenharmony_ci s = strstr(buf, name_newline); 61562306a36Sopenharmony_ci if (s) 61662306a36Sopenharmony_ci return true; 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci return false; 61962306a36Sopenharmony_ci } 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci ksft_print_msg("Failed to find Features in /proc/cpuinfo\n"); 62262306a36Sopenharmony_ci fclose(f); 62362306a36Sopenharmony_ci return false; 62462306a36Sopenharmony_ci} 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_cistatic int install_sigaction(int signum, sighandler_fn handler) 62762306a36Sopenharmony_ci{ 62862306a36Sopenharmony_ci int ret; 62962306a36Sopenharmony_ci struct sigaction sa; 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci memset(&sa, 0, sizeof(sa)); 63262306a36Sopenharmony_ci sa.sa_sigaction = handler; 63362306a36Sopenharmony_ci sa.sa_flags = SA_RESTART | SA_SIGINFO; 63462306a36Sopenharmony_ci sigemptyset(&sa.sa_mask); 63562306a36Sopenharmony_ci ret = sigaction(signum, &sa, NULL); 63662306a36Sopenharmony_ci if (ret < 0) 63762306a36Sopenharmony_ci ksft_exit_fail_msg("Failed to install SIGNAL handler: %s (%d)\n", 63862306a36Sopenharmony_ci strerror(errno), errno); 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci return ret; 64162306a36Sopenharmony_ci} 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_cistatic void uninstall_sigaction(int signum) 64462306a36Sopenharmony_ci{ 64562306a36Sopenharmony_ci if (sigaction(signum, NULL, NULL) < 0) 64662306a36Sopenharmony_ci ksft_exit_fail_msg("Failed to uninstall SIGNAL handler: %s (%d)\n", 64762306a36Sopenharmony_ci strerror(errno), errno); 64862306a36Sopenharmony_ci} 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci#define DEF_INST_RAISE_SIG(SIG, NUM) \ 65162306a36Sopenharmony_cistatic bool inst_raise_##SIG(const struct hwcap_data *hwcap, \ 65262306a36Sopenharmony_ci bool have_hwcap) \ 65362306a36Sopenharmony_ci{ \ 65462306a36Sopenharmony_ci if (!hwcap->SIG##_fn) { \ 65562306a36Sopenharmony_ci ksft_test_result_skip(#SIG"_%s\n", hwcap->name); \ 65662306a36Sopenharmony_ci /* assume that it would raise exception in default */ \ 65762306a36Sopenharmony_ci return true; \ 65862306a36Sopenharmony_ci } \ 65962306a36Sopenharmony_ci \ 66062306a36Sopenharmony_ci install_sigaction(NUM, handle_##SIG); \ 66162306a36Sopenharmony_ci \ 66262306a36Sopenharmony_ci seen_##SIG = false; \ 66362306a36Sopenharmony_ci hwcap->SIG##_fn(); \ 66462306a36Sopenharmony_ci \ 66562306a36Sopenharmony_ci if (have_hwcap) { \ 66662306a36Sopenharmony_ci /* Should be able to use the extension */ \ 66762306a36Sopenharmony_ci ksft_test_result(!seen_##SIG, \ 66862306a36Sopenharmony_ci #SIG"_%s\n", hwcap->name); \ 66962306a36Sopenharmony_ci } else if (hwcap->SIG##_reliable) { \ 67062306a36Sopenharmony_ci /* Guaranteed a SIGNAL */ \ 67162306a36Sopenharmony_ci ksft_test_result(seen_##SIG, \ 67262306a36Sopenharmony_ci #SIG"_%s\n", hwcap->name); \ 67362306a36Sopenharmony_ci } else { \ 67462306a36Sopenharmony_ci /* Missing SIGNAL might be fine */ \ 67562306a36Sopenharmony_ci ksft_print_msg(#SIG"_%sreported for %s\n", \ 67662306a36Sopenharmony_ci seen_##SIG ? "" : "not ", \ 67762306a36Sopenharmony_ci hwcap->name); \ 67862306a36Sopenharmony_ci ksft_test_result_skip(#SIG"_%s\n", \ 67962306a36Sopenharmony_ci hwcap->name); \ 68062306a36Sopenharmony_ci } \ 68162306a36Sopenharmony_ci \ 68262306a36Sopenharmony_ci uninstall_sigaction(NUM); \ 68362306a36Sopenharmony_ci return seen_##SIG; \ 68462306a36Sopenharmony_ci} 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ciDEF_INST_RAISE_SIG(sigill, SIGILL); 68762306a36Sopenharmony_ciDEF_INST_RAISE_SIG(sigbus, SIGBUS); 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ciint main(void) 69062306a36Sopenharmony_ci{ 69162306a36Sopenharmony_ci int i; 69262306a36Sopenharmony_ci const struct hwcap_data *hwcap; 69362306a36Sopenharmony_ci bool have_cpuinfo, have_hwcap, raise_sigill; 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci ksft_print_header(); 69662306a36Sopenharmony_ci ksft_set_plan(ARRAY_SIZE(hwcaps) * TESTS_PER_HWCAP); 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(hwcaps); i++) { 69962306a36Sopenharmony_ci hwcap = &hwcaps[i]; 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci have_hwcap = getauxval(hwcap->at_hwcap) & hwcap->hwcap_bit; 70262306a36Sopenharmony_ci have_cpuinfo = cpuinfo_present(hwcap->cpuinfo); 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci if (have_hwcap) 70562306a36Sopenharmony_ci ksft_print_msg("%s present\n", hwcap->name); 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci ksft_test_result(have_hwcap == have_cpuinfo, 70862306a36Sopenharmony_ci "cpuinfo_match_%s\n", hwcap->name); 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci /* 71162306a36Sopenharmony_ci * Testing for SIGBUS only makes sense after make sure 71262306a36Sopenharmony_ci * that the instruction does not cause a SIGILL signal. 71362306a36Sopenharmony_ci */ 71462306a36Sopenharmony_ci raise_sigill = inst_raise_sigill(hwcap, have_hwcap); 71562306a36Sopenharmony_ci if (!raise_sigill) 71662306a36Sopenharmony_ci inst_raise_sigbus(hwcap, have_hwcap); 71762306a36Sopenharmony_ci else 71862306a36Sopenharmony_ci ksft_test_result_skip("sigbus_%s\n", hwcap->name); 71962306a36Sopenharmony_ci } 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci ksft_print_cnts(); 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci return 0; 72462306a36Sopenharmony_ci} 725