// SPDX-License-Identifier: GPL-2.0-only #include #include #include #include #include #include #include #include "../../kselftest.h" #include "v_helpers.h" int parent_set_val, child_set_val; static long do_ptrace(enum __ptrace_request op, pid_t pid, long type, size_t size, void *data) { struct iovec v_iovec = { .iov_len = size, .iov_base = data }; return ptrace(op, pid, type, &v_iovec); } static int do_child(void) { int out; if (ptrace(PTRACE_TRACEME, -1, NULL, NULL)) { ksft_perror("PTRACE_TRACEME failed\n"); return EXIT_FAILURE; } asm volatile (".option push\n\t" ".option arch, +v\n\t" ".option norvc\n\t" "vsetivli x0, 1, e32, m1, ta, ma\n\t" "vmv.s.x v31, %[in]\n\t" "ebreak\n\t" "vmv.x.s %[out], v31\n\t" ".option pop\n\t" : [out] "=r" (out) : [in] "r" (child_set_val)); if (out != parent_set_val) return EXIT_FAILURE; return EXIT_SUCCESS; } static void do_parent(pid_t child) { int status; void *data = NULL; /* Attach to the child */ while (waitpid(child, &status, 0)) { if (WIFEXITED(status)) { ksft_test_result(WEXITSTATUS(status) == 0, "SETREGSET vector\n"); goto out; } else if (WIFSTOPPED(status) && (WSTOPSIG(status) == SIGTRAP)) { size_t size; void *data, *v31; struct __riscv_v_regset_state *v_regset_hdr; struct user_regs_struct *gpreg; size = sizeof(*v_regset_hdr); data = malloc(size); if (!data) goto out; v_regset_hdr = (struct __riscv_v_regset_state *)data; if (do_ptrace(PTRACE_GETREGSET, child, NT_RISCV_VECTOR, size, data)) goto out; ksft_print_msg("vlenb %ld\n", v_regset_hdr->vlenb); data = realloc(data, size + v_regset_hdr->vlenb * 32); if (!data) goto out; v_regset_hdr = (struct __riscv_v_regset_state *)data; v31 = (void *)(data + size + v_regset_hdr->vlenb * 31); size += v_regset_hdr->vlenb * 32; if (do_ptrace(PTRACE_GETREGSET, child, NT_RISCV_VECTOR, size, data)) goto out; ksft_test_result(*(int *)v31 == child_set_val, "GETREGSET vector\n"); *(int *)v31 = parent_set_val; if (do_ptrace(PTRACE_SETREGSET, child, NT_RISCV_VECTOR, size, data)) goto out; /* move the pc forward */ size = sizeof(*gpreg); data = realloc(data, size); gpreg = (struct user_regs_struct *)data; if (do_ptrace(PTRACE_GETREGSET, child, NT_PRSTATUS, size, data)) goto out; gpreg->pc += 4; if (do_ptrace(PTRACE_SETREGSET, child, NT_PRSTATUS, size, data)) goto out; } ptrace(PTRACE_CONT, child, NULL, NULL); } out: free(data); } int main(void) { pid_t child; ksft_set_plan(2); if (!is_vector_supported() && !is_xtheadvector_supported()) ksft_exit_skip("Vector not supported\n"); srandom(getpid()); parent_set_val = rand(); child_set_val = rand(); child = fork(); if (child < 0) ksft_exit_fail_msg("Fork failed %d\n", child); if (!child) return do_child(); do_parent(child); ksft_finished(); }