1 | /* SPDX-License-Identifier: GPL-2.0 */ |
2 | /* |
3 | * Copyright (C) 2014 Intel Corporation; author Matt Fleming |
4 | * |
5 | * Support for invoking 32-bit EFI runtime services from a 64-bit |
6 | * kernel. |
7 | * |
8 | * The below thunking functions are only used after ExitBootServices() |
9 | * has been called. This simplifies things considerably as compared with |
10 | * the early EFI thunking because we can leave all the kernel state |
11 | * intact (GDT, IDT, etc) and simply invoke the 32-bit EFI runtime |
12 | * services from __KERNEL32_CS. This means we can continue to service |
13 | * interrupts across an EFI mixed mode call. |
14 | * |
15 | * We do however, need to handle the fact that we're running in a full |
16 | * 64-bit virtual address space. Things like the stack and instruction |
17 | * addresses need to be accessible by the 32-bit firmware, so we rely on |
18 | * using the identity mappings in the EFI page table to access the stack |
19 | * and kernel text (see efi_setup_page_tables()). |
20 | */ |
21 | |
22 | #include <linux/linkage.h> |
23 | #include <linux/objtool.h> |
24 | #include <asm/page_types.h> |
25 | #include <asm/segment.h> |
26 | |
27 | .text |
28 | .code64 |
29 | SYM_FUNC_START(__efi64_thunk) |
30 | STACK_FRAME_NON_STANDARD __efi64_thunk |
31 | push %rbp |
32 | push %rbx |
33 | |
34 | /* |
35 | * Switch to 1:1 mapped 32-bit stack pointer. |
36 | */ |
37 | movq %rsp, %rax |
38 | movq efi_mixed_mode_stack_pa(%rip), %rsp |
39 | push %rax |
40 | |
41 | /* |
42 | * Copy args passed via the stack |
43 | */ |
44 | subq $0x24, %rsp |
45 | movq 0x18(%rax), %rbp |
46 | movq 0x20(%rax), %rbx |
47 | movq 0x28(%rax), %rax |
48 | movl %ebp, 0x18(%rsp) |
49 | movl %ebx, 0x1c(%rsp) |
50 | movl %eax, 0x20(%rsp) |
51 | |
52 | /* |
53 | * Calculate the physical address of the kernel text. |
54 | */ |
55 | movq $__START_KERNEL_map, %rax |
56 | subq phys_base(%rip), %rax |
57 | |
58 | leaq 1f(%rip), %rbp |
59 | leaq 2f(%rip), %rbx |
60 | subq %rax, %rbp |
61 | subq %rax, %rbx |
62 | |
63 | movl %ebx, 0x0(%rsp) /* return address */ |
64 | movl %esi, 0x4(%rsp) |
65 | movl %edx, 0x8(%rsp) |
66 | movl %ecx, 0xc(%rsp) |
67 | movl %r8d, 0x10(%rsp) |
68 | movl %r9d, 0x14(%rsp) |
69 | |
70 | /* Switch to 32-bit descriptor */ |
71 | pushq $__KERNEL32_CS |
72 | pushq %rdi /* EFI runtime service address */ |
73 | lretq |
74 | |
75 | // This return instruction is not needed for correctness, as it will |
76 | // never be reached. It only exists to make objtool happy, which will |
77 | // otherwise complain about unreachable instructions in the callers. |
78 | RET |
79 | SYM_FUNC_END(__efi64_thunk) |
80 | |
81 | .section ".rodata" , "a" , @progbits |
82 | .balign 16 |
83 | SYM_DATA_START(__efi64_thunk_ret_tramp) |
84 | 1: movq 0x20(%rsp), %rsp |
85 | pop %rbx |
86 | pop %rbp |
87 | ret |
88 | int3 |
89 | |
90 | .code32 |
91 | 2: pushl $__KERNEL_CS |
92 | pushl %ebp |
93 | lret |
94 | SYM_DATA_END(__efi64_thunk_ret_tramp) |
95 | |
96 | .bss |
97 | .balign 8 |
98 | SYM_DATA(efi_mixed_mode_stack_pa, .quad 0) |
99 | |