|
@@ -1,9 +1,26 @@
|
|
/*
|
|
/*
|
|
* Copyright (C) 2014 Intel Corporation; author Matt Fleming
|
|
* Copyright (C) 2014 Intel Corporation; author Matt Fleming
|
|
|
|
+ *
|
|
|
|
+ * Support for invoking 32-bit EFI runtime services from a 64-bit
|
|
|
|
+ * kernel.
|
|
|
|
+ *
|
|
|
|
+ * The below thunking functions are only used after ExitBootServices()
|
|
|
|
+ * has been called. This simplifies things considerably as compared with
|
|
|
|
+ * the early EFI thunking because we can leave all the kernel state
|
|
|
|
+ * intact (GDT, IDT, etc) and simply invoke the the 32-bit EFI runtime
|
|
|
|
+ * services from __KERNEL32_CS. This means we can continue to service
|
|
|
|
+ * interrupts across an EFI mixed mode call.
|
|
|
|
+ *
|
|
|
|
+ * We do however, need to handle the fact that we're running in a full
|
|
|
|
+ * 64-bit virtual address space. Things like the stack and instruction
|
|
|
|
+ * addresses need to be accessible by the 32-bit firmware, so we rely on
|
|
|
|
+ * using the identity mappings in the EFI page table to access the stack
|
|
|
|
+ * and kernel text (see efi_setup_page_tables()).
|
|
*/
|
|
*/
|
|
|
|
|
|
#include <linux/linkage.h>
|
|
#include <linux/linkage.h>
|
|
#include <asm/page_types.h>
|
|
#include <asm/page_types.h>
|
|
|
|
+#include <asm/segment.h>
|
|
|
|
|
|
.text
|
|
.text
|
|
.code64
|
|
.code64
|
|
@@ -33,14 +50,6 @@ ENTRY(efi64_thunk)
|
|
leaq efi_exit32(%rip), %rbx
|
|
leaq efi_exit32(%rip), %rbx
|
|
subq %rax, %rbx
|
|
subq %rax, %rbx
|
|
movl %ebx, 8(%rsp)
|
|
movl %ebx, 8(%rsp)
|
|
- leaq efi_gdt64(%rip), %rbx
|
|
|
|
- subq %rax, %rbx
|
|
|
|
- movl %ebx, 2(%ebx)
|
|
|
|
- movl %ebx, 4(%rsp)
|
|
|
|
- leaq efi_gdt32(%rip), %rbx
|
|
|
|
- subq %rax, %rbx
|
|
|
|
- movl %ebx, 2(%ebx)
|
|
|
|
- movl %ebx, (%rsp)
|
|
|
|
|
|
|
|
leaq __efi64_thunk(%rip), %rbx
|
|
leaq __efi64_thunk(%rip), %rbx
|
|
subq %rax, %rbx
|
|
subq %rax, %rbx
|
|
@@ -52,14 +61,92 @@ ENTRY(efi64_thunk)
|
|
retq
|
|
retq
|
|
ENDPROC(efi64_thunk)
|
|
ENDPROC(efi64_thunk)
|
|
|
|
|
|
- .data
|
|
|
|
-efi_gdt32:
|
|
|
|
- .word efi_gdt32_end - efi_gdt32
|
|
|
|
- .long 0 /* Filled out above */
|
|
|
|
- .word 0
|
|
|
|
- .quad 0x0000000000000000 /* NULL descriptor */
|
|
|
|
- .quad 0x00cf9a000000ffff /* __KERNEL_CS */
|
|
|
|
- .quad 0x00cf93000000ffff /* __KERNEL_DS */
|
|
|
|
-efi_gdt32_end:
|
|
|
|
|
|
+/*
|
|
|
|
+ * We run this function from the 1:1 mapping.
|
|
|
|
+ *
|
|
|
|
+ * This function must be invoked with a 1:1 mapped stack.
|
|
|
|
+ */
|
|
|
|
+ENTRY(__efi64_thunk)
|
|
|
|
+ movl %ds, %eax
|
|
|
|
+ push %rax
|
|
|
|
+ movl %es, %eax
|
|
|
|
+ push %rax
|
|
|
|
+ movl %ss, %eax
|
|
|
|
+ push %rax
|
|
|
|
+
|
|
|
|
+ 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)
|
|
|
|
+
|
|
|
|
+ leaq 1f(%rip), %rbx
|
|
|
|
+ movq %rbx, func_rt_ptr(%rip)
|
|
|
|
+
|
|
|
|
+ /* Switch to 32-bit descriptor */
|
|
|
|
+ pushq $__KERNEL32_CS
|
|
|
|
+ leaq efi_enter32(%rip), %rax
|
|
|
|
+ pushq %rax
|
|
|
|
+ lretq
|
|
|
|
+
|
|
|
|
+1: addq $32, %rsp
|
|
|
|
+
|
|
|
|
+ pop %rbx
|
|
|
|
+ movl %ebx, %ss
|
|
|
|
+ pop %rbx
|
|
|
|
+ movl %ebx, %es
|
|
|
|
+ pop %rbx
|
|
|
|
+ movl %ebx, %ds
|
|
|
|
|
|
|
|
+ /*
|
|
|
|
+ * 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)
|
|
|
|
+ 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
|
|
|
|
+
|
|
|
|
+ call *%edi
|
|
|
|
+
|
|
|
|
+ /* We must preserve return value */
|
|
|
|
+ movl %eax, %edi
|
|
|
|
+
|
|
|
|
+ movl 72(%esp), %eax
|
|
|
|
+ pushl $__KERNEL_CS
|
|
|
|
+ pushl %eax
|
|
|
|
+
|
|
|
|
+ lret
|
|
|
|
+ENDPROC(efi_enter32)
|
|
|
|
+
|
|
|
|
+ .data
|
|
|
|
+ .balign 8
|
|
|
|
+func_rt_ptr: .quad 0
|
|
efi_saved_sp: .quad 0
|
|
efi_saved_sp: .quad 0
|