aboutsummaryrefslogtreecommitdiffstats
path: root/arch/i386/kernel/efi_stub.S
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/i386/kernel/efi_stub.S
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
Diffstat (limited to 'arch/i386/kernel/efi_stub.S')
-rw-r--r--arch/i386/kernel/efi_stub.S124
1 files changed, 124 insertions, 0 deletions
diff --git a/arch/i386/kernel/efi_stub.S b/arch/i386/kernel/efi_stub.S
new file mode 100644
index 000000000000..08c0312d9b6c
--- /dev/null
+++ b/arch/i386/kernel/efi_stub.S
@@ -0,0 +1,124 @@
1/*
2 * EFI call stub for IA32.
3 *
4 * This stub allows us to make EFI calls in physical mode with interrupts
5 * turned off.
6 */
7
8#include <linux/config.h>
9#include <linux/linkage.h>
10#include <asm/page.h>
11#include <asm/pgtable.h>
12
13/*
14 * efi_call_phys(void *, ...) is a function with variable parameters.
15 * All the callers of this function assure that all the parameters are 4-bytes.
16 */
17
18/*
19 * In gcc calling convention, EBX, ESP, EBP, ESI and EDI are all callee save.
20 * So we'd better save all of them at the beginning of this function and restore
21 * at the end no matter how many we use, because we can not assure EFI runtime
22 * service functions will comply with gcc calling convention, too.
23 */
24
25.text
26ENTRY(efi_call_phys)
27 /*
28 * 0. The function can only be called in Linux kernel. So CS has been
29 * set to 0x0010, DS and SS have been set to 0x0018. In EFI, I found
30 * the values of these registers are the same. And, the corresponding
31 * GDT entries are identical. So I will do nothing about segment reg
32 * and GDT, but change GDT base register in prelog and epilog.
33 */
34
35 /*
36 * 1. Now I am running with EIP = <physical address> + PAGE_OFFSET.
37 * But to make it smoothly switch from virtual mode to flat mode.
38 * The mapping of lower virtual memory has been created in prelog and
39 * epilog.
40 */
41 movl $1f, %edx
42 subl $__PAGE_OFFSET, %edx
43 jmp *%edx
441:
45
46 /*
47 * 2. Now on the top of stack is the return
48 * address in the caller of efi_call_phys(), then parameter 1,
49 * parameter 2, ..., param n. To make things easy, we save the return
50 * address of efi_call_phys in a global variable.
51 */
52 popl %edx
53 movl %edx, saved_return_addr
54 /* get the function pointer into ECX*/
55 popl %ecx
56 movl %ecx, efi_rt_function_ptr
57 movl $2f, %edx
58 subl $__PAGE_OFFSET, %edx
59 pushl %edx
60
61 /*
62 * 3. Clear PG bit in %CR0.
63 */
64 movl %cr0, %edx
65 andl $0x7fffffff, %edx
66 movl %edx, %cr0
67 jmp 1f
681:
69
70 /*
71 * 4. Adjust stack pointer.
72 */
73 subl $__PAGE_OFFSET, %esp
74
75 /*
76 * 5. Call the physical function.
77 */
78 jmp *%ecx
79
802:
81 /*
82 * 6. After EFI runtime service returns, control will return to
83 * following instruction. We'd better readjust stack pointer first.
84 */
85 addl $__PAGE_OFFSET, %esp
86
87 /*
88 * 7. Restore PG bit
89 */
90 movl %cr0, %edx
91 orl $0x80000000, %edx
92 movl %edx, %cr0
93 jmp 1f
941:
95 /*
96 * 8. Now restore the virtual mode from flat mode by
97 * adding EIP with PAGE_OFFSET.
98 */
99 movl $1f, %edx
100 jmp *%edx
1011:
102
103 /*
104 * 9. Balance the stack. And because EAX contain the return value,
105 * we'd better not clobber it.
106 */
107 leal efi_rt_function_ptr, %edx
108 movl (%edx), %ecx
109 pushl %ecx
110
111 /*
112 * 10. Push the saved return address onto the stack and return.
113 */
114 leal saved_return_addr, %edx
115 movl (%edx), %ecx
116 pushl %ecx
117 ret
118.previous
119
120.data
121saved_return_addr:
122 .long 0
123efi_rt_function_ptr:
124 .long 0