summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/arch/x86/include/mode_switch.h20
-rw-r--r--src/cpu/x86/64bit/mode_switch.S72
2 files changed, 44 insertions, 48 deletions
diff --git a/src/arch/x86/include/mode_switch.h b/src/arch/x86/include/mode_switch.h
index 24efb1ef58..4235db9be3 100644
--- a/src/arch/x86/include/mode_switch.h
+++ b/src/arch/x86/include/mode_switch.h
@@ -3,10 +3,18 @@
#include <stdint.h>
#if ENV_X86_64
-int protected_mode_call_narg(uint32_t arg_count,
- uint32_t func_ptr,
+/*
+ * Assembly code that drops into protected mode and calls the function
+ * specified as first argument, which must have been compiled for x86_32.
+ * After the function returns it enters long mode again.
+ * The function pointer destination must be below 4GiB in physical memory.
+ *
+ * The called function has 0-3 arguments and returns an int.
+ */
+int protected_mode_call_3arg(uint32_t func_ptr,
uint32_t opt_arg1,
- uint32_t opt_arg2);
+ uint32_t opt_arg2,
+ uint32_t opt_arg3);
/*
* Drops into protected mode and calls the function, which must have been compiled for x86_32.
@@ -17,7 +25,7 @@ int protected_mode_call_narg(uint32_t arg_count,
*/
static inline int protected_mode_call(void *func)
{
- return protected_mode_call_narg(0, (uintptr_t)func, 0, 0);
+ return protected_mode_call_3arg((uintptr_t)func, 0, 0, 0);
}
/*
@@ -30,7 +38,7 @@ static inline int protected_mode_call(void *func)
*/
static inline int protected_mode_call_1arg(void *func, uint32_t arg1)
{
- return protected_mode_call_narg(1, (uintptr_t)func, arg1, 0);
+ return protected_mode_call_3arg((uintptr_t)func, arg1, 0, 0);
}
/*
@@ -43,7 +51,7 @@ static inline int protected_mode_call_1arg(void *func, uint32_t arg1)
*/
static inline int protected_mode_call_2arg(void *func, uint32_t arg1, uint32_t arg2)
{
- return protected_mode_call_narg(2, (uintptr_t)func, arg1, arg2);
+ return protected_mode_call_3arg((uintptr_t)func, arg1, arg2, 0);
}
#else
static inline int protected_mode_call(void *func)
diff --git a/src/cpu/x86/64bit/mode_switch.S b/src/cpu/x86/64bit/mode_switch.S
index c27f540ba3..f9f784e8c4 100644
--- a/src/cpu/x86/64bit/mode_switch.S
+++ b/src/cpu/x86/64bit/mode_switch.S
@@ -1,14 +1,13 @@
/* SPDX-License-Identifier: GPL-2.0-only */
+/* Calls a x86_32 function from x86_64 context */
.text
.code64
.section ".text.protected_mode_call", "ax", @progbits
- .globl protected_mode_call_narg
-protected_mode_call_narg:
-
- push %rbp
- mov %rsp, %rbp
+ .globl protected_mode_call_3arg
+protected_mode_call_3arg:
/* Preserve registers */
+ push %rbp
push %rbx
push %r12
push %r13
@@ -19,58 +18,47 @@ protected_mode_call_narg:
movl %gs, %eax
push %rax
- /* Arguments to stack */
- push %rdi
- push %rsi
- push %rdx
- push %rcx
-
- #include <cpu/x86/64bit/exit32.inc>
+ /* Store stack pointer */
+ mov %rsp, %rbp
- movl -56(%ebp), %eax /* Argument count */
- movl -72(%ebp), %edx /* Argument 0 */
- movl -80(%ebp), %ecx /* Argument 1 */
+ /* Align stack and make space for arguments */
+ movabs $0xfffffffffffffff0, %rax
+ andq %rax, %rsp
+ sub $16, %rsp
- /* Align the stack */
- andl $0xFFFFFFF0, %esp
- test %eax, %eax
- je 1f /* Zero arguments */
+ /* Arguments to stack */
+ movl %edi, 12(%rsp)
+ movl %esi, 0(%rsp)
+ movl %edx, 4(%rsp)
+ movl %ecx, 8(%rsp)
- subl $1, %eax
- test %eax, %eax
- je 2f /* One argument */
+ /* Drop to protected mode */
+ #include <cpu/x86/64bit/exit32.inc>
- /* Two arguments */
- subl $8, %esp
- pushl %ecx /* Argument 1 */
- pushl %edx /* Argument 0 */
- jmp 1f
-2:
- subl $12, %esp
- pushl %edx /* Argument 0 */
+ /* Fetch function to call */
+ movl 12(%esp), %ebx
-1:
- movl -64(%ebp), %ebx /* Function to call */
+ /* Call function */
call *%ebx
movl %eax, %ebx
- /* Preserves ebx */
+ /* Jump to long mode. Preserves ebx */
#include <cpu/x86/64bit/entry64.inc>
/* Place return value in rax */
movl %ebx, %eax
- /* Restore registers */
- mov -48(%rbp), %rbx
- movl %ebx, %gs
- mov -40(%rbp), %r15
- mov -32(%rbp), %r14
- mov -24(%rbp), %r13
- mov -16(%rbp), %r12
- mov -8(%rbp), %rbx
-
/* Restore stack pointer */
mov %rbp, %rsp
+
+ /* Restore registers */
+ pop %rbx
+ movl %ebx, %gs
+ pop %r15
+ pop %r14
+ pop %r13
+ pop %r12
+ pop %rbx
pop %rbp
ret