1 // SPDX-License-Identifier: GPL-2.0-only 2 #include <stdio.h> 3 #include <stdlib.h> 4 #include <asm/ptrace.h> 5 #include <linux/elf.h> 6 #include <sys/ptrace.h> 7 #include <sys/uio.h> 8 #include <sys/wait.h> 9 #include "../../kselftest.h" 10 #include "v_helpers.h" 11 12 int parent_set_val, child_set_val; 13 14 static long do_ptrace(enum __ptrace_request op, pid_t pid, long type, size_t size, void *data) 15 { 16 struct iovec v_iovec = { 17 .iov_len = size, 18 .iov_base = data 19 }; 20 21 return ptrace(op, pid, type, &v_iovec); 22 } 23 24 static int do_child(void) 25 { 26 int out; 27 28 if (ptrace(PTRACE_TRACEME, -1, NULL, NULL)) { 29 ksft_perror("PTRACE_TRACEME failed\n"); 30 return EXIT_FAILURE; 31 } 32 33 asm volatile (".option push\n\t" 34 ".option arch, +v\n\t" 35 ".option norvc\n\t" 36 "vsetivli x0, 1, e32, m1, ta, ma\n\t" 37 "vmv.s.x v31, %[in]\n\t" 38 "ebreak\n\t" 39 "vmv.x.s %[out], v31\n\t" 40 ".option pop\n\t" 41 : [out] "=r" (out) 42 : [in] "r" (child_set_val)); 43 44 if (out != parent_set_val) 45 return EXIT_FAILURE; 46 47 return EXIT_SUCCESS; 48 } 49 50 static void do_parent(pid_t child) 51 { 52 int status; 53 void *data = NULL; 54 55 /* Attach to the child */ 56 while (waitpid(child, &status, 0)) { 57 if (WIFEXITED(status)) { 58 ksft_test_result(WEXITSTATUS(status) == 0, "SETREGSET vector\n"); 59 goto out; 60 } else if (WIFSTOPPED(status) && (WSTOPSIG(status) == SIGTRAP)) { 61 size_t size; 62 void *data, *v31; 63 struct __riscv_v_regset_state *v_regset_hdr; 64 struct user_regs_struct *gpreg; 65 66 size = sizeof(*v_regset_hdr); 67 data = malloc(size); 68 if (!data) 69 goto out; 70 v_regset_hdr = (struct __riscv_v_regset_state *)data; 71 72 if (do_ptrace(PTRACE_GETREGSET, child, NT_RISCV_VECTOR, size, data)) 73 goto out; 74 75 ksft_print_msg("vlenb %ld\n", v_regset_hdr->vlenb); 76 data = realloc(data, size + v_regset_hdr->vlenb * 32); 77 if (!data) 78 goto out; 79 v_regset_hdr = (struct __riscv_v_regset_state *)data; 80 v31 = (void *)(data + size + v_regset_hdr->vlenb * 31); 81 size += v_regset_hdr->vlenb * 32; 82 83 if (do_ptrace(PTRACE_GETREGSET, child, NT_RISCV_VECTOR, size, data)) 84 goto out; 85 86 ksft_test_result(*(int *)v31 == child_set_val, "GETREGSET vector\n"); 87 88 *(int *)v31 = parent_set_val; 89 if (do_ptrace(PTRACE_SETREGSET, child, NT_RISCV_VECTOR, size, data)) 90 goto out; 91 92 /* move the pc forward */ 93 size = sizeof(*gpreg); 94 data = realloc(data, size); 95 gpreg = (struct user_regs_struct *)data; 96 97 if (do_ptrace(PTRACE_GETREGSET, child, NT_PRSTATUS, size, data)) 98 goto out; 99 100 gpreg->pc += 4; 101 if (do_ptrace(PTRACE_SETREGSET, child, NT_PRSTATUS, size, data)) 102 goto out; 103 } 104 105 ptrace(PTRACE_CONT, child, NULL, NULL); 106 } 107 108 out: 109 free(data); 110 } 111 112 int main(void) 113 { 114 pid_t child; 115 116 ksft_set_plan(2); 117 if (!is_vector_supported() && !is_xtheadvector_supported()) 118 ksft_exit_skip("Vector not supported\n"); 119 120 srandom(getpid()); 121 parent_set_val = rand(); 122 child_set_val = rand(); 123 124 child = fork(); 125 if (child < 0) 126 ksft_exit_fail_msg("Fork failed %d\n", child); 127 128 if (!child) 129 return do_child(); 130 131 do_parent(child); 132 133 ksft_finished(); 134 } 135