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>
10#include <asm/segment.h>
11#include <asm/msr.h>
12#include <asm/processor-flags.h>
13#include <asm/page_types.h>
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
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
76ENTRY(efi_call0)
77	SAVE_XMM
78	subq $32, %rsp
79	SWITCH_PGT
80	call *%rdi
81	RESTORE_PGT
82	addq $32, %rsp
83	RESTORE_XMM
84	ret
85ENDPROC(efi_call0)
86
87ENTRY(efi_call1)
88	SAVE_XMM
89	subq $32, %rsp
90	mov  %rsi, %rcx
91	SWITCH_PGT
92	call *%rdi
93	RESTORE_PGT
94	addq $32, %rsp
95	RESTORE_XMM
96	ret
97ENDPROC(efi_call1)
98
99ENTRY(efi_call2)
100	SAVE_XMM
101	subq $32, %rsp
102	mov  %rsi, %rcx
103	SWITCH_PGT
104	call *%rdi
105	RESTORE_PGT
106	addq $32, %rsp
107	RESTORE_XMM
108	ret
109ENDPROC(efi_call2)
110
111ENTRY(efi_call3)
112	SAVE_XMM
113	subq $32, %rsp
114	mov  %rcx, %r8
115	mov  %rsi, %rcx
116	SWITCH_PGT
117	call *%rdi
118	RESTORE_PGT
119	addq $32, %rsp
120	RESTORE_XMM
121	ret
122ENDPROC(efi_call3)
123
124ENTRY(efi_call4)
125	SAVE_XMM
126	subq $32, %rsp
127	mov %r8, %r9
128	mov %rcx, %r8
129	mov %rsi, %rcx
130	SWITCH_PGT
131	call *%rdi
132	RESTORE_PGT
133	addq $32, %rsp
134	RESTORE_XMM
135	ret
136ENDPROC(efi_call4)
137
138ENTRY(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
145	SWITCH_PGT
146	call *%rdi
147	RESTORE_PGT
148	addq $48, %rsp
149	RESTORE_XMM
150	ret
151ENDPROC(efi_call5)
152
153ENTRY(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
163	SWITCH_PGT
164	call *%rdi
165	RESTORE_PGT
166	addq $48, %rsp
167	RESTORE_XMM
168	ret
169ENDPROC(efi_call6)
170
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 */
178ENTRY(__efi64_thunk)
179	movl	%ds, %eax
180	push	%rax
181	movl	%es, %eax
182	push	%rax
183	movl	%ss, %eax
184	push	%rax
185
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 */
201	movl	64(%rsp), %eax
202	lgdt	(%rax)
203
204	leaq	efi_enter32(%rip), %rax
205	pushq	$__KERNEL_CS
206	pushq	%rax
207	lretq
208
2091:	addq	$32, %rsp
210
211	lgdt	save_gdt(%rip)
212
213	pop	%rbx
214	movl	%ebx, %ss
215	pop	%rbx
216	movl	%ebx, %es
217	pop	%rbx
218	movl	%ebx, %ds
219
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
2301:
231	ret
232ENDPROC(__efi64_thunk)
233
234ENTRY(efi_exit32)
235	movq	func_rt_ptr(%rip), %rax
236	push	%rax
237	mov	%rdi, %rax
238	ret
239ENDPROC(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 */
247ENTRY(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
273	/*
274	 * Some firmware will return with interrupts enabled. Be sure to
275	 * disable them before we switch GDTs.
276	 */
277	cli
278
279	movl	68(%esp), %eax
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
298	movl	72(%esp), %eax
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
307ENDPROC(efi_enter32)
308
309	.data
310	.balign	8
311	.global	efi32_boot_gdt
312efi32_boot_gdt:	.word	0
313		.quad	0
314
315save_gdt:	.word	0
316		.quad	0
317func_rt_ptr:	.quad	0
318
319	.global efi_gdt64
320efi_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 */
329efi_gdt64_end:
330#endif /* CONFIG_EFI_MIXED */
331
332	.data
333ENTRY(efi_scratch)
334	.fill 3,8,0
335	.byte 0
336	.quad 0
337