root/arch/x86/boot/compressed/efi_stub_32.S

/* [<][>][^][v][top][bottom][index][help] */
   1 /* SPDX-License-Identifier: GPL-2.0 */
   2 /*
   3  * EFI call stub for IA32.
   4  *
   5  * This stub allows us to make EFI calls in physical mode with interrupts
   6  * turned off. Note that this implementation is different from the one in
   7  * arch/x86/platform/efi/efi_stub_32.S because we're _already_ in physical
   8  * mode at this point.
   9  */
  10 
  11 #include <linux/linkage.h>
  12 #include <asm/page_types.h>
  13 
  14 /*
  15  * efi_call_phys(void *, ...) is a function with variable parameters.
  16  * All the callers of this function assure that all the parameters are 4-bytes.
  17  */
  18 
  19 /*
  20  * In gcc calling convention, EBX, ESP, EBP, ESI and EDI are all callee save.
  21  * So we'd better save all of them at the beginning of this function and restore
  22  * at the end no matter how many we use, because we can not assure EFI runtime
  23  * service functions will comply with gcc calling convention, too.
  24  */
  25 
  26 .text
  27 ENTRY(efi_call_phys)
  28         /*
  29          * 0. The function can only be called in Linux kernel. So CS has been
  30          * set to 0x0010, DS and SS have been set to 0x0018. In EFI, I found
  31          * the values of these registers are the same. And, the corresponding
  32          * GDT entries are identical. So I will do nothing about segment reg
  33          * and GDT, but change GDT base register in prelog and epilog.
  34          */
  35 
  36         /*
  37          * 1. Because we haven't been relocated by this point we need to
  38          * use relative addressing.
  39          */
  40         call    1f
  41 1:      popl    %edx
  42         subl    $1b, %edx
  43 
  44         /*
  45          * 2. Now on the top of stack is the return
  46          * address in the caller of efi_call_phys(), then parameter 1,
  47          * parameter 2, ..., param n. To make things easy, we save the return
  48          * address of efi_call_phys in a global variable.
  49          */
  50         popl    %ecx
  51         movl    %ecx, saved_return_addr(%edx)
  52         /* get the function pointer into ECX*/
  53         popl    %ecx
  54         movl    %ecx, efi_rt_function_ptr(%edx)
  55 
  56         /*
  57          * 3. Call the physical function.
  58          */
  59         call    *%ecx
  60 
  61         /*
  62          * 4. Balance the stack. And because EAX contain the return value,
  63          * we'd better not clobber it. We need to calculate our address
  64          * again because %ecx and %edx are not preserved across EFI function
  65          * calls.
  66          */
  67         call    1f
  68 1:      popl    %edx
  69         subl    $1b, %edx
  70 
  71         movl    efi_rt_function_ptr(%edx), %ecx
  72         pushl   %ecx
  73 
  74         /*
  75          * 10. Push the saved return address onto the stack and return.
  76          */
  77         movl    saved_return_addr(%edx), %ecx
  78         pushl   %ecx
  79         ret
  80 ENDPROC(efi_call_phys)
  81 .previous
  82 
  83 .data
  84 saved_return_addr:
  85         .long 0
  86 efi_rt_function_ptr:
  87         .long 0

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