xref: /aosp_15_r20/external/coreboot/src/arch/x86/thread.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <thread.h>
4 
5 #if ENV_X86_64
6 #error COOP_MULTITASKING does not currently support x86_64
7 #endif
8 
9 /* The stack frame looks like the following after a pushad instruction. */
10 struct pushad_regs {
11 	uint32_t edi; /* Offset 0x00 */
12 	uint32_t esi; /* Offset 0x04 */
13 	uint32_t ebp; /* Offset 0x08 */
14 	uint32_t esp; /* Offset 0x0c */
15 	uint32_t ebx; /* Offset 0x10 */
16 	uint32_t edx; /* Offset 0x14 */
17 	uint32_t ecx; /* Offset 0x18 */
18 	uint32_t eax; /* Offset 0x1c */
19 };
20 
push_stack(uintptr_t cur_stack,uintptr_t value)21 static inline uintptr_t push_stack(uintptr_t cur_stack, uintptr_t value)
22 {
23 	uintptr_t *addr;
24 
25 	cur_stack -= sizeof(value);
26 	addr = (uintptr_t *)cur_stack;
27 	*addr = value;
28 	return cur_stack;
29 }
30 
arch_prepare_thread(struct thread * t,asmlinkage void (* thread_entry)(void *),void * arg)31 void arch_prepare_thread(struct thread *t,
32 			asmlinkage void (*thread_entry)(void *), void *arg)
33 {
34 	uintptr_t stack = t->stack_current;
35 
36 	/* Imitate thread_entry(t) with return address of 0. thread_entry()
37 	 * is assumed to never return. */
38 	stack = push_stack(stack, (uintptr_t)arg);
39 	stack = push_stack(stack, (uintptr_t)0);
40 	stack = push_stack(stack, (uintptr_t)thread_entry);
41 	/* Make room for the registers. Ignore initial values. */
42 	stack -= sizeof(struct pushad_regs);
43 
44 	t->stack_current = stack;
45 }
46