123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153 |
- /*
- * 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 <asm/page_types.h>
- #include <asm/segment.h>
- .text
- .code64
- ENTRY(efi64_thunk)
- push %rbp
- push %rbx
- /*
- * Switch to 1:1 mapped 32-bit stack pointer.
- */
- movq %rsp, efi_saved_sp(%rip)
- movq efi_scratch+25(%rip), %rsp
- /*
- * Calculate the physical address of the kernel text.
- */
- movq $__START_KERNEL_map, %rax
- subq phys_base(%rip), %rax
- /*
- * Push some physical addresses onto the stack. This is easier
- * to do now in a code64 section while the assembler can address
- * 64-bit values. Note that all the addresses on the stack are
- * 32-bit.
- */
- subq $16, %rsp
- leaq efi_exit32(%rip), %rbx
- subq %rax, %rbx
- movl %ebx, 8(%rsp)
- leaq __efi64_thunk(%rip), %rbx
- subq %rax, %rbx
- call *%rbx
- movq efi_saved_sp(%rip), %rsp
- pop %rbx
- pop %rbp
- retq
- ENDPROC(efi64_thunk)
- /*
- * 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
|