Loading...
Note: File does not exist in v3.15.
1/* SPDX-License-Identifier: GPL-2.0 */
2/*
3 * Copyright (C) 2014, 2015 Intel Corporation; author Matt Fleming
4 *
5 * Early support for invoking 32-bit EFI services from a 64-bit kernel.
6 *
7 * Because this thunking occurs before ExitBootServices() we have to
8 * restore the firmware's 32-bit GDT and IDT before we make EFI service
9 * calls.
10 *
11 * On the plus side, we don't have to worry about mangling 64-bit
12 * addresses into 32-bits because we're executing with an identity
13 * mapped pagetable and haven't transitioned to 64-bit virtual addresses
14 * yet.
15 */
16
17#include <linux/linkage.h>
18#include <asm/msr.h>
19#include <asm/page_types.h>
20#include <asm/processor-flags.h>
21#include <asm/segment.h>
22
23 .code64
24 .text
25/*
26 * When booting in 64-bit mode on 32-bit EFI firmware, startup_64_mixed_mode()
27 * is the first thing that runs after switching to long mode. Depending on
28 * whether the EFI handover protocol or the compat entry point was used to
29 * enter the kernel, it will either branch to the 64-bit EFI handover
30 * entrypoint at offset 0x390 in the image, or to the 64-bit EFI PE/COFF
31 * entrypoint efi_pe_entry(). In the former case, the bootloader must provide a
32 * struct bootparams pointer as the third argument, so the presence of such a
33 * pointer is used to disambiguate.
34 *
35 * +--------------+
36 * +------------------+ +------------+ +------>| efi_pe_entry |
37 * | efi32_pe_entry |---->| | | +-----------+--+
38 * +------------------+ | | +------+----------------+ |
39 * | startup_32 |---->| startup_64_mixed_mode | |
40 * +------------------+ | | +------+----------------+ V
41 * | efi32_stub_entry |---->| | | +------------------+
42 * +------------------+ +------------+ +---->| efi64_stub_entry |
43 * +-------------+----+
44 * +------------+ +----------+ |
45 * | startup_64 |<----| efi_main |<--------------+
46 * +------------+ +----------+
47 */
48SYM_FUNC_START(startup_64_mixed_mode)
49 lea efi32_boot_args(%rip), %rdx
50 mov 0(%rdx), %edi
51 mov 4(%rdx), %esi
52 mov 8(%rdx), %edx // saved bootparams pointer
53 test %edx, %edx
54 jnz efi64_stub_entry
55 /*
56 * efi_pe_entry uses MS calling convention, which requires 32 bytes of
57 * shadow space on the stack even if all arguments are passed in
58 * registers. We also need an additional 8 bytes for the space that
59 * would be occupied by the return address, and this also results in
60 * the correct stack alignment for entry.
61 */
62 sub $40, %rsp
63 mov %rdi, %rcx // MS calling convention
64 mov %rsi, %rdx
65 jmp efi_pe_entry
66SYM_FUNC_END(startup_64_mixed_mode)
67
68SYM_FUNC_START(__efi64_thunk)
69 push %rbp
70 push %rbx
71
72 movl %ds, %eax
73 push %rax
74 movl %es, %eax
75 push %rax
76 movl %ss, %eax
77 push %rax
78
79 /* Copy args passed on stack */
80 movq 0x30(%rsp), %rbp
81 movq 0x38(%rsp), %rbx
82 movq 0x40(%rsp), %rax
83
84 /*
85 * Convert x86-64 ABI params to i386 ABI
86 */
87 subq $64, %rsp
88 movl %esi, 0x0(%rsp)
89 movl %edx, 0x4(%rsp)
90 movl %ecx, 0x8(%rsp)
91 movl %r8d, 0xc(%rsp)
92 movl %r9d, 0x10(%rsp)
93 movl %ebp, 0x14(%rsp)
94 movl %ebx, 0x18(%rsp)
95 movl %eax, 0x1c(%rsp)
96
97 leaq 0x20(%rsp), %rbx
98 sgdt (%rbx)
99 sidt 16(%rbx)
100
101 leaq 1f(%rip), %rbp
102
103 /*
104 * Switch to IDT and GDT with 32-bit segments. These are the firmware
105 * GDT and IDT that were installed when the kernel started executing.
106 * The pointers were saved by the efi32_entry() routine below.
107 *
108 * Pass the saved DS selector to the 32-bit code, and use far return to
109 * restore the saved CS selector.
110 */
111 lidt efi32_boot_idt(%rip)
112 lgdt efi32_boot_gdt(%rip)
113
114 movzwl efi32_boot_ds(%rip), %edx
115 movzwq efi32_boot_cs(%rip), %rax
116 pushq %rax
117 leaq efi_enter32(%rip), %rax
118 pushq %rax
119 lretq
120
1211: addq $64, %rsp
122 movq %rdi, %rax
123
124 pop %rbx
125 movl %ebx, %ss
126 pop %rbx
127 movl %ebx, %es
128 pop %rbx
129 movl %ebx, %ds
130 /* Clear out 32-bit selector from FS and GS */
131 xorl %ebx, %ebx
132 movl %ebx, %fs
133 movl %ebx, %gs
134
135 pop %rbx
136 pop %rbp
137 RET
138SYM_FUNC_END(__efi64_thunk)
139
140 .code32
141/*
142 * EFI service pointer must be in %edi.
143 *
144 * The stack should represent the 32-bit calling convention.
145 */
146SYM_FUNC_START_LOCAL(efi_enter32)
147 /* Load firmware selector into data and stack segment registers */
148 movl %edx, %ds
149 movl %edx, %es
150 movl %edx, %fs
151 movl %edx, %gs
152 movl %edx, %ss
153
154 /* Reload pgtables */
155 movl %cr3, %eax
156 movl %eax, %cr3
157
158 /* Disable paging */
159 movl %cr0, %eax
160 btrl $X86_CR0_PG_BIT, %eax
161 movl %eax, %cr0
162
163 /* Disable long mode via EFER */
164 movl $MSR_EFER, %ecx
165 rdmsr
166 btrl $_EFER_LME, %eax
167 wrmsr
168
169 call *%edi
170
171 /* We must preserve return value */
172 movl %eax, %edi
173
174 /*
175 * Some firmware will return with interrupts enabled. Be sure to
176 * disable them before we switch GDTs and IDTs.
177 */
178 cli
179
180 lidtl 16(%ebx)
181 lgdtl (%ebx)
182
183 movl %cr4, %eax
184 btsl $(X86_CR4_PAE_BIT), %eax
185 movl %eax, %cr4
186
187 movl %cr3, %eax
188 movl %eax, %cr3
189
190 movl $MSR_EFER, %ecx
191 rdmsr
192 btsl $_EFER_LME, %eax
193 wrmsr
194
195 xorl %eax, %eax
196 lldt %ax
197
198 pushl $__KERNEL_CS
199 pushl %ebp
200
201 /* Enable paging */
202 movl %cr0, %eax
203 btsl $X86_CR0_PG_BIT, %eax
204 movl %eax, %cr0
205 lret
206SYM_FUNC_END(efi_enter32)
207
208/*
209 * This is the common EFI stub entry point for mixed mode.
210 *
211 * Arguments: %ecx image handle
212 * %edx EFI system table pointer
213 * %esi struct bootparams pointer (or NULL when not using
214 * the EFI handover protocol)
215 *
216 * Since this is the point of no return for ordinary execution, no registers
217 * are considered live except for the function parameters. [Note that the EFI
218 * stub may still exit and return to the firmware using the Exit() EFI boot
219 * service.]
220 */
221SYM_FUNC_START(efi32_entry)
222 call 1f
2231: pop %ebx
224
225 /* Save firmware GDTR and code/data selectors */
226 sgdtl (efi32_boot_gdt - 1b)(%ebx)
227 movw %cs, (efi32_boot_cs - 1b)(%ebx)
228 movw %ds, (efi32_boot_ds - 1b)(%ebx)
229
230 /* Store firmware IDT descriptor */
231 sidtl (efi32_boot_idt - 1b)(%ebx)
232
233 /* Store boot arguments */
234 leal (efi32_boot_args - 1b)(%ebx), %ebx
235 movl %ecx, 0(%ebx)
236 movl %edx, 4(%ebx)
237 movl %esi, 8(%ebx)
238 movb $0x0, 12(%ebx) // efi_is64
239
240 /* Disable paging */
241 movl %cr0, %eax
242 btrl $X86_CR0_PG_BIT, %eax
243 movl %eax, %cr0
244
245 jmp startup_32
246SYM_FUNC_END(efi32_entry)
247
248#define ST32_boottime 60 // offsetof(efi_system_table_32_t, boottime)
249#define BS32_handle_protocol 88 // offsetof(efi_boot_services_32_t, handle_protocol)
250#define LI32_image_base 32 // offsetof(efi_loaded_image_32_t, image_base)
251
252/*
253 * efi_status_t efi32_pe_entry(efi_handle_t image_handle,
254 * efi_system_table_32_t *sys_table)
255 */
256SYM_FUNC_START(efi32_pe_entry)
257 pushl %ebp
258 movl %esp, %ebp
259 pushl %eax // dummy push to allocate loaded_image
260
261 pushl %ebx // save callee-save registers
262 pushl %edi
263
264 call verify_cpu // check for long mode support
265 testl %eax, %eax
266 movl $0x80000003, %eax // EFI_UNSUPPORTED
267 jnz 2f
268
269 call 1f
2701: pop %ebx
271
272 /* Get the loaded image protocol pointer from the image handle */
273 leal -4(%ebp), %eax
274 pushl %eax // &loaded_image
275 leal (loaded_image_proto - 1b)(%ebx), %eax
276 pushl %eax // pass the GUID address
277 pushl 8(%ebp) // pass the image handle
278
279 /*
280 * Note the alignment of the stack frame.
281 * sys_table
282 * handle <-- 16-byte aligned on entry by ABI
283 * return address
284 * frame pointer
285 * loaded_image <-- local variable
286 * saved %ebx <-- 16-byte aligned here
287 * saved %edi
288 * &loaded_image
289 * &loaded_image_proto
290 * handle <-- 16-byte aligned for call to handle_protocol
291 */
292
293 movl 12(%ebp), %eax // sys_table
294 movl ST32_boottime(%eax), %eax // sys_table->boottime
295 call *BS32_handle_protocol(%eax) // sys_table->boottime->handle_protocol
296 addl $12, %esp // restore argument space
297 testl %eax, %eax
298 jnz 2f
299
300 movl 8(%ebp), %ecx // image_handle
301 movl 12(%ebp), %edx // sys_table
302 movl -4(%ebp), %esi // loaded_image
303 movl LI32_image_base(%esi), %esi // loaded_image->image_base
304 leal (startup_32 - 1b)(%ebx), %ebp // runtime address of startup_32
305 /*
306 * We need to set the image_offset variable here since startup_32() will
307 * use it before we get to the 64-bit efi_pe_entry() in C code.
308 */
309 subl %esi, %ebp // calculate image_offset
310 movl %ebp, (image_offset - 1b)(%ebx) // save image_offset
311 xorl %esi, %esi
312 jmp efi32_entry // pass %ecx, %edx, %esi
313 // no other registers remain live
314
3152: popl %edi // restore callee-save registers
316 popl %ebx
317 leave
318 RET
319SYM_FUNC_END(efi32_pe_entry)
320
321 .section ".rodata"
322 /* EFI loaded image protocol GUID */
323 .balign 4
324SYM_DATA_START_LOCAL(loaded_image_proto)
325 .long 0x5b1b31a1
326 .word 0x9562, 0x11d2
327 .byte 0x8e, 0x3f, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b
328SYM_DATA_END(loaded_image_proto)
329
330 .data
331 .balign 8
332SYM_DATA_START_LOCAL(efi32_boot_gdt)
333 .word 0
334 .quad 0
335SYM_DATA_END(efi32_boot_gdt)
336
337SYM_DATA_START_LOCAL(efi32_boot_idt)
338 .word 0
339 .quad 0
340SYM_DATA_END(efi32_boot_idt)
341
342SYM_DATA_LOCAL(efi32_boot_cs, .word 0)
343SYM_DATA_LOCAL(efi32_boot_ds, .word 0)
344SYM_DATA_LOCAL(efi32_boot_args, .long 0, 0, 0)
345SYM_DATA(efi_is64, .byte 1)