Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/x86/platform/efi/efi_stub_32.S
10820 views
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/linkage.h>
9
#include <asm/page_types.h>
10
11
/*
12
* efi_call_phys(void *, ...) is a function with variable parameters.
13
* All the callers of this function assure that all the parameters are 4-bytes.
14
*/
15
16
/*
17
* In gcc calling convention, EBX, ESP, EBP, ESI and EDI are all callee save.
18
* So we'd better save all of them at the beginning of this function and restore
19
* at the end no matter how many we use, because we can not assure EFI runtime
20
* service functions will comply with gcc calling convention, too.
21
*/
22
23
.text
24
ENTRY(efi_call_phys)
25
/*
26
* 0. The function can only be called in Linux kernel. So CS has been
27
* set to 0x0010, DS and SS have been set to 0x0018. In EFI, I found
28
* the values of these registers are the same. And, the corresponding
29
* GDT entries are identical. So I will do nothing about segment reg
30
* and GDT, but change GDT base register in prelog and epilog.
31
*/
32
33
/*
34
* 1. Now I am running with EIP = <physical address> + PAGE_OFFSET.
35
* But to make it smoothly switch from virtual mode to flat mode.
36
* The mapping of lower virtual memory has been created in prelog and
37
* epilog.
38
*/
39
movl $1f, %edx
40
subl $__PAGE_OFFSET, %edx
41
jmp *%edx
42
1:
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 %edx
51
movl %edx, saved_return_addr
52
/* get the function pointer into ECX*/
53
popl %ecx
54
movl %ecx, efi_rt_function_ptr
55
movl $2f, %edx
56
subl $__PAGE_OFFSET, %edx
57
pushl %edx
58
59
/*
60
* 3. Clear PG bit in %CR0.
61
*/
62
movl %cr0, %edx
63
andl $0x7fffffff, %edx
64
movl %edx, %cr0
65
jmp 1f
66
1:
67
68
/*
69
* 4. Adjust stack pointer.
70
*/
71
subl $__PAGE_OFFSET, %esp
72
73
/*
74
* 5. Call the physical function.
75
*/
76
jmp *%ecx
77
78
2:
79
/*
80
* 6. After EFI runtime service returns, control will return to
81
* following instruction. We'd better readjust stack pointer first.
82
*/
83
addl $__PAGE_OFFSET, %esp
84
85
/*
86
* 7. Restore PG bit
87
*/
88
movl %cr0, %edx
89
orl $0x80000000, %edx
90
movl %edx, %cr0
91
jmp 1f
92
1:
93
/*
94
* 8. Now restore the virtual mode from flat mode by
95
* adding EIP with PAGE_OFFSET.
96
*/
97
movl $1f, %edx
98
jmp *%edx
99
1:
100
101
/*
102
* 9. Balance the stack. And because EAX contain the return value,
103
* we'd better not clobber it.
104
*/
105
leal efi_rt_function_ptr, %edx
106
movl (%edx), %ecx
107
pushl %ecx
108
109
/*
110
* 10. Push the saved return address onto the stack and return.
111
*/
112
leal saved_return_addr, %edx
113
movl (%edx), %ecx
114
pushl %ecx
115
ret
116
ENDPROC(efi_call_phys)
117
.previous
118
119
.data
120
saved_return_addr:
121
.long 0
122
efi_rt_function_ptr:
123
.long 0
124
125