blob: 0accc5aa37d4d70558cb52b1ad232e5f6a1afd1b [file] [log] [blame] [edit]
/*
* Copyright 2019, Data61, CSIRO (ABN 41 687 119 230)
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <autoconf.h>
/* test_registers (below) runs in a context without a valid SP. At the end it
* needs to call into a C function and needs a valid stack to do this. We
* provide it a stack it can switch to here.
*/
.section .bss
.align 4
.space 4096
_safe_stack:
.section .text
#if defined(CONFIG_ARCH_AARCH32)
/* Trampoline for providing the thread a valid stack before entering
* reply_to_parent. No blx required because reply_to_parent does not
* return.
*/
reply_trampoline:
ldr sp, =_safe_stack
b reply_to_parent
.global test_registers
test_registers:
/* Assume the PC and CPSR are correct because there's no good way of
* testing them. Test each of the registers against the magic numbers our
* parent set.
*/
cmp sp, #13
bne test_registers_fail
cmp r0, #15
bne test_registers_fail
cmp r1, #1
bne test_registers_fail
cmp r2, #2
bne test_registers_fail
cmp r3, #3
bne test_registers_fail
cmp r4, #4
bne test_registers_fail
cmp r5, #5
bne test_registers_fail
cmp r6, #6
bne test_registers_fail
cmp r7, #7
bne test_registers_fail
cmp r8, #8
bne test_registers_fail
cmp r9, #9
bne test_registers_fail
cmp r10, #10
bne test_registers_fail
cmp r11, #11
bne test_registers_fail
cmp r12, #12
bne test_registers_fail
cmp r14, #14
bne test_registers_fail
/* Return success. Note that we don't bother saving registers or bl because
* we're not planning to return here and we don't have a valid stack.
*/
mov r0, #0
b reply_trampoline
/* Return failure. */
test_registers_fail:
mov r0, #1
b reply_trampoline
#elif defined(CONFIG_ARCH_AARCH64)
/* Trampoline for providing the thread a valid stack before entering
* reply_to_parent. No blx required because reply_to_parent does not
* return.
*/
reply_trampoline:
ldr x1, =_safe_stack
mov sp, x1
b reply_to_parent
.global test_registers
test_registers:
cmp sp, #1
bne test_registers_fail
cmp x0, #2
bne test_registers_fail
cmp x1, #3
bne test_registers_fail
cmp x2, #4
bne test_registers_fail
cmp x3, #5
bne test_registers_fail
cmp x4, #6
bne test_registers_fail
cmp x5, #7
bne test_registers_fail
cmp x6, #8
bne test_registers_fail
cmp x7, #9
bne test_registers_fail
cmp x8, #10
bne test_registers_fail
cmp x9, #11
bne test_registers_fail
cmp x10, #12
bne test_registers_fail
cmp x11, #13
bne test_registers_fail
cmp x12, #14
bne test_registers_fail
cmp x13, #15
bne test_registers_fail
cmp x14, #16
bne test_registers_fail
cmp x15, #17
bne test_registers_fail
cmp x16, #18
bne test_registers_fail
cmp x17, #19
bne test_registers_fail
cmp x18, #20
bne test_registers_fail
cmp x19, #21
bne test_registers_fail
cmp x20, #22
bne test_registers_fail
cmp x21, #23
bne test_registers_fail
cmp x22, #24
bne test_registers_fail
cmp x23, #25
bne test_registers_fail
cmp x24, #26
bne test_registers_fail
cmp x25, #27
bne test_registers_fail
cmp x26, #28
bne test_registers_fail
cmp x27, #29
bne test_registers_fail
cmp x28, #30
bne test_registers_fail
cmp x29, #31
bne test_registers_fail
cmp x30, #32
bne test_registers_fail
/* Return success. Note that we don't bother saving registers or bl because
* we're not planning to return here and we don't have a valid stack.
*/
mov x0, #0
b reply_trampoline
/* Return failure. */
test_registers_fail:
mov x0, #1
b reply_trampoline
#elif defined(CONFIG_ARCH_X86_64)
reply_trampoline:
leaq _safe_stack, %rsp
movq %rax, %rdi
call reply_to_parent
.global test_registers
test_registers:
jb rflags_ok
jmp test_registers_fail
rflags_ok:
cmpq $0x0000000a, %rax
jne test_registers_fail
movq $2, %rax
cmpq $0x0000000b, %rbx
jne test_registers_fail
movq $3, %rax
cmpq $0x0000000c, %rcx
jne test_registers_fail
movq $4, %rax
cmpq $0x0000000d, %rdx
jne test_registers_fail
movq $5, %rax
cmpq $0x00000005, %rsi
jne test_registers_fail
movq $6, %rax
cmpq $0x00000002, %rdi
jne test_registers_fail
movq $7, %rax
cmpq $0x00000003, %rbp
jne test_registers_fail
movq $8, %rax
cmpq $0x00000004, %rsp
jne test_registers_fail
movq $9, %rax
cmpq $0x00000088, %r8
jne test_registers_fail
movq $100, %rax
cmpq $0x00000099, %r9
jne test_registers_fail
movq $11, %rax
cmpq $0x00000010, %r10
jne test_registers_fail
movq $12, %rax
cmpq $0x00000011, %r11
jne test_registers_fail
movq $13, %rax
cmpq $0x00000012, %r12
jne test_registers_fail
movq $14, %rax
cmpq $0x00000013, %r13
jne test_registers_fail
movq $15, %rax
cmpq $0x00000014, %r14
jne test_registers_fail
movq $16, %rax
cmpq $0x00000015, %r15
jne test_registers_fail
movq $0, %rax
jmp reply_trampoline
test_registers_fail:
movq $1, %rax
jmp reply_trampoline
#elif defined(CONFIG_ARCH_X86)
/* As for the ARM implementation above, but we also need to massage the
* calling convention by taking the value test_registers passed us in EAX
* and put it on the stack where reply_to_parent expects it.
*/
reply_trampoline:
leal _safe_stack, %esp
pushl %eax
call reply_to_parent
.global test_registers
test_registers:
/* Assume EIP, GS and FS are correct. Is there a good way to
* test these?
* EIP - If this is incorrect we'll never arrive at this function.
* GS - With an incorrect GDT selector we fault and die immediately.
* FS - Overwritten by the kernel before we jump here.
*/
/* We need to test EFLAGS indirectly because we can't cmp it. The jb
* should only be taken if CF (bit 0) is set.
*/
jb eflags_ok
jmp test_registers_fail
eflags_ok:
cmpl $0x0000000a, %eax
jne test_registers_fail
cmpl $0x0000000b, %ebx
jne test_registers_fail
cmpl $0x0000000c, %ecx
jne test_registers_fail
cmpl $0x0000000d, %edx
jne test_registers_fail
cmpl $0x00000005, %esi
jne test_registers_fail
cmpl $0x00000002, %edi
jne test_registers_fail
cmpl $0x00000003, %ebp
jne test_registers_fail
cmpl $0x00000004, %esp
jne test_registers_fail
/* Return success. Note we use a custom calling convention because we
* don't have a valid stack.
*/
movl $0, %eax
jmp reply_trampoline
/* Return failure. */
test_registers_fail:
movl $1, %eax
jmp reply_trampoline
#elif defined(CONFIG_ARCH_RISCV)
/* Trampoline for providing the thread a valid stack before entering
* reply_to_parent. No jal required because reply_to_parent does not
* return.
*/
reply_trampoline:
la a1, _safe_stack
mv sp, a1
j reply_to_parent
.global test_registers
test_registers:
li a0, 1
bne ra, a0, test_registers_fail
li a0, 2
bne sp, a0, test_registers_fail
li a0, 4
bne t0, a0, test_registers_fail
li a0, 5
bne t1, a0, test_registers_fail
li a0, 6
bne t2, a0, test_registers_fail
li a0, 7
bne s0, a0, test_registers_fail
li a0, 8
bne s1, a0, test_registers_fail
li a0, 10
bne a1, a0, test_registers_fail
li a0, 11
bne a2, a0, test_registers_fail
li a0, 12
bne a0, a3, test_registers_fail
li a0, 13
bne a0, a4, test_registers_fail
li a0, 14
bne a0, a5, test_registers_fail
li a0, 15
bne a0, a6, test_registers_fail
#if 0
/* skip x3, see below */
context.x4 = 3;
#endif
/* Return success. Note that we don't bother saving registers or bl because
* we're not planning to return here and we don't have a valid stack.
*/
mv a0, x0
j reply_trampoline
/* Return failure. */
test_registers_fail:
li a0, 1
j reply_trampoline
#else
#error Unsupported architecture
#endif