root/arch/x86/platform/efi/efi_thunk_64.S

/* [<][>][^][v][top][bottom][index][help] */
   1 /* SPDX-License-Identifier: GPL-2.0 */
   2 /*
   3  * Copyright (C) 2014 Intel Corporation; author Matt Fleming
   4  *
   5  * Support for invoking 32-bit EFI runtime services from a 64-bit
   6  * kernel.
   7  *
   8  * The below thunking functions are only used after ExitBootServices()
   9  * has been called. This simplifies things considerably as compared with
  10  * the early EFI thunking because we can leave all the kernel state
  11  * intact (GDT, IDT, etc) and simply invoke the the 32-bit EFI runtime
  12  * services from __KERNEL32_CS. This means we can continue to service
  13  * interrupts across an EFI mixed mode call.
  14  *
  15  * We do however, need to handle the fact that we're running in a full
  16  * 64-bit virtual address space. Things like the stack and instruction
  17  * addresses need to be accessible by the 32-bit firmware, so we rely on
  18  * using the identity mappings in the EFI page table to access the stack
  19  * and kernel text (see efi_setup_page_tables()).
  20  */
  21 
  22 #include <linux/linkage.h>
  23 #include <asm/page_types.h>
  24 #include <asm/segment.h>
  25 
  26         .text
  27         .code64
  28 ENTRY(efi64_thunk)
  29         push    %rbp
  30         push    %rbx
  31 
  32         /*
  33          * Switch to 1:1 mapped 32-bit stack pointer.
  34          */
  35         movq    %rsp, efi_saved_sp(%rip)
  36         movq    efi_scratch(%rip), %rsp
  37 
  38         /*
  39          * Calculate the physical address of the kernel text.
  40          */
  41         movq    $__START_KERNEL_map, %rax
  42         subq    phys_base(%rip), %rax
  43 
  44         /*
  45          * Push some physical addresses onto the stack. This is easier
  46          * to do now in a code64 section while the assembler can address
  47          * 64-bit values. Note that all the addresses on the stack are
  48          * 32-bit.
  49          */
  50         subq    $16, %rsp
  51         leaq    efi_exit32(%rip), %rbx
  52         subq    %rax, %rbx
  53         movl    %ebx, 8(%rsp)
  54 
  55         leaq    __efi64_thunk(%rip), %rbx
  56         subq    %rax, %rbx
  57         call    *%rbx
  58 
  59         movq    efi_saved_sp(%rip), %rsp
  60         pop     %rbx
  61         pop     %rbp
  62         retq
  63 ENDPROC(efi64_thunk)
  64 
  65 /*
  66  * We run this function from the 1:1 mapping.
  67  *
  68  * This function must be invoked with a 1:1 mapped stack.
  69  */
  70 ENTRY(__efi64_thunk)
  71         movl    %ds, %eax
  72         push    %rax
  73         movl    %es, %eax
  74         push    %rax
  75         movl    %ss, %eax
  76         push    %rax
  77 
  78         subq    $32, %rsp
  79         movl    %esi, 0x0(%rsp)
  80         movl    %edx, 0x4(%rsp)
  81         movl    %ecx, 0x8(%rsp)
  82         movq    %r8, %rsi
  83         movl    %esi, 0xc(%rsp)
  84         movq    %r9, %rsi
  85         movl    %esi,  0x10(%rsp)
  86 
  87         leaq    1f(%rip), %rbx
  88         movq    %rbx, func_rt_ptr(%rip)
  89 
  90         /* Switch to 32-bit descriptor */
  91         pushq   $__KERNEL32_CS
  92         leaq    efi_enter32(%rip), %rax
  93         pushq   %rax
  94         lretq
  95 
  96 1:      addq    $32, %rsp
  97 
  98         pop     %rbx
  99         movl    %ebx, %ss
 100         pop     %rbx
 101         movl    %ebx, %es
 102         pop     %rbx
 103         movl    %ebx, %ds
 104 
 105         /*
 106          * Convert 32-bit status code into 64-bit.
 107          */
 108         test    %rax, %rax
 109         jz      1f
 110         movl    %eax, %ecx
 111         andl    $0x0fffffff, %ecx
 112         andl    $0xf0000000, %eax
 113         shl     $32, %rax
 114         or      %rcx, %rax
 115 1:
 116         ret
 117 ENDPROC(__efi64_thunk)
 118 
 119 ENTRY(efi_exit32)
 120         movq    func_rt_ptr(%rip), %rax
 121         push    %rax
 122         mov     %rdi, %rax
 123         ret
 124 ENDPROC(efi_exit32)
 125 
 126         .code32
 127 /*
 128  * EFI service pointer must be in %edi.
 129  *
 130  * The stack should represent the 32-bit calling convention.
 131  */
 132 ENTRY(efi_enter32)
 133         movl    $__KERNEL_DS, %eax
 134         movl    %eax, %ds
 135         movl    %eax, %es
 136         movl    %eax, %ss
 137 
 138         call    *%edi
 139 
 140         /* We must preserve return value */
 141         movl    %eax, %edi
 142 
 143         movl    72(%esp), %eax
 144         pushl   $__KERNEL_CS
 145         pushl   %eax
 146 
 147         lret
 148 ENDPROC(efi_enter32)
 149 
 150         .data
 151         .balign 8
 152 func_rt_ptr:            .quad 0
 153 efi_saved_sp:           .quad 0

/* [<][>][^][v][top][bottom][index][help] */