Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
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
12int parent_set_val, child_set_val;
13
14static 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
24static 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
50static 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
108out:
109 free(data);
110}
111
112int 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}