WIP FPC-III support
[linux/fpc-iii.git] / tools / testing / selftests / arm64 / fp / fpsimd-test.S
blob1c5556bdd11d16e599677f661a6997cdd7f27538
1 // SPDX-License-Identifier: GPL-2.0-only
2 // Copyright (C) 2015-2019 ARM Limited.
3 // Original author: Dave Martin <Dave.Martin@arm.com>
4 //
5 // Simple FPSIMD context switch test
6 // Repeatedly writes unique test patterns into each FPSIMD register
7 // and reads them back to verify integrity.
8 //
9 // for x in `seq 1 NR_CPUS`; do fpsimd-test & pids=$pids\ $! ; done
10 // (leave it running for as long as you want...)
11 // kill $pids
13 #include <asm/unistd.h>
14 #include "assembler.h"
15 #include "asm-offsets.h"
17 #define NVR     32
18 #define MAXVL_B (128 / 8)
20 .macro _vldr Vn:req, Xt:req
21         ld1     {v\Vn\().2d}, [x\Xt]
22 .endm
24 .macro _vstr Vn:req, Xt:req
25         st1     {v\Vn\().2d}, [x\Xt]
26 .endm
28 // Generate accessor functions to read/write programmatically selected
29 // FPSIMD registers.
30 // x0 is the register index to access
31 // x1 is the memory address to read from (getv,setp) or store to (setv,setp)
32 // All clobber x0-x2
33 define_accessor setv, NVR, _vldr
34 define_accessor getv, NVR, _vstr
36 // Print a single character x0 to stdout
37 // Clobbers x0-x2,x8
38 function putc
39         str     x0, [sp, #-16]!
41         mov     x0, #1                  // STDOUT_FILENO
42         mov     x1, sp
43         mov     x2, #1
44         mov     x8, #__NR_write
45         svc     #0
47         add     sp, sp, #16
48         ret
49 endfunction
51 // Print a NUL-terminated string starting at address x0 to stdout
52 // Clobbers x0-x3,x8
53 function puts
54         mov     x1, x0
56         mov     x2, #0
57 0:      ldrb    w3, [x0], #1
58         cbz     w3, 1f
59         add     x2, x2, #1
60         b       0b
62 1:      mov     w0, #1                  // STDOUT_FILENO
63         mov     x8, #__NR_write
64         svc     #0
66         ret
67 endfunction
69 // Utility macro to print a literal string
70 // Clobbers x0-x4,x8
71 .macro puts string
72         .pushsection .rodata.str1.1, "aMS", 1
73 .L__puts_literal\@: .string "\string"
74         .popsection
76         ldr     x0, =.L__puts_literal\@
77         bl      puts
78 .endm
80 // Print an unsigned decimal number x0 to stdout
81 // Clobbers x0-x4,x8
82 function putdec
83         mov     x1, sp
84         str     x30, [sp, #-32]!        // Result can't be > 20 digits
86         mov     x2, #0
87         strb    w2, [x1, #-1]!          // Write the NUL terminator
89         mov     x2, #10
90 0:      udiv    x3, x0, x2              // div-mod loop to generate the digits
91         msub    x0, x3, x2, x0
92         add     w0, w0, #'0'
93         strb    w0, [x1, #-1]!
94         mov     x0, x3
95         cbnz    x3, 0b
97         ldrb    w0, [x1]
98         cbnz    w0, 1f
99         mov     w0, #'0'                // Print "0" for 0, not ""
100         strb    w0, [x1, #-1]!
102 1:      mov     x0, x1
103         bl      puts
105         ldr     x30, [sp], #32
106         ret
107 endfunction
109 // Print an unsigned decimal number x0 to stdout, followed by a newline
110 // Clobbers x0-x5,x8
111 function putdecn
112         mov     x5, x30
114         bl      putdec
115         mov     x0, #'\n'
116         bl      putc
118         ret     x5
119 endfunction
122 // Clobbers x0-x3,x8
123 function puthexb
124         str     x30, [sp, #-0x10]!
126         mov     w3, w0
127         lsr     w0, w0, #4
128         bl      puthexnibble
129         mov     w0, w3
131         ldr     x30, [sp], #0x10
132         // fall through to puthexnibble
133 endfunction
134 // Clobbers x0-x2,x8
135 function puthexnibble
136         and     w0, w0, #0xf
137         cmp     w0, #10
138         blo     1f
139         add     w0, w0, #'a' - ('9' + 1)
140 1:      add     w0, w0, #'0'
141         b       putc
142 endfunction
144 // x0=data in, x1=size in, clobbers x0-x5,x8
145 function dumphex
146         str     x30, [sp, #-0x10]!
148         mov     x4, x0
149         mov     x5, x1
151 0:      subs    x5, x5, #1
152         b.lo    1f
153         ldrb    w0, [x4], #1
154         bl      puthexb
155         b       0b
157 1:      ldr     x30, [sp], #0x10
158         ret
159 endfunction
161 // Declare some storate space to shadow the SVE register contents:
162 .pushsection .text
163 .data
164 .align 4
165 vref:
166         .space  MAXVL_B * NVR
167 scratch:
168         .space  MAXVL_B
169 .popsection
171 // Trivial memory copy: copy x2 bytes, starting at address x1, to address x0.
172 // Clobbers x0-x3
173 function memcpy
174         cmp     x2, #0
175         b.eq    1f
176 0:      ldrb    w3, [x1], #1
177         strb    w3, [x0], #1
178         subs    x2, x2, #1
179         b.ne    0b
180 1:      ret
181 endfunction
183 // Generate a test pattern for storage in SVE registers
184 // x0: pid      (16 bits)
185 // x1: register number (6 bits)
186 // x2: generation (4 bits)
187 function pattern
188         orr     w1, w0, w1, lsl #16
189         orr     w2, w1, w2, lsl #28
191         ldr     x0, =scratch
192         mov     w1, #MAXVL_B / 4
194 0:      str     w2, [x0], #4
195         add     w2, w2, #(1 << 22)
196         subs    w1, w1, #1
197         bne     0b
199         ret
200 endfunction
202 // Get the address of shadow data for FPSIMD V-register V<xn>
203 .macro _adrv xd, xn, nrtmp
204         ldr     \xd, =vref
205         mov     x\nrtmp, #16
206         madd    \xd, x\nrtmp, \xn, \xd
207 .endm
209 // Set up test pattern in a FPSIMD V-register
210 // x0: pid
211 // x1: register number
212 // x2: generation
213 function setup_vreg
214         mov     x4, x30
216         mov     x6, x1
217         bl      pattern
218         _adrv   x0, x6, 2
219         mov     x5, x0
220         ldr     x1, =scratch
221         bl      memcpy
223         mov     x0, x6
224         mov     x1, x5
225         bl      setv
227         ret     x4
228 endfunction
230 // Fill x1 bytes starting at x0 with 0xae (for canary purposes)
231 // Clobbers x1, x2.
232 function memfill_ae
233         mov     w2, #0xae
234         b       memfill
235 endfunction
237 // Fill x1 bytes starting at x0 with 0.
238 // Clobbers x1, x2.
239 function memclr
240         mov     w2, #0
241 endfunction
242         // fall through to memfill
244 // Trivial memory fill: fill x1 bytes starting at address x0 with byte w2
245 // Clobbers x1
246 function memfill
247         cmp     x1, #0
248         b.eq    1f
250 0:      strb    w2, [x0], #1
251         subs    x1, x1, #1
252         b.ne    0b
254 1:      ret
255 endfunction
257 // Trivial memory compare: compare x2 bytes starting at address x0 with
258 // bytes starting at address x1.
259 // Returns only if all bytes match; otherwise, the program is aborted.
260 // Clobbers x0-x5.
261 function memcmp
262         cbz     x2, 1f
264         mov     x5, #0
265 0:      ldrb    w3, [x0, x5]
266         ldrb    w4, [x1, x5]
267         add     x5, x5, #1
268         cmp     w3, w4
269         b.ne    barf
270         subs    x2, x2, #1
271         b.ne    0b
273 1:      ret
274 endfunction
276 // Verify that a FPSIMD V-register matches its shadow in memory, else abort
277 // x0: reg number
278 // Clobbers x0-x5.
279 function check_vreg
280         mov     x3, x30
282         _adrv   x5, x0, 6
283         mov     x4, x0
284         ldr     x7, =scratch
286         mov     x0, x7
287         mov     x1, x6
288         bl      memfill_ae
290         mov     x0, x4
291         mov     x1, x7
292         bl      getv
294         mov     x0, x5
295         mov     x1, x7
296         mov     x2, x6
297         mov     x30, x3
298         b       memcmp
299 endfunction
301 // Any SVE register modified here can cause corruption in the main
302 // thread -- but *only* the registers modified here.
303 function irritator_handler
304         // Increment the irritation signal count (x23):
305         ldr     x0, [x2, #ucontext_regs + 8 * 23]
306         add     x0, x0, #1
307         str     x0, [x2, #ucontext_regs + 8 * 23]
309         // Corrupt some random V-regs
310         adr     x0, .text + (irritator_handler - .text) / 16 * 16
311         movi    v0.8b, #7
312         movi    v9.16b, #9
313         movi    v31.8b, #31
315         ret
316 endfunction
318 function terminate_handler
319         mov     w21, w0
320         mov     x20, x2
322         puts    "Terminated by signal "
323         mov     w0, w21
324         bl      putdec
325         puts    ", no error, iterations="
326         ldr     x0, [x20, #ucontext_regs + 8 * 22]
327         bl      putdec
328         puts    ", signals="
329         ldr     x0, [x20, #ucontext_regs + 8 * 23]
330         bl      putdecn
332         mov     x0, #0
333         mov     x8, #__NR_exit
334         svc     #0
335 endfunction
337 // w0: signal number
338 // x1: sa_action
339 // w2: sa_flags
340 // Clobbers x0-x6,x8
341 function setsignal
342         str     x30, [sp, #-((sa_sz + 15) / 16 * 16 + 16)]!
344         mov     w4, w0
345         mov     x5, x1
346         mov     w6, w2
348         add     x0, sp, #16
349         mov     x1, #sa_sz
350         bl      memclr
352         mov     w0, w4
353         add     x1, sp, #16
354         str     w6, [x1, #sa_flags]
355         str     x5, [x1, #sa_handler]
356         mov     x2, #0
357         mov     x3, #sa_mask_sz
358         mov     x8, #__NR_rt_sigaction
359         svc     #0
361         cbz     w0, 1f
363         puts    "sigaction failure\n"
364         b       .Labort
366 1:      ldr     x30, [sp], #((sa_sz + 15) / 16 * 16 + 16)
367         ret
368 endfunction
370 // Main program entry point
371 .globl _start
372 function _start
373 _start:
374         // Sanity-check and report the vector length
376         mov     x19, #128
377         cmp     x19, #128
378         b.lo    1f
379         cmp     x19, #2048
380         b.hi    1f
381         tst     x19, #(8 - 1)
382         b.eq    2f
384 1:      puts    "Bad vector length: "
385         mov     x0, x19
386         bl      putdecn
387         b       .Labort
389 2:      puts    "Vector length:\t"
390         mov     x0, x19
391         bl      putdec
392         puts    " bits\n"
394         // Obtain our PID, to ensure test pattern uniqueness between processes
396         mov     x8, #__NR_getpid
397         svc     #0
398         mov     x20, x0
400         puts    "PID:\t"
401         mov     x0, x20
402         bl      putdecn
404         mov     x23, #0         // Irritation signal count
406         mov     w0, #SIGINT
407         adr     x1, terminate_handler
408         mov     w2, #SA_SIGINFO
409         bl      setsignal
411         mov     w0, #SIGTERM
412         adr     x1, terminate_handler
413         mov     w2, #SA_SIGINFO
414         bl      setsignal
416         mov     w0, #SIGUSR1
417         adr     x1, irritator_handler
418         mov     w2, #SA_SIGINFO
419         orr     w2, w2, #SA_NODEFER
420         bl      setsignal
422         mov     x22, #0         // generation number, increments per iteration
423 .Ltest_loop:
425         mov     x21, #0         // Set up V-regs & shadow with test pattern
426 0:      mov     x0, x20
427         mov     x1, x21
428         and     x2, x22, #0xf
429         bl      setup_vreg
430         add     x21, x21, #1
431         cmp     x21, #NVR
432         b.lo    0b
434 // Can't do this when SVE state is volatile across SVC:
435         mov     x8, #__NR_sched_yield   // Encourage preemption
436         svc     #0
438         mov     x21, #0
439 0:      mov     x0, x21
440         bl      check_vreg
441         add     x21, x21, #1
442         cmp     x21, #NVR
443         b.lo    0b
445         add     x22, x22, #1
446         b       .Ltest_loop
448 .Labort:
449         mov     x0, #0
450         mov     x1, #SIGABRT
451         mov     x8, #__NR_kill
452         svc     #0
453 endfunction
455 function barf
456         mov     x10, x0 // expected data
457         mov     x11, x1 // actual data
458         mov     x12, x2 // data size
460         puts    "Mistatch: PID="
461         mov     x0, x20
462         bl      putdec
463         puts    ", iteration="
464         mov     x0, x22
465         bl      putdec
466         puts    ", reg="
467         mov     x0, x21
468         bl      putdecn
469         puts    "\tExpected ["
470         mov     x0, x10
471         mov     x1, x12
472         bl      dumphex
473         puts    "]\n\tGot      ["
474         mov     x0, x11
475         mov     x1, x12
476         bl      dumphex
477         puts    "]\n"
479         mov     x8, #__NR_exit
480         mov     x1, #1
481         svc     #0
482 endfunction