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