mirror of
https://git.FreeBSD.org/src.git
synced 2025-01-20 15:43:16 +00:00
arm64: add tests for swp/swpb emulation
One test is suitable to be hooked up to the build, so I've done this here. The other test lives in tools/regression because failure is a bit more subjective -- generally, one runs it for some unbounded amount of time and observe if it eventually exits because two threads acquired the same mutex. Reviewed by: imp, mmel Sponsored by: Stormshield Sponsored by: Klara, Inc. Differential Revision: https://reviews.freebsd.org/D39668
This commit is contained in:
parent
4b500174dd
commit
ccb59683b9
@ -750,6 +750,8 @@
|
||||
..
|
||||
..
|
||||
..
|
||||
compat32
|
||||
..
|
||||
devrandom
|
||||
..
|
||||
dtrace
|
||||
|
@ -10,6 +10,7 @@ TESTS_SUBDIRS+= ${_audit}
|
||||
TESTS_SUBDIRS+= auditpipe
|
||||
TESTS_SUBDIRS+= capsicum
|
||||
TESTS_SUBDIRS+= ${_cddl}
|
||||
TESTS_SUBDIRS+= compat32
|
||||
TESTS_SUBDIRS+= devrandom
|
||||
TESTS_SUBDIRS+= fifo
|
||||
TESTS_SUBDIRS+= file
|
||||
|
6
tests/sys/compat32/Makefile
Normal file
6
tests/sys/compat32/Makefile
Normal file
@ -0,0 +1,6 @@
|
||||
|
||||
.if exists(${.CURDIR}/${MACHINE_ARCH})
|
||||
SUBDIR+= ${MACHINE_ARCH}
|
||||
.endif
|
||||
|
||||
.include <bsd.subdir.mk>
|
4
tests/sys/compat32/Makefile.inc
Normal file
4
tests/sys/compat32/Makefile.inc
Normal file
@ -0,0 +1,4 @@
|
||||
|
||||
TESTSDIR= ${TESTSBASE}/sys/compat32
|
||||
|
||||
.include "../Makefile.inc"
|
24
tests/sys/compat32/aarch64/Makefile
Normal file
24
tests/sys/compat32/aarch64/Makefile
Normal file
@ -0,0 +1,24 @@
|
||||
PACKAGE= tests
|
||||
FILESGROUPS+= asmprogs
|
||||
|
||||
ACFLAGS= -target armv7-unknown-freebsd${OS_REVISION} -nostdlib -Wl,-e -Wl,main -static
|
||||
|
||||
TAP_TESTS_SH+= swp_cond_test
|
||||
TAP_TESTS_SH+= swp_test
|
||||
${PACKAGE}FILES+= common.sh
|
||||
|
||||
# Each test will individually respect the compat.arm.emul_swp
|
||||
# sysctl upon entry.
|
||||
TEST_METADATA.swp_cond_test+= is_exclusive=true
|
||||
TEST_METADATA.swp_test+= is_exclusive=true
|
||||
|
||||
asmprogsMODE= 0755
|
||||
asmprogs+= swp_cond_test_impl swp_test_impl
|
||||
asmprogsDIR= ${TESTSDIR}
|
||||
|
||||
.for aprog in ${asmprogs}
|
||||
${aprog}: ${aprog}.S
|
||||
${CC} ${ACFLAGS} -o ${.TARGET} ${.ALLSRC}
|
||||
.endfor
|
||||
|
||||
.include <bsd.test.mk>
|
9
tests/sys/compat32/aarch64/common.sh
Normal file
9
tests/sys/compat32/aarch64/common.sh
Normal file
@ -0,0 +1,9 @@
|
||||
#!/bin/sh
|
||||
|
||||
if ! sysctl -n kern.features.compat_freebsd_32bit >/dev/null 2>&1; then
|
||||
echo "1..0 # Skipped: Kernel not built with COMPAT_FREEBSD32"
|
||||
exit 0
|
||||
elif ! sysctl -n kern.supported_archs | grep -q '\<armv7\>'; then
|
||||
echo "1..0 # Skipped: 32-bit ARM not supported on this hardware"
|
||||
exit 0
|
||||
fi
|
14
tests/sys/compat32/aarch64/swp_cond_test.sh
Normal file
14
tests/sys/compat32/aarch64/swp_cond_test.sh
Normal file
@ -0,0 +1,14 @@
|
||||
#!/bin/sh
|
||||
|
||||
scriptdir=$(dirname $(realpath "$0"))
|
||||
|
||||
. ${scriptdir}/common.sh
|
||||
|
||||
# Ensure emul_swp is enabled just for this test; we'll turn it back off if
|
||||
# it wasn't enabled before the test.
|
||||
emul_swpval=$(sysctl -n compat.arm.emul_swp)
|
||||
sysctl compat.arm.emul_swp=1 >/dev/null
|
||||
${scriptdir}/swp_test_impl
|
||||
if [ "$emul_swpval" -ne 1 ]; then
|
||||
sysctl compat.arm.emul_swp="$emul_swpval" >/dev/null
|
||||
fi
|
413
tests/sys/compat32/aarch64/swp_cond_test_impl.S
Normal file
413
tests/sys/compat32/aarch64/swp_cond_test_impl.S
Normal file
@ -0,0 +1,413 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2021 Warner Losh
|
||||
* Copyright (c) 2023 Stormshield
|
||||
* Copyright (c) 2023 Klara, Inc.
|
||||
*/
|
||||
|
||||
#include <sys/syscall.h>
|
||||
|
||||
#define STDOUT_FILENO 1
|
||||
#define SWP_MAGIC 0xffc0
|
||||
#define SWPB_MAGIC 0xc0c0
|
||||
|
||||
.text
|
||||
.file "swp_test.S"
|
||||
.syntax unified
|
||||
.globl main
|
||||
.p2align 2
|
||||
.type main,%function
|
||||
.code 32
|
||||
|
||||
main:
|
||||
sub sp, #0x04
|
||||
/* r4 is our failed test counter */
|
||||
mov r4, #0
|
||||
/* r6 is our current teset counter */
|
||||
mov r6, #1
|
||||
|
||||
movw r0, :lower16:.L.testheader
|
||||
movt r0, :upper16:.L.testheader
|
||||
ldr r1, =(.L.testheaderEnd - .L.testheader - 1)
|
||||
bl print
|
||||
|
||||
/* eq */
|
||||
bl reset
|
||||
mov r1, #SWP_MAGIC
|
||||
cmp r1, r1
|
||||
swpeq r0, r1, [r0]
|
||||
bl expect_success
|
||||
|
||||
/* Returned 0 (bad) or 1 (ok) */
|
||||
cmp r0, #0
|
||||
beq 1f
|
||||
|
||||
/* !eq */
|
||||
bl reset
|
||||
mov r1, #SWP_MAGIC
|
||||
mov r2, #0
|
||||
cmp r1, r2
|
||||
swpeq r0, r1, [r0]
|
||||
bl expect_fail
|
||||
|
||||
/* Don't care about the return of the second one, just print */
|
||||
1:
|
||||
movw r0, :lower16:.L.eq
|
||||
movt r0, :upper16:.L.eq
|
||||
ldr r1, =(.L.eqEnd - .L.eq - 1)
|
||||
bl print_result
|
||||
add r6, r6, #1 /* Next test */
|
||||
|
||||
/* cs */
|
||||
bl reset
|
||||
mov r1, #SWP_MAGIC
|
||||
movw r3, #0xffff
|
||||
movt r3, #0xffff
|
||||
/* Overflow */
|
||||
adds r2, r3, r3
|
||||
swpcs r0, r1, [r0]
|
||||
bl expect_success
|
||||
|
||||
/* Returned 0 (bad) or 1 (ok) */
|
||||
cmp r0, #0
|
||||
beq 2f
|
||||
|
||||
/* !cs */
|
||||
bl reset
|
||||
mov r1, #SWP_MAGIC
|
||||
mov r3, #0x00
|
||||
adds r2, r3, #0x08
|
||||
swpcs r0, r1, [r0]
|
||||
bl expect_fail
|
||||
|
||||
/* Don't care about the return of the second one, just print */
|
||||
2:
|
||||
movw r0, :lower16:.L.cs
|
||||
movt r0, :upper16:.L.cs
|
||||
ldr r1, =(.L.csEnd - .L.cs - 1)
|
||||
bl print_result
|
||||
add r6, r6, #1 /* Next test */
|
||||
|
||||
/* mi */
|
||||
bl reset
|
||||
mov r1, #SWP_MAGIC
|
||||
mov r2, #0
|
||||
/* Underflow */
|
||||
subs r2, r2, #0x05
|
||||
swpmi r0, r1, [r0]
|
||||
bl expect_success
|
||||
|
||||
/* Returned 0 (bad) or 1 (ok) */
|
||||
cmp r0, #0
|
||||
beq 3f
|
||||
|
||||
/* !mi */
|
||||
bl reset
|
||||
mov r1, #SWP_MAGIC
|
||||
mov r2, #0x10
|
||||
subs r2, r2, #0x08
|
||||
swpmi r0, r1, [r0]
|
||||
bl expect_fail
|
||||
|
||||
/* Don't care about the return of the second one, just print */
|
||||
3:
|
||||
movw r0, :lower16:.L.mi
|
||||
movt r0, :upper16:.L.mi
|
||||
ldr r1, =(.L.miEnd - .L.mi - 1)
|
||||
bl print_result
|
||||
add r6, r6, #1 /* Next test */
|
||||
|
||||
/* vs */
|
||||
bl reset
|
||||
mov r1, #SWP_MAGIC
|
||||
movw r3, #0xffff
|
||||
movt r3, #0x7fff
|
||||
/* Overflow */
|
||||
adds r2, r3, #0x10
|
||||
swpvs r0, r1, [r0]
|
||||
bl expect_success
|
||||
|
||||
/* Returned 0 (bad) or 1 (ok) */
|
||||
cmp r0, #0
|
||||
beq 4f
|
||||
|
||||
/* !vs */
|
||||
bl reset
|
||||
mov r1, #SWP_MAGIC
|
||||
mov r3, #0x00
|
||||
adds r2, r3, #0x08
|
||||
swpvs r0, r1, [r0]
|
||||
bl expect_fail
|
||||
|
||||
/* Don't care about the return of the second one, just print */
|
||||
4:
|
||||
movw r0, :lower16:.L.vs
|
||||
movt r0, :upper16:.L.vs
|
||||
ldr r1, =(.L.vsEnd - .L.vs - 1)
|
||||
bl print_result
|
||||
add r6, r6, #1 /* Next test */
|
||||
|
||||
/* hi */
|
||||
bl reset
|
||||
mov r1, #SWP_MAGIC
|
||||
mov r2, #0x00
|
||||
mov r3, #0x01
|
||||
cmp r3, r2
|
||||
swphi r0, r1, [r0]
|
||||
bl expect_success
|
||||
|
||||
/* Returned 0 (bad) or 1 (ok) */
|
||||
cmp r0, #0
|
||||
beq 5f
|
||||
|
||||
/* !hi */
|
||||
bl reset
|
||||
mov r1, #SWP_MAGIC
|
||||
mov r2, #0x00
|
||||
mov r3, #0x01
|
||||
cmp r2, r3
|
||||
swphi r0, r1, [r0]
|
||||
bl expect_fail
|
||||
|
||||
/* Don't care about the return of the second one, just print */
|
||||
5:
|
||||
movw r0, :lower16:.L.hi
|
||||
movt r0, :upper16:.L.hi
|
||||
ldr r1, =(.L.hiEnd - .L.hi - 1)
|
||||
bl print_result
|
||||
add r6, r6, #1 /* Next test */
|
||||
|
||||
/* ge */
|
||||
bl reset
|
||||
mov r1, #SWP_MAGIC
|
||||
mov r2, #0x01
|
||||
cmp r2, r2
|
||||
swpge r0, r1, [r0]
|
||||
bl expect_success
|
||||
|
||||
/* Returned 0 (bad) or 1 (ok) */
|
||||
cmp r0, #0
|
||||
beq 6f
|
||||
|
||||
/* !ge */
|
||||
bl reset
|
||||
mov r1, #SWP_MAGIC
|
||||
mov r2, #0x00
|
||||
mov r3, #0x01
|
||||
cmp r2, r3
|
||||
swpge r0, r1, [r0]
|
||||
bl expect_fail
|
||||
|
||||
/* Don't care about the return of the second one, just print */
|
||||
6:
|
||||
movw r0, :lower16:.L.ge
|
||||
movt r0, :upper16:.L.ge
|
||||
ldr r1, =(.L.geEnd - .L.ge - 1)
|
||||
bl print_result
|
||||
add r6, r6, #1 /* Next test */
|
||||
|
||||
/* gt */
|
||||
bl reset
|
||||
mov r1, #SWP_MAGIC
|
||||
mov r2, #0x00
|
||||
mov r3, #0x01
|
||||
cmp r3, r2
|
||||
swpgt r0, r1, [r0]
|
||||
bl expect_success
|
||||
|
||||
/* Returned 0 (bad) or 1 (ok) */
|
||||
cmp r0, #0
|
||||
beq 7f
|
||||
|
||||
/* !ge */
|
||||
bl reset
|
||||
mov r1, #SWP_MAGIC
|
||||
mov r2, #0x00
|
||||
mov r3, #0x01
|
||||
cmp r2, r3
|
||||
swpgt r0, r1, [r0]
|
||||
bl expect_fail
|
||||
|
||||
/* Don't care about the return of the second one, just print */
|
||||
7:
|
||||
movw r0, :lower16:.L.gt
|
||||
movt r0, :upper16:.L.gt
|
||||
ldr r1, =(.L.gtEnd - .L.gt - 1)
|
||||
bl print_result
|
||||
add r6, r6, #1 /* Next test */
|
||||
|
||||
mov r0, r4 /* retval */
|
||||
ldr r7, =SYS_exit
|
||||
swi 0
|
||||
|
||||
.p2align 2
|
||||
.type print_result,%function
|
||||
.code 32
|
||||
print_result:
|
||||
push {r4, r5, lr}
|
||||
/* Save the label, size for our result */
|
||||
mov r4, r0
|
||||
mov r5, r1
|
||||
|
||||
movw r0, :lower16:.L.ok
|
||||
movt r0, :upper16:.L.ok
|
||||
ldr r1, =(.L.okEnd - .L.ok - 1)
|
||||
bl print
|
||||
mov r0, r6
|
||||
add r0, #0x30 /* "0" + test number */
|
||||
mov r1, #0x01
|
||||
str r0, [sp]
|
||||
mov r0, sp
|
||||
bl print
|
||||
movw r0, :lower16:.L.swp
|
||||
movt r0, :upper16:.L.swp
|
||||
ldr r1, =(.L.swpEnd - .L.swp - 1)
|
||||
bl print
|
||||
mov r0, r4
|
||||
mov r1, r5
|
||||
bl print
|
||||
movw r0, :lower16:.L.term
|
||||
movt r0, :upper16:.L.term
|
||||
ldr r1, =(.L.termEnd - .L.term - 1)
|
||||
bl print
|
||||
|
||||
pop {r4, r5, lr}
|
||||
bx lr
|
||||
|
||||
.p2align 2
|
||||
.type reset,%function
|
||||
.code 32
|
||||
reset:
|
||||
/* Reset sp[0] and return the address used */
|
||||
mov r0, #0x03
|
||||
str r0, [sp]
|
||||
mov r0, sp
|
||||
bx lr
|
||||
|
||||
.p2align 2
|
||||
.type expect_fail,%function
|
||||
.code 32
|
||||
expect_fail:
|
||||
/* Just check the stack value */
|
||||
ldr r0, [sp]
|
||||
mov r1, #0x03
|
||||
cmp r0, r1
|
||||
bne 1f
|
||||
|
||||
/* Success (not swapped) */
|
||||
mov r0, #1
|
||||
bx lr
|
||||
|
||||
1:
|
||||
/* Fail (swapped) */
|
||||
/* Print the "not" part */
|
||||
movw r0, :lower16:.L.not
|
||||
movt r0, :upper16:.L.not
|
||||
ldr r1, =(.L.notEnd - .L.not - 1)
|
||||
push {lr}
|
||||
bl print
|
||||
pop {lr}
|
||||
|
||||
/* Failed */
|
||||
add r4, r4, #1
|
||||
mov r0, #0
|
||||
bx lr
|
||||
|
||||
.p2align 2
|
||||
.type expect_success,%function
|
||||
.code 32
|
||||
expect_success:
|
||||
/* Old value should be 3 */
|
||||
cmp r0, #0x03
|
||||
beq 1f
|
||||
b 3f
|
||||
|
||||
1:
|
||||
/* Check stack value */
|
||||
ldr r0, [sp]
|
||||
mov r1, #SWP_MAGIC
|
||||
cmp r0, r1
|
||||
beq 2f
|
||||
b 3f
|
||||
|
||||
2:
|
||||
mov r0, #1
|
||||
bx lr
|
||||
|
||||
3:
|
||||
/* Print the "not" part */
|
||||
movw r0, :lower16:.L.not
|
||||
movt r0, :upper16:.L.not
|
||||
ldr r1, =(.L.notEnd - .L.not - 1)
|
||||
push {lr}
|
||||
bl print
|
||||
pop {lr}
|
||||
|
||||
/* Failed */
|
||||
add r4, r4, #1
|
||||
mov r0, #0
|
||||
bx lr
|
||||
|
||||
.p2align 2
|
||||
.type print,%function
|
||||
.code 32
|
||||
print:
|
||||
/* r0 - string, r1 = size */
|
||||
mov r2, r1
|
||||
mov r1, r0
|
||||
ldr r0, =STDOUT_FILENO
|
||||
ldr r7, =SYS_write
|
||||
swi 0
|
||||
|
||||
bx lr
|
||||
|
||||
.L.testheader:
|
||||
.asciz "1..7\n"
|
||||
.L.testheaderEnd:
|
||||
.size .L.testheader, .L.testheaderEnd - .L.testheader
|
||||
|
||||
.L.not:
|
||||
.asciz "not "
|
||||
.L.notEnd:
|
||||
.size .L.not, .L.notEnd - .L.not
|
||||
.L.ok:
|
||||
.asciz "ok "
|
||||
.L.okEnd:
|
||||
.size .L.ok, .L.okEnd - .L.ok
|
||||
.L.swp:
|
||||
.asciz " - swp"
|
||||
.L.swpEnd:
|
||||
.size .L.swp, .L.swpEnd - .L.swp
|
||||
.L.eq:
|
||||
.asciz "eq"
|
||||
.L.eqEnd:
|
||||
.size .L.eq, .L.eqEnd - .L.eq
|
||||
.L.cs:
|
||||
.asciz "cs"
|
||||
.L.csEnd:
|
||||
.size .L.cs, .L.csEnd - .L.cs
|
||||
.L.mi:
|
||||
.asciz "mi"
|
||||
.L.miEnd:
|
||||
.size .L.mi, .L.miEnd - .L.mi
|
||||
.L.vs:
|
||||
.asciz "vs"
|
||||
.L.vsEnd:
|
||||
.size .L.vs, .L.vsEnd - .L.vs
|
||||
.L.hi:
|
||||
.asciz "hi"
|
||||
.L.hiEnd:
|
||||
.size .L.hi, .L.hiEnd - .L.hi
|
||||
.L.ge:
|
||||
.asciz "ge"
|
||||
.L.geEnd:
|
||||
.size .L.ge, .L.geEnd - .L.ge
|
||||
.L.gt:
|
||||
.asciz "gt"
|
||||
.L.gtEnd:
|
||||
.size .L.gt, .L.gtEnd - .L.gt
|
||||
.L.term:
|
||||
.asciz "\n"
|
||||
.L.termEnd:
|
||||
.size .L.term, .L.termEnd - .L.term
|
14
tests/sys/compat32/aarch64/swp_test.sh
Normal file
14
tests/sys/compat32/aarch64/swp_test.sh
Normal file
@ -0,0 +1,14 @@
|
||||
#!/bin/sh
|
||||
|
||||
scriptdir=$(dirname $(realpath "$0"))
|
||||
|
||||
. ${scriptdir}/common.sh
|
||||
|
||||
# Ensure emul_swp is enabled just for this test; we'll turn it back off if
|
||||
# it wasn't enabled before the test.
|
||||
emul_swpval=$(sysctl -n compat.arm.emul_swp)
|
||||
sysctl compat.arm.emul_swp=1 >/dev/null
|
||||
${scriptdir}/swp_test_impl
|
||||
if [ "$emul_swpval" -ne 1 ]; then
|
||||
sysctl compat.arm.emul_swp="$emul_swpval" >/dev/null
|
||||
fi
|
216
tests/sys/compat32/aarch64/swp_test_impl.S
Normal file
216
tests/sys/compat32/aarch64/swp_test_impl.S
Normal file
@ -0,0 +1,216 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2021 Warner Losh
|
||||
* Copyright (c) 2023 Stormshield
|
||||
* Copyright (c) 2023 Klara, Inc.
|
||||
*/
|
||||
|
||||
#include <sys/syscall.h>
|
||||
|
||||
#define STDOUT_FILENO 1
|
||||
#define SWP_MAGIC 0xffc0
|
||||
#define SWPB_MAGIC 0xc0c0
|
||||
|
||||
.text
|
||||
.file "swp_test.S"
|
||||
.syntax unified
|
||||
.globl main
|
||||
.p2align 2
|
||||
.type main,%function
|
||||
.code 32
|
||||
|
||||
main:
|
||||
sub sp, #0x04
|
||||
/* r4 is our failed test counter */
|
||||
mov r4, #0
|
||||
|
||||
movw r0, :lower16:.L.testheader
|
||||
movt r0, :upper16:.L.testheader
|
||||
ldr r1, =(.L.testheaderEnd - .L.testheader - 1)
|
||||
bl print
|
||||
|
||||
/* Target address */
|
||||
mov r0, #0x03
|
||||
str r0, [sp]
|
||||
mov r0, sp
|
||||
|
||||
/* Load value */
|
||||
mov r1, #SWP_MAGIC
|
||||
|
||||
/* swp it */
|
||||
swp r0, r1, [r0]
|
||||
|
||||
/* Old value should be 3 */
|
||||
cmp r0, #0x03
|
||||
bne 1f
|
||||
|
||||
/* Check stack value */
|
||||
ldr r0, [sp]
|
||||
mov r1, #SWP_MAGIC
|
||||
cmp r0, r1
|
||||
bne 1f
|
||||
b 2f
|
||||
|
||||
1:
|
||||
/* Denote the failed test */
|
||||
add r4, #1
|
||||
/* "No" part of the notification */
|
||||
movw r0, :lower16:.L.boknot
|
||||
movt r0, :upper16:.L.boknot
|
||||
ldr r1, =(.L.boknotEnd - .L.boknot - 1)
|
||||
bl print
|
||||
|
||||
2:
|
||||
/* Notify */
|
||||
movw r0, :lower16:.L.ok1
|
||||
movt r0, :upper16:.L.ok1
|
||||
ldr r1, =(.L.ok1End - .L.ok1 - 1)
|
||||
bl print
|
||||
|
||||
movw r5, #SWPB_MAGIC
|
||||
movt r5, #SWPB_MAGIC
|
||||
|
||||
/* Using r6 as our accumulator */
|
||||
mov r6, sp
|
||||
/* Simplify the loop */
|
||||
sub r6, #1
|
||||
3:
|
||||
/* Restore our magic value every time */
|
||||
str r5, [sp]
|
||||
/* Move on to the next byte */
|
||||
add r6, #1
|
||||
|
||||
/* swp it in */
|
||||
mov r0, r6
|
||||
mov r1, #3
|
||||
swpb r0, r1, [r0]
|
||||
|
||||
/* Check the old value */
|
||||
cmp r0, #0xc0
|
||||
bne 6f
|
||||
|
||||
/* Check the stack value */
|
||||
ldrb r0, [r6]
|
||||
cmp r0, #0x03
|
||||
bne 6f
|
||||
|
||||
/* Just loop over the rest of the word and check those values. */
|
||||
mov r1, r6
|
||||
sub r1, sp
|
||||
|
||||
mov r0, #0x00
|
||||
4:
|
||||
cmp r0, r1
|
||||
beq 5f
|
||||
|
||||
/* Check the next byte */
|
||||
ldrb r3, [sp, r0]
|
||||
cmp r3, #0xc0
|
||||
bne 6f
|
||||
|
||||
5:
|
||||
add r0, #0x01
|
||||
cmp r0, #0x04
|
||||
/* Hit the end, this one succeeded */
|
||||
beq 7f
|
||||
|
||||
/* Move on to the next byte */
|
||||
b 4b
|
||||
|
||||
6:
|
||||
/* Denote the failed test */
|
||||
add r4, #1
|
||||
/* "No" part of the notification */
|
||||
movw r0, :lower16:.L.boknot
|
||||
movt r0, :upper16:.L.boknot
|
||||
ldr r1, =(.L.boknotEnd - .L.boknot - 1)
|
||||
bl print
|
||||
|
||||
/* FALLTHROUGH */
|
||||
7:
|
||||
/* "ok" part */
|
||||
movw r0, :lower16:.L.bok
|
||||
movt r0, :upper16:.L.bok
|
||||
ldr r1, =(.L.bokEnd - .L.bok - 1)
|
||||
bl print
|
||||
|
||||
/* test number */
|
||||
mov r0, r6
|
||||
sub r0, sp
|
||||
add r0, #0x32 /* "0" + 2 because we start at test 2. */
|
||||
mov r1, #0x01
|
||||
str r0, [sp]
|
||||
mov r0, sp
|
||||
bl print
|
||||
|
||||
/* boklabel */
|
||||
movw r0, :lower16:.L.boklabel
|
||||
movt r0, :upper16:.L.boklabel
|
||||
ldr r1, =(.L.boklabelEnd - .L.boklabel - 1)
|
||||
bl print
|
||||
|
||||
/* index */
|
||||
mov r0, r6
|
||||
sub r0, sp
|
||||
add r0, #0x30 /* "0" */
|
||||
str r0, [sp]
|
||||
mov r0, sp
|
||||
mov r1, #0x01
|
||||
bl print
|
||||
|
||||
/* bokterm */
|
||||
movw r0, :lower16:.L.bokterm
|
||||
movt r0, :upper16:.L.bokterm
|
||||
ldr r1, =(.L.boktermEnd - .L.bokterm - 1)
|
||||
bl print
|
||||
|
||||
mov r0, sp
|
||||
add r0, #0x3
|
||||
cmp r0, r6
|
||||
bne 3b
|
||||
|
||||
mov r0, r4 /* retval */
|
||||
ldr r7, =SYS_exit
|
||||
swi 0
|
||||
|
||||
.p2align 2
|
||||
.type print,%function
|
||||
.code 32
|
||||
print:
|
||||
/* r0 - string, r1 = size */
|
||||
mov r2, r1
|
||||
mov r1, r0
|
||||
ldr r0, =STDOUT_FILENO
|
||||
ldr r7, =SYS_write
|
||||
swi 0
|
||||
|
||||
bx lr
|
||||
|
||||
.L.testheader:
|
||||
.asciz "1..5\n"
|
||||
.L.testheaderEnd:
|
||||
.size .L.testheader, .L.testheaderEnd - .L.testheader
|
||||
|
||||
/* Maybe not the most efficient, but meh. */
|
||||
.L.ok1:
|
||||
.asciz "ok 1 - swp\n"
|
||||
.L.ok1End:
|
||||
.size .L.ok1, .L.ok1End - .L.ok1
|
||||
|
||||
.L.boknot:
|
||||
.asciz "not "
|
||||
.L.boknotEnd:
|
||||
.size .L.boknot, .L.boknotEnd - .L.boknot
|
||||
.L.bok:
|
||||
.asciz "ok "
|
||||
.L.bokEnd:
|
||||
.size .L.bok, .L.bokEnd - .L.bok
|
||||
.L.boklabel:
|
||||
.asciz " - swpb["
|
||||
.L.boklabelEnd:
|
||||
.size .L.boklabel, .L.boklabelEnd - .L.boklabel
|
||||
.L.bokterm:
|
||||
.asciz "]\n"
|
||||
.L.boktermEnd:
|
||||
.size .L.bokterm, .L.boktermEnd - .L.bokterm
|
4
tools/regression/compat32/aarch64/Makefile
Normal file
4
tools/regression/compat32/aarch64/Makefile
Normal file
@ -0,0 +1,4 @@
|
||||
ACFLAGS= -target armv7-unknown-freebsd${OS_REVISION} -nostdlib -Wl,-e -Wl,main -static -mhwdiv=arm
|
||||
|
||||
swp_test_impl: swp_test_impl.S
|
||||
${CC} ${ACFLAGS} -o ${.TARGET} ${.ALLSRC}
|
410
tools/regression/compat32/aarch64/swp_test_impl.S
Normal file
410
tools/regression/compat32/aarch64/swp_test_impl.S
Normal file
@ -0,0 +1,410 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2021 Warner Losh
|
||||
* Copyright (c) 2023 Stormshield
|
||||
* Copyright (c) 2023 Klara, Inc.
|
||||
*/
|
||||
|
||||
#include <sys/syscall.h>
|
||||
|
||||
#define STDOUT_FILENO 1
|
||||
|
||||
#define MUTEX_LOCKED 0x01
|
||||
#define MUTEX_UNLOCKED 0x00
|
||||
|
||||
#define STACK_SIZE 4096
|
||||
#define TLS_SIZE 4096
|
||||
|
||||
.text
|
||||
.file "swp_test.S"
|
||||
.syntax unified
|
||||
.globl main
|
||||
.p2align 2
|
||||
.type main,%function
|
||||
.code 32
|
||||
|
||||
main:
|
||||
/*
|
||||
* Stack slots:
|
||||
* 0 - Sync word
|
||||
* 1 - Thread id
|
||||
* 2 - Shared word
|
||||
*/
|
||||
sub sp, sp, #12
|
||||
|
||||
/* Print a message */
|
||||
movw r0, :lower16:.L.mainmsg
|
||||
movt r0, :upper16:.L.mainmsg
|
||||
ldr r1, =(.L.mainmsgEnd - .L.mainmsg - 1)
|
||||
bl print
|
||||
|
||||
/* Create two secondary threads */
|
||||
mov r0, #1
|
||||
str r0, [sp, #4] /* Thread ID */
|
||||
movw r0, :lower16:secondary_thread
|
||||
movt r0, :upper16:secondary_thread
|
||||
mov r1, sp
|
||||
movw r2, :lower16:stack1
|
||||
movt r2, :upper16:stack1
|
||||
movw r3, :lower16:tls1
|
||||
movt r3, :upper16:tls1
|
||||
bl create_thr
|
||||
|
||||
1:
|
||||
/*
|
||||
* Wait for the first new thread to ack its existence by
|
||||
* incrementing the thread id.
|
||||
*/
|
||||
ldr r0, [sp, #4]
|
||||
cmp r0, #1
|
||||
bne 2f
|
||||
ldr r7, =SYS_sched_yield
|
||||
swi 0
|
||||
b 1b
|
||||
|
||||
2:
|
||||
/* Create thread #2 */
|
||||
movw r0, :lower16:secondary_thread
|
||||
movt r0, :upper16:secondary_thread
|
||||
mov r1, sp
|
||||
movw r2, :lower16:stack2
|
||||
movt r2, :upper16:stack2
|
||||
movw r3, :lower16:tls2
|
||||
movt r3, :upper16:tls2
|
||||
bl create_thr
|
||||
|
||||
3:
|
||||
/*
|
||||
* Wait for the first new thread to ack its existence by
|
||||
* incrementing the thread id.
|
||||
*/
|
||||
ldr r0, [sp, #4]
|
||||
cmp r0, #2
|
||||
bne 4f
|
||||
ldr r7, =SYS_sched_yield
|
||||
swi 0
|
||||
b 3b
|
||||
|
||||
/* Loop */
|
||||
4:
|
||||
mov r0, sp
|
||||
mov r1, #0 /* Thread loop */
|
||||
add r2, sp, #8
|
||||
bl thread_loop
|
||||
b 4b
|
||||
|
||||
/* UNREACHABLE */
|
||||
mov r0, #0
|
||||
ldr r7, =SYS_exit
|
||||
swi 0
|
||||
|
||||
.p2align 2
|
||||
.type secondary_thread,%function
|
||||
.code 32
|
||||
secondary_thread:
|
||||
/*
|
||||
* On entry, r0 is where we stashed our sync word and
|
||||
* ack word (thread ID).
|
||||
*
|
||||
* Stash the sync word in r4, thread ID in r5.
|
||||
*/
|
||||
mov r4, r0
|
||||
ldr r5, [r0, #4]
|
||||
|
||||
/* Print a message */
|
||||
movw r0, :lower16:.L.secondarymsg
|
||||
movt r0, :upper16:.L.secondarymsg
|
||||
ldr r1, =(.L.secondarymsgEnd - .L.secondarymsg - 1)
|
||||
bl print
|
||||
|
||||
/* Acknowledge that we started */
|
||||
add r0, r5, #1
|
||||
str r0, [r4, #4]
|
||||
|
||||
1:
|
||||
mov r0, r4
|
||||
mov r1, r5
|
||||
add r2, r4, #8
|
||||
bl thread_loop
|
||||
b 1b
|
||||
|
||||
.p2align 2
|
||||
.type thread_loop,%function
|
||||
.code 32
|
||||
thread_loop:
|
||||
push {r4, r5, r6, r7, r8, lr}
|
||||
|
||||
/*
|
||||
* r0 == sync word
|
||||
* r1 == thread ID
|
||||
* r2 == shared word
|
||||
*/
|
||||
mov r4, r0
|
||||
mov r5, r1
|
||||
mov r6, r2
|
||||
bl lock_mutex_swp
|
||||
str r5, [r6] /* Write the thread ID */
|
||||
bl random_cycles
|
||||
|
||||
# Save off the now cycle count */
|
||||
mov r8, r0
|
||||
|
||||
/* Print the thread ID and cycle count */
|
||||
mov r0, r5
|
||||
mov r1, #0
|
||||
bl printnum
|
||||
|
||||
/* Separator */
|
||||
movw r0, :lower16:.L.idsep
|
||||
movt r0, :upper16:.L.idsep
|
||||
ldr r1, =(.L.idsepEnd - .L.idsep - 1)
|
||||
bl print
|
||||
|
||||
/* Cycle count */
|
||||
mov r0, r8
|
||||
mov r1, #1
|
||||
bl printnum
|
||||
|
||||
1:
|
||||
ldr r0, [r6]
|
||||
cmp r0, r5 /* Check against the thread ID */
|
||||
bne 2f
|
||||
str r5, [r6]
|
||||
|
||||
/*
|
||||
* Check if the count hit 0, otherwise go again.
|
||||
*/
|
||||
cmp r8, #0
|
||||
beq 3f
|
||||
sub r8, r8, #1
|
||||
b 1b
|
||||
|
||||
2:
|
||||
/* exit(1) */
|
||||
mov r0, #1
|
||||
ldr r7, =SYS_exit
|
||||
swi 0
|
||||
|
||||
3:
|
||||
mov r0, r4
|
||||
bl unlock_mutex_swp
|
||||
|
||||
/*
|
||||
* Yield to lower the chance that we end up re-acquiring, the other two
|
||||
* threads are still actively trying to acquire the lock.
|
||||
*/
|
||||
ldr r7, =SYS_sched_yield
|
||||
swi 0
|
||||
|
||||
pop {r4, r5, r6, r7, r8, lr}
|
||||
bx lr
|
||||
|
||||
.p2align 2
|
||||
.type random_cycles,%function
|
||||
.code 32
|
||||
random_cycles:
|
||||
/* Return a random number < 4k */
|
||||
sub sp, sp, #4
|
||||
mov r0, sp
|
||||
mov r1, #4
|
||||
mov r2, #0
|
||||
ldr r7, =SYS_getrandom
|
||||
swi 0
|
||||
|
||||
/*
|
||||
* Just truncate the result of getrandom(2)
|
||||
* to put us within range. Naive, but functional.
|
||||
*/
|
||||
ldr r0, [sp]
|
||||
mov r1, #0xfff
|
||||
and r0, r0, r1
|
||||
add sp, sp, #4
|
||||
bx lr
|
||||
|
||||
/*
|
||||
* lock_mutex_swp and unlock_mutex_swp lifted from
|
||||
* ARM documentation on SWP/SWPB.
|
||||
*/
|
||||
.p2align 2
|
||||
.type lock_mutex_swp,%function
|
||||
.code 32
|
||||
lock_mutex_swp:
|
||||
mov r2, #MUTEX_LOCKED
|
||||
swp r1, r2, [r0] /* Swap in lock value. */
|
||||
cmp r1, r2 /* Check if we were locked already. */
|
||||
beq lock_mutex_swp /* Retry if so */
|
||||
bx lr /* Return locked */
|
||||
|
||||
.p2align 2
|
||||
.type unlock_mutex_swp,%function
|
||||
.code 32
|
||||
unlock_mutex_swp:
|
||||
mov r1, #MUTEX_UNLOCKED
|
||||
str r1, [r0] /* Move in unlocked */
|
||||
bx lr
|
||||
|
||||
.p2align 2
|
||||
.type create_thr,%function
|
||||
.code 32
|
||||
create_thr:
|
||||
/*
|
||||
* r0 == start_func
|
||||
* r1 == arg
|
||||
* r2 == stack_base
|
||||
* r3 == tls_base
|
||||
*/
|
||||
sub sp, sp, #56
|
||||
str r0, [sp, #4] /* start_func */
|
||||
str r1, [sp, #8] /* arg */
|
||||
str r2, [sp, #12] /* stack_base */
|
||||
mov r0, #STACK_SIZE
|
||||
str r0, [sp, #16] /* stack_size */
|
||||
str r3, [sp, #20] /* tls_base */
|
||||
mov r0, #TLS_SIZE
|
||||
str r0, [sp, #24] /* tls_size */
|
||||
mov r0, #0
|
||||
str r0, [sp, #28]
|
||||
str r0, [sp, #32]
|
||||
str r0, [sp, #36]
|
||||
str r0, [sp, #40]
|
||||
|
||||
add r0, sp, #4 /* &thrp */
|
||||
mov r1, #52 /* sizeof(thrp) */
|
||||
ldr r7, =SYS_thr_new
|
||||
swi 0
|
||||
|
||||
add sp, sp, #56
|
||||
bx lr
|
||||
|
||||
.p2align 2
|
||||
.type printnum,%function
|
||||
.code 32
|
||||
printnum:
|
||||
push {r4, r5, r6, r7, r8, r10, lr}
|
||||
sub sp, #4
|
||||
|
||||
/* 1000000000 */
|
||||
movw r6, #0xca00
|
||||
movt r6, #0x3b9a
|
||||
|
||||
udiv r5, r0, r6
|
||||
cmp r5, #9
|
||||
bhi abort
|
||||
|
||||
/* r4 is our accumulator */
|
||||
mov r4, r0
|
||||
/* r5 to be used as our "significant bit" */
|
||||
mov r5, #0
|
||||
/* r10 is "output_newline" */
|
||||
mov r10, r1
|
||||
|
||||
1:
|
||||
cmp r6, #0
|
||||
beq 4f
|
||||
|
||||
/* Divide by current place */
|
||||
udiv r0, r4, r6
|
||||
/* Significant already? print anyways */
|
||||
cmp r5, #0
|
||||
bne 2f
|
||||
|
||||
/*
|
||||
* Not significant, maybe print. If we made it all the way to 1, we
|
||||
* need to just print the 0 anyways.
|
||||
*/
|
||||
cmp r6, #1
|
||||
beq 2f
|
||||
|
||||
cmp r0, #0
|
||||
bne 2f
|
||||
b 3f /* Proceed */
|
||||
|
||||
/* Print */
|
||||
2:
|
||||
mov r5, #1
|
||||
mov r8, r0
|
||||
add r0, r0, #0x30
|
||||
str r0, [sp]
|
||||
mov r0, sp
|
||||
mov r1, #1
|
||||
bl print
|
||||
|
||||
/* Multiply back into place and subtract from accumulator */
|
||||
mul r0, r8, r6
|
||||
sub r4, r4, r0
|
||||
|
||||
3:
|
||||
mov r3, #10
|
||||
udiv r6, r6, r3
|
||||
b 1b
|
||||
|
||||
4:
|
||||
cmp r10, #0
|
||||
beq 5f
|
||||
|
||||
/* newline */
|
||||
mov r0, #0x0a
|
||||
str r0, [sp]
|
||||
mov r0, sp
|
||||
mov r1, #1
|
||||
bl print
|
||||
|
||||
5:
|
||||
add sp, sp, #4
|
||||
pop {r4, r5, r6, r7, r8, r10, lr}
|
||||
bx lr
|
||||
|
||||
abort:
|
||||
movw r0, :lower16:.L.badnum
|
||||
movt r0, :upper16:.L.badnum
|
||||
ldr r1, =(.L.badnumEnd - .L.badnum - 1)
|
||||
bl print
|
||||
|
||||
mov r0, #1
|
||||
ldr r7, =SYS_exit
|
||||
swi 0
|
||||
|
||||
.p2align 2
|
||||
.type print,%function
|
||||
.code 32
|
||||
print:
|
||||
/* r0 - string, r1 = size */
|
||||
mov r2, r1
|
||||
mov r1, r0
|
||||
ldr r0, =STDOUT_FILENO
|
||||
ldr r7, =SYS_write
|
||||
swi 0
|
||||
|
||||
bx lr
|
||||
|
||||
.L.mainmsg:
|
||||
.asciz "Main thread\n"
|
||||
.L.mainmsgEnd:
|
||||
.size .L.mainmsg, .L.mainmsgEnd - .L.mainmsg
|
||||
.L.secondarymsg:
|
||||
.asciz "Secondary thread\n"
|
||||
.L.secondarymsgEnd:
|
||||
.size .L.secondarymsg, .L.secondarymsgEnd - .L.secondarymsg
|
||||
.L.badnum:
|
||||
.asciz "Bad number\n"
|
||||
.L.badnumEnd:
|
||||
.size .L.badnum, .L.badnumEnd - .L.badnum
|
||||
.L.idsep:
|
||||
.asciz " - cycles "
|
||||
.L.idsepEnd:
|
||||
.size .L.idsep, .L.idsepEnd - .L.idsep
|
||||
|
||||
.type stack1,%object
|
||||
.local stack1
|
||||
.comm stack1,STACK_SIZE,1
|
||||
.type tls1,%object
|
||||
.local tls1
|
||||
.comm tls1,TLS_SIZE,1
|
||||
|
||||
.type stack2,%object
|
||||
.local stack2
|
||||
.comm stack2,STACK_SIZE,1
|
||||
.type tls2,%object
|
||||
.local tls2
|
||||
.comm tls2,TLS_SIZE,1
|
Loading…
Reference in New Issue
Block a user