linux/arch/x86/boot/compressed/efi_stub_32.S
<<
>>
Prefs
   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
  27ENTRY(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
  411:      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
  681:      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
  80ENDPROC(efi_call_phys)
  81.previous
  82
  83.data
  84saved_return_addr:
  85        .long 0
  86efi_rt_function_ptr:
  87        .long 0
  88