Page MenuHomeFreeBSD

D39668.id121039.diff
No OneTemporary

D39668.id121039.diff

diff --git a/etc/mtree/BSD.tests.dist b/etc/mtree/BSD.tests.dist
--- a/etc/mtree/BSD.tests.dist
+++ b/etc/mtree/BSD.tests.dist
@@ -750,6 +750,8 @@
..
..
..
+ compat32
+ ..
devrandom
..
dtrace
diff --git a/tests/sys/Makefile b/tests/sys/Makefile
--- a/tests/sys/Makefile
+++ b/tests/sys/Makefile
@@ -10,6 +10,7 @@
TESTS_SUBDIRS+= auditpipe
TESTS_SUBDIRS+= capsicum
TESTS_SUBDIRS+= ${_cddl}
+TESTS_SUBDIRS+= compat32
TESTS_SUBDIRS+= devrandom
TESTS_SUBDIRS+= fifo
TESTS_SUBDIRS+= file
diff --git a/tests/sys/compat32/Makefile b/tests/sys/compat32/Makefile
new file mode 100644
--- /dev/null
+++ b/tests/sys/compat32/Makefile
@@ -0,0 +1,6 @@
+
+.if exists(${.CURDIR}/${MACHINE_ARCH})
+SUBDIR+= ${MACHINE_ARCH}
+.endif
+
+.include <bsd.subdir.mk>
diff --git a/tests/sys/compat32/Makefile.inc b/tests/sys/compat32/Makefile.inc
new file mode 100644
--- /dev/null
+++ b/tests/sys/compat32/Makefile.inc
@@ -0,0 +1,4 @@
+
+TESTSDIR= ${TESTSBASE}/sys/compat32
+
+.include "../Makefile.inc"
diff --git a/tests/sys/compat32/aarch64/Makefile b/tests/sys/compat32/aarch64/Makefile
new file mode 100644
--- /dev/null
+++ b/tests/sys/compat32/aarch64/Makefile
@@ -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>
diff --git a/tests/sys/compat32/aarch64/common.sh b/tests/sys/compat32/aarch64/common.sh
new file mode 100644
--- /dev/null
+++ b/tests/sys/compat32/aarch64/common.sh
@@ -0,0 +1,10 @@
+#!/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
+
diff --git a/tests/sys/compat32/aarch64/swp_cond_test.sh b/tests/sys/compat32/aarch64/swp_cond_test.sh
new file mode 100644
--- /dev/null
+++ b/tests/sys/compat32/aarch64/swp_cond_test.sh
@@ -0,0 +1,15 @@
+#!/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
+
diff --git a/tests/sys/compat32/aarch64/swp_cond_test_impl.S b/tests/sys/compat32/aarch64/swp_cond_test_impl.S
new file mode 100644
--- /dev/null
+++ b/tests/sys/compat32/aarch64/swp_cond_test_impl.S
@@ -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
diff --git a/tests/sys/compat32/aarch64/swp_test.sh b/tests/sys/compat32/aarch64/swp_test.sh
new file mode 100644
--- /dev/null
+++ b/tests/sys/compat32/aarch64/swp_test.sh
@@ -0,0 +1,15 @@
+#!/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
+
diff --git a/tests/sys/compat32/aarch64/swp_test_impl.S b/tests/sys/compat32/aarch64/swp_test_impl.S
new file mode 100644
--- /dev/null
+++ b/tests/sys/compat32/aarch64/swp_test_impl.S
@@ -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
diff --git a/tools/regression/compat32/aarch64/Makefile b/tools/regression/compat32/aarch64/Makefile
new file mode 100644
--- /dev/null
+++ b/tools/regression/compat32/aarch64/Makefile
@@ -0,0 +1,5 @@
+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}
+
diff --git a/tools/regression/compat32/aarch64/swp_test_impl.S b/tools/regression/compat32/aarch64/swp_test_impl.S
new file mode 100644
--- /dev/null
+++ b/tools/regression/compat32/aarch64/swp_test_impl.S
@@ -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

File Metadata

Mime Type
text/plain
Expires
Tue, Jul 7, 9:40 PM (14 h, 47 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
34814338
Default Alt Text
D39668.id121039.diff (22 KB)

Event Timeline