1// SPDX-License-Identifier: GPL-2.0-only
2// Copyright (C) 2021 ARM Limited.
3//
4// Assembly portion of the syscall ABI test
5
6//
7// Load values from memory into registers, invoke a syscall and save the
8// register values back to memory for later checking. The syscall to be
9// invoked is configured in x8 of the input GPR data.
10//
11// x0: SVE VL, 0 for FP only
12// x1: SME VL
13//
14// GPRs: gpr_in, gpr_out
15// FPRs: fpr_in, fpr_out
16// Zn: z_in, z_out
17// Pn: p_in, p_out
18// FFR: ffr_in, ffr_out
19// ZA: za_in, za_out
20// SVCR: svcr_in, svcr_out
21
22#include "syscall-abi.h"
23
24.arch_extension sve
25
26#define ID_AA64SMFR0_EL1_SMEver_SHIFT 56
27#define ID_AA64SMFR0_EL1_SMEver_WIDTH 4
28
29/*
30 * LDR (vector to ZA array):
31 * LDR ZA[\nw, #\offset], [X\nxbase, #\offset, MUL VL]
32 */
33.macro _ldr_za nw, nxbase, offset=0
34 .inst 0xe1000000 \
35 | (((\nw) & 3) << 13) \
36 | ((\nxbase) << 5) \
37 | ((\offset) & 7)
38.endm
39
40/*
41 * STR (vector from ZA array):
42 * STR ZA[\nw, #\offset], [X\nxbase, #\offset, MUL VL]
43 */
44.macro _str_za nw, nxbase, offset=0
45 .inst 0xe1200000 \
46 | (((\nw) & 3) << 13) \
47 | ((\nxbase) << 5) \
48 | ((\offset) & 7)
49.endm
50
51/*
52 * LDR (ZT0)
53 *
54 * LDR ZT0, nx
55 */
56.macro _ldr_zt nx
57 .inst 0xe11f8000 \
58 | (((\nx) & 0x1f) << 5)
59.endm
60
61/*
62 * STR (ZT0)
63 *
64 * STR ZT0, nx
65 */
66.macro _str_zt nx
67 .inst 0xe13f8000 \
68 | (((\nx) & 0x1f) << 5)
69.endm
70
71.globl do_syscall
72do_syscall:
73 // Store callee saved registers x19-x29 (80 bytes) plus x0 and x1
74 stp x29, x30, [sp, #-112]!
75 mov x29, sp
76 stp x0, x1, [sp, #16]
77 stp x19, x20, [sp, #32]
78 stp x21, x22, [sp, #48]
79 stp x23, x24, [sp, #64]
80 stp x25, x26, [sp, #80]
81 stp x27, x28, [sp, #96]
82
83 // Set SVCR if we're doing SME
84 cbz x1, load_gpr
85 adrp x2, svcr_in
86 ldr x2, [x2, :lo12:svcr_in]
87 msr S3_3_C4_C2_2, x2
88
89 // Load ZA and ZT0 if enabled - uses x12 as scratch due to SME LDR
90 tbz x2, #SVCR_ZA_SHIFT, load_gpr
91 mov w12, #0
92 ldr x2, =za_in
931: _ldr_za 12, 2
94 add x2, x2, x1
95 add x12, x12, #1
96 cmp x1, x12
97 bne 1b
98
99 // ZT0
100 mrs x2, S3_0_C0_C4_5 // ID_AA64SMFR0_EL1
101 ubfx x2, x2, #ID_AA64SMFR0_EL1_SMEver_SHIFT, \
102 #ID_AA64SMFR0_EL1_SMEver_WIDTH
103 cbz x2, load_gpr
104 adrp x2, zt_in
105 add x2, x2, :lo12:zt_in
106 _ldr_zt 2
107
108load_gpr:
109 // Load GPRs x8-x28, and save our SP/FP for later comparison
110 ldr x2, =gpr_in
111 add x2, x2, #64
112 ldp x8, x9, [x2], #16
113 ldp x10, x11, [x2], #16
114 ldp x12, x13, [x2], #16
115 ldp x14, x15, [x2], #16
116 ldp x16, x17, [x2], #16
117 ldp x18, x19, [x2], #16
118 ldp x20, x21, [x2], #16
119 ldp x22, x23, [x2], #16
120 ldp x24, x25, [x2], #16
121 ldp x26, x27, [x2], #16
122 ldr x28, [x2], #8
123 str x29, [x2], #8 // FP
124 str x30, [x2], #8 // LR
125
126 // Load FPRs if we're not doing neither SVE nor streaming SVE
127 cbnz x0, check_sve_in
128 ldr x2, =svcr_in
129 tbnz x2, #SVCR_SM_SHIFT, check_sve_in
130
131 ldr x2, =fpr_in
132 ldp q0, q1, [x2]
133 ldp q2, q3, [x2, #16 * 2]
134 ldp q4, q5, [x2, #16 * 4]
135 ldp q6, q7, [x2, #16 * 6]
136 ldp q8, q9, [x2, #16 * 8]
137 ldp q10, q11, [x2, #16 * 10]
138 ldp q12, q13, [x2, #16 * 12]
139 ldp q14, q15, [x2, #16 * 14]
140 ldp q16, q17, [x2, #16 * 16]
141 ldp q18, q19, [x2, #16 * 18]
142 ldp q20, q21, [x2, #16 * 20]
143 ldp q22, q23, [x2, #16 * 22]
144 ldp q24, q25, [x2, #16 * 24]
145 ldp q26, q27, [x2, #16 * 26]
146 ldp q28, q29, [x2, #16 * 28]
147 ldp q30, q31, [x2, #16 * 30]
148
149 b 2f
150
151check_sve_in:
152 // Load the SVE registers if we're doing SVE/SME
153
154 ldr x2, =z_in
155 ldr z0, [x2, #0, MUL VL]
156 ldr z1, [x2, #1, MUL VL]
157 ldr z2, [x2, #2, MUL VL]
158 ldr z3, [x2, #3, MUL VL]
159 ldr z4, [x2, #4, MUL VL]
160 ldr z5, [x2, #5, MUL VL]
161 ldr z6, [x2, #6, MUL VL]
162 ldr z7, [x2, #7, MUL VL]
163 ldr z8, [x2, #8, MUL VL]
164 ldr z9, [x2, #9, MUL VL]
165 ldr z10, [x2, #10, MUL VL]
166 ldr z11, [x2, #11, MUL VL]
167 ldr z12, [x2, #12, MUL VL]
168 ldr z13, [x2, #13, MUL VL]
169 ldr z14, [x2, #14, MUL VL]
170 ldr z15, [x2, #15, MUL VL]
171 ldr z16, [x2, #16, MUL VL]
172 ldr z17, [x2, #17, MUL VL]
173 ldr z18, [x2, #18, MUL VL]
174 ldr z19, [x2, #19, MUL VL]
175 ldr z20, [x2, #20, MUL VL]
176 ldr z21, [x2, #21, MUL VL]
177 ldr z22, [x2, #22, MUL VL]
178 ldr z23, [x2, #23, MUL VL]
179 ldr z24, [x2, #24, MUL VL]
180 ldr z25, [x2, #25, MUL VL]
181 ldr z26, [x2, #26, MUL VL]
182 ldr z27, [x2, #27, MUL VL]
183 ldr z28, [x2, #28, MUL VL]
184 ldr z29, [x2, #29, MUL VL]
185 ldr z30, [x2, #30, MUL VL]
186 ldr z31, [x2, #31, MUL VL]
187
188 // Only set a non-zero FFR, test patterns must be zero since the
189 // syscall should clear it - this lets us handle FA64.
190 ldr x2, =ffr_in
191 ldr p0, [x2]
192 ldr x2, [x2, #0]
193 cbz x2, 1f
194 wrffr p0.b
1951:
196
197 ldr x2, =p_in
198 ldr p0, [x2, #0, MUL VL]
199 ldr p1, [x2, #1, MUL VL]
200 ldr p2, [x2, #2, MUL VL]
201 ldr p3, [x2, #3, MUL VL]
202 ldr p4, [x2, #4, MUL VL]
203 ldr p5, [x2, #5, MUL VL]
204 ldr p6, [x2, #6, MUL VL]
205 ldr p7, [x2, #7, MUL VL]
206 ldr p8, [x2, #8, MUL VL]
207 ldr p9, [x2, #9, MUL VL]
208 ldr p10, [x2, #10, MUL VL]
209 ldr p11, [x2, #11, MUL VL]
210 ldr p12, [x2, #12, MUL VL]
211 ldr p13, [x2, #13, MUL VL]
212 ldr p14, [x2, #14, MUL VL]
213 ldr p15, [x2, #15, MUL VL]
2142:
215
216 // Do the syscall
217 svc #0
218
219 // Save GPRs x8-x30
220 ldr x2, =gpr_out
221 add x2, x2, #64
222 stp x8, x9, [x2], #16
223 stp x10, x11, [x2], #16
224 stp x12, x13, [x2], #16
225 stp x14, x15, [x2], #16
226 stp x16, x17, [x2], #16
227 stp x18, x19, [x2], #16
228 stp x20, x21, [x2], #16
229 stp x22, x23, [x2], #16
230 stp x24, x25, [x2], #16
231 stp x26, x27, [x2], #16
232 stp x28, x29, [x2], #16
233 str x30, [x2]
234
235 // Restore x0 and x1 for feature checks
236 ldp x0, x1, [sp, #16]
237
238 // Save FPSIMD state
239 ldr x2, =fpr_out
240 stp q0, q1, [x2]
241 stp q2, q3, [x2, #16 * 2]
242 stp q4, q5, [x2, #16 * 4]
243 stp q6, q7, [x2, #16 * 6]
244 stp q8, q9, [x2, #16 * 8]
245 stp q10, q11, [x2, #16 * 10]
246 stp q12, q13, [x2, #16 * 12]
247 stp q14, q15, [x2, #16 * 14]
248 stp q16, q17, [x2, #16 * 16]
249 stp q18, q19, [x2, #16 * 18]
250 stp q20, q21, [x2, #16 * 20]
251 stp q22, q23, [x2, #16 * 22]
252 stp q24, q25, [x2, #16 * 24]
253 stp q26, q27, [x2, #16 * 26]
254 stp q28, q29, [x2, #16 * 28]
255 stp q30, q31, [x2, #16 * 30]
256
257 // Save SVCR if we're doing SME
258 cbz x1, check_sve_out
259 mrs x2, S3_3_C4_C2_2
260 adrp x3, svcr_out
261 str x2, [x3, :lo12:svcr_out]
262
263 // Save ZA if it's enabled - uses x12 as scratch due to SME STR
264 tbz x2, #SVCR_ZA_SHIFT, check_sve_out
265 mov w12, #0
266 ldr x2, =za_out
2671: _str_za 12, 2
268 add x2, x2, x1
269 add x12, x12, #1
270 cmp x1, x12
271 bne 1b
272
273 // ZT0
274 mrs x2, S3_0_C0_C4_5 // ID_AA64SMFR0_EL1
275 ubfx x2, x2, #ID_AA64SMFR0_EL1_SMEver_SHIFT, \
276 #ID_AA64SMFR0_EL1_SMEver_WIDTH
277 cbz x2, check_sve_out
278 adrp x2, zt_out
279 add x2, x2, :lo12:zt_out
280 _str_zt 2
281
282check_sve_out:
283 // Save the SVE state if we have some
284 cbz x0, 1f
285
286 ldr x2, =z_out
287 str z0, [x2, #0, MUL VL]
288 str z1, [x2, #1, MUL VL]
289 str z2, [x2, #2, MUL VL]
290 str z3, [x2, #3, MUL VL]
291 str z4, [x2, #4, MUL VL]
292 str z5, [x2, #5, MUL VL]
293 str z6, [x2, #6, MUL VL]
294 str z7, [x2, #7, MUL VL]
295 str z8, [x2, #8, MUL VL]
296 str z9, [x2, #9, MUL VL]
297 str z10, [x2, #10, MUL VL]
298 str z11, [x2, #11, MUL VL]
299 str z12, [x2, #12, MUL VL]
300 str z13, [x2, #13, MUL VL]
301 str z14, [x2, #14, MUL VL]
302 str z15, [x2, #15, MUL VL]
303 str z16, [x2, #16, MUL VL]
304 str z17, [x2, #17, MUL VL]
305 str z18, [x2, #18, MUL VL]
306 str z19, [x2, #19, MUL VL]
307 str z20, [x2, #20, MUL VL]
308 str z21, [x2, #21, MUL VL]
309 str z22, [x2, #22, MUL VL]
310 str z23, [x2, #23, MUL VL]
311 str z24, [x2, #24, MUL VL]
312 str z25, [x2, #25, MUL VL]
313 str z26, [x2, #26, MUL VL]
314 str z27, [x2, #27, MUL VL]
315 str z28, [x2, #28, MUL VL]
316 str z29, [x2, #29, MUL VL]
317 str z30, [x2, #30, MUL VL]
318 str z31, [x2, #31, MUL VL]
319
320 ldr x2, =p_out
321 str p0, [x2, #0, MUL VL]
322 str p1, [x2, #1, MUL VL]
323 str p2, [x2, #2, MUL VL]
324 str p3, [x2, #3, MUL VL]
325 str p4, [x2, #4, MUL VL]
326 str p5, [x2, #5, MUL VL]
327 str p6, [x2, #6, MUL VL]
328 str p7, [x2, #7, MUL VL]
329 str p8, [x2, #8, MUL VL]
330 str p9, [x2, #9, MUL VL]
331 str p10, [x2, #10, MUL VL]
332 str p11, [x2, #11, MUL VL]
333 str p12, [x2, #12, MUL VL]
334 str p13, [x2, #13, MUL VL]
335 str p14, [x2, #14, MUL VL]
336 str p15, [x2, #15, MUL VL]
337
338 // Only save FFR if we wrote a value for SME
339 ldr x2, =ffr_in
340 ldr x2, [x2, #0]
341 cbz x2, 1f
342 ldr x2, =ffr_out
343 rdffr p0.b
344 str p0, [x2]
3451:
346
347 // Restore callee saved registers x19-x30
348 ldp x19, x20, [sp, #32]
349 ldp x21, x22, [sp, #48]
350 ldp x23, x24, [sp, #64]
351 ldp x25, x26, [sp, #80]
352 ldp x27, x28, [sp, #96]
353 ldp x29, x30, [sp], #112
354
355 // Clear SVCR if we were doing SME so future tests don't have ZA
356 cbz x1, 1f
357 msr S3_3_C4_C2_2, xzr
3581:
359
360 ret
361

source code of linux/tools/testing/selftests/arm64/abi/syscall-abi-asm.S