Commit | Line | Data |
---|---|---|
b2441318 | 1 | /* SPDX-License-Identifier: GPL-2.0 */ |
4f9dbcfc MF |
2 | /* |
3 | * Copyright (C) 2014 Intel Corporation; author Matt Fleming | |
96738c69 MF |
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 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()). | |
4f9dbcfc MF |
20 | */ |
21 | ||
22 | #include <linux/linkage.h> | |
23 | #include <asm/page_types.h> | |
96738c69 | 24 | #include <asm/segment.h> |
4f9dbcfc MF |
25 | |
26 | .text | |
27 | .code64 | |
28 | ENTRY(efi64_thunk) | |
29 | push %rbp | |
30 | push %rbx | |
31 | ||
32 | /* | |
33 | * Switch to 1:1 mapped 32-bit stack pointer. | |
34 | */ | |
35 | movq %rsp, efi_saved_sp(%rip) | |
03781e40 | 36 | movq efi_scratch(%rip), %rsp |
4f9dbcfc MF |
37 | |
38 | /* | |
39 | * Calculate the physical address of the kernel text. | |
40 | */ | |
41 | movq $__START_KERNEL_map, %rax | |
42 | subq phys_base(%rip), %rax | |
43 | ||
44 | /* | |
45 | * Push some physical addresses onto the stack. This is easier | |
46 | * to do now in a code64 section while the assembler can address | |
47 | * 64-bit values. Note that all the addresses on the stack are | |
48 | * 32-bit. | |
49 | */ | |
50 | subq $16, %rsp | |
51 | leaq efi_exit32(%rip), %rbx | |
52 | subq %rax, %rbx | |
53 | movl %ebx, 8(%rsp) | |
4f9dbcfc MF |
54 | |
55 | leaq __efi64_thunk(%rip), %rbx | |
56 | subq %rax, %rbx | |
57 | call *%rbx | |
58 | ||
59 | movq efi_saved_sp(%rip), %rsp | |
60 | pop %rbx | |
61 | pop %rbp | |
62 | retq | |
63 | ENDPROC(efi64_thunk) | |
64 | ||
96738c69 MF |
65 | /* |
66 | * We run this function from the 1:1 mapping. | |
67 | * | |
68 | * This function must be invoked with a 1:1 mapped stack. | |
69 | */ | |
70 | ENTRY(__efi64_thunk) | |
71 | movl %ds, %eax | |
72 | push %rax | |
73 | movl %es, %eax | |
74 | push %rax | |
75 | movl %ss, %eax | |
76 | push %rax | |
77 | ||
78 | subq $32, %rsp | |
79 | movl %esi, 0x0(%rsp) | |
80 | movl %edx, 0x4(%rsp) | |
81 | movl %ecx, 0x8(%rsp) | |
82 | movq %r8, %rsi | |
83 | movl %esi, 0xc(%rsp) | |
84 | movq %r9, %rsi | |
85 | movl %esi, 0x10(%rsp) | |
86 | ||
87 | leaq 1f(%rip), %rbx | |
88 | movq %rbx, func_rt_ptr(%rip) | |
89 | ||
90 | /* Switch to 32-bit descriptor */ | |
91 | pushq $__KERNEL32_CS | |
92 | leaq efi_enter32(%rip), %rax | |
93 | pushq %rax | |
94 | lretq | |
95 | ||
96 | 1: addq $32, %rsp | |
97 | ||
98 | pop %rbx | |
99 | movl %ebx, %ss | |
100 | pop %rbx | |
101 | movl %ebx, %es | |
102 | pop %rbx | |
103 | movl %ebx, %ds | |
4f9dbcfc | 104 | |
96738c69 MF |
105 | /* |
106 | * Convert 32-bit status code into 64-bit. | |
107 | */ | |
108 | test %rax, %rax | |
109 | jz 1f | |
110 | movl %eax, %ecx | |
111 | andl $0x0fffffff, %ecx | |
112 | andl $0xf0000000, %eax | |
113 | shl $32, %rax | |
114 | or %rcx, %rax | |
115 | 1: | |
116 | ret | |
117 | ENDPROC(__efi64_thunk) | |
118 | ||
119 | ENTRY(efi_exit32) | |
120 | movq func_rt_ptr(%rip), %rax | |
121 | push %rax | |
122 | mov %rdi, %rax | |
123 | ret | |
124 | ENDPROC(efi_exit32) | |
125 | ||
126 | .code32 | |
127 | /* | |
128 | * EFI service pointer must be in %edi. | |
129 | * | |
130 | * The stack should represent the 32-bit calling convention. | |
131 | */ | |
132 | ENTRY(efi_enter32) | |
133 | movl $__KERNEL_DS, %eax | |
134 | movl %eax, %ds | |
135 | movl %eax, %es | |
136 | movl %eax, %ss | |
137 | ||
138 | call *%edi | |
139 | ||
140 | /* We must preserve return value */ | |
141 | movl %eax, %edi | |
142 | ||
143 | movl 72(%esp), %eax | |
144 | pushl $__KERNEL_CS | |
145 | pushl %eax | |
146 | ||
147 | lret | |
148 | ENDPROC(efi_enter32) | |
149 | ||
150 | .data | |
151 | .balign 8 | |
152 | func_rt_ptr: .quad 0 | |
4f9dbcfc | 153 | efi_saved_sp: .quad 0 |