git: ccb59683b983 - main - arm64: add tests for swp/swpb emulation
Date: Mon, 15 May 2023 15:42:24 UTC
The branch main has been updated by kevans: URL: https://cgit.FreeBSD.org/src/commit/?id=ccb59683b98360afaf5b5bb641a68fea22c68d0b commit ccb59683b98360afaf5b5bb641a68fea22c68d0b Author: Kyle Evans <kevans@FreeBSD.org> AuthorDate: 2023-05-15 15:42:16 +0000 Commit: Kyle Evans <kevans@FreeBSD.org> CommitDate: 2023-05-15 15:42:16 +0000 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 --- etc/mtree/BSD.tests.dist | 2 + tests/sys/Makefile | 1 + tests/sys/compat32/Makefile | 6 + tests/sys/compat32/Makefile.inc | 4 + tests/sys/compat32/aarch64/Makefile | 24 ++ tests/sys/compat32/aarch64/common.sh | 9 + tests/sys/compat32/aarch64/swp_cond_test.sh | 14 + tests/sys/compat32/aarch64/swp_cond_test_impl.S | 413 ++++++++++++++++++++++ tests/sys/compat32/aarch64/swp_test.sh | 14 + tests/sys/compat32/aarch64/swp_test_impl.S | 216 +++++++++++ tools/regression/compat32/aarch64/Makefile | 4 + tools/regression/compat32/aarch64/swp_test_impl.S | 410 +++++++++++++++++++++ 12 files changed, 1117 insertions(+) diff --git a/etc/mtree/BSD.tests.dist b/etc/mtree/BSD.tests.dist index 5d99653100df..77c07960f938 100644 --- 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 index 8f83445f9d91..3e9a30105a1d 100644 --- a/tests/sys/Makefile +++ b/tests/sys/Makefile @@ -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 diff --git a/tests/sys/compat32/Makefile b/tests/sys/compat32/Makefile new file mode 100644 index 000000000000..31834de16246 --- /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 index 000000000000..0220ac0431e9 --- /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 index 000000000000..716182b15d9c --- /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 index 000000000000..f8b02e8ac157 --- /dev/null +++ b/tests/sys/compat32/aarch64/common.sh @@ -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 diff --git a/tests/sys/compat32/aarch64/swp_cond_test.sh b/tests/sys/compat32/aarch64/swp_cond_test.sh new file mode 100644 index 000000000000..8edfa43b3e7e --- /dev/null +++ b/tests/sys/compat32/aarch64/swp_cond_test.sh @@ -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 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 index 000000000000..d29db44832b1 --- /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 index 000000000000..8edfa43b3e7e --- /dev/null +++ b/tests/sys/compat32/aarch64/swp_test.sh @@ -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 diff --git a/tests/sys/compat32/aarch64/swp_test_impl.S b/tests/sys/compat32/aarch64/swp_test_impl.S new file mode 100644 index 000000000000..0e8047f1a6cf --- /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 index 000000000000..34428a58caa1 --- /dev/null +++ b/tools/regression/compat32/aarch64/Makefile @@ -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} diff --git a/tools/regression/compat32/aarch64/swp_test_impl.S b/tools/regression/compat32/aarch64/swp_test_impl.S new file mode 100644 index 000000000000..9f28ab17748e --- /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) *** 249 LINES SKIPPED ***