mirror of
https://git.hardenedbsd.org/hardenedbsd/HardenedBSD.git
synced 2024-11-22 21:01:05 +01:00
ccb59683b9
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
411 lines
6.6 KiB
ArmAsm
411 lines
6.6 KiB
ArmAsm
/*
|
|
* 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
|