xref: /openbmc/linux/tools/testing/selftests/arm64/fp/fpsimd-test.S (revision 9a87ffc99ec8eb8d35eed7c4f816d75f5cc9662e)
15e992c63SMark Brown// SPDX-License-Identifier: GPL-2.0-only
25e992c63SMark Brown// Copyright (C) 2015-2019 ARM Limited.
35e992c63SMark Brown// Original author: Dave Martin <Dave.Martin@arm.com>
45e992c63SMark Brown//
55e992c63SMark Brown// Simple FPSIMD context switch test
65e992c63SMark Brown// Repeatedly writes unique test patterns into each FPSIMD register
75e992c63SMark Brown// and reads them back to verify integrity.
85e992c63SMark Brown//
95e992c63SMark Brown// for x in `seq 1 NR_CPUS`; do fpsimd-test & pids=$pids\ $! ; done
105e992c63SMark Brown// (leave it running for as long as you want...)
115e992c63SMark Brown// kill $pids
125e992c63SMark Brown
135e992c63SMark Brown#include <asm/unistd.h>
145e992c63SMark Brown#include "assembler.h"
155e992c63SMark Brown#include "asm-offsets.h"
165e992c63SMark Brown
175e992c63SMark Brown#define NVR	32
185e992c63SMark Brown#define MAXVL_B	(128 / 8)
195e992c63SMark Brown
205e992c63SMark Brown.macro _vldr Vn:req, Xt:req
215e992c63SMark Brown	ld1	{v\Vn\().2d}, [x\Xt]
225e992c63SMark Brown.endm
235e992c63SMark Brown
245e992c63SMark Brown.macro _vstr Vn:req, Xt:req
255e992c63SMark Brown	st1	{v\Vn\().2d}, [x\Xt]
265e992c63SMark Brown.endm
275e992c63SMark Brown
285e992c63SMark Brown// Generate accessor functions to read/write programmatically selected
295e992c63SMark Brown// FPSIMD registers.
305e992c63SMark Brown// x0 is the register index to access
315e992c63SMark Brown// x1 is the memory address to read from (getv,setp) or store to (setv,setp)
325e992c63SMark Brown// All clobber x0-x2
335e992c63SMark Browndefine_accessor setv, NVR, _vldr
345e992c63SMark Browndefine_accessor getv, NVR, _vstr
355e992c63SMark Brown
365e992c63SMark Brown// Declare some storate space to shadow the SVE register contents:
375e992c63SMark Brown.pushsection .text
385e992c63SMark Brown.data
395e992c63SMark Brown.align 4
405e992c63SMark Brownvref:
415e992c63SMark Brown	.space	MAXVL_B * NVR
425e992c63SMark Brownscratch:
435e992c63SMark Brown	.space	MAXVL_B
445e992c63SMark Brown.popsection
455e992c63SMark Brown
465e992c63SMark Brown// Generate a test pattern for storage in SVE registers
475e992c63SMark Brown// x0: pid	(16 bits)
485e992c63SMark Brown// x1: register number (6 bits)
495e992c63SMark Brown// x2: generation (4 bits)
505e992c63SMark Brownfunction pattern
515e992c63SMark Brown	orr	w1, w0, w1, lsl #16
525e992c63SMark Brown	orr	w2, w1, w2, lsl #28
535e992c63SMark Brown
545e992c63SMark Brown	ldr	x0, =scratch
555e992c63SMark Brown	mov	w1, #MAXVL_B / 4
565e992c63SMark Brown
575e992c63SMark Brown0:	str	w2, [x0], #4
585e992c63SMark Brown	add	w2, w2, #(1 << 22)
595e992c63SMark Brown	subs	w1, w1, #1
605e992c63SMark Brown	bne	0b
615e992c63SMark Brown
625e992c63SMark Brown	ret
635e992c63SMark Brownendfunction
645e992c63SMark Brown
655e992c63SMark Brown// Get the address of shadow data for FPSIMD V-register V<xn>
665e992c63SMark Brown.macro _adrv xd, xn, nrtmp
675e992c63SMark Brown	ldr	\xd, =vref
685e992c63SMark Brown	mov	x\nrtmp, #16
695e992c63SMark Brown	madd	\xd, x\nrtmp, \xn, \xd
705e992c63SMark Brown.endm
715e992c63SMark Brown
725e992c63SMark Brown// Set up test pattern in a FPSIMD V-register
735e992c63SMark Brown// x0: pid
745e992c63SMark Brown// x1: register number
755e992c63SMark Brown// x2: generation
765e992c63SMark Brownfunction setup_vreg
775e992c63SMark Brown	mov	x4, x30
785e992c63SMark Brown
795e992c63SMark Brown	mov	x6, x1
805e992c63SMark Brown	bl	pattern
815e992c63SMark Brown	_adrv	x0, x6, 2
825e992c63SMark Brown	mov	x5, x0
835e992c63SMark Brown	ldr	x1, =scratch
845e992c63SMark Brown	bl	memcpy
855e992c63SMark Brown
865e992c63SMark Brown	mov	x0, x6
875e992c63SMark Brown	mov	x1, x5
885e992c63SMark Brown	bl	setv
895e992c63SMark Brown
905e992c63SMark Brown	ret	x4
915e992c63SMark Brownendfunction
925e992c63SMark Brown
935e992c63SMark Brown// Trivial memory compare: compare x2 bytes starting at address x0 with
945e992c63SMark Brown// bytes starting at address x1.
955e992c63SMark Brown// Returns only if all bytes match; otherwise, the program is aborted.
965e992c63SMark Brown// Clobbers x0-x5.
975e992c63SMark Brownfunction memcmp
985e992c63SMark Brown	cbz	x2, 1f
995e992c63SMark Brown
1005e992c63SMark Brown	mov	x5, #0
1015e992c63SMark Brown0:	ldrb	w3, [x0, x5]
1025e992c63SMark Brown	ldrb	w4, [x1, x5]
1035e992c63SMark Brown	add	x5, x5, #1
1045e992c63SMark Brown	cmp	w3, w4
1055e992c63SMark Brown	b.ne	barf
1065e992c63SMark Brown	subs	x2, x2, #1
1075e992c63SMark Brown	b.ne	0b
1085e992c63SMark Brown
1095e992c63SMark Brown1:	ret
1105e992c63SMark Brownendfunction
1115e992c63SMark Brown
1125e992c63SMark Brown// Verify that a FPSIMD V-register matches its shadow in memory, else abort
1135e992c63SMark Brown// x0: reg number
1145e992c63SMark Brown// Clobbers x0-x5.
1155e992c63SMark Brownfunction check_vreg
1165e992c63SMark Brown	mov	x3, x30
1175e992c63SMark Brown
1185e992c63SMark Brown	_adrv	x5, x0, 6
1195e992c63SMark Brown	mov	x4, x0
1205e992c63SMark Brown	ldr	x7, =scratch
1215e992c63SMark Brown
1225e992c63SMark Brown	mov	x0, x7
1235e992c63SMark Brown	mov	x1, x6
1245e992c63SMark Brown	bl	memfill_ae
1255e992c63SMark Brown
1265e992c63SMark Brown	mov	x0, x4
1275e992c63SMark Brown	mov	x1, x7
1285e992c63SMark Brown	bl	getv
1295e992c63SMark Brown
1305e992c63SMark Brown	mov	x0, x5
1315e992c63SMark Brown	mov	x1, x7
1325e992c63SMark Brown	mov	x2, x6
1335e992c63SMark Brown	mov	x30, x3
1345e992c63SMark Brown	b	memcmp
1355e992c63SMark Brownendfunction
1365e992c63SMark Brown
1375e992c63SMark Brown// Any SVE register modified here can cause corruption in the main
1385e992c63SMark Brown// thread -- but *only* the registers modified here.
1395e992c63SMark Brownfunction irritator_handler
1405e992c63SMark Brown	// Increment the irritation signal count (x23):
1415e992c63SMark Brown	ldr	x0, [x2, #ucontext_regs + 8 * 23]
1425e992c63SMark Brown	add	x0, x0, #1
1435e992c63SMark Brown	str	x0, [x2, #ucontext_regs + 8 * 23]
1445e992c63SMark Brown
1455e992c63SMark Brown	// Corrupt some random V-regs
1465e992c63SMark Brown	adr	x0, .text + (irritator_handler - .text) / 16 * 16
1475e992c63SMark Brown	movi	v0.8b, #7
1485e992c63SMark Brown	movi	v9.16b, #9
1495e992c63SMark Brown	movi	v31.8b, #31
1505e992c63SMark Brown
1515e992c63SMark Brown	ret
1525e992c63SMark Brownendfunction
1535e992c63SMark Brown
15405a5980fSMark Brownfunction tickle_handler
15505a5980fSMark Brown	// Increment the signal count (x23):
15605a5980fSMark Brown	ldr	x0, [x2, #ucontext_regs + 8 * 23]
15705a5980fSMark Brown	add	x0, x0, #1
15805a5980fSMark Brown	str	x0, [x2, #ucontext_regs + 8 * 23]
15905a5980fSMark Brown
16005a5980fSMark Brown	ret
16105a5980fSMark Brownendfunction
16205a5980fSMark Brown
1635e992c63SMark Brownfunction terminate_handler
1645e992c63SMark Brown	mov	w21, w0
1655e992c63SMark Brown	mov	x20, x2
1665e992c63SMark Brown
1675e992c63SMark Brown	puts	"Terminated by signal "
1685e992c63SMark Brown	mov	w0, w21
1695e992c63SMark Brown	bl	putdec
1705e992c63SMark Brown	puts	", no error, iterations="
1715e992c63SMark Brown	ldr	x0, [x20, #ucontext_regs + 8 * 22]
1725e992c63SMark Brown	bl	putdec
1735e992c63SMark Brown	puts	", signals="
1745e992c63SMark Brown	ldr	x0, [x20, #ucontext_regs + 8 * 23]
1755e992c63SMark Brown	bl	putdecn
1765e992c63SMark Brown
1775e992c63SMark Brown	mov	x0, #0
1785e992c63SMark Brown	mov	x8, #__NR_exit
1795e992c63SMark Brown	svc	#0
1805e992c63SMark Brownendfunction
1815e992c63SMark Brown
1825e992c63SMark Brown// w0: signal number
1835e992c63SMark Brown// x1: sa_action
1845e992c63SMark Brown// w2: sa_flags
1855e992c63SMark Brown// Clobbers x0-x6,x8
1865e992c63SMark Brownfunction setsignal
1875e992c63SMark Brown	str	x30, [sp, #-((sa_sz + 15) / 16 * 16 + 16)]!
1885e992c63SMark Brown
1895e992c63SMark Brown	mov	w4, w0
1905e992c63SMark Brown	mov	x5, x1
1915e992c63SMark Brown	mov	w6, w2
1925e992c63SMark Brown
1935e992c63SMark Brown	add	x0, sp, #16
1945e992c63SMark Brown	mov	x1, #sa_sz
1955e992c63SMark Brown	bl	memclr
1965e992c63SMark Brown
1975e992c63SMark Brown	mov	w0, w4
1985e992c63SMark Brown	add	x1, sp, #16
1995e992c63SMark Brown	str	w6, [x1, #sa_flags]
2005e992c63SMark Brown	str	x5, [x1, #sa_handler]
2015e992c63SMark Brown	mov	x2, #0
2025e992c63SMark Brown	mov	x3, #sa_mask_sz
2035e992c63SMark Brown	mov	x8, #__NR_rt_sigaction
2045e992c63SMark Brown	svc	#0
2055e992c63SMark Brown
2065e992c63SMark Brown	cbz	w0, 1f
2075e992c63SMark Brown
2085e992c63SMark Brown	puts	"sigaction failure\n"
2095e992c63SMark Brown	b	.Labort
2105e992c63SMark Brown
2115e992c63SMark Brown1:	ldr	x30, [sp], #((sa_sz + 15) / 16 * 16 + 16)
2125e992c63SMark Brown	ret
2135e992c63SMark Brownendfunction
2145e992c63SMark Brown
2155e992c63SMark Brown// Main program entry point
2165e992c63SMark Brown.globl _start
2175e992c63SMark Brownfunction _start
218*d47d8a5eSMark Brown	mov	x23, #0		// signal count
219*d47d8a5eSMark Brown
220*d47d8a5eSMark Brown	mov	w0, #SIGINT
221*d47d8a5eSMark Brown	adr	x1, terminate_handler
222*d47d8a5eSMark Brown	mov	w2, #SA_SIGINFO
223*d47d8a5eSMark Brown	bl	setsignal
224*d47d8a5eSMark Brown
225*d47d8a5eSMark Brown	mov	w0, #SIGTERM
226*d47d8a5eSMark Brown	adr	x1, terminate_handler
227*d47d8a5eSMark Brown	mov	w2, #SA_SIGINFO
228*d47d8a5eSMark Brown	bl	setsignal
229*d47d8a5eSMark Brown
230*d47d8a5eSMark Brown	mov	w0, #SIGUSR1
231*d47d8a5eSMark Brown	adr	x1, irritator_handler
232*d47d8a5eSMark Brown	mov	w2, #SA_SIGINFO
233*d47d8a5eSMark Brown	orr	w2, w2, #SA_NODEFER
234*d47d8a5eSMark Brown	bl	setsignal
235*d47d8a5eSMark Brown
236*d47d8a5eSMark Brown	mov	w0, #SIGUSR2
237*d47d8a5eSMark Brown	adr	x1, tickle_handler
238*d47d8a5eSMark Brown	mov	w2, #SA_SIGINFO
239*d47d8a5eSMark Brown	orr	w2, w2, #SA_NODEFER
240*d47d8a5eSMark Brown	bl	setsignal
241*d47d8a5eSMark Brown
2425e992c63SMark Brown	// Sanity-check and report the vector length
2435e992c63SMark Brown
2445e992c63SMark Brown	mov	x19, #128
2455e992c63SMark Brown	cmp	x19, #128
2465e992c63SMark Brown	b.lo	1f
2475e992c63SMark Brown	cmp	x19, #2048
2485e992c63SMark Brown	b.hi	1f
2495e992c63SMark Brown	tst	x19, #(8 - 1)
2505e992c63SMark Brown	b.eq	2f
2515e992c63SMark Brown
2525e992c63SMark Brown1:	puts	"Bad vector length: "
2535e992c63SMark Brown	mov	x0, x19
2545e992c63SMark Brown	bl	putdecn
2555e992c63SMark Brown	b	.Labort
2565e992c63SMark Brown
2575e992c63SMark Brown2:	puts	"Vector length:\t"
2585e992c63SMark Brown	mov	x0, x19
2595e992c63SMark Brown	bl	putdec
2605e992c63SMark Brown	puts	" bits\n"
2615e992c63SMark Brown
2625e992c63SMark Brown	// Obtain our PID, to ensure test pattern uniqueness between processes
2635e992c63SMark Brown
2645e992c63SMark Brown	mov	x8, #__NR_getpid
2655e992c63SMark Brown	svc	#0
2665e992c63SMark Brown	mov	x20, x0
2675e992c63SMark Brown
2685e992c63SMark Brown	puts	"PID:\t"
2695e992c63SMark Brown	mov	x0, x20
2705e992c63SMark Brown	bl	putdecn
2715e992c63SMark Brown
2725e992c63SMark Brown	mov	x22, #0		// generation number, increments per iteration
2735e992c63SMark Brown.Ltest_loop:
2745e992c63SMark Brown
2755e992c63SMark Brown	mov	x21, #0		// Set up V-regs & shadow with test pattern
2765e992c63SMark Brown0:	mov	x0, x20
2775e992c63SMark Brown	mov	x1, x21
2785e992c63SMark Brown	and	x2, x22, #0xf
2795e992c63SMark Brown	bl	setup_vreg
2805e992c63SMark Brown	add	x21, x21, #1
2815e992c63SMark Brown	cmp	x21, #NVR
2825e992c63SMark Brown	b.lo	0b
2835e992c63SMark Brown
2845e992c63SMark Brown// Can't do this when SVE state is volatile across SVC:
2855e992c63SMark Brown	mov	x8, #__NR_sched_yield	// Encourage preemption
2865e992c63SMark Brown	svc	#0
2875e992c63SMark Brown
2885e992c63SMark Brown	mov	x21, #0
2895e992c63SMark Brown0:	mov	x0, x21
2905e992c63SMark Brown	bl	check_vreg
2915e992c63SMark Brown	add	x21, x21, #1
2925e992c63SMark Brown	cmp	x21, #NVR
2935e992c63SMark Brown	b.lo	0b
2945e992c63SMark Brown
2955e992c63SMark Brown	add	x22, x22, #1
2965e992c63SMark Brown	b	.Ltest_loop
2975e992c63SMark Brown
2985e992c63SMark Brown.Labort:
2995e992c63SMark Brown	mov	x0, #0
3005e992c63SMark Brown	mov	x1, #SIGABRT
3015e992c63SMark Brown	mov	x8, #__NR_kill
3025e992c63SMark Brown	svc	#0
3035e992c63SMark Brownendfunction
3045e992c63SMark Brown
3055e992c63SMark Brownfunction barf
3065e992c63SMark Brown	mov	x10, x0	// expected data
3075e992c63SMark Brown	mov	x11, x1	// actual data
3085e992c63SMark Brown	mov	x12, x2	// data size
3095e992c63SMark Brown
3103a57a643SMark Brown	puts	"Mismatch: PID="
3115e992c63SMark Brown	mov	x0, x20
3125e992c63SMark Brown	bl	putdec
3135e992c63SMark Brown	puts	", iteration="
3145e992c63SMark Brown	mov	x0, x22
3155e992c63SMark Brown	bl	putdec
3165e992c63SMark Brown	puts	", reg="
3175e992c63SMark Brown	mov	x0, x21
3185e992c63SMark Brown	bl	putdecn
3195e992c63SMark Brown	puts	"\tExpected ["
3205e992c63SMark Brown	mov	x0, x10
3215e992c63SMark Brown	mov	x1, x12
3225e992c63SMark Brown	bl	dumphex
3235e992c63SMark Brown	puts	"]\n\tGot      ["
3245e992c63SMark Brown	mov	x0, x11
3255e992c63SMark Brown	mov	x1, x12
3265e992c63SMark Brown	bl	dumphex
3275e992c63SMark Brown	puts	"]\n"
3285e992c63SMark Brown
3295e992c63SMark Brown	mov	x8, #__NR_exit
3305e992c63SMark Brown	mov	x1, #1
3315e992c63SMark Brown	svc	#0
3325e992c63SMark Brownendfunction
333