Attention is currently required from: Jérémy Compostella.
Patrick Rudolph has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/79753?usp=email )
Change subject: cpu/x86/64bit/mode_switch2: The reverse function to mode_switch ......................................................................
cpu/x86/64bit/mode_switch2: The reverse function to mode_switch
Add another mode_switch assembly function to call x86_64 code from x86_32 code. This is particullary useful for BLOBs like mrc.bin or FSP that calls back into coreboot.
Tested: - Called x86_64 code from x86_32 code in qemu. - Booted Lenovo X220 using x86_32 MRC using x86_64 console.
Change-Id: Ib625233e5f673eae9f3dcb2d03004c06bb07b149 Signed-off-by: Patrick Rudolph patrick.rudolph@9elements.com --- M src/arch/x86/include/mode_switch.h M src/cpu/x86/64bit/Makefile.inc A src/cpu/x86/64bit/mode_switch2.S 3 files changed, 114 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/53/79753/1
diff --git a/src/arch/x86/include/mode_switch.h b/src/arch/x86/include/mode_switch.h index 4235db9..c2cbbf5 100644 --- a/src/arch/x86/include/mode_switch.h +++ b/src/arch/x86/include/mode_switch.h @@ -3,6 +3,27 @@ #include <stdint.h>
#if ENV_X86_64 +static inline int long_mode_call(void *func) +{ + int (*doit)(void) = func; + + return doit(); +} + +static inline int long_mode_call_1arg(void *func, uint32_t arg1) +{ + int (*doit)(uint32_t arg1) = func; + + return doit(arg1); +} + +static inline int long_mode_call_2arg(void *func, uint32_t arg1, uint32_t arg2) +{ + int (*doit)(uint32_t arg1, uint32_t arg2) = func; + + return doit(arg1, arg2); +} + /* * Assembly code that drops into protected mode and calls the function * specified as first argument, which must have been compiled for x86_32. @@ -54,6 +75,55 @@ return protected_mode_call_3arg((uintptr_t)func, arg1, arg2, 0); } #else +/* + * Assembly function that elevates into long mode and calls the function + * specified as first argument, which must have been compiled for x86_64. + * After the function returns it enters protected mode again. + * The function pointer destination must be below 4GiB in physical memory. + * + * The called function has three arguments and returns an int. + */ +int long_mode_call_3arg(uint32_t func_ptr, + uint32_t opt_arg1, + uint32_t opt_arg2, + uint32_t opt_arg3); + +/* + * Elevates into long mode and calls the function, which must have been compiled for x86_64. + * After the function returns it enters protected mode again. + * The function pointer destination must be below 4GiB in physical memory. + * + * The called function doesn't have arguments and returns an int. + */ +static inline int long_mode_call(void *func) +{ + return long_mode_call_3arg((uintptr_t)func, 0, 0, 0); +} + +/* + * Elevates into long mode and calls the function, which must have been compiled for x86_64. + * After the function returns it enters protected mode again. + * The function pointer destination must be below 4GiB in physical memory. + * + * The called function has one argument and returns an int. + */ +static inline int long_mode_call_1arg(void *func, uint32_t arg1) +{ + return long_mode_call_3arg((uintptr_t)func, arg1, 0, 0); +} + +/* + * Elevates into long mode and calls the function, which must have been compiled for x86_64. + * After the function returns it enters protected mode again. + * The function pointer destination must be below 4GiB in physical memory. + * + * The called function has two arguments and returns an int. + */ +static inline int long_mode_call_2arg(void *func, uint32_t arg1, uint32_t arg2) +{ + return long_mode_call_3arg((uintptr_t)func, arg1, arg2, 0); +} + static inline int protected_mode_call(void *func) { int (*doit)(void) = func; diff --git a/src/cpu/x86/64bit/Makefile.inc b/src/cpu/x86/64bit/Makefile.inc index e1cf743..24a5a96 100644 --- a/src/cpu/x86/64bit/Makefile.inc +++ b/src/cpu/x86/64bit/Makefile.inc @@ -1,6 +1,7 @@ ## SPDX-License-Identifier: GPL-2.0-only
all_x86-y += mode_switch.S +all_x86-y += mode_switch2.S
# Add --defsym=_start=0 to suppress a linker warning. $(objcbfs)/pt: $(dir)/pt.S $(obj)/config.h diff --git a/src/cpu/x86/64bit/mode_switch2.S b/src/cpu/x86/64bit/mode_switch2.S new file mode 100644 index 0000000..0d39f50 --- /dev/null +++ b/src/cpu/x86/64bit/mode_switch2.S @@ -0,0 +1,43 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Calls a x86_64 function from x86_32 context */ + +.text +.code32 + .section ".text.long_mode_call_3arg", "ax", @progbits + .globl long_mode_call_3arg +long_mode_call_3arg: + + /* Backup registers */ + pushal + + /* Backup stack pointer */ + mov %esp, %ebp + + /* Enter long mode, preserves ebx */ + #include <cpu/x86/64bit/entry64.inc> + + /* Align stack */ + movabs $0xfffffffffffffff0, %rax + andq %rax, %rsp + + movl 36(%rbp), %ebx /* Function to call */ + movl 40(%rbp), %edi /* 1st arg */ + movl 44(%rbp), %esi /* 2nd arg */ + movl 48(%rbp), %edx /* 3rd arg */ + + call *%rbx + + /* Store return value on stack. popal will fetch it. */ + mov %eax, 28(%rbp) + shr $32, %rax + movl %eax, 24(%rbp) + + #include <cpu/x86/64bit/exit32.inc> + + /* Restore stack pointer */ + mov %ebp, %esp + + /* Restore registers */ + popal + + ret