1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (C) 2015-2020 ARM Limited.
4 * Original author: Dave Martin <Dave.Martin@arm.com>
13 #include <sys/ptrace.h>
14 #include <sys/types.h>
17 #include <asm/sigcontext.h>
18 #include <asm/ptrace.h>
20 #include "../../kselftest.h"
22 /* <linux/elf.h> and <sys/auxv.h> don't like each other, so: */
24 #define NT_ARM_SVE 0x405
27 /* Number of registers filled in by sve_store_patterns */
30 void sve_store_patterns(__uint128_t v
[NR_VREGS
]);
32 static void dump(const void *buf
, size_t size
)
35 const unsigned char *p
= buf
;
37 for (i
= 0; i
< size
; ++i
)
38 printf(" %.2x", *p
++);
41 static int check_vregs(const __uint128_t vregs
[NR_VREGS
])
46 for (i
= 0; i
< NR_VREGS
; ++i
) {
47 printf("# v[%d]:", i
);
48 dump(&vregs
[i
], sizeof vregs
[i
]);
51 if (vregs
[i
] != vregs
[0])
58 static int do_child(void)
60 if (ptrace(PTRACE_TRACEME
, -1, NULL
, NULL
))
61 ksft_exit_fail_msg("PTRACE_TRACEME", strerror(errno
));
64 ksft_exit_fail_msg("raise(SIGSTOP)", strerror(errno
));
69 static struct user_sve_header
*get_sve(pid_t pid
, void **buf
, size_t *size
)
71 struct user_sve_header
*sve
;
73 size_t sz
= sizeof *sve
;
78 p
= realloc(*buf
, sz
);
90 if (ptrace(PTRACE_GETREGSET
, pid
, NT_ARM_SVE
, &iov
))
106 static int set_sve(pid_t pid
, const struct user_sve_header
*sve
)
110 iov
.iov_base
= (void *)sve
;
111 iov
.iov_len
= sve
->size
;
112 return ptrace(PTRACE_SETREGSET
, pid
, NT_ARM_SVE
, &iov
);
115 static void dump_sve_regs(const struct user_sve_header
*sve
, unsigned int num
,
121 if ((sve
->flags
& SVE_PT_REGS_MASK
) != SVE_PT_REGS_SVE
)
122 ksft_exit_fail_msg("Dumping non-SVE register\n");
127 vq
= sve_vq_from_vl(sve
->vl
);
128 for (i
= 0; i
< num
; ++i
) {
130 dump((const char *)sve
+ SVE_PT_SVE_ZREG_OFFSET(vq
, i
),
132 printf("%s\n", vlmax
== sve
->vl
? "" : " ...");
136 static int do_parent(pid_t child
)
138 int ret
= EXIT_FAILURE
;
142 void *svebuf
= NULL
, *newsvebuf
;
143 size_t svebufsz
= 0, newsvebufsz
;
144 struct user_sve_header
*sve
, *new_sve
;
145 struct user_fpsimd_state
*fpsimd
;
150 /* Attach to the child */
161 * This should never happen but it's hard to flag in
167 if (WIFEXITED(status
) || WIFSIGNALED(status
))
168 ksft_exit_fail_msg("Child died unexpectedly\n");
170 ksft_test_result(WIFSTOPPED(status
), "WIFSTOPPED(%d)\n",
172 if (!WIFSTOPPED(status
))
175 sig
= WSTOPSIG(status
);
177 if (ptrace(PTRACE_GETSIGINFO
, pid
, NULL
, &si
)) {
181 if (errno
== EINVAL
) {
182 sig
= 0; /* bust group-stop */
186 ksft_test_result_fail("PTRACE_GETSIGINFO: %s\n",
191 if (sig
== SIGSTOP
&& si
.si_code
== SI_TKILL
&&
196 if (ptrace(PTRACE_CONT
, pid
, NULL
, sig
)) {
200 ksft_test_result_fail("PTRACE_CONT: %s\n",
206 sve
= get_sve(pid
, &svebuf
, &svebufsz
);
210 ksft_test_result_fail("get_sve: %s\n", strerror(errno
));
216 ksft_test_result_pass("get_sve\n");
219 ksft_test_result((sve
->flags
& SVE_PT_REGS_MASK
) == SVE_PT_REGS_FPSIMD
,
220 "FPSIMD registers\n");
221 if ((sve
->flags
& SVE_PT_REGS_MASK
) != SVE_PT_REGS_FPSIMD
)
224 fpsimd
= (struct user_fpsimd_state
*)((char *)sve
+
225 SVE_PT_FPSIMD_OFFSET
);
226 for (i
= 0; i
< 32; ++i
) {
227 p
= (unsigned char *)&fpsimd
->vregs
[i
];
229 for (j
= 0; j
< sizeof fpsimd
->vregs
[i
]; ++j
)
233 if (set_sve(pid
, sve
)) {
236 ksft_test_result_fail("set_sve(FPSIMD): %s\n",
244 vq
= sve_vq_from_vl(sve
->vl
);
246 newsvebufsz
= SVE_PT_SVE_ZREG_OFFSET(vq
, 1);
247 new_sve
= newsvebuf
= malloc(newsvebufsz
);
255 new_sve
->flags
&= ~SVE_PT_REGS_MASK
;
256 new_sve
->flags
|= SVE_PT_REGS_SVE
;
257 memset((char *)new_sve
+ SVE_PT_SVE_ZREG_OFFSET(vq
, 0),
258 0, SVE_PT_SVE_ZREG_SIZE(vq
));
259 new_sve
->size
= SVE_PT_SVE_ZREG_OFFSET(vq
, 1);
260 if (set_sve(pid
, new_sve
)) {
263 ksft_test_result_fail("set_sve(ZREG): %s\n", strerror(errno
));
270 new_sve
= get_sve(pid
, &newsvebuf
, &newsvebufsz
);
274 ksft_test_result_fail("get_sve(ZREG): %s\n", strerror(errno
));
281 ksft_test_result((new_sve
->flags
& SVE_PT_REGS_MASK
) == SVE_PT_REGS_SVE
,
283 if ((new_sve
->flags
& SVE_PT_REGS_MASK
) != SVE_PT_REGS_SVE
)
286 dump_sve_regs(new_sve
, 3, sizeof fpsimd
->vregs
[0]);
288 p
= (unsigned char *)new_sve
+ SVE_PT_SVE_ZREG_OFFSET(vq
, 1);
289 for (i
= 0; i
< sizeof fpsimd
->vregs
[0]; ++i
) {
290 unsigned char expected
= i
;
292 if (__BYTE_ORDER
== __BIG_ENDIAN
)
293 expected
= sizeof fpsimd
->vregs
[0] - 1 - expected
;
295 ksft_test_result(p
[i
] == expected
, "p[%d] == expected\n", i
);
296 if (p
[i
] != expected
)
303 kill(child
, SIGKILL
);
311 int ret
= EXIT_SUCCESS
;
312 __uint128_t v
[NR_VREGS
];
318 if (!(getauxval(AT_HWCAP
) & HWCAP_SVE
))
319 ksft_exit_skip("SVE not available\n");
321 sve_store_patterns(v
);
324 ksft_exit_fail_msg("Initial check_vregs() failed\n");
330 if (do_parent(child
))