| /* SPDX-License-Identifier: GPL-2.0 */ |
| /* |
| * Copyright (C) 2014 Intel Corporation; author Matt Fleming |
| * |
| * Support for invoking 32-bit EFI runtime services from a 64-bit |
| * kernel. |
| * |
| * The below thunking functions are only used after ExitBootServices() |
| * has been called. This simplifies things considerably as compared with |
| * the early EFI thunking because we can leave all the kernel state |
| * intact (GDT, IDT, etc) and simply invoke the 32-bit EFI runtime |
| * services from __KERNEL32_CS. This means we can continue to service |
| * interrupts across an EFI mixed mode call. |
| * |
| * We do however, need to handle the fact that we're running in a full |
| * 64-bit virtual address space. Things like the stack and instruction |
| * addresses need to be accessible by the 32-bit firmware, so we rely on |
| * using the identity mappings in the EFI page table to access the stack |
| * and kernel text (see efi_setup_page_tables()). |
| */ |
| |
| #include <linux/linkage.h> |
| #include <linux/objtool.h> |
| #include <asm/page_types.h> |
| #include <asm/segment.h> |
| |
| .text |
| .code64 |
| SYM_FUNC_START(__efi64_thunk) |
| STACK_FRAME_NON_STANDARD __efi64_thunk |
| push %rbp |
| push %rbx |
| |
| /* |
| * Switch to 1:1 mapped 32-bit stack pointer. |
| */ |
| movq %rsp, %rax |
| movq efi_mixed_mode_stack_pa(%rip), %rsp |
| push %rax |
| |
| /* |
| * Copy args passed via the stack |
| */ |
| subq $0x24, %rsp |
| movq 0x18(%rax), %rbp |
| movq 0x20(%rax), %rbx |
| movq 0x28(%rax), %rax |
| movl %ebp, 0x18(%rsp) |
| movl %ebx, 0x1c(%rsp) |
| movl %eax, 0x20(%rsp) |
| |
| /* |
| * Calculate the physical address of the kernel text. |
| */ |
| movq $__START_KERNEL_map, %rax |
| subq phys_base(%rip), %rax |
| |
| leaq 1f(%rip), %rbp |
| leaq 2f(%rip), %rbx |
| subq %rax, %rbp |
| subq %rax, %rbx |
| |
| movl %ebx, 0x0(%rsp) /* return address */ |
| movl %esi, 0x4(%rsp) |
| movl %edx, 0x8(%rsp) |
| movl %ecx, 0xc(%rsp) |
| movl %r8d, 0x10(%rsp) |
| movl %r9d, 0x14(%rsp) |
| |
| /* Switch to 32-bit descriptor */ |
| pushq $__KERNEL32_CS |
| pushq %rdi /* EFI runtime service address */ |
| lretq |
| |
| // This return instruction is not needed for correctness, as it will |
| // never be reached. It only exists to make objtool happy, which will |
| // otherwise complain about unreachable instructions in the callers. |
| RET |
| SYM_FUNC_END(__efi64_thunk) |
| |
| .section ".rodata", "a", @progbits |
| .balign 16 |
| SYM_DATA_START(__efi64_thunk_ret_tramp) |
| 1: movq 0x20(%rsp), %rsp |
| pop %rbx |
| pop %rbp |
| ret |
| int3 |
| |
| .code32 |
| 2: pushl $__KERNEL_CS |
| pushl %ebp |
| lret |
| SYM_DATA_END(__efi64_thunk_ret_tramp) |
| |
| .bss |
| .balign 8 |
| SYM_DATA(efi_mixed_mode_stack_pa, .quad 0) |