1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2015-2021 ARM Limited. 4 * Original author: Dave Martin <Dave.Martin@arm.com> 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 <sys/ptrace.h> 16 #include <sys/types.h> 17 #include <sys/uio.h> 18 #include <sys/wait.h> 19 #include <asm/sigcontext.h> 20 #include <asm/ptrace.h> 21 22 #include "../../kselftest.h" 23 24 #define VL_TESTS (((SVE_VQ_MAX - SVE_VQ_MIN) + 1) * 3) 25 #define FPSIMD_TESTS 5 26 27 #define EXPECTED_TESTS (VL_TESTS + FPSIMD_TESTS) 28 29 /* <linux/elf.h> and <sys/auxv.h> don't like each other, so: */ 30 #ifndef NT_ARM_SVE 31 #define NT_ARM_SVE 0x405 32 #endif 33 34 static void fill_buf(char *buf, size_t size) 35 { 36 int i; 37 38 for (i = 0; i < size; i++) 39 buf[i] = random(); 40 } 41 42 static int do_child(void) 43 { 44 if (ptrace(PTRACE_TRACEME, -1, NULL, NULL)) 45 ksft_exit_fail_msg("PTRACE_TRACEME", strerror(errno)); 46 47 if (raise(SIGSTOP)) 48 ksft_exit_fail_msg("raise(SIGSTOP)", strerror(errno)); 49 50 return EXIT_SUCCESS; 51 } 52 53 static int get_fpsimd(pid_t pid, struct user_fpsimd_state *fpsimd) 54 { 55 struct iovec iov; 56 57 iov.iov_base = fpsimd; 58 iov.iov_len = sizeof(*fpsimd); 59 return ptrace(PTRACE_GETREGSET, pid, NT_PRFPREG, &iov); 60 } 61 62 static struct user_sve_header *get_sve(pid_t pid, void **buf, size_t *size) 63 { 64 struct user_sve_header *sve; 65 void *p; 66 size_t sz = sizeof *sve; 67 struct iovec iov; 68 69 while (1) { 70 if (*size < sz) { 71 p = realloc(*buf, sz); 72 if (!p) { 73 errno = ENOMEM; 74 goto error; 75 } 76 77 *buf = p; 78 *size = sz; 79 } 80 81 iov.iov_base = *buf; 82 iov.iov_len = sz; 83 if (ptrace(PTRACE_GETREGSET, pid, NT_ARM_SVE, &iov)) 84 goto error; 85 86 sve = *buf; 87 if (sve->size <= sz) 88 break; 89 90 sz = sve->size; 91 } 92 93 return sve; 94 95 error: 96 return NULL; 97 } 98 99 static int set_sve(pid_t pid, const struct user_sve_header *sve) 100 { 101 struct iovec iov; 102 103 iov.iov_base = (void *)sve; 104 iov.iov_len = sve->size; 105 return ptrace(PTRACE_SETREGSET, pid, NT_ARM_SVE, &iov); 106 } 107 108 /* Validate setting and getting the inherit flag */ 109 static void ptrace_set_get_inherit(pid_t child) 110 { 111 struct user_sve_header sve; 112 struct user_sve_header *new_sve = NULL; 113 size_t new_sve_size = 0; 114 int ret; 115 116 /* First set the flag */ 117 memset(&sve, 0, sizeof(sve)); 118 sve.size = sizeof(sve); 119 sve.vl = sve_vl_from_vq(SVE_VQ_MIN); 120 sve.flags = SVE_PT_VL_INHERIT; 121 ret = set_sve(child, &sve); 122 if (ret != 0) { 123 ksft_test_result_fail("Failed to set SVE_PT_VL_INHERIT\n"); 124 return; 125 } 126 127 /* 128 * Read back the new register state and verify that we have 129 * set the flags we expected. 130 */ 131 if (!get_sve(child, (void **)&new_sve, &new_sve_size)) { 132 ksft_test_result_fail("Failed to read SVE flags\n"); 133 return; 134 } 135 136 ksft_test_result(new_sve->flags & SVE_PT_VL_INHERIT, 137 "SVE_PT_VL_INHERIT set\n"); 138 139 /* Now clear */ 140 sve.flags &= ~SVE_PT_VL_INHERIT; 141 ret = set_sve(child, &sve); 142 if (ret != 0) { 143 ksft_test_result_fail("Failed to clear SVE_PT_VL_INHERIT\n"); 144 return; 145 } 146 147 if (!get_sve(child, (void **)&new_sve, &new_sve_size)) { 148 ksft_test_result_fail("Failed to read SVE flags\n"); 149 return; 150 } 151 152 ksft_test_result(!(new_sve->flags & SVE_PT_VL_INHERIT), 153 "SVE_PT_VL_INHERIT cleared\n"); 154 155 free(new_sve); 156 } 157 158 /* Validate attempting to set the specfied VL via ptrace */ 159 static void ptrace_set_get_vl(pid_t child, unsigned int vl, bool *supported) 160 { 161 struct user_sve_header sve; 162 struct user_sve_header *new_sve = NULL; 163 size_t new_sve_size = 0; 164 int ret, prctl_vl; 165 166 *supported = false; 167 168 /* Check if the VL is supported in this process */ 169 prctl_vl = prctl(PR_SVE_SET_VL, vl); 170 if (prctl_vl == -1) 171 ksft_exit_fail_msg("prctl(PR_SVE_SET_VL) failed: %s (%d)\n", 172 strerror(errno), errno); 173 174 /* If the VL is not supported then a supported VL will be returned */ 175 *supported = (prctl_vl == vl); 176 177 /* Set the VL by doing a set with no register payload */ 178 memset(&sve, 0, sizeof(sve)); 179 sve.size = sizeof(sve); 180 sve.vl = vl; 181 ret = set_sve(child, &sve); 182 if (ret != 0) { 183 ksft_test_result_fail("Failed to set VL %u\n", vl); 184 return; 185 } 186 187 /* 188 * Read back the new register state and verify that we have the 189 * same VL that we got from prctl() on ourselves. 190 */ 191 if (!get_sve(child, (void **)&new_sve, &new_sve_size)) { 192 ksft_test_result_fail("Failed to read VL %u\n", vl); 193 return; 194 } 195 196 ksft_test_result(new_sve->vl = prctl_vl, "Set VL %u\n", vl); 197 198 free(new_sve); 199 } 200 201 static void check_u32(unsigned int vl, const char *reg, 202 uint32_t *in, uint32_t *out, int *errors) 203 { 204 if (*in != *out) { 205 printf("# VL %d %s wrote %x read %x\n", 206 vl, reg, *in, *out); 207 (*errors)++; 208 } 209 } 210 211 /* Access the FPSIMD registers via the SVE regset */ 212 static void ptrace_sve_fpsimd(pid_t child) 213 { 214 void *svebuf = NULL; 215 size_t svebufsz = 0; 216 struct user_sve_header *sve; 217 struct user_fpsimd_state *fpsimd, new_fpsimd; 218 unsigned int i, j; 219 unsigned char *p; 220 221 /* New process should start with FPSIMD registers only */ 222 sve = get_sve(child, &svebuf, &svebufsz); 223 if (!sve) { 224 ksft_test_result_fail("get_sve: %s\n", strerror(errno)); 225 226 return; 227 } else { 228 ksft_test_result_pass("get_sve(FPSIMD)\n"); 229 } 230 231 ksft_test_result((sve->flags & SVE_PT_REGS_MASK) == SVE_PT_REGS_FPSIMD, 232 "Set FPSIMD registers\n"); 233 if ((sve->flags & SVE_PT_REGS_MASK) != SVE_PT_REGS_FPSIMD) 234 goto out; 235 236 /* Try to set a known FPSIMD state via PT_REGS_SVE */ 237 fpsimd = (struct user_fpsimd_state *)((char *)sve + 238 SVE_PT_FPSIMD_OFFSET); 239 for (i = 0; i < 32; ++i) { 240 p = (unsigned char *)&fpsimd->vregs[i]; 241 242 for (j = 0; j < sizeof(fpsimd->vregs[i]); ++j) 243 p[j] = j; 244 } 245 246 if (set_sve(child, sve)) { 247 ksft_test_result_fail("set_sve(FPSIMD): %s\n", 248 strerror(errno)); 249 250 goto out; 251 } 252 253 /* Verify via the FPSIMD regset */ 254 if (get_fpsimd(child, &new_fpsimd)) { 255 ksft_test_result_fail("get_fpsimd(): %s\n", 256 strerror(errno)); 257 goto out; 258 } 259 if (memcmp(fpsimd, &new_fpsimd, sizeof(*fpsimd)) == 0) 260 ksft_test_result_pass("get_fpsimd() gave same state\n"); 261 else 262 ksft_test_result_fail("get_fpsimd() gave different state\n"); 263 264 out: 265 free(svebuf); 266 } 267 268 /* Validate attempting to set SVE data and read SVE data */ 269 static void ptrace_set_sve_get_sve_data(pid_t child, unsigned int vl) 270 { 271 void *write_buf; 272 void *read_buf = NULL; 273 struct user_sve_header *write_sve; 274 struct user_sve_header *read_sve; 275 size_t read_sve_size = 0; 276 unsigned int vq = sve_vq_from_vl(vl); 277 int ret, i; 278 size_t data_size; 279 int errors = 0; 280 281 data_size = SVE_PT_SVE_OFFSET + SVE_PT_SVE_SIZE(vq, SVE_PT_REGS_SVE); 282 write_buf = malloc(data_size); 283 if (!write_buf) { 284 ksft_test_result_fail("Error allocating %d byte buffer for VL %u\n", 285 data_size, vl); 286 return; 287 } 288 write_sve = write_buf; 289 290 /* Set up some data and write it out */ 291 memset(write_sve, 0, data_size); 292 write_sve->size = data_size; 293 write_sve->vl = vl; 294 write_sve->flags = SVE_PT_REGS_SVE; 295 296 for (i = 0; i < __SVE_NUM_ZREGS; i++) 297 fill_buf(write_buf + SVE_PT_SVE_ZREG_OFFSET(vq, i), 298 SVE_PT_SVE_ZREG_SIZE(vq)); 299 300 for (i = 0; i < __SVE_NUM_PREGS; i++) 301 fill_buf(write_buf + SVE_PT_SVE_PREG_OFFSET(vq, i), 302 SVE_PT_SVE_PREG_SIZE(vq)); 303 304 fill_buf(write_buf + SVE_PT_SVE_FPSR_OFFSET(vq), SVE_PT_SVE_FPSR_SIZE); 305 fill_buf(write_buf + SVE_PT_SVE_FPCR_OFFSET(vq), SVE_PT_SVE_FPCR_SIZE); 306 307 /* TODO: Generate a valid FFR pattern */ 308 309 ret = set_sve(child, write_sve); 310 if (ret != 0) { 311 ksft_test_result_fail("Failed to set VL %u data\n", vl); 312 goto out; 313 } 314 315 /* Read the data back */ 316 if (!get_sve(child, (void **)&read_buf, &read_sve_size)) { 317 ksft_test_result_fail("Failed to read VL %u data\n", vl); 318 goto out; 319 } 320 read_sve = read_buf; 321 322 /* We might read more data if there's extensions we don't know */ 323 if (read_sve->size < write_sve->size) { 324 ksft_test_result_fail("Wrote %d bytes, only read %d\n", 325 write_sve->size, read_sve->size); 326 goto out_read; 327 } 328 329 for (i = 0; i < __SVE_NUM_ZREGS; i++) { 330 if (memcmp(write_buf + SVE_PT_SVE_ZREG_OFFSET(vq, i), 331 read_buf + SVE_PT_SVE_ZREG_OFFSET(vq, i), 332 SVE_PT_SVE_ZREG_SIZE(vq)) != 0) { 333 printf("# Mismatch in %u Z%d\n", vl, i); 334 errors++; 335 } 336 } 337 338 for (i = 0; i < __SVE_NUM_PREGS; i++) { 339 if (memcmp(write_buf + SVE_PT_SVE_PREG_OFFSET(vq, i), 340 read_buf + SVE_PT_SVE_PREG_OFFSET(vq, i), 341 SVE_PT_SVE_PREG_SIZE(vq)) != 0) { 342 printf("# Mismatch in %u P%d\n", vl, i); 343 errors++; 344 } 345 } 346 347 check_u32(vl, "FPSR", write_buf + SVE_PT_SVE_FPSR_OFFSET(vq), 348 read_buf + SVE_PT_SVE_FPSR_OFFSET(vq), &errors); 349 check_u32(vl, "FPCR", write_buf + SVE_PT_SVE_FPCR_OFFSET(vq), 350 read_buf + SVE_PT_SVE_FPCR_OFFSET(vq), &errors); 351 352 ksft_test_result(errors == 0, "Set and get SVE data for VL %u\n", vl); 353 354 out_read: 355 free(read_buf); 356 out: 357 free(write_buf); 358 } 359 360 /* Validate attempting to set SVE data and read SVE data */ 361 static void ptrace_set_sve_get_fpsimd_data(pid_t child, unsigned int vl) 362 { 363 void *write_buf; 364 struct user_sve_header *write_sve; 365 unsigned int vq = sve_vq_from_vl(vl); 366 struct user_fpsimd_state fpsimd_state; 367 int ret, i; 368 size_t data_size; 369 int errors = 0; 370 371 if (__BYTE_ORDER == __BIG_ENDIAN) { 372 ksft_test_result_skip("Big endian not supported\n"); 373 return; 374 } 375 376 data_size = SVE_PT_SVE_OFFSET + SVE_PT_SVE_SIZE(vq, SVE_PT_REGS_SVE); 377 write_buf = malloc(data_size); 378 if (!write_buf) { 379 ksft_test_result_fail("Error allocating %d byte buffer for VL %u\n", 380 data_size, vl); 381 return; 382 } 383 write_sve = write_buf; 384 385 /* Set up some data and write it out */ 386 memset(write_sve, 0, data_size); 387 write_sve->size = data_size; 388 write_sve->vl = vl; 389 write_sve->flags = SVE_PT_REGS_SVE; 390 391 for (i = 0; i < __SVE_NUM_ZREGS; i++) 392 fill_buf(write_buf + SVE_PT_SVE_ZREG_OFFSET(vq, i), 393 SVE_PT_SVE_ZREG_SIZE(vq)); 394 395 fill_buf(write_buf + SVE_PT_SVE_FPSR_OFFSET(vq), SVE_PT_SVE_FPSR_SIZE); 396 fill_buf(write_buf + SVE_PT_SVE_FPCR_OFFSET(vq), SVE_PT_SVE_FPCR_SIZE); 397 398 ret = set_sve(child, write_sve); 399 if (ret != 0) { 400 ksft_test_result_fail("Failed to set VL %u data\n", vl); 401 goto out; 402 } 403 404 /* Read the data back */ 405 if (get_fpsimd(child, &fpsimd_state)) { 406 ksft_test_result_fail("Failed to read VL %u FPSIMD data\n", 407 vl); 408 goto out; 409 } 410 411 for (i = 0; i < __SVE_NUM_ZREGS; i++) { 412 __uint128_t tmp = 0; 413 414 /* 415 * Z regs are stored endianness invariant, this won't 416 * work for big endian 417 */ 418 memcpy(&tmp, write_buf + SVE_PT_SVE_ZREG_OFFSET(vq, i), 419 sizeof(tmp)); 420 421 if (tmp != fpsimd_state.vregs[i]) { 422 printf("# Mismatch in FPSIMD for VL %u Z%d\n", vl, i); 423 errors++; 424 } 425 } 426 427 check_u32(vl, "FPSR", write_buf + SVE_PT_SVE_FPSR_OFFSET(vq), 428 &fpsimd_state.fpsr, &errors); 429 check_u32(vl, "FPCR", write_buf + SVE_PT_SVE_FPCR_OFFSET(vq), 430 &fpsimd_state.fpcr, &errors); 431 432 ksft_test_result(errors == 0, "Set and get FPSIMD data for VL %u\n", 433 vl); 434 435 out: 436 free(write_buf); 437 } 438 439 static int do_parent(pid_t child) 440 { 441 int ret = EXIT_FAILURE; 442 pid_t pid; 443 int status; 444 siginfo_t si; 445 unsigned int vq, vl; 446 bool vl_supported; 447 448 /* Attach to the child */ 449 while (1) { 450 int sig; 451 452 pid = wait(&status); 453 if (pid == -1) { 454 perror("wait"); 455 goto error; 456 } 457 458 /* 459 * This should never happen but it's hard to flag in 460 * the framework. 461 */ 462 if (pid != child) 463 continue; 464 465 if (WIFEXITED(status) || WIFSIGNALED(status)) 466 ksft_exit_fail_msg("Child died unexpectedly\n"); 467 468 if (!WIFSTOPPED(status)) 469 goto error; 470 471 sig = WSTOPSIG(status); 472 473 if (ptrace(PTRACE_GETSIGINFO, pid, NULL, &si)) { 474 if (errno == ESRCH) 475 goto disappeared; 476 477 if (errno == EINVAL) { 478 sig = 0; /* bust group-stop */ 479 goto cont; 480 } 481 482 ksft_test_result_fail("PTRACE_GETSIGINFO: %s\n", 483 strerror(errno)); 484 goto error; 485 } 486 487 if (sig == SIGSTOP && si.si_code == SI_TKILL && 488 si.si_pid == pid) 489 break; 490 491 cont: 492 if (ptrace(PTRACE_CONT, pid, NULL, sig)) { 493 if (errno == ESRCH) 494 goto disappeared; 495 496 ksft_test_result_fail("PTRACE_CONT: %s\n", 497 strerror(errno)); 498 goto error; 499 } 500 } 501 502 /* FPSIMD via SVE regset */ 503 ptrace_sve_fpsimd(child); 504 505 /* prctl() flags */ 506 ptrace_set_get_inherit(child); 507 508 /* Step through every possible VQ */ 509 for (vq = SVE_VQ_MIN; vq <= SVE_VQ_MAX; vq++) { 510 vl = sve_vl_from_vq(vq); 511 512 /* First, try to set this vector length */ 513 ptrace_set_get_vl(child, vl, &vl_supported); 514 515 /* If the VL is supported validate data set/get */ 516 if (vl_supported) { 517 ptrace_set_sve_get_sve_data(child, vl); 518 ptrace_set_sve_get_fpsimd_data(child, vl); 519 } else { 520 ksft_test_result_skip("set SVE get SVE for VL %d\n", vl); 521 ksft_test_result_skip("set SVE get FPSIMD for VL %d\n", vl); 522 } 523 } 524 525 ret = EXIT_SUCCESS; 526 527 error: 528 kill(child, SIGKILL); 529 530 disappeared: 531 return ret; 532 } 533 534 int main(void) 535 { 536 int ret = EXIT_SUCCESS; 537 pid_t child; 538 539 srandom(getpid()); 540 541 ksft_print_header(); 542 ksft_set_plan(EXPECTED_TESTS); 543 544 if (!(getauxval(AT_HWCAP) & HWCAP_SVE)) 545 ksft_exit_skip("SVE not available\n"); 546 547 child = fork(); 548 if (!child) 549 return do_child(); 550 551 if (do_parent(child)) 552 ret = EXIT_FAILURE; 553 554 ksft_print_cnts(); 555 556 return ret; 557 } 558