1 /* SPDX-License-Identifier: GPL-2.0 */
3 * Copyright (C) 2014, 2015 Intel Corporation; author Matt Fleming
5 * Early support for invoking 32-bit EFI services from a 64-bit kernel.
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
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
17 #include <linux/linkage.h>
19 #include <asm/page_types.h>
20 #include <asm/processor-flags.h>
21 #include <asm/segment.h>
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 common 64-bit EFI stub
30 * entrypoint efi_stub_entry() directly, or via 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.
36 * +------------------+ +------------+ +------>| efi_pe_entry |
37 * | efi32_pe_entry |---->| | | +-----------+--+
38 * +------------------+ | | +------+----------------+ |
39 * | startup_32 |---->| startup_64_mixed_mode | |
40 * +------------------+ | | +------+----------------+ |
41 * | efi32_stub_entry |---->| | | |
42 * +------------------+ +------------+ | |
44 * +------------+ +----------------+ |
45 * | startup_64 |<----| efi_stub_entry |<--------+
46 * +------------+ +----------------+
48 SYM_FUNC_START(startup_64_mixed_mode)
49 lea efi32_boot_args(%rip), %rdx
53 /* Switch to the firmware's stack */
54 movl efi32_boot_sp(%rip), %esp
57 #ifdef CONFIG_EFI_HANDOVER_PROTOCOL
58 mov 8(%rdx), %edx // saved bootparams pointer
63 * efi_pe_entry uses MS calling convention, which requires 32 bytes of
64 * shadow space on the stack even if all arguments are passed in
65 * registers. We also need an additional 8 bytes for the space that
66 * would be occupied by the return address, and this also results in
67 * the correct stack alignment for entry.
70 mov %rdi, %rcx // MS calling convention
73 SYM_FUNC_END(startup_64_mixed_mode)
75 SYM_FUNC_START(__efi64_thunk)
86 /* Copy args passed on stack */
92 * Convert x86-64 ABI params to i386 ABI
100 movl %ebp, 0x14(%rsp)
101 movl %ebx, 0x18(%rsp)
102 movl %eax, 0x1c(%rsp)
104 leaq 0x20(%rsp), %rbx
111 * Switch to IDT and GDT with 32-bit segments. These are the firmware
112 * GDT and IDT that were installed when the kernel started executing.
113 * The pointers were saved by the efi32_entry() routine below.
115 * Pass the saved DS selector to the 32-bit code, and use far return to
116 * restore the saved CS selector.
118 lidt efi32_boot_idt(%rip)
119 lgdt efi32_boot_gdt(%rip)
121 movzwl efi32_boot_ds(%rip), %edx
122 movzwq efi32_boot_cs(%rip), %rax
124 leaq efi_enter32(%rip), %rax
137 /* Clear out 32-bit selector from FS and GS */
145 SYM_FUNC_END(__efi64_thunk)
148 #ifdef CONFIG_EFI_HANDOVER_PROTOCOL
149 SYM_FUNC_START(efi32_stub_entry)
155 leal (_bss - 1b)(%ecx), %edi
156 leal (_ebss - 1b)(%ecx), %ecx
162 add $0x4, %esp /* Discard return address */
167 SYM_FUNC_END(efi32_stub_entry)
171 * EFI service pointer must be in %edi.
173 * The stack should represent the 32-bit calling convention.
175 SYM_FUNC_START_LOCAL(efi_enter32)
176 /* Load firmware selector into data and stack segment registers */
183 /* Reload pgtables */
189 btrl $X86_CR0_PG_BIT, %eax
192 /* Disable long mode via EFER */
195 btrl $_EFER_LME, %eax
200 /* We must preserve return value */
204 * Some firmware will return with interrupts enabled. Be sure to
205 * disable them before we switch GDTs and IDTs.
213 btsl $(X86_CR4_PAE_BIT), %eax
221 btsl $_EFER_LME, %eax
232 btsl $X86_CR0_PG_BIT, %eax
235 SYM_FUNC_END(efi_enter32)
238 * This is the common EFI stub entry point for mixed mode.
240 * Arguments: %ecx image handle
241 * %edx EFI system table pointer
242 * %esi struct bootparams pointer (or NULL when not using
243 * the EFI handover protocol)
245 * Since this is the point of no return for ordinary execution, no registers
246 * are considered live except for the function parameters. [Note that the EFI
247 * stub may still exit and return to the firmware using the Exit() EFI boot
250 SYM_FUNC_START_LOCAL(efi32_entry)
254 /* Save firmware GDTR and code/data selectors */
255 sgdtl (efi32_boot_gdt - 1b)(%ebx)
256 movw %cs, (efi32_boot_cs - 1b)(%ebx)
257 movw %ds, (efi32_boot_ds - 1b)(%ebx)
259 /* Store firmware IDT descriptor */
260 sidtl (efi32_boot_idt - 1b)(%ebx)
262 /* Store firmware stack pointer */
263 movl %esp, (efi32_boot_sp - 1b)(%ebx)
265 /* Store boot arguments */
266 leal (efi32_boot_args - 1b)(%ebx), %ebx
270 movb $0x0, 12(%ebx) // efi_is64
274 btrl $X86_CR0_PG_BIT, %eax
278 SYM_FUNC_END(efi32_entry)
281 * efi_status_t efi32_pe_entry(efi_handle_t image_handle,
282 * efi_system_table_32_t *sys_table)
284 SYM_FUNC_START(efi32_pe_entry)
287 pushl %ebx // save callee-save registers
290 call verify_cpu // check for long mode support
292 movl $0x80000003, %eax // EFI_UNSUPPORTED
295 movl 8(%ebp), %ecx // image_handle
296 movl 12(%ebp), %edx // sys_table
298 jmp efi32_entry // pass %ecx, %edx, %esi
299 // no other registers remain live
301 2: popl %edi // restore callee-save registers
305 SYM_FUNC_END(efi32_pe_entry)
307 #ifdef CONFIG_EFI_HANDOVER_PROTOCOL
308 .org efi32_stub_entry + 0x200
310 SYM_FUNC_START_NOALIGN(efi64_stub_entry)
311 jmp efi_handover_entry
312 SYM_FUNC_END(efi64_stub_entry)
317 SYM_DATA_START_LOCAL(efi32_boot_gdt)
320 SYM_DATA_END(efi32_boot_gdt)
322 SYM_DATA_START_LOCAL(efi32_boot_idt)
325 SYM_DATA_END(efi32_boot_idt)
327 SYM_DATA_LOCAL(efi32_boot_cs, .word 0)
328 SYM_DATA_LOCAL(efi32_boot_ds, .word 0)
329 SYM_DATA_LOCAL(efi32_boot_sp, .long 0)
330 SYM_DATA_LOCAL(efi32_boot_args, .long 0, 0, 0)
331 SYM_DATA(efi_is64, .byte 1)