Calling 32-bit EFI runtime services from a 64-bit OS involves switching back to the flat mapping with a stack carved out of memory that is 32-bit addressable. There is no need to actually execute the 64-bit part of this routine from the flat mapping as well, as long as the entry and return address fit in 32 bits. There is also no need to preserve part of the calling context in global variables: we can simply preserve the old stack pointer in %r11 across the call into 32-bit firmware, and use either stack to preserve other values. Signed-off-by: Ard Biesheuvel <ardb@xxxxxxxxxx> --- arch/x86/platform/efi/efi_thunk_64.S | 106 ++++++-------------- 1 file changed, 29 insertions(+), 77 deletions(-) diff --git a/arch/x86/platform/efi/efi_thunk_64.S b/arch/x86/platform/efi/efi_thunk_64.S index 3189f1394701..7357808d3ae8 100644 --- a/arch/x86/platform/efi/efi_thunk_64.S +++ b/arch/x86/platform/efi/efi_thunk_64.S @@ -28,11 +28,17 @@ SYM_FUNC_START(efi64_thunk) push %rbp push %rbx + movl %ds, %ebx + push %rbx + movl %es, %ebx + push %rbx + movl %ss, %ebx + push %rbx /* * Switch to 1:1 mapped 32-bit stack pointer. */ - movq %rsp, efi_saved_sp(%rip) + movq %rsp, %r11 movq efi_scratch(%rip), %rsp /* @@ -41,87 +47,41 @@ SYM_FUNC_START(efi64_thunk) movq $__START_KERNEL_map, %rax subq phys_base(%rip), %rax - /* - * Push some physical addresses onto the stack. This is easier - * to do now in a code64 section while the assembler can address - * 64-bit values. Note that all the addresses on the stack are - * 32-bit. - */ - subq $16, %rsp - leaq efi_exit32(%rip), %rbx - subq %rax, %rbx - movl %ebx, 8(%rsp) - - leaq __efi64_thunk(%rip), %rbx - subq %rax, %rbx - call *%rbx - - movq efi_saved_sp(%rip), %rsp - pop %rbx - pop %rbp - retq -SYM_FUNC_END(efi64_thunk) - -/* - * We run this function from the 1:1 mapping. - * - * This function must be invoked with a 1:1 mapped stack. - */ -SYM_FUNC_START_LOCAL(__efi64_thunk) - movl %ds, %eax - push %rax - movl %es, %eax - push %rax - movl %ss, %eax - push %rax - - subq $32, %rsp + subq $24, %rsp movl %esi, 0x0(%rsp) movl %edx, 0x4(%rsp) movl %ecx, 0x8(%rsp) - movq %r8, %rsi - movl %esi, 0xc(%rsp) - movq %r9, %rsi - movl %esi, 0x10(%rsp) - + movl %r8d, 0xc(%rsp) + movl %r9d, 0x10(%rsp) leaq 1f(%rip), %rbx - movq %rbx, func_rt_ptr(%rip) + subq %rax, %rbx + movl %ebx, 0x14(%rsp) /* Switch to 32-bit descriptor */ pushq $__KERNEL32_CS - leaq efi_enter32(%rip), %rax - pushq %rax + leaq efi_enter32(%rip), %rbx + subq %rax, %rbx + pushq %rbx lretq -1: addq $32, %rsp - + /* + * Convert 32-bit status code into 64-bit. + */ +1: btrl $31, %eax + jb 3f +2: mov %r11, %rsp pop %rbx movl %ebx, %ss pop %rbx movl %ebx, %es pop %rbx movl %ebx, %ds - - /* - * Convert 32-bit status code into 64-bit. - */ - test %rax, %rax - jz 1f - movl %eax, %ecx - andl $0x0fffffff, %ecx - andl $0xf0000000, %eax - shl $32, %rax - or %rcx, %rax -1: - ret -SYM_FUNC_END(__efi64_thunk) - -SYM_FUNC_START_LOCAL(efi_exit32) - movq func_rt_ptr(%rip), %rax - push %rax - mov %rdi, %rax - ret -SYM_FUNC_END(efi_exit32) + pop %rbx + pop %rbp + retq +3: btsq $63, %rax + jmp 2b +SYM_FUNC_END(efi64_thunk) .code32 /* @@ -137,17 +97,9 @@ SYM_FUNC_START_LOCAL(efi_enter32) call *%edi - /* We must preserve return value */ - movl %eax, %edi - - movl 72(%esp), %eax + movl 20(%esp), %edi pushl $__KERNEL_CS - pushl %eax + pushl %edi lret SYM_FUNC_END(efi_enter32) - - .data - .balign 8 -func_rt_ptr: .quad 0 -efi_saved_sp: .quad 0 -- 2.17.1