2 * Copyright (C) 2014, 2015 Intel Corporation; author Matt Fleming
4 * Early support for invoking 32-bit EFI services from a 64-bit kernel.
6 * Because this thunking occurs before ExitBootServices() we have to
7 * restore the firmware's 32-bit GDT before we make EFI serivce calls,
8 * since the firmware's 32-bit IDT is still currently installed and it
9 * needs to be able to service interrupts.
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 identify
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>
30 leaq efi_exit32(%rip), %rax
32 leaq efi_gdt64(%rip), %rax
34 movl %eax, 2(%rax) /* Fixup the gdt base address */
44 * Convert x86-64 ABI params to i386 ABI
58 movq %rbx, func_rt_ptr(%rip)
61 * Switch to gdt with 32-bit segments. This is the firmware GDT
62 * that was installed when the kernel started executing. This
63 * pointer was saved at the EFI stub entry point in head_64.S.
65 leaq efi32_boot_gdt(%rip), %rax
69 leaq efi_enter32(%rip), %rax
85 * Convert 32-bit status code into 64-bit.
90 andl $0x0fffffff, %ecx
91 andl $0xf0000000, %eax
102 movq func_rt_ptr(%rip), %rax
110 * EFI service pointer must be in %edi.
112 * The stack should represent the 32-bit calling convention.
115 movl $__KERNEL_DS, %eax
120 /* Reload pgtables */
126 btrl $X86_CR0_PG_BIT, %eax
129 /* Disable long mode via EFER */
132 btrl $_EFER_LME, %eax
137 /* We must preserve return value */
141 * Some firmware will return with interrupts enabled. Be sure to
142 * disable them before we switch GDTs.
151 btsl $(X86_CR4_PAE_BIT), %eax
159 btsl $_EFER_LME, %eax
171 btsl $X86_CR0_PG_BIT, %eax
178 .global efi32_boot_gdt
179 efi32_boot_gdt: .word 0
188 .word efi_gdt64_end - efi_gdt64
189 .long 0 /* Filled out by user */
191 .quad 0x0000000000000000 /* NULL descriptor */
192 .quad 0x00af9a000000ffff /* __KERNEL_CS */
193 .quad 0x00cf92000000ffff /* __KERNEL_DS */
194 .quad 0x0080890000000000 /* TS descriptor */
195 .quad 0x0000000000000000 /* TS continued */