Commit | Line | Data |
---|---|---|
5b83683f HY |
1 | /* |
2 | * Function calling ABI conversion from Linux to EFI for x86_64 | |
3 | * | |
4 | * Copyright (C) 2007 Intel Corp | |
5 | * Bibo Mao <bibo.mao@intel.com> | |
6 | * Huang Ying <ying.huang@intel.com> | |
7 | */ | |
8 | ||
9 | #include <linux/linkage.h> | |
0154416a MF |
10 | #include <asm/segment.h> |
11 | #include <asm/msr.h> | |
12 | #include <asm/processor-flags.h> | |
13 | #include <asm/page_types.h> | |
5b83683f HY |
14 | |
15 | #define SAVE_XMM \ | |
16 | mov %rsp, %rax; \ | |
17 | subq $0x70, %rsp; \ | |
18 | and $~0xf, %rsp; \ | |
19 | mov %rax, (%rsp); \ | |
20 | mov %cr0, %rax; \ | |
21 | clts; \ | |
22 | mov %rax, 0x8(%rsp); \ | |
23 | movaps %xmm0, 0x60(%rsp); \ | |
24 | movaps %xmm1, 0x50(%rsp); \ | |
25 | movaps %xmm2, 0x40(%rsp); \ | |
26 | movaps %xmm3, 0x30(%rsp); \ | |
27 | movaps %xmm4, 0x20(%rsp); \ | |
28 | movaps %xmm5, 0x10(%rsp) | |
29 | ||
30 | #define RESTORE_XMM \ | |
31 | movaps 0x60(%rsp), %xmm0; \ | |
32 | movaps 0x50(%rsp), %xmm1; \ | |
33 | movaps 0x40(%rsp), %xmm2; \ | |
34 | movaps 0x30(%rsp), %xmm3; \ | |
35 | movaps 0x20(%rsp), %xmm4; \ | |
36 | movaps 0x10(%rsp), %xmm5; \ | |
37 | mov 0x8(%rsp), %rsi; \ | |
38 | mov %rsi, %cr0; \ | |
39 | mov (%rsp), %rsp | |
40 | ||
d2f7cbe7 BP |
41 | /* stolen from gcc */ |
42 | .macro FLUSH_TLB_ALL | |
43 | movq %r15, efi_scratch(%rip) | |
44 | movq %r14, efi_scratch+8(%rip) | |
45 | movq %cr4, %r15 | |
46 | movq %r15, %r14 | |
47 | andb $0x7f, %r14b | |
48 | movq %r14, %cr4 | |
49 | movq %r15, %cr4 | |
50 | movq efi_scratch+8(%rip), %r14 | |
51 | movq efi_scratch(%rip), %r15 | |
52 | .endm | |
53 | ||
54 | .macro SWITCH_PGT | |
55 | cmpb $0, efi_scratch+24(%rip) | |
56 | je 1f | |
57 | movq %r15, efi_scratch(%rip) # r15 | |
58 | # save previous CR3 | |
59 | movq %cr3, %r15 | |
60 | movq %r15, efi_scratch+8(%rip) # prev_cr3 | |
61 | movq efi_scratch+16(%rip), %r15 # EFI pgt | |
62 | movq %r15, %cr3 | |
63 | 1: | |
64 | .endm | |
65 | ||
66 | .macro RESTORE_PGT | |
67 | cmpb $0, efi_scratch+24(%rip) | |
68 | je 2f | |
69 | movq efi_scratch+8(%rip), %r15 | |
70 | movq %r15, %cr3 | |
71 | movq efi_scratch(%rip), %r15 | |
72 | FLUSH_TLB_ALL | |
73 | 2: | |
74 | .endm | |
75 | ||
5b83683f HY |
76 | ENTRY(efi_call0) |
77 | SAVE_XMM | |
78 | subq $32, %rsp | |
d2f7cbe7 | 79 | SWITCH_PGT |
5b83683f | 80 | call *%rdi |
d2f7cbe7 | 81 | RESTORE_PGT |
5b83683f HY |
82 | addq $32, %rsp |
83 | RESTORE_XMM | |
84 | ret | |
9f331119 | 85 | ENDPROC(efi_call0) |
5b83683f HY |
86 | |
87 | ENTRY(efi_call1) | |
88 | SAVE_XMM | |
89 | subq $32, %rsp | |
90 | mov %rsi, %rcx | |
d2f7cbe7 | 91 | SWITCH_PGT |
5b83683f | 92 | call *%rdi |
d2f7cbe7 | 93 | RESTORE_PGT |
5b83683f HY |
94 | addq $32, %rsp |
95 | RESTORE_XMM | |
96 | ret | |
9f331119 | 97 | ENDPROC(efi_call1) |
5b83683f HY |
98 | |
99 | ENTRY(efi_call2) | |
100 | SAVE_XMM | |
101 | subq $32, %rsp | |
102 | mov %rsi, %rcx | |
d2f7cbe7 | 103 | SWITCH_PGT |
5b83683f | 104 | call *%rdi |
d2f7cbe7 | 105 | RESTORE_PGT |
5b83683f HY |
106 | addq $32, %rsp |
107 | RESTORE_XMM | |
108 | ret | |
9f331119 | 109 | ENDPROC(efi_call2) |
5b83683f HY |
110 | |
111 | ENTRY(efi_call3) | |
112 | SAVE_XMM | |
113 | subq $32, %rsp | |
114 | mov %rcx, %r8 | |
115 | mov %rsi, %rcx | |
d2f7cbe7 | 116 | SWITCH_PGT |
5b83683f | 117 | call *%rdi |
d2f7cbe7 | 118 | RESTORE_PGT |
5b83683f HY |
119 | addq $32, %rsp |
120 | RESTORE_XMM | |
121 | ret | |
9f331119 | 122 | ENDPROC(efi_call3) |
5b83683f HY |
123 | |
124 | ENTRY(efi_call4) | |
125 | SAVE_XMM | |
126 | subq $32, %rsp | |
127 | mov %r8, %r9 | |
128 | mov %rcx, %r8 | |
129 | mov %rsi, %rcx | |
d2f7cbe7 | 130 | SWITCH_PGT |
5b83683f | 131 | call *%rdi |
d2f7cbe7 | 132 | RESTORE_PGT |
5b83683f HY |
133 | addq $32, %rsp |
134 | RESTORE_XMM | |
135 | ret | |
9f331119 | 136 | ENDPROC(efi_call4) |
5b83683f HY |
137 | |
138 | ENTRY(efi_call5) | |
139 | SAVE_XMM | |
140 | subq $48, %rsp | |
141 | mov %r9, 32(%rsp) | |
142 | mov %r8, %r9 | |
143 | mov %rcx, %r8 | |
144 | mov %rsi, %rcx | |
d2f7cbe7 | 145 | SWITCH_PGT |
5b83683f | 146 | call *%rdi |
d2f7cbe7 | 147 | RESTORE_PGT |
5b83683f HY |
148 | addq $48, %rsp |
149 | RESTORE_XMM | |
150 | ret | |
9f331119 | 151 | ENDPROC(efi_call5) |
5b83683f HY |
152 | |
153 | ENTRY(efi_call6) | |
154 | SAVE_XMM | |
155 | mov (%rsp), %rax | |
156 | mov 8(%rax), %rax | |
157 | subq $48, %rsp | |
158 | mov %r9, 32(%rsp) | |
159 | mov %rax, 40(%rsp) | |
160 | mov %r8, %r9 | |
161 | mov %rcx, %r8 | |
162 | mov %rsi, %rcx | |
d2f7cbe7 | 163 | SWITCH_PGT |
5b83683f | 164 | call *%rdi |
d2f7cbe7 | 165 | RESTORE_PGT |
5b83683f HY |
166 | addq $48, %rsp |
167 | RESTORE_XMM | |
168 | ret | |
9f331119 | 169 | ENDPROC(efi_call6) |
d2f7cbe7 | 170 | |
0154416a MF |
171 | #ifdef CONFIG_EFI_MIXED |
172 | ||
173 | /* | |
174 | * We run this function from the 1:1 mapping. | |
175 | * | |
176 | * This function must be invoked with a 1:1 mapped stack. | |
177 | */ | |
178 | ENTRY(__efi64_thunk) | |
e10848a2 MF |
179 | movl %ds, %eax |
180 | push %rax | |
181 | movl %es, %eax | |
182 | push %rax | |
183 | movl %ss, %eax | |
184 | push %rax | |
185 | ||
0154416a MF |
186 | subq $32, %rsp |
187 | movl %esi, 0x0(%rsp) | |
188 | movl %edx, 0x4(%rsp) | |
189 | movl %ecx, 0x8(%rsp) | |
190 | movq %r8, %rsi | |
191 | movl %esi, 0xc(%rsp) | |
192 | movq %r9, %rsi | |
193 | movl %esi, 0x10(%rsp) | |
194 | ||
195 | sgdt save_gdt(%rip) | |
196 | ||
197 | leaq 1f(%rip), %rbx | |
198 | movq %rbx, func_rt_ptr(%rip) | |
199 | ||
200 | /* Switch to gdt with 32-bit segments */ | |
e10848a2 | 201 | movl 64(%rsp), %eax |
0154416a MF |
202 | lgdt (%rax) |
203 | ||
204 | leaq efi_enter32(%rip), %rax | |
205 | pushq $__KERNEL_CS | |
206 | pushq %rax | |
207 | lretq | |
208 | ||
209 | 1: addq $32, %rsp | |
210 | ||
211 | lgdt save_gdt(%rip) | |
212 | ||
e10848a2 MF |
213 | pop %rbx |
214 | movl %ebx, %ss | |
215 | pop %rbx | |
216 | movl %ebx, %es | |
217 | pop %rbx | |
218 | movl %ebx, %ds | |
219 | ||
0154416a MF |
220 | /* |
221 | * Convert 32-bit status code into 64-bit. | |
222 | */ | |
223 | test %rax, %rax | |
224 | jz 1f | |
225 | movl %eax, %ecx | |
226 | andl $0x0fffffff, %ecx | |
227 | andl $0xf0000000, %eax | |
228 | shl $32, %rax | |
229 | or %rcx, %rax | |
230 | 1: | |
231 | ret | |
232 | ENDPROC(__efi64_thunk) | |
233 | ||
234 | ENTRY(efi_exit32) | |
0154416a MF |
235 | movq func_rt_ptr(%rip), %rax |
236 | push %rax | |
237 | mov %rdi, %rax | |
238 | ret | |
239 | ENDPROC(efi_exit32) | |
240 | ||
241 | .code32 | |
242 | /* | |
243 | * EFI service pointer must be in %edi. | |
244 | * | |
245 | * The stack should represent the 32-bit calling convention. | |
246 | */ | |
247 | ENTRY(efi_enter32) | |
248 | movl $__KERNEL_DS, %eax | |
249 | movl %eax, %ds | |
250 | movl %eax, %es | |
251 | movl %eax, %ss | |
252 | ||
253 | /* Reload pgtables */ | |
254 | movl %cr3, %eax | |
255 | movl %eax, %cr3 | |
256 | ||
257 | /* Disable paging */ | |
258 | movl %cr0, %eax | |
259 | btrl $X86_CR0_PG_BIT, %eax | |
260 | movl %eax, %cr0 | |
261 | ||
262 | /* Disable long mode via EFER */ | |
263 | movl $MSR_EFER, %ecx | |
264 | rdmsr | |
265 | btrl $_EFER_LME, %eax | |
266 | wrmsr | |
267 | ||
268 | call *%edi | |
269 | ||
270 | /* We must preserve return value */ | |
271 | movl %eax, %edi | |
272 | ||
18c46461 MF |
273 | /* |
274 | * Some firmware will return with interrupts enabled. Be sure to | |
275 | * disable them before we switch GDTs. | |
276 | */ | |
277 | cli | |
278 | ||
e10848a2 | 279 | movl 68(%esp), %eax |
0154416a MF |
280 | movl %eax, 2(%eax) |
281 | lgdtl (%eax) | |
282 | ||
283 | movl %cr4, %eax | |
284 | btsl $(X86_CR4_PAE_BIT), %eax | |
285 | movl %eax, %cr4 | |
286 | ||
287 | movl %cr3, %eax | |
288 | movl %eax, %cr3 | |
289 | ||
290 | movl $MSR_EFER, %ecx | |
291 | rdmsr | |
292 | btsl $_EFER_LME, %eax | |
293 | wrmsr | |
294 | ||
295 | xorl %eax, %eax | |
296 | lldt %ax | |
297 | ||
e10848a2 | 298 | movl 72(%esp), %eax |
0154416a MF |
299 | pushl $__KERNEL_CS |
300 | pushl %eax | |
301 | ||
302 | /* Enable paging */ | |
303 | movl %cr0, %eax | |
304 | btsl $X86_CR0_PG_BIT, %eax | |
305 | movl %eax, %cr0 | |
306 | lret | |
307 | ENDPROC(efi_enter32) | |
308 | ||
309 | .data | |
310 | .balign 8 | |
311 | .global efi32_boot_gdt | |
312 | efi32_boot_gdt: .word 0 | |
313 | .quad 0 | |
314 | ||
315 | save_gdt: .word 0 | |
316 | .quad 0 | |
317 | func_rt_ptr: .quad 0 | |
318 | ||
319 | .global efi_gdt64 | |
320 | efi_gdt64: | |
321 | .word efi_gdt64_end - efi_gdt64 | |
322 | .long 0 /* Filled out by user */ | |
323 | .word 0 | |
324 | .quad 0x0000000000000000 /* NULL descriptor */ | |
325 | .quad 0x00af9a000000ffff /* __KERNEL_CS */ | |
326 | .quad 0x00cf92000000ffff /* __KERNEL_DS */ | |
327 | .quad 0x0080890000000000 /* TS descriptor */ | |
328 | .quad 0x0000000000000000 /* TS continued */ | |
329 | efi_gdt64_end: | |
330 | #endif /* CONFIG_EFI_MIXED */ | |
331 | ||
d2f7cbe7 BP |
332 | .data |
333 | ENTRY(efi_scratch) | |
334 | .fill 3,8,0 | |
335 | .byte 0 | |
4f9dbcfc | 336 | .quad 0 |