1*0ddaa4c8SAndrew Turner /*-
2*0ddaa4c8SAndrew Turner * SPDX-License-Identifier: BSD-2-Clause
3*0ddaa4c8SAndrew Turner *
4*0ddaa4c8SAndrew Turner * Copyright (c) 2023,2024 Arm Ltd
5*0ddaa4c8SAndrew Turner *
6*0ddaa4c8SAndrew Turner * Redistribution and use in source and binary forms, with or without
7*0ddaa4c8SAndrew Turner * modification, are permitted provided that the following conditions
8*0ddaa4c8SAndrew Turner * are met:
9*0ddaa4c8SAndrew Turner * 1. Redistributions of source code must retain the above copyright
10*0ddaa4c8SAndrew Turner * notice, this list of conditions and the following disclaimer.
11*0ddaa4c8SAndrew Turner * 2. Redistributions in binary form must reproduce the above copyright
12*0ddaa4c8SAndrew Turner * notice, this list of conditions and the following disclaimer in the
13*0ddaa4c8SAndrew Turner * documentation and/or other materials provided with the distribution.
14*0ddaa4c8SAndrew Turner *
15*0ddaa4c8SAndrew Turner * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16*0ddaa4c8SAndrew Turner * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17*0ddaa4c8SAndrew Turner * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18*0ddaa4c8SAndrew Turner * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19*0ddaa4c8SAndrew Turner * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20*0ddaa4c8SAndrew Turner * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21*0ddaa4c8SAndrew Turner * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22*0ddaa4c8SAndrew Turner * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23*0ddaa4c8SAndrew Turner * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24*0ddaa4c8SAndrew Turner * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25*0ddaa4c8SAndrew Turner * SUCH DAMAGE.
26*0ddaa4c8SAndrew Turner */
27*0ddaa4c8SAndrew Turner
28*0ddaa4c8SAndrew Turner #include <sys/types.h>
29*0ddaa4c8SAndrew Turner #include <sys/auxv.h>
30*0ddaa4c8SAndrew Turner #include <sys/ptrace.h>
31*0ddaa4c8SAndrew Turner #include <sys/reg.h>
32*0ddaa4c8SAndrew Turner #include <sys/ucontext.h>
33*0ddaa4c8SAndrew Turner #include <sys/user.h>
34*0ddaa4c8SAndrew Turner #include <sys/wait.h>
35*0ddaa4c8SAndrew Turner
36*0ddaa4c8SAndrew Turner #include <machine/armreg.h>
37*0ddaa4c8SAndrew Turner #include <machine/sysarch.h>
38*0ddaa4c8SAndrew Turner
39*0ddaa4c8SAndrew Turner #include <signal.h>
40*0ddaa4c8SAndrew Turner #include <stdint.h>
41*0ddaa4c8SAndrew Turner #include <stdio.h>
42*0ddaa4c8SAndrew Turner #include <stdlib.h>
43*0ddaa4c8SAndrew Turner
44*0ddaa4c8SAndrew Turner #include <atf-c.h>
45*0ddaa4c8SAndrew Turner
46*0ddaa4c8SAndrew Turner static unsigned long vl;
47*0ddaa4c8SAndrew Turner
48*0ddaa4c8SAndrew Turner static void
check_for_sve(void)49*0ddaa4c8SAndrew Turner check_for_sve(void)
50*0ddaa4c8SAndrew Turner {
51*0ddaa4c8SAndrew Turner unsigned long hwcap;
52*0ddaa4c8SAndrew Turner
53*0ddaa4c8SAndrew Turner if (elf_aux_info(AT_HWCAP, &hwcap, sizeof(hwcap)) != 0)
54*0ddaa4c8SAndrew Turner atf_tc_skip("No HWCAP");
55*0ddaa4c8SAndrew Turner
56*0ddaa4c8SAndrew Turner if ((hwcap & HWCAP_SVE) == 0)
57*0ddaa4c8SAndrew Turner atf_tc_skip("No SVE support in HW");
58*0ddaa4c8SAndrew Turner
59*0ddaa4c8SAndrew Turner ATF_REQUIRE(sysarch(ARM64_GET_SVE_VL, &vl) == 0);
60*0ddaa4c8SAndrew Turner }
61*0ddaa4c8SAndrew Turner
62*0ddaa4c8SAndrew Turner ATF_TC_WITHOUT_HEAD(sve_registers);
ATF_TC_BODY(sve_registers,tc)63*0ddaa4c8SAndrew Turner ATF_TC_BODY(sve_registers, tc)
64*0ddaa4c8SAndrew Turner {
65*0ddaa4c8SAndrew Turner uint64_t reg, val;
66*0ddaa4c8SAndrew Turner
67*0ddaa4c8SAndrew Turner check_for_sve();
68*0ddaa4c8SAndrew Turner
69*0ddaa4c8SAndrew Turner /* Check the ID registers are sane */
70*0ddaa4c8SAndrew Turner reg = READ_SPECIALREG(id_aa64pfr0_el1);
71*0ddaa4c8SAndrew Turner ATF_REQUIRE((reg & ID_AA64PFR0_SVE_MASK) >= ID_AA64PFR0_SVE_IMPL);
72*0ddaa4c8SAndrew Turner
73*0ddaa4c8SAndrew Turner /*
74*0ddaa4c8SAndrew Turner * Store 1.0 in z0, repeated every 16 bits. Read it from d0 as
75*0ddaa4c8SAndrew Turner * the registers alias.
76*0ddaa4c8SAndrew Turner */
77*0ddaa4c8SAndrew Turner asm volatile(
78*0ddaa4c8SAndrew Turner ".arch_extension sve \n"
79*0ddaa4c8SAndrew Turner "fmov z0.h, #1 \n"
80*0ddaa4c8SAndrew Turner "str d0, [%0] \n"
81*0ddaa4c8SAndrew Turner ".arch_extension nosve \n"
82*0ddaa4c8SAndrew Turner :: "r"(&val) : "z0", "d0"
83*0ddaa4c8SAndrew Turner );
84*0ddaa4c8SAndrew Turner
85*0ddaa4c8SAndrew Turner /* Check for the 1.0 bit pattern */
86*0ddaa4c8SAndrew Turner ATF_REQUIRE_EQ(val, 0x3c003c003c003c00);
87*0ddaa4c8SAndrew Turner }
88*0ddaa4c8SAndrew Turner
89*0ddaa4c8SAndrew Turner static void
sve_signal_handler(int sig __unused,siginfo_t * info,void * context)90*0ddaa4c8SAndrew Turner sve_signal_handler(int sig __unused, siginfo_t *info, void *context)
91*0ddaa4c8SAndrew Turner {
92*0ddaa4c8SAndrew Turner struct arm64_reg_context *regctx;
93*0ddaa4c8SAndrew Turner struct sve_context *svectx;
94*0ddaa4c8SAndrew Turner ucontext_t *ctx;
95*0ddaa4c8SAndrew Turner uint64_t *sveregs;
96*0ddaa4c8SAndrew Turner
97*0ddaa4c8SAndrew Turner ctx = context;
98*0ddaa4c8SAndrew Turner
99*0ddaa4c8SAndrew Turner /* Check the trap is from a breakpoint instruction */
100*0ddaa4c8SAndrew Turner ATF_REQUIRE_EQ(info->si_trapno, EXCP_BRK);
101*0ddaa4c8SAndrew Turner ctx->uc_mcontext.mc_gpregs.gp_elr += 4;
102*0ddaa4c8SAndrew Turner
103*0ddaa4c8SAndrew Turner /* Trash z0 to check it's not kept when exiting the handler */
104*0ddaa4c8SAndrew Turner asm volatile(
105*0ddaa4c8SAndrew Turner ".arch_extension sve \n"
106*0ddaa4c8SAndrew Turner "fmov z0.h, #2 \n"
107*0ddaa4c8SAndrew Turner ".arch_extension nosve \n"
108*0ddaa4c8SAndrew Turner ::: "z0");
109*0ddaa4c8SAndrew Turner
110*0ddaa4c8SAndrew Turner /* Change the lower bits of z1 through the siginfo struct */
111*0ddaa4c8SAndrew Turner ctx->uc_mcontext.mc_fpregs.fp_q[1] = 0x5a5a5a5a5a5a5a5a;
112*0ddaa4c8SAndrew Turner
113*0ddaa4c8SAndrew Turner /* Find the SVE registers */
114*0ddaa4c8SAndrew Turner regctx = (struct arm64_reg_context *)ctx->uc_mcontext.mc_ptr;
115*0ddaa4c8SAndrew Turner if (regctx != NULL) {
116*0ddaa4c8SAndrew Turner int idx, next;
117*0ddaa4c8SAndrew Turner do {
118*0ddaa4c8SAndrew Turner if (regctx->ctx_id == ARM64_CTX_SVE)
119*0ddaa4c8SAndrew Turner break;
120*0ddaa4c8SAndrew Turner
121*0ddaa4c8SAndrew Turner ATF_REQUIRE(regctx->ctx_id != ARM64_CTX_END);
122*0ddaa4c8SAndrew Turner regctx = (struct arm64_reg_context *)
123*0ddaa4c8SAndrew Turner ((uintptr_t)regctx + regctx->ctx_size);
124*0ddaa4c8SAndrew Turner } while (1);
125*0ddaa4c8SAndrew Turner
126*0ddaa4c8SAndrew Turner /* Update the register context */
127*0ddaa4c8SAndrew Turner svectx = (struct sve_context *)regctx;
128*0ddaa4c8SAndrew Turner ATF_REQUIRE_EQ(svectx->sve_vector_len, vl);
129*0ddaa4c8SAndrew Turner
130*0ddaa4c8SAndrew Turner sveregs = (uint64_t *)(void *)(svectx + 1);
131*0ddaa4c8SAndrew Turner /* Find the array entries to change */
132*0ddaa4c8SAndrew Turner idx = 2 * svectx->sve_vector_len / sizeof(*sveregs);
133*0ddaa4c8SAndrew Turner next = 3 * svectx->sve_vector_len / sizeof(*sveregs);
134*0ddaa4c8SAndrew Turner while (idx != next) {
135*0ddaa4c8SAndrew Turner sveregs[idx] = 0xdeaddeaddeaddead;
136*0ddaa4c8SAndrew Turner idx++;
137*0ddaa4c8SAndrew Turner }
138*0ddaa4c8SAndrew Turner }
139*0ddaa4c8SAndrew Turner }
140*0ddaa4c8SAndrew Turner
141*0ddaa4c8SAndrew Turner ATF_TC_WITHOUT_HEAD(sve_signal);
ATF_TC_BODY(sve_signal,tc)142*0ddaa4c8SAndrew Turner ATF_TC_BODY(sve_signal, tc)
143*0ddaa4c8SAndrew Turner {
144*0ddaa4c8SAndrew Turner struct sigaction sa = {
145*0ddaa4c8SAndrew Turner .sa_sigaction = sve_signal_handler,
146*0ddaa4c8SAndrew Turner .sa_flags = SA_SIGINFO,
147*0ddaa4c8SAndrew Turner };
148*0ddaa4c8SAndrew Turner uint64_t val0, val1, *val2;
149*0ddaa4c8SAndrew Turner
150*0ddaa4c8SAndrew Turner check_for_sve();
151*0ddaa4c8SAndrew Turner ATF_REQUIRE(sigaction(SIGTRAP, &sa, NULL) == 0);
152*0ddaa4c8SAndrew Turner val2 = malloc(vl);
153*0ddaa4c8SAndrew Turner ATF_REQUIRE(val2 != NULL);
154*0ddaa4c8SAndrew Turner
155*0ddaa4c8SAndrew Turner asm volatile(
156*0ddaa4c8SAndrew Turner ".arch_extension sve \n"
157*0ddaa4c8SAndrew Turner "fmov z0.h, #1 \n"
158*0ddaa4c8SAndrew Turner "fmov z1.h, #1 \n"
159*0ddaa4c8SAndrew Turner "fmov z2.h, #1 \n"
160*0ddaa4c8SAndrew Turner /* Raise a SIGTRAP */
161*0ddaa4c8SAndrew Turner "brk #1 \n"
162*0ddaa4c8SAndrew Turner "str d0, [%0] \n"
163*0ddaa4c8SAndrew Turner "str d1, [%1] \n"
164*0ddaa4c8SAndrew Turner "str z2, [%2] \n"
165*0ddaa4c8SAndrew Turner ".arch_extension nosve \n"
166*0ddaa4c8SAndrew Turner :: "r"(&val0), "r"(&val1), "r"(val2) : "z0", "z1", "z2", "d0", "d1"
167*0ddaa4c8SAndrew Turner );
168*0ddaa4c8SAndrew Turner
169*0ddaa4c8SAndrew Turner /* Check for the 1.0 bit pattern */
170*0ddaa4c8SAndrew Turner ATF_REQUIRE_EQ(val0, 0x3c003c003c003c00);
171*0ddaa4c8SAndrew Turner /* Check for the changed bit pattern */
172*0ddaa4c8SAndrew Turner ATF_REQUIRE_EQ(val1, 0x5a5a5a5a5a5a5a5a);
173*0ddaa4c8SAndrew Turner /*
174*0ddaa4c8SAndrew Turner * Check the lower 128 bits are restored from fp_q and the
175*0ddaa4c8SAndrew Turner * upper bits are restored from the sve data region
176*0ddaa4c8SAndrew Turner */
177*0ddaa4c8SAndrew Turner for (size_t i = 0; i < vl / sizeof(*val2); i++) {
178*0ddaa4c8SAndrew Turner if (i < 2)
179*0ddaa4c8SAndrew Turner ATF_REQUIRE_EQ(val2[i], 0x3c003c003c003c00);
180*0ddaa4c8SAndrew Turner else
181*0ddaa4c8SAndrew Turner ATF_REQUIRE_EQ(val2[i], 0xdeaddeaddeaddead);
182*0ddaa4c8SAndrew Turner }
183*0ddaa4c8SAndrew Turner
184*0ddaa4c8SAndrew Turner free(val2);
185*0ddaa4c8SAndrew Turner }
186*0ddaa4c8SAndrew Turner
187*0ddaa4c8SAndrew Turner ATF_TC_WITHOUT_HEAD(sve_signal_altstack);
ATF_TC_BODY(sve_signal_altstack,tc)188*0ddaa4c8SAndrew Turner ATF_TC_BODY(sve_signal_altstack, tc)
189*0ddaa4c8SAndrew Turner {
190*0ddaa4c8SAndrew Turner struct sigaction sa = {
191*0ddaa4c8SAndrew Turner .sa_sigaction = sve_signal_handler,
192*0ddaa4c8SAndrew Turner .sa_flags = SA_ONSTACK | SA_SIGINFO,
193*0ddaa4c8SAndrew Turner };
194*0ddaa4c8SAndrew Turner stack_t ss = {
195*0ddaa4c8SAndrew Turner .ss_size = SIGSTKSZ,
196*0ddaa4c8SAndrew Turner };
197*0ddaa4c8SAndrew Turner uint64_t val0, val1, *val2;
198*0ddaa4c8SAndrew Turner
199*0ddaa4c8SAndrew Turner check_for_sve();
200*0ddaa4c8SAndrew Turner ss.ss_sp = malloc(ss.ss_size);
201*0ddaa4c8SAndrew Turner ATF_REQUIRE(ss.ss_sp != NULL);
202*0ddaa4c8SAndrew Turner ATF_REQUIRE(sigaltstack(&ss, NULL) == 0);
203*0ddaa4c8SAndrew Turner ATF_REQUIRE(sigaction(SIGTRAP, &sa, NULL) == 0);
204*0ddaa4c8SAndrew Turner val2 = malloc(vl);
205*0ddaa4c8SAndrew Turner ATF_REQUIRE(val2 != NULL);
206*0ddaa4c8SAndrew Turner
207*0ddaa4c8SAndrew Turner asm volatile(
208*0ddaa4c8SAndrew Turner ".arch_extension sve \n"
209*0ddaa4c8SAndrew Turner "fmov z0.h, #1 \n"
210*0ddaa4c8SAndrew Turner "fmov z1.h, #1 \n"
211*0ddaa4c8SAndrew Turner "fmov z2.h, #1 \n"
212*0ddaa4c8SAndrew Turner /* Raise a SIGTRAP */
213*0ddaa4c8SAndrew Turner "brk #1 \n"
214*0ddaa4c8SAndrew Turner "str d0, [%0] \n"
215*0ddaa4c8SAndrew Turner "str d1, [%1] \n"
216*0ddaa4c8SAndrew Turner "str z2, [%2] \n"
217*0ddaa4c8SAndrew Turner ".arch_extension nosve \n"
218*0ddaa4c8SAndrew Turner :: "r"(&val0), "r"(&val1), "r"(val2) : "z0", "z1", "z2", "d0", "d1"
219*0ddaa4c8SAndrew Turner );
220*0ddaa4c8SAndrew Turner
221*0ddaa4c8SAndrew Turner /* Check for the 1.0 bit pattern */
222*0ddaa4c8SAndrew Turner ATF_REQUIRE_EQ(val0, 0x3c003c003c003c00);
223*0ddaa4c8SAndrew Turner /* Check for the changed bit pattern */
224*0ddaa4c8SAndrew Turner ATF_REQUIRE_EQ(val1, 0x5a5a5a5a5a5a5a5a);
225*0ddaa4c8SAndrew Turner /*
226*0ddaa4c8SAndrew Turner * Check the lower 128 bits are restored from fp_q and the
227*0ddaa4c8SAndrew Turner * upper bits are restored from the sve data region
228*0ddaa4c8SAndrew Turner */
229*0ddaa4c8SAndrew Turner for (size_t i = 0; i < vl / sizeof(*val2); i++) {
230*0ddaa4c8SAndrew Turner if (i < 2)
231*0ddaa4c8SAndrew Turner ATF_REQUIRE_EQ(val2[i], 0x3c003c003c003c00);
232*0ddaa4c8SAndrew Turner else
233*0ddaa4c8SAndrew Turner ATF_REQUIRE_EQ(val2[i], 0xdeaddeaddeaddead);
234*0ddaa4c8SAndrew Turner }
235*0ddaa4c8SAndrew Turner
236*0ddaa4c8SAndrew Turner free(val2);
237*0ddaa4c8SAndrew Turner }
238*0ddaa4c8SAndrew Turner
239*0ddaa4c8SAndrew Turner ATF_TC_WITHOUT_HEAD(sve_ptrace);
ATF_TC_BODY(sve_ptrace,tc)240*0ddaa4c8SAndrew Turner ATF_TC_BODY(sve_ptrace, tc)
241*0ddaa4c8SAndrew Turner {
242*0ddaa4c8SAndrew Turner struct reg reg;
243*0ddaa4c8SAndrew Turner struct iovec fpvec, svevec;
244*0ddaa4c8SAndrew Turner struct svereg_header *header;
245*0ddaa4c8SAndrew Turner pid_t child, wpid;
246*0ddaa4c8SAndrew Turner int status;
247*0ddaa4c8SAndrew Turner
248*0ddaa4c8SAndrew Turner check_for_sve();
249*0ddaa4c8SAndrew Turner
250*0ddaa4c8SAndrew Turner child = fork();
251*0ddaa4c8SAndrew Turner ATF_REQUIRE(child >= 0);
252*0ddaa4c8SAndrew Turner if (child == 0) {
253*0ddaa4c8SAndrew Turner char exec_path[1024];
254*0ddaa4c8SAndrew Turner
255*0ddaa4c8SAndrew Turner /* Calculate the location of the helper */
256*0ddaa4c8SAndrew Turner snprintf(exec_path, sizeof(exec_path), "%s/sve_ptrace_helper",
257*0ddaa4c8SAndrew Turner atf_tc_get_config_var(tc, "srcdir"));
258*0ddaa4c8SAndrew Turner
259*0ddaa4c8SAndrew Turner ptrace(PT_TRACE_ME, 0, NULL, 0);
260*0ddaa4c8SAndrew Turner
261*0ddaa4c8SAndrew Turner /* Execute the helper so SVE will be disabled */
262*0ddaa4c8SAndrew Turner execl(exec_path, "sve_ptrace_helper", NULL);
263*0ddaa4c8SAndrew Turner _exit(1);
264*0ddaa4c8SAndrew Turner }
265*0ddaa4c8SAndrew Turner
266*0ddaa4c8SAndrew Turner /* The first event should be the SIGSTOP at the start of the child */
267*0ddaa4c8SAndrew Turner wpid = waitpid(child, &status, 0);
268*0ddaa4c8SAndrew Turner ATF_REQUIRE(WIFSTOPPED(status));
269*0ddaa4c8SAndrew Turner
270*0ddaa4c8SAndrew Turner fpvec.iov_base = NULL;
271*0ddaa4c8SAndrew Turner fpvec.iov_len = 0;
272*0ddaa4c8SAndrew Turner /* Read the length before SVE has been used */
273*0ddaa4c8SAndrew Turner ATF_REQUIRE(ptrace(PT_GETREGSET, wpid, (caddr_t)&fpvec, NT_ARM_SVE) ==
274*0ddaa4c8SAndrew Turner 0);
275*0ddaa4c8SAndrew Turner ATF_REQUIRE(fpvec.iov_len == (sizeof(struct svereg_header) +
276*0ddaa4c8SAndrew Turner sizeof(struct fpregs)));
277*0ddaa4c8SAndrew Turner
278*0ddaa4c8SAndrew Turner fpvec.iov_base = malloc(fpvec.iov_len);
279*0ddaa4c8SAndrew Turner header = fpvec.iov_base;
280*0ddaa4c8SAndrew Turner ATF_REQUIRE(fpvec.iov_base != NULL);
281*0ddaa4c8SAndrew Turner ATF_REQUIRE(ptrace(PT_GETREGSET, wpid, (caddr_t)&fpvec, NT_ARM_SVE) ==
282*0ddaa4c8SAndrew Turner 0);
283*0ddaa4c8SAndrew Turner ATF_REQUIRE((header->sve_flags & SVEREG_FLAG_REGS_MASK) ==
284*0ddaa4c8SAndrew Turner SVEREG_FLAG_FP);
285*0ddaa4c8SAndrew Turner
286*0ddaa4c8SAndrew Turner /* Check writing back the FP registers works */
287*0ddaa4c8SAndrew Turner ATF_REQUIRE(ptrace(PT_SETREGSET, wpid, (caddr_t)&fpvec, NT_ARM_SVE) ==
288*0ddaa4c8SAndrew Turner 0);
289*0ddaa4c8SAndrew Turner
290*0ddaa4c8SAndrew Turner ptrace(PT_CONTINUE, wpid, (caddr_t)1, 0);
291*0ddaa4c8SAndrew Turner
292*0ddaa4c8SAndrew Turner /* The second event should be the SIGINFO at the end */
293*0ddaa4c8SAndrew Turner wpid = waitpid(child, &status, 0);
294*0ddaa4c8SAndrew Turner ATF_REQUIRE(WIFSTOPPED(status));
295*0ddaa4c8SAndrew Turner ATF_REQUIRE_EQ(WSTOPSIG(status), SIGTRAP);
296*0ddaa4c8SAndrew Turner
297*0ddaa4c8SAndrew Turner /* Check writing back FP registers when SVE has started will fail */
298*0ddaa4c8SAndrew Turner ATF_REQUIRE(ptrace(PT_SETREGSET, wpid, (caddr_t)&fpvec, NT_ARM_SVE) ==
299*0ddaa4c8SAndrew Turner -1);
300*0ddaa4c8SAndrew Turner
301*0ddaa4c8SAndrew Turner svevec.iov_base = NULL;
302*0ddaa4c8SAndrew Turner svevec.iov_len = 0;
303*0ddaa4c8SAndrew Turner /* Read the length after SVE has been used */
304*0ddaa4c8SAndrew Turner ATF_REQUIRE(ptrace(PT_GETREGSET, wpid, (caddr_t)&svevec, NT_ARM_SVE) ==
305*0ddaa4c8SAndrew Turner 0);
306*0ddaa4c8SAndrew Turner /* TODO: Check the length is correct based on vector length */
307*0ddaa4c8SAndrew Turner ATF_REQUIRE(svevec.iov_len > (sizeof(struct svereg_header) +
308*0ddaa4c8SAndrew Turner sizeof(struct fpregs)));
309*0ddaa4c8SAndrew Turner
310*0ddaa4c8SAndrew Turner svevec.iov_base = malloc(svevec.iov_len);
311*0ddaa4c8SAndrew Turner header = svevec.iov_base;
312*0ddaa4c8SAndrew Turner ATF_REQUIRE(svevec.iov_base != NULL);
313*0ddaa4c8SAndrew Turner ATF_REQUIRE(ptrace(PT_GETREGSET, wpid, (caddr_t)&svevec, NT_ARM_SVE) ==
314*0ddaa4c8SAndrew Turner 0);
315*0ddaa4c8SAndrew Turner ATF_REQUIRE((header->sve_flags & SVEREG_FLAG_REGS_MASK) ==
316*0ddaa4c8SAndrew Turner SVEREG_FLAG_SVE);
317*0ddaa4c8SAndrew Turner
318*0ddaa4c8SAndrew Turner /* Test writing back the SVE registers works */
319*0ddaa4c8SAndrew Turner ATF_REQUIRE(ptrace(PT_SETREGSET, wpid, (caddr_t)&svevec, NT_ARM_SVE) ==
320*0ddaa4c8SAndrew Turner 0);
321*0ddaa4c8SAndrew Turner
322*0ddaa4c8SAndrew Turner free(svevec.iov_base);
323*0ddaa4c8SAndrew Turner free(fpvec.iov_base);
324*0ddaa4c8SAndrew Turner
325*0ddaa4c8SAndrew Turner /* Step over the brk instruction */
326*0ddaa4c8SAndrew Turner ATF_REQUIRE(ptrace(PT_GETREGS, wpid, (caddr_t)®, 0) != -1);
327*0ddaa4c8SAndrew Turner reg.elr += 4;
328*0ddaa4c8SAndrew Turner ATF_REQUIRE(ptrace(PT_SETREGS, wpid, (caddr_t)®, 0) != -1);
329*0ddaa4c8SAndrew Turner
330*0ddaa4c8SAndrew Turner ptrace(PT_CONTINUE, wpid, (caddr_t)1, 0);
331*0ddaa4c8SAndrew Turner waitpid(child, &status, 0);
332*0ddaa4c8SAndrew Turner ATF_REQUIRE(WIFEXITED(status));
333*0ddaa4c8SAndrew Turner ATF_REQUIRE_EQ(WEXITSTATUS(status), 0);
334*0ddaa4c8SAndrew Turner }
335*0ddaa4c8SAndrew Turner
336*0ddaa4c8SAndrew Turner ATF_TC_WITHOUT_HEAD(sve_fork_env);
ATF_TC_BODY(sve_fork_env,tc)337*0ddaa4c8SAndrew Turner ATF_TC_BODY(sve_fork_env, tc)
338*0ddaa4c8SAndrew Turner {
339*0ddaa4c8SAndrew Turner pid_t child, wpid;
340*0ddaa4c8SAndrew Turner int status;
341*0ddaa4c8SAndrew Turner
342*0ddaa4c8SAndrew Turner check_for_sve();
343*0ddaa4c8SAndrew Turner
344*0ddaa4c8SAndrew Turner child = fork();
345*0ddaa4c8SAndrew Turner ATF_REQUIRE(child >= 0);
346*0ddaa4c8SAndrew Turner
347*0ddaa4c8SAndrew Turner /* Check the child environment is sane */
348*0ddaa4c8SAndrew Turner if (child == 0) {
349*0ddaa4c8SAndrew Turner unsigned long child_vl, hwcap;
350*0ddaa4c8SAndrew Turner
351*0ddaa4c8SAndrew Turner if (elf_aux_info(AT_HWCAP, &hwcap, sizeof(hwcap)) != 0)
352*0ddaa4c8SAndrew Turner _exit(1);
353*0ddaa4c8SAndrew Turner
354*0ddaa4c8SAndrew Turner if ((hwcap & HWCAP_SVE) == 0)
355*0ddaa4c8SAndrew Turner _exit(2);
356*0ddaa4c8SAndrew Turner
357*0ddaa4c8SAndrew Turner if (sysarch(ARM64_GET_SVE_VL, &child_vl) != 0)
358*0ddaa4c8SAndrew Turner _exit(3);
359*0ddaa4c8SAndrew Turner
360*0ddaa4c8SAndrew Turner if (child_vl != vl)
361*0ddaa4c8SAndrew Turner _exit(4);
362*0ddaa4c8SAndrew Turner
363*0ddaa4c8SAndrew Turner _exit(0);
364*0ddaa4c8SAndrew Turner }
365*0ddaa4c8SAndrew Turner
366*0ddaa4c8SAndrew Turner wpid = waitpid(child, &status, 0);
367*0ddaa4c8SAndrew Turner ATF_REQUIRE_EQ(child, wpid);
368*0ddaa4c8SAndrew Turner ATF_REQUIRE(WIFEXITED(status));
369*0ddaa4c8SAndrew Turner ATF_REQUIRE(WEXITSTATUS(status) == 0);
370*0ddaa4c8SAndrew Turner }
371*0ddaa4c8SAndrew Turner
372*0ddaa4c8SAndrew Turner ATF_TC_WITHOUT_HEAD(sve_fork_regs);
ATF_TC_BODY(sve_fork_regs,tc)373*0ddaa4c8SAndrew Turner ATF_TC_BODY(sve_fork_regs, tc)
374*0ddaa4c8SAndrew Turner {
375*0ddaa4c8SAndrew Turner pid_t child, wpid;
376*0ddaa4c8SAndrew Turner uint64_t *val;
377*0ddaa4c8SAndrew Turner int status;
378*0ddaa4c8SAndrew Turner
379*0ddaa4c8SAndrew Turner check_for_sve();
380*0ddaa4c8SAndrew Turner
381*0ddaa4c8SAndrew Turner /*
382*0ddaa4c8SAndrew Turner * Malloc before fork to reduce the change of trashing sve registers
383*0ddaa4c8SAndrew Turner */
384*0ddaa4c8SAndrew Turner val = malloc(vl);
385*0ddaa4c8SAndrew Turner ATF_REQUIRE(val != NULL);
386*0ddaa4c8SAndrew Turner
387*0ddaa4c8SAndrew Turner /*
388*0ddaa4c8SAndrew Turner * Store 1.0 in z0, repeated every 16 bits. Read it from d0 as
389*0ddaa4c8SAndrew Turner * the registers alias.
390*0ddaa4c8SAndrew Turner */
391*0ddaa4c8SAndrew Turner asm volatile(
392*0ddaa4c8SAndrew Turner ".arch_extension sve \n"
393*0ddaa4c8SAndrew Turner "fmov z8.h, #1 \n"
394*0ddaa4c8SAndrew Turner ".arch_extension nosve \n"
395*0ddaa4c8SAndrew Turner ::: "z8"
396*0ddaa4c8SAndrew Turner );
397*0ddaa4c8SAndrew Turner
398*0ddaa4c8SAndrew Turner /* TODO: Move to asm to ensure z8 isn't trashed */
399*0ddaa4c8SAndrew Turner child = fork();
400*0ddaa4c8SAndrew Turner
401*0ddaa4c8SAndrew Turner asm volatile(
402*0ddaa4c8SAndrew Turner ".arch_extension sve \n"
403*0ddaa4c8SAndrew Turner "str z8, [%0] \n"
404*0ddaa4c8SAndrew Turner ".arch_extension nosve \n"
405*0ddaa4c8SAndrew Turner :: "r"(val) : "z8"
406*0ddaa4c8SAndrew Turner );
407*0ddaa4c8SAndrew Turner
408*0ddaa4c8SAndrew Turner ATF_REQUIRE(child >= 0);
409*0ddaa4c8SAndrew Turner
410*0ddaa4c8SAndrew Turner /* Check the child environment is sane */
411*0ddaa4c8SAndrew Turner if (child == 0) {
412*0ddaa4c8SAndrew Turner for (size_t i = 0; i < vl / sizeof(*val); i++) {
413*0ddaa4c8SAndrew Turner if (val[i] != 0x3c003c003c003c00)
414*0ddaa4c8SAndrew Turner _exit(i + 1);
415*0ddaa4c8SAndrew Turner }
416*0ddaa4c8SAndrew Turner
417*0ddaa4c8SAndrew Turner free(val);
418*0ddaa4c8SAndrew Turner _exit(0);
419*0ddaa4c8SAndrew Turner }
420*0ddaa4c8SAndrew Turner
421*0ddaa4c8SAndrew Turner free(val);
422*0ddaa4c8SAndrew Turner wpid = waitpid(child, &status, 0);
423*0ddaa4c8SAndrew Turner ATF_REQUIRE_EQ(child, wpid);
424*0ddaa4c8SAndrew Turner ATF_REQUIRE(WIFEXITED(status));
425*0ddaa4c8SAndrew Turner ATF_REQUIRE(WEXITSTATUS(status) == 0);
426*0ddaa4c8SAndrew Turner }
427*0ddaa4c8SAndrew Turner
ATF_TP_ADD_TCS(tp)428*0ddaa4c8SAndrew Turner ATF_TP_ADD_TCS(tp)
429*0ddaa4c8SAndrew Turner {
430*0ddaa4c8SAndrew Turner ATF_TP_ADD_TC(tp, sve_registers);
431*0ddaa4c8SAndrew Turner ATF_TP_ADD_TC(tp, sve_signal);
432*0ddaa4c8SAndrew Turner ATF_TP_ADD_TC(tp, sve_signal_altstack);
433*0ddaa4c8SAndrew Turner /* TODO: Check a too small signal stack */
434*0ddaa4c8SAndrew Turner ATF_TP_ADD_TC(tp, sve_ptrace);
435*0ddaa4c8SAndrew Turner ATF_TP_ADD_TC(tp, sve_fork_env);
436*0ddaa4c8SAndrew Turner ATF_TP_ADD_TC(tp, sve_fork_regs);
437*0ddaa4c8SAndrew Turner return (atf_no_error());
438*0ddaa4c8SAndrew Turner }
439