1 /* SPDX-License-Identifier: GPL-2.0-only */
5 /* The stack frame looks like the following. */
18 static inline uintptr_t push_stack(uintptr_t cur_stack
, uintptr_t value
)
22 cur_stack
-= sizeof(value
);
23 addr
= (uintptr_t *)cur_stack
;
28 void arch_prepare_thread(struct thread
*t
,
29 void asmlinkage(*thread_entry
)(void *), void *arg
)
31 uintptr_t stack
= t
->stack_current
;
33 uintptr_t poison
= 0xdeadbeef;
35 /* Push the LR. thread_entry()
36 * is assumed to never return.
38 stack
= push_stack(stack
, (uintptr_t)thread_entry
);
39 /* Make room for the registers.
40 * Poison the initial stack. This is good hygiene and finds bugs.
41 * Poisoning the stack with different values helps when you're
42 * hunting for (e.g.) misaligned stacks or other such
43 * weirdness. The -1 is because we already pushed lr.
45 for (i
= 0; i
< sizeof(struct pushed_regs
) / sizeof(u32
) - 1; i
++)
46 stack
= push_stack(stack
, poison
++);
48 t
->stack_current
= stack
;
51 /* We could write this as a .S and the first time around that's how we
52 * did it. But there's always the question of matching our ARM
53 * directives in the .S with how gcc is doing things. It seems best
54 * to follow the pattern of the rest of the ARM port and just use
55 * inline assembly and let gcc get all the ELF magic right.
57 void __attribute__((naked
))
58 switch_to_thread(uintptr_t new_stack
, uintptr_t *saved_stack
)
60 /* Definitions for those of us not totally familiar with ARM:
61 * R15 -- PC, R14 -- LR, R13 -- SP
62 * R0-R3 need not be saved, nor R12.
63 * on entry, the only saved state is in LR -- the old PC.
64 * The args are in R0,R1.
66 * R1 is a pointer to the old stack save location
69 * then pop R0-R12 and LR
74 * | LR | <-- sp + 0x20
76 * | R11 | <-- sp + 0x1c
78 * | R10 | <-- sp + 0x18
80 * | R9 | <-- sp + 0x14
82 * | R8 | <-- sp + 0x10
84 * | R7 | <-- sp + 0x0c
86 * | R6 | <-- sp + 0x08
88 * | R5 | <-- sp + 0x04
90 * | R4 | <-- sp + 0x00
95 "push {r4-r11,lr}\n\t"
96 /* Save the current stack */
98 /* switch to the new stack */
100 /* restore the registers */
101 "pop {r4-r11,lr}\n\t"
102 /* resume other thread. */
107 void *arch_get_thread_stackbase(void)
109 return (void *)CONFIG_STACK_BOTTOM
;