arch/x86: Add support for cooperative multitasking on x86_64

This commit extends the cooperative multitasking functionality to
support the x86_64 architecture. Previously, cooperative multitasking
was only available for x86_32, as indicated by the error directive in
thread.c.

A new thread_switch_64.S file has been added to implement 64-bit
register handling for thread switching, and thread_switch.S has been
renamed to thread_switch_32.S accordingly.

Change-Id: I14ed625160a62e42d800757d30397c6c85f943b4
Signed-off-by: Jeremy Compostella <jeremy.compostella@intel.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/88216
Reviewed-by: Shuo Liu <shuo.liu@intel.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
This commit is contained in:
Jeremy Compostella 2025-06-27 14:48:43 -07:00 committed by Matt DeVillier
commit 8b52167a9f
4 changed files with 115 additions and 7 deletions

View file

@ -159,7 +159,10 @@ romstage-y += postcar_loader.c
romstage-$(CONFIG_COLLECT_TIMESTAMPS_TSC) += timestamp.c
romstage-$(CONFIG_HAVE_CF9_RESET) += cf9_reset.c
romstage-$(CONFIG_COOP_MULTITASKING) += thread.c
romstage-$(CONFIG_COOP_MULTITASKING) += thread_switch.S
ifeq ($(CONFIG_COOP_MULTITASKING),y)
romstage-$(CONFIG_ARCH_ROMSTAGE_X86_32) += thread_switch_32.S
romstage-$(CONFIG_ARCH_ROMSTAGE_X86_64) += thread_switch_64.S
endif # CONFIG_COOP_MULTITASKING
romstage-y += car.ld
romstage-srcs += $(wildcard $(src)/mainboard/$(MAINBOARDDIR)/romstage.c)
@ -248,7 +251,10 @@ ramstage-y += rdrand.c
ramstage-$(CONFIG_GENERATE_SMBIOS_TABLES) += smbios.c
ramstage-y += tables.c
ramstage-$(CONFIG_COOP_MULTITASKING) += thread.c
ramstage-$(CONFIG_COOP_MULTITASKING) += thread_switch.S
ifeq ($(CONFIG_COOP_MULTITASKING),y)
ramstage-$(CONFIG_ARCH_RAMSTAGE_X86_32) += thread_switch_32.S
ramstage-$(CONFIG_ARCH_RAMSTAGE_X86_64) += thread_switch_64.S
endif # CONFIG_COOP_MULTITASKING
ramstage-$(CONFIG_COLLECT_TIMESTAMPS_TSC) += timestamp.c
ramstage-$(CONFIG_HAVE_ACPI_RESUME) += wakeup.S
ramstage-$(CONFIG_HAVE_CF9_RESET) += cf9_reset.c

View file

@ -3,11 +3,26 @@
#include <thread.h>
#if ENV_X86_64
#error COOP_MULTITASKING does not currently support x86_64
#endif
struct saved_regs {
uint64_t r15; /* Offset 0x00 */
uint64_t r14; /* Offset 0x08 */
uint64_t r13; /* Offset 0x10 */
uint64_t r12; /* Offset 0x18 */
uint64_t r11; /* Offset 0x20 */
uint64_t r10; /* Offset 0x28 */
uint64_t r9; /* Offset 0x30 */
uint64_t r8; /* Offset 0x38 */
uint64_t rdi; /* Offset 0x40 */
uint64_t rsi; /* Offset 0x48 */
uint64_t rbp; /* Offset 0x50 */
uint64_t rbx; /* Offset 0x58 */
uint64_t rdx; /* Offset 0x60 */
uint64_t rcx; /* Offset 0x68 */
uint64_t rax; /* Offset 0x70 */
};
#else
/* The stack frame looks like the following after a pushad instruction. */
struct pushad_regs {
struct saved_regs {
uint32_t edi; /* Offset 0x00 */
uint32_t esi; /* Offset 0x04 */
uint32_t ebp; /* Offset 0x08 */
@ -17,6 +32,7 @@ struct pushad_regs {
uint32_t ecx; /* Offset 0x18 */
uint32_t eax; /* Offset 0x1c */
};
#endif /* ENV_X86_64 */
static inline uintptr_t push_stack(uintptr_t cur_stack, uintptr_t value)
{
@ -39,7 +55,7 @@ void arch_prepare_thread(struct thread *t,
stack = push_stack(stack, (uintptr_t)0);
stack = push_stack(stack, (uintptr_t)thread_entry);
/* Make room for the registers. Ignore initial values. */
stack -= sizeof(struct pushad_regs);
stack -= sizeof(struct saved_regs);
t->stack_current = stack;
}

View file

@ -0,0 +1,86 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Stack layout after pushing all the registers.
* +------------+
* | ret addr | <-- esp + 0x78
* +------------+
* | rax | <-- esp + 0x70
* +------------+
* | rcx | <-- esp + 0x68
* +------------+
* | rdx | <-- esp + 0x60
* +------------+
* | rbx | <-- esp + 0x58
* +------------+
* | rbp | <-- esp + 0x50
* +------------+
* | rsi | <-- esp + 0x48
* +------------+
* | rdi | <-- esp + 0x40
* +------------+
* | r8 | <-- esp + 0x38
* +------------+
* | r9 | <-- esp + 0x30
* +------------+
* | r10 | <-- esp + 0x28
* +------------+
* | r11 | <-- esp + 0x20
* +------------+
* | r12 | <-- esp + 0x18
* +------------+
* | r13 | <-- esp + 0x10
* +------------+
* | r14 | <-- esp + 0x08
* +------------+
* | r15 | <-- esp + 0x00
* +------------+
*/
.global switch_to_thread
switch_to_thread:
/* Backup registers. */
push %rax
push %rcx
push %rdx
push %rbx
push %rbp
push %rsi
push %rdi
push %r8
push %r9
push %r10
push %r11
push %r12
push %r13
push %r14
push %r15
/* Save the current stack */
mov %rsp, (%rsi)
/* Switch to the new stack. */
mov %rdi, %rsp
/* Restore registers. */
pop %r15
pop %r14
pop %r13
pop %r12
pop %r11
pop %r10
pop %r9
pop %r8
pop %rdi
pop %rsi
pop %rbp
pop %rbx
pop %rdx
pop %rcx
pop %rax
/* Done. */
ret