Path: blob/master/arch/x86/platform/efi/efi_stub_32.S
10820 views
/*1* EFI call stub for IA32.2*3* This stub allows us to make EFI calls in physical mode with interrupts4* turned off.5*/67#include <linux/linkage.h>8#include <asm/page_types.h>910/*11* efi_call_phys(void *, ...) is a function with variable parameters.12* All the callers of this function assure that all the parameters are 4-bytes.13*/1415/*16* In gcc calling convention, EBX, ESP, EBP, ESI and EDI are all callee save.17* So we'd better save all of them at the beginning of this function and restore18* at the end no matter how many we use, because we can not assure EFI runtime19* service functions will comply with gcc calling convention, too.20*/2122.text23ENTRY(efi_call_phys)24/*25* 0. The function can only be called in Linux kernel. So CS has been26* set to 0x0010, DS and SS have been set to 0x0018. In EFI, I found27* the values of these registers are the same. And, the corresponding28* GDT entries are identical. So I will do nothing about segment reg29* and GDT, but change GDT base register in prelog and epilog.30*/3132/*33* 1. Now I am running with EIP = <physical address> + PAGE_OFFSET.34* But to make it smoothly switch from virtual mode to flat mode.35* The mapping of lower virtual memory has been created in prelog and36* epilog.37*/38movl $1f, %edx39subl $__PAGE_OFFSET, %edx40jmp *%edx411:4243/*44* 2. Now on the top of stack is the return45* address in the caller of efi_call_phys(), then parameter 1,46* parameter 2, ..., param n. To make things easy, we save the return47* address of efi_call_phys in a global variable.48*/49popl %edx50movl %edx, saved_return_addr51/* get the function pointer into ECX*/52popl %ecx53movl %ecx, efi_rt_function_ptr54movl $2f, %edx55subl $__PAGE_OFFSET, %edx56pushl %edx5758/*59* 3. Clear PG bit in %CR0.60*/61movl %cr0, %edx62andl $0x7fffffff, %edx63movl %edx, %cr064jmp 1f651:6667/*68* 4. Adjust stack pointer.69*/70subl $__PAGE_OFFSET, %esp7172/*73* 5. Call the physical function.74*/75jmp *%ecx76772:78/*79* 6. After EFI runtime service returns, control will return to80* following instruction. We'd better readjust stack pointer first.81*/82addl $__PAGE_OFFSET, %esp8384/*85* 7. Restore PG bit86*/87movl %cr0, %edx88orl $0x80000000, %edx89movl %edx, %cr090jmp 1f911:92/*93* 8. Now restore the virtual mode from flat mode by94* adding EIP with PAGE_OFFSET.95*/96movl $1f, %edx97jmp *%edx981:99100/*101* 9. Balance the stack. And because EAX contain the return value,102* we'd better not clobber it.103*/104leal efi_rt_function_ptr, %edx105movl (%edx), %ecx106pushl %ecx107108/*109* 10. Push the saved return address onto the stack and return.110*/111leal saved_return_addr, %edx112movl (%edx), %ecx113pushl %ecx114ret115ENDPROC(efi_call_phys)116.previous117118.data119saved_return_addr:120.long 0121efi_rt_function_ptr:122.long 0123124125