1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2021 ARM Limited. 4 */ 5 6 #include <errno.h> 7 #include <stdbool.h> 8 #include <stddef.h> 9 #include <stdio.h> 10 #include <stdlib.h> 11 #include <string.h> 12 #include <unistd.h> 13 #include <sys/auxv.h> 14 #include <sys/prctl.h> 15 #include <asm/hwcap.h> 16 #include <asm/sigcontext.h> 17 #include <asm/unistd.h> 18 19 #include "../../kselftest.h" 20 21 #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) 22 #define NUM_VL ((SVE_VQ_MAX - SVE_VQ_MIN) + 1) 23 24 extern void do_syscall(int sve_vl); 25 26 static void fill_random(void *buf, size_t size) 27 { 28 int i; 29 uint32_t *lbuf = buf; 30 31 /* random() returns a 32 bit number regardless of the size of long */ 32 for (i = 0; i < size / sizeof(uint32_t); i++) 33 lbuf[i] = random(); 34 } 35 36 /* 37 * We also repeat the test for several syscalls to try to expose different 38 * behaviour. 39 */ 40 static struct syscall_cfg { 41 int syscall_nr; 42 const char *name; 43 } syscalls[] = { 44 { __NR_getpid, "getpid()" }, 45 { __NR_sched_yield, "sched_yield()" }, 46 }; 47 48 #define NUM_GPR 31 49 uint64_t gpr_in[NUM_GPR]; 50 uint64_t gpr_out[NUM_GPR]; 51 52 static void setup_gpr(struct syscall_cfg *cfg, int sve_vl) 53 { 54 fill_random(gpr_in, sizeof(gpr_in)); 55 gpr_in[8] = cfg->syscall_nr; 56 memset(gpr_out, 0, sizeof(gpr_out)); 57 } 58 59 static int check_gpr(struct syscall_cfg *cfg, int sve_vl) 60 { 61 int errors = 0; 62 int i; 63 64 /* 65 * GPR x0-x7 may be clobbered, and all others should be preserved. 66 */ 67 for (i = 9; i < ARRAY_SIZE(gpr_in); i++) { 68 if (gpr_in[i] != gpr_out[i]) { 69 ksft_print_msg("%s SVE VL %d mismatch in GPR %d: %llx != %llx\n", 70 cfg->name, sve_vl, i, 71 gpr_in[i], gpr_out[i]); 72 errors++; 73 } 74 } 75 76 return errors; 77 } 78 79 #define NUM_FPR 32 80 uint64_t fpr_in[NUM_FPR * 2]; 81 uint64_t fpr_out[NUM_FPR * 2]; 82 83 static void setup_fpr(struct syscall_cfg *cfg, int sve_vl) 84 { 85 fill_random(fpr_in, sizeof(fpr_in)); 86 memset(fpr_out, 0, sizeof(fpr_out)); 87 } 88 89 static int check_fpr(struct syscall_cfg *cfg, int sve_vl) 90 { 91 int errors = 0; 92 int i; 93 94 if (!sve_vl) { 95 for (i = 0; i < ARRAY_SIZE(fpr_in); i++) { 96 if (fpr_in[i] != fpr_out[i]) { 97 ksft_print_msg("%s Q%d/%d mismatch %llx != %llx\n", 98 cfg->name, 99 i / 2, i % 2, 100 fpr_in[i], fpr_out[i]); 101 errors++; 102 } 103 } 104 } 105 106 return errors; 107 } 108 109 static uint8_t z_zero[__SVE_ZREG_SIZE(SVE_VQ_MAX)]; 110 uint8_t z_in[SVE_NUM_PREGS * __SVE_ZREG_SIZE(SVE_VQ_MAX)]; 111 uint8_t z_out[SVE_NUM_PREGS * __SVE_ZREG_SIZE(SVE_VQ_MAX)]; 112 113 static void setup_z(struct syscall_cfg *cfg, int sve_vl) 114 { 115 fill_random(z_in, sizeof(z_in)); 116 fill_random(z_out, sizeof(z_out)); 117 } 118 119 static int check_z(struct syscall_cfg *cfg, int sve_vl) 120 { 121 size_t reg_size = sve_vl; 122 int errors = 0; 123 int i; 124 125 if (!sve_vl) 126 return 0; 127 128 /* 129 * After a syscall the low 128 bits of the Z registers should 130 * be preserved and the rest be zeroed or preserved. 131 */ 132 for (i = 0; i < SVE_NUM_ZREGS; i++) { 133 void *in = &z_in[reg_size * i]; 134 void *out = &z_out[reg_size * i]; 135 136 if (memcmp(in, out, SVE_VQ_BYTES) != 0) { 137 ksft_print_msg("%s SVE VL %d Z%d low 128 bits changed\n", 138 cfg->name, sve_vl, i); 139 errors++; 140 } 141 } 142 143 return errors; 144 } 145 146 uint8_t p_in[SVE_NUM_PREGS * __SVE_PREG_SIZE(SVE_VQ_MAX)]; 147 uint8_t p_out[SVE_NUM_PREGS * __SVE_PREG_SIZE(SVE_VQ_MAX)]; 148 149 static void setup_p(struct syscall_cfg *cfg, int sve_vl) 150 { 151 fill_random(p_in, sizeof(p_in)); 152 fill_random(p_out, sizeof(p_out)); 153 } 154 155 static int check_p(struct syscall_cfg *cfg, int sve_vl) 156 { 157 size_t reg_size = sve_vq_from_vl(sve_vl) * 2; /* 1 bit per VL byte */ 158 159 int errors = 0; 160 int i; 161 162 if (!sve_vl) 163 return 0; 164 165 /* After a syscall the P registers should be preserved or zeroed */ 166 for (i = 0; i < SVE_NUM_PREGS * reg_size; i++) 167 if (p_out[i] && (p_in[i] != p_out[i])) 168 errors++; 169 if (errors) 170 ksft_print_msg("%s SVE VL %d predicate registers non-zero\n", 171 cfg->name, sve_vl); 172 173 return errors; 174 } 175 176 uint8_t ffr_in[__SVE_PREG_SIZE(SVE_VQ_MAX)]; 177 uint8_t ffr_out[__SVE_PREG_SIZE(SVE_VQ_MAX)]; 178 179 static void setup_ffr(struct syscall_cfg *cfg, int sve_vl) 180 { 181 /* 182 * It is only valid to set a contiguous set of bits starting 183 * at 0. For now since we're expecting this to be cleared by 184 * a syscall just set all bits. 185 */ 186 memset(ffr_in, 0xff, sizeof(ffr_in)); 187 fill_random(ffr_out, sizeof(ffr_out)); 188 } 189 190 static int check_ffr(struct syscall_cfg *cfg, int sve_vl) 191 { 192 size_t reg_size = sve_vq_from_vl(sve_vl) * 2; /* 1 bit per VL byte */ 193 int errors = 0; 194 int i; 195 196 if (!sve_vl) 197 return 0; 198 199 /* After a syscall the P registers should be preserved or zeroed */ 200 for (i = 0; i < reg_size; i++) 201 if (ffr_out[i] && (ffr_in[i] != ffr_out[i])) 202 errors++; 203 if (errors) 204 ksft_print_msg("%s SVE VL %d FFR non-zero\n", 205 cfg->name, sve_vl); 206 207 return errors; 208 } 209 210 typedef void (*setup_fn)(struct syscall_cfg *cfg, int sve_vl); 211 typedef int (*check_fn)(struct syscall_cfg *cfg, int sve_vl); 212 213 /* 214 * Each set of registers has a setup function which is called before 215 * the syscall to fill values in a global variable for loading by the 216 * test code and a check function which validates that the results are 217 * as expected. Vector lengths are passed everywhere, a vector length 218 * of 0 should be treated as do not test. 219 */ 220 static struct { 221 setup_fn setup; 222 check_fn check; 223 } regset[] = { 224 { setup_gpr, check_gpr }, 225 { setup_fpr, check_fpr }, 226 { setup_z, check_z }, 227 { setup_p, check_p }, 228 { setup_ffr, check_ffr }, 229 }; 230 231 static bool do_test(struct syscall_cfg *cfg, int sve_vl) 232 { 233 int errors = 0; 234 int i; 235 236 for (i = 0; i < ARRAY_SIZE(regset); i++) 237 regset[i].setup(cfg, sve_vl); 238 239 do_syscall(sve_vl); 240 241 for (i = 0; i < ARRAY_SIZE(regset); i++) 242 errors += regset[i].check(cfg, sve_vl); 243 244 return errors == 0; 245 } 246 247 static void test_one_syscall(struct syscall_cfg *cfg) 248 { 249 int sve_vq, sve_vl; 250 251 /* FPSIMD only case */ 252 ksft_test_result(do_test(cfg, 0), 253 "%s FPSIMD\n", cfg->name); 254 255 if (!(getauxval(AT_HWCAP) & HWCAP_SVE)) 256 return; 257 258 for (sve_vq = SVE_VQ_MAX; sve_vq > 0; --sve_vq) { 259 sve_vl = prctl(PR_SVE_SET_VL, sve_vq * 16); 260 if (sve_vl == -1) 261 ksft_exit_fail_msg("PR_SVE_SET_VL failed: %s (%d)\n", 262 strerror(errno), errno); 263 264 sve_vl &= PR_SVE_VL_LEN_MASK; 265 266 if (sve_vq != sve_vq_from_vl(sve_vl)) 267 sve_vq = sve_vq_from_vl(sve_vl); 268 269 ksft_test_result(do_test(cfg, sve_vl), 270 "%s SVE VL %d\n", cfg->name, sve_vl); 271 } 272 } 273 274 int sve_count_vls(void) 275 { 276 unsigned int vq; 277 int vl_count = 0; 278 int vl; 279 280 if (!(getauxval(AT_HWCAP) & HWCAP_SVE)) 281 return 0; 282 283 /* 284 * Enumerate up to SVE_VQ_MAX vector lengths 285 */ 286 for (vq = SVE_VQ_MAX; vq > 0; --vq) { 287 vl = prctl(PR_SVE_SET_VL, vq * 16); 288 if (vl == -1) 289 ksft_exit_fail_msg("PR_SVE_SET_VL failed: %s (%d)\n", 290 strerror(errno), errno); 291 292 vl &= PR_SVE_VL_LEN_MASK; 293 294 if (vq != sve_vq_from_vl(vl)) 295 vq = sve_vq_from_vl(vl); 296 297 vl_count++; 298 } 299 300 return vl_count; 301 } 302 303 int main(void) 304 { 305 int i; 306 307 srandom(getpid()); 308 309 ksft_print_header(); 310 ksft_set_plan(ARRAY_SIZE(syscalls) * (sve_count_vls() + 1)); 311 312 for (i = 0; i < ARRAY_SIZE(syscalls); i++) 313 test_one_syscall(&syscalls[i]); 314 315 ksft_print_cnts(); 316 317 return 0; 318 } 319