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 before we make EFI serivce calls,
9 * since the firmware's 32-bit IDT is still currently installed and it
10 * needs to be able to service interrupts.
12 * On the plus side, we don't have to worry about mangling 64-bit
13 * addresses into 32-bits because we're executing with an identity
14 * mapped pagetable and haven't transitioned to 64-bit virtual addresses
18 #include <linux/linkage.h>
20 #include <asm/page_types.h>
21 #include <asm/processor-flags.h>
22 #include <asm/segment.h>
26 SYM_FUNC_START(__efi64_thunk)
31 leaq efi_gdt64(%rip), %rbx
32 movl %ebx, 2(%rbx) /* Fixup the gdt base address */
42 * Convert x86-64 ABI params to i386 ABI
54 * Switch to gdt with 32-bit segments. This is the firmware GDT
55 * that was installed when the kernel started executing. This
56 * pointer was saved at the EFI stub entry point in head_64.S.
58 * Pass the saved DS selector to the 32-bit code, and use far return to
59 * restore the saved CS selector.
61 leaq efi32_boot_gdt(%rip), %rax
64 movzwl efi32_boot_ds(%rip), %edx
65 movzwq efi32_boot_cs(%rip), %rax
67 leaq efi_enter32(%rip), %rax
81 /* Clear out 32-bit selector from FS and GS */
87 * Convert 32-bit status code into 64-bit.
95 SYM_FUNC_END(__efi64_thunk)
99 * EFI service pointer must be in %edi.
101 * The stack should represent the 32-bit calling convention.
103 SYM_FUNC_START_LOCAL(efi_enter32)
104 /* Load firmware selector into data and stack segment registers */
111 /* Reload pgtables */
117 btrl $X86_CR0_PG_BIT, %eax
120 /* Disable long mode via EFER */
123 btrl $_EFER_LME, %eax
128 /* We must preserve return value */
132 * Some firmware will return with interrupts enabled. Be sure to
133 * disable them before we switch GDTs.
140 btsl $(X86_CR4_PAE_BIT), %eax
148 btsl $_EFER_LME, %eax
159 btsl $X86_CR0_PG_BIT, %eax
162 SYM_FUNC_END(efi_enter32)
166 SYM_DATA_START(efi32_boot_gdt)
169 SYM_DATA_END(efi32_boot_gdt)
171 SYM_DATA_START(efi32_boot_cs)
173 SYM_DATA_END(efi32_boot_cs)
175 SYM_DATA_START(efi32_boot_ds)
177 SYM_DATA_END(efi32_boot_ds)
179 SYM_DATA_START(efi_gdt64)
180 .word efi_gdt64_end - efi_gdt64
181 .long 0 /* Filled out by user */
183 .quad 0x0000000000000000 /* NULL descriptor */
184 .quad 0x00af9a000000ffff /* __KERNEL_CS */
185 .quad 0x00cf92000000ffff /* __KERNEL_DS */
186 .quad 0x0080890000000000 /* TS descriptor */
187 .quad 0x0000000000000000 /* TS continued */
188 SYM_DATA_END_LABEL(efi_gdt64, SYM_L_LOCAL, efi_gdt64_end)