|
@@ -7,6 +7,10 @@
|
|
|
*/
|
|
|
|
|
|
#include <linux/linkage.h>
|
|
|
+#include <asm/segment.h>
|
|
|
+#include <asm/msr.h>
|
|
|
+#include <asm/processor-flags.h>
|
|
|
+#include <asm/page_types.h>
|
|
|
|
|
|
#define SAVE_XMM \
|
|
|
mov %rsp, %rax; \
|
|
@@ -164,6 +168,152 @@ ENTRY(efi_call6)
|
|
|
ret
|
|
|
ENDPROC(efi_call6)
|
|
|
|
|
|
+#ifdef CONFIG_EFI_MIXED
|
|
|
+
|
|
|
+/*
|
|
|
+ * We run this function from the 1:1 mapping.
|
|
|
+ *
|
|
|
+ * This function must be invoked with a 1:1 mapped stack.
|
|
|
+ */
|
|
|
+ENTRY(__efi64_thunk)
|
|
|
+ subq $32, %rsp
|
|
|
+ movl %esi, 0x0(%rsp)
|
|
|
+ movl %edx, 0x4(%rsp)
|
|
|
+ movl %ecx, 0x8(%rsp)
|
|
|
+ movq %r8, %rsi
|
|
|
+ movl %esi, 0xc(%rsp)
|
|
|
+ movq %r9, %rsi
|
|
|
+ movl %esi, 0x10(%rsp)
|
|
|
+
|
|
|
+ sgdt save_gdt(%rip)
|
|
|
+
|
|
|
+ leaq 1f(%rip), %rbx
|
|
|
+ movq %rbx, func_rt_ptr(%rip)
|
|
|
+
|
|
|
+ /* Switch to gdt with 32-bit segments */
|
|
|
+ movl 40(%rsp), %eax
|
|
|
+ lgdt (%rax)
|
|
|
+
|
|
|
+ leaq efi_enter32(%rip), %rax
|
|
|
+ pushq $__KERNEL_CS
|
|
|
+ pushq %rax
|
|
|
+ lretq
|
|
|
+
|
|
|
+1: addq $32, %rsp
|
|
|
+
|
|
|
+ lgdt save_gdt(%rip)
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Convert 32-bit status code into 64-bit.
|
|
|
+ */
|
|
|
+ test %rax, %rax
|
|
|
+ jz 1f
|
|
|
+ movl %eax, %ecx
|
|
|
+ andl $0x0fffffff, %ecx
|
|
|
+ andl $0xf0000000, %eax
|
|
|
+ shl $32, %rax
|
|
|
+ or %rcx, %rax
|
|
|
+1:
|
|
|
+ ret
|
|
|
+ENDPROC(__efi64_thunk)
|
|
|
+
|
|
|
+ENTRY(efi_exit32)
|
|
|
+ xorq %rax, %rax
|
|
|
+ movl %eax, %ds
|
|
|
+ movl %eax, %es
|
|
|
+ movl %eax, %ss
|
|
|
+
|
|
|
+ movq func_rt_ptr(%rip), %rax
|
|
|
+ push %rax
|
|
|
+ mov %rdi, %rax
|
|
|
+ ret
|
|
|
+ENDPROC(efi_exit32)
|
|
|
+
|
|
|
+ .code32
|
|
|
+/*
|
|
|
+ * EFI service pointer must be in %edi.
|
|
|
+ *
|
|
|
+ * The stack should represent the 32-bit calling convention.
|
|
|
+ */
|
|
|
+ENTRY(efi_enter32)
|
|
|
+ movl $__KERNEL_DS, %eax
|
|
|
+ movl %eax, %ds
|
|
|
+ movl %eax, %es
|
|
|
+ movl %eax, %ss
|
|
|
+
|
|
|
+ /* Reload pgtables */
|
|
|
+ movl %cr3, %eax
|
|
|
+ movl %eax, %cr3
|
|
|
+
|
|
|
+ /* Disable paging */
|
|
|
+ movl %cr0, %eax
|
|
|
+ btrl $X86_CR0_PG_BIT, %eax
|
|
|
+ movl %eax, %cr0
|
|
|
+
|
|
|
+ /* Disable long mode via EFER */
|
|
|
+ movl $MSR_EFER, %ecx
|
|
|
+ rdmsr
|
|
|
+ btrl $_EFER_LME, %eax
|
|
|
+ wrmsr
|
|
|
+
|
|
|
+ call *%edi
|
|
|
+
|
|
|
+ /* We must preserve return value */
|
|
|
+ movl %eax, %edi
|
|
|
+
|
|
|
+ movl 44(%esp), %eax
|
|
|
+ movl %eax, 2(%eax)
|
|
|
+ lgdtl (%eax)
|
|
|
+
|
|
|
+ movl %cr4, %eax
|
|
|
+ btsl $(X86_CR4_PAE_BIT), %eax
|
|
|
+ movl %eax, %cr4
|
|
|
+
|
|
|
+ movl %cr3, %eax
|
|
|
+ movl %eax, %cr3
|
|
|
+
|
|
|
+ movl $MSR_EFER, %ecx
|
|
|
+ rdmsr
|
|
|
+ btsl $_EFER_LME, %eax
|
|
|
+ wrmsr
|
|
|
+
|
|
|
+ xorl %eax, %eax
|
|
|
+ lldt %ax
|
|
|
+
|
|
|
+ movl 48(%esp), %eax
|
|
|
+ pushl $__KERNEL_CS
|
|
|
+ pushl %eax
|
|
|
+
|
|
|
+ /* Enable paging */
|
|
|
+ movl %cr0, %eax
|
|
|
+ btsl $X86_CR0_PG_BIT, %eax
|
|
|
+ movl %eax, %cr0
|
|
|
+ lret
|
|
|
+ENDPROC(efi_enter32)
|
|
|
+
|
|
|
+ .data
|
|
|
+ .balign 8
|
|
|
+ .global efi32_boot_gdt
|
|
|
+efi32_boot_gdt: .word 0
|
|
|
+ .quad 0
|
|
|
+
|
|
|
+save_gdt: .word 0
|
|
|
+ .quad 0
|
|
|
+func_rt_ptr: .quad 0
|
|
|
+
|
|
|
+ .global efi_gdt64
|
|
|
+efi_gdt64:
|
|
|
+ .word efi_gdt64_end - efi_gdt64
|
|
|
+ .long 0 /* Filled out by user */
|
|
|
+ .word 0
|
|
|
+ .quad 0x0000000000000000 /* NULL descriptor */
|
|
|
+ .quad 0x00af9a000000ffff /* __KERNEL_CS */
|
|
|
+ .quad 0x00cf92000000ffff /* __KERNEL_DS */
|
|
|
+ .quad 0x0080890000000000 /* TS descriptor */
|
|
|
+ .quad 0x0000000000000000 /* TS continued */
|
|
|
+efi_gdt64_end:
|
|
|
+#endif /* CONFIG_EFI_MIXED */
|
|
|
+
|
|
|
.data
|
|
|
ENTRY(efi_scratch)
|
|
|
.fill 3,8,0
|