1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2022 ARM Limited. 4 */ 5 6 #include <errno.h> 7 #include <signal.h> 8 #include <stdbool.h> 9 #include <stddef.h> 10 #include <stdio.h> 11 #include <stdlib.h> 12 #include <string.h> 13 #include <unistd.h> 14 #include <sys/auxv.h> 15 #include <sys/prctl.h> 16 #include <asm/hwcap.h> 17 #include <asm/sigcontext.h> 18 #include <asm/unistd.h> 19 20 #include "../../kselftest.h" 21 22 #define TESTS_PER_HWCAP 2 23 24 /* 25 * Function expected to generate SIGILL when the feature is not 26 * supported and return when it is supported. If SIGILL is generated 27 * then the handler must be able to skip over the instruction safely. 28 * 29 * Note that it is expected that for many architecture extensions 30 * there are no specific traps due to no architecture state being 31 * added so we may not fault if running on a kernel which doesn't know 32 * to add the hwcap. 33 */ 34 typedef void (*sigill_fn)(void); 35 36 static void rng_sigill(void) 37 { 38 asm volatile("mrs x0, S3_3_C2_C4_0" : : : "x0"); 39 } 40 41 static void sme_sigill(void) 42 { 43 /* RDSVL x0, #0 */ 44 asm volatile(".inst 0x04bf5800" : : : "x0"); 45 } 46 47 static void sve_sigill(void) 48 { 49 /* RDVL x0, #0 */ 50 asm volatile(".inst 0x04bf5000" : : : "x0"); 51 } 52 53 static void sve2_sigill(void) 54 { 55 /* SQABS Z0.b, P0/M, Z0.B */ 56 asm volatile(".inst 0x4408A000" : : : "z0"); 57 } 58 59 static void sveaes_sigill(void) 60 { 61 /* AESD z0.b, z0.b, z0.b */ 62 asm volatile(".inst 0x4522e400" : : : "z0"); 63 } 64 65 static void svepmull_sigill(void) 66 { 67 /* PMULLB Z0.Q, Z0.D, Z0.D */ 68 asm volatile(".inst 0x45006800" : : : "z0"); 69 } 70 71 static void svebitperm_sigill(void) 72 { 73 /* BDEP Z0.B, Z0.B, Z0.B */ 74 asm volatile(".inst 0x4500b400" : : : "z0"); 75 } 76 77 static void svesha3_sigill(void) 78 { 79 /* EOR3 Z0.D, Z0.D, Z0.D, Z0.D */ 80 asm volatile(".inst 0x4203800" : : : "z0"); 81 } 82 83 static void svesm4_sigill(void) 84 { 85 /* SM4E Z0.S, Z0.S, Z0.S */ 86 asm volatile(".inst 0x4523e000" : : : "z0"); 87 } 88 89 static void svei8mm_sigill(void) 90 { 91 /* USDOT Z0.S, Z0.B, Z0.B[0] */ 92 asm volatile(".inst 0x44a01800" : : : "z0"); 93 } 94 95 static void svef32mm_sigill(void) 96 { 97 /* FMMLA Z0.S, Z0.S, Z0.S */ 98 asm volatile(".inst 0x64a0e400" : : : "z0"); 99 } 100 101 static void svef64mm_sigill(void) 102 { 103 /* FMMLA Z0.D, Z0.D, Z0.D */ 104 asm volatile(".inst 0x64e0e400" : : : "z0"); 105 } 106 107 static void svebf16_sigill(void) 108 { 109 /* BFCVT Z0.H, P0/M, Z0.S */ 110 asm volatile(".inst 0x658aa000" : : : "z0"); 111 } 112 113 static const struct hwcap_data { 114 const char *name; 115 unsigned long at_hwcap; 116 unsigned long hwcap_bit; 117 const char *cpuinfo; 118 sigill_fn sigill_fn; 119 bool sigill_reliable; 120 } hwcaps[] = { 121 { 122 .name = "RNG", 123 .at_hwcap = AT_HWCAP2, 124 .hwcap_bit = HWCAP2_RNG, 125 .cpuinfo = "rng", 126 .sigill_fn = rng_sigill, 127 }, 128 { 129 .name = "SME", 130 .at_hwcap = AT_HWCAP2, 131 .hwcap_bit = HWCAP2_SME, 132 .cpuinfo = "sme", 133 .sigill_fn = sme_sigill, 134 .sigill_reliable = true, 135 }, 136 { 137 .name = "SVE", 138 .at_hwcap = AT_HWCAP, 139 .hwcap_bit = HWCAP_SVE, 140 .cpuinfo = "sve", 141 .sigill_fn = sve_sigill, 142 .sigill_reliable = true, 143 }, 144 { 145 .name = "SVE 2", 146 .at_hwcap = AT_HWCAP2, 147 .hwcap_bit = HWCAP2_SVE2, 148 .cpuinfo = "sve2", 149 .sigill_fn = sve2_sigill, 150 }, 151 { 152 .name = "SVE AES", 153 .at_hwcap = AT_HWCAP2, 154 .hwcap_bit = HWCAP2_SVEAES, 155 .cpuinfo = "sveaes", 156 .sigill_fn = sveaes_sigill, 157 }, 158 { 159 .name = "SVE2 PMULL", 160 .at_hwcap = AT_HWCAP2, 161 .hwcap_bit = HWCAP2_SVEPMULL, 162 .cpuinfo = "svepmull", 163 .sigill_fn = svepmull_sigill, 164 }, 165 { 166 .name = "SVE2 BITPERM", 167 .at_hwcap = AT_HWCAP2, 168 .hwcap_bit = HWCAP2_SVEBITPERM, 169 .cpuinfo = "svebitperm", 170 .sigill_fn = svebitperm_sigill, 171 }, 172 { 173 .name = "SVE2 SHA3", 174 .at_hwcap = AT_HWCAP2, 175 .hwcap_bit = HWCAP2_SVESHA3, 176 .cpuinfo = "svesha3", 177 .sigill_fn = svesha3_sigill, 178 }, 179 { 180 .name = "SVE2 SM4", 181 .at_hwcap = AT_HWCAP2, 182 .hwcap_bit = HWCAP2_SVESM4, 183 .cpuinfo = "svesm4", 184 .sigill_fn = svesm4_sigill, 185 }, 186 { 187 .name = "SVE2 I8MM", 188 .at_hwcap = AT_HWCAP2, 189 .hwcap_bit = HWCAP2_SVEI8MM, 190 .cpuinfo = "svei8mm", 191 .sigill_fn = svei8mm_sigill, 192 }, 193 { 194 .name = "SVE2 F32MM", 195 .at_hwcap = AT_HWCAP2, 196 .hwcap_bit = HWCAP2_SVEF32MM, 197 .cpuinfo = "svef32mm", 198 .sigill_fn = svef32mm_sigill, 199 }, 200 { 201 .name = "SVE2 F64MM", 202 .at_hwcap = AT_HWCAP2, 203 .hwcap_bit = HWCAP2_SVEF64MM, 204 .cpuinfo = "svef64mm", 205 .sigill_fn = svef64mm_sigill, 206 }, 207 { 208 .name = "SVE2 BF16", 209 .at_hwcap = AT_HWCAP2, 210 .hwcap_bit = HWCAP2_SVEBF16, 211 .cpuinfo = "svebf16", 212 .sigill_fn = svebf16_sigill, 213 }, 214 { 215 .name = "SVE2 EBF16", 216 .at_hwcap = AT_HWCAP2, 217 .hwcap_bit = HWCAP2_SVE_EBF16, 218 .cpuinfo = "sveebf16", 219 }, 220 }; 221 222 static bool seen_sigill; 223 224 static void handle_sigill(int sig, siginfo_t *info, void *context) 225 { 226 ucontext_t *uc = context; 227 228 seen_sigill = true; 229 230 /* Skip over the offending instruction */ 231 uc->uc_mcontext.pc += 4; 232 } 233 234 bool cpuinfo_present(const char *name) 235 { 236 FILE *f; 237 char buf[2048], name_space[30], name_newline[30]; 238 char *s; 239 240 /* 241 * The feature should appear with a leading space and either a 242 * trailing space or a newline. 243 */ 244 snprintf(name_space, sizeof(name_space), " %s ", name); 245 snprintf(name_newline, sizeof(name_newline), " %s\n", name); 246 247 f = fopen("/proc/cpuinfo", "r"); 248 if (!f) { 249 ksft_print_msg("Failed to open /proc/cpuinfo\n"); 250 return false; 251 } 252 253 while (fgets(buf, sizeof(buf), f)) { 254 /* Features: line? */ 255 if (strncmp(buf, "Features\t:", strlen("Features\t:")) != 0) 256 continue; 257 258 /* All CPUs should be symmetric, don't read any more */ 259 fclose(f); 260 261 s = strstr(buf, name_space); 262 if (s) 263 return true; 264 s = strstr(buf, name_newline); 265 if (s) 266 return true; 267 268 return false; 269 } 270 271 ksft_print_msg("Failed to find Features in /proc/cpuinfo\n"); 272 fclose(f); 273 return false; 274 } 275 276 int main(void) 277 { 278 const struct hwcap_data *hwcap; 279 int i, ret; 280 bool have_cpuinfo, have_hwcap; 281 struct sigaction sa; 282 283 ksft_print_header(); 284 ksft_set_plan(ARRAY_SIZE(hwcaps) * TESTS_PER_HWCAP); 285 286 memset(&sa, 0, sizeof(sa)); 287 sa.sa_sigaction = handle_sigill; 288 sa.sa_flags = SA_RESTART | SA_SIGINFO; 289 sigemptyset(&sa.sa_mask); 290 ret = sigaction(SIGILL, &sa, NULL); 291 if (ret < 0) 292 ksft_exit_fail_msg("Failed to install SIGILL handler: %s (%d)\n", 293 strerror(errno), errno); 294 295 for (i = 0; i < ARRAY_SIZE(hwcaps); i++) { 296 hwcap = &hwcaps[i]; 297 298 have_hwcap = getauxval(hwcap->at_hwcap) & hwcap->hwcap_bit; 299 have_cpuinfo = cpuinfo_present(hwcap->cpuinfo); 300 301 if (have_hwcap) 302 ksft_print_msg("%s present\n", hwcap->name); 303 304 ksft_test_result(have_hwcap == have_cpuinfo, 305 "cpuinfo_match_%s\n", hwcap->name); 306 307 if (hwcap->sigill_fn) { 308 seen_sigill = false; 309 hwcap->sigill_fn(); 310 311 if (have_hwcap) { 312 /* Should be able to use the extension */ 313 ksft_test_result(!seen_sigill, "sigill_%s\n", 314 hwcap->name); 315 } else if (hwcap->sigill_reliable) { 316 /* Guaranteed a SIGILL */ 317 ksft_test_result(seen_sigill, "sigill_%s\n", 318 hwcap->name); 319 } else { 320 /* Missing SIGILL might be fine */ 321 ksft_print_msg("SIGILL %sreported for %s\n", 322 seen_sigill ? "" : "not ", 323 hwcap->name); 324 ksft_test_result_skip("sigill_%s\n", 325 hwcap->name); 326 } 327 } else { 328 ksft_test_result_skip("sigill_%s\n", 329 hwcap->name); 330 } 331 } 332 333 ksft_print_cnts(); 334 335 return 0; 336 } 337