From 8b52167a9f7d31a009b123e152c5c62dcf0a5202 Mon Sep 17 00:00:00 2001 From: Jeremy Compostella Date: Fri, 27 Jun 2025 14:48:43 -0700 Subject: [PATCH] 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 Reviewed-on: https://review.coreboot.org/c/coreboot/+/88216 Reviewed-by: Shuo Liu Tested-by: build bot (Jenkins) --- src/arch/x86/Makefile.mk | 10 ++- src/arch/x86/thread.c | 26 ++++-- .../{thread_switch.S => thread_switch_32.S} | 0 src/arch/x86/thread_switch_64.S | 86 +++++++++++++++++++ 4 files changed, 115 insertions(+), 7 deletions(-) rename src/arch/x86/{thread_switch.S => thread_switch_32.S} (100%) create mode 100644 src/arch/x86/thread_switch_64.S diff --git a/src/arch/x86/Makefile.mk b/src/arch/x86/Makefile.mk index a455a09100..0aaa962cfa 100644 --- a/src/arch/x86/Makefile.mk +++ b/src/arch/x86/Makefile.mk @@ -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 diff --git a/src/arch/x86/thread.c b/src/arch/x86/thread.c index fa6096161b..bdc02fbfa2 100644 --- a/src/arch/x86/thread.c +++ b/src/arch/x86/thread.c @@ -3,11 +3,26 @@ #include #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; } diff --git a/src/arch/x86/thread_switch.S b/src/arch/x86/thread_switch_32.S similarity index 100% rename from src/arch/x86/thread_switch.S rename to src/arch/x86/thread_switch_32.S diff --git a/src/arch/x86/thread_switch_64.S b/src/arch/x86/thread_switch_64.S new file mode 100644 index 0000000000..b4397f10dc --- /dev/null +++ b/src/arch/x86/thread_switch_64.S @@ -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