xref: /linux/arch/x86/boot/compressed/efi_mixed.S (revision 0526b56cbc3c489642bd6a5fe4b718dea7ef0ee8)
1/* SPDX-License-Identifier: GPL-2.0 */
2/*
3 * Copyright (C) 2014, 2015 Intel Corporation; author Matt Fleming
4 *
5 * Early support for invoking 32-bit EFI services from a 64-bit kernel.
6 *
7 * Because this thunking occurs before ExitBootServices() we have to
8 * restore the firmware's 32-bit GDT and IDT before we make EFI service
9 * calls.
10 *
11 * On the plus side, we don't have to worry about mangling 64-bit
12 * addresses into 32-bits because we're executing with an identity
13 * mapped pagetable and haven't transitioned to 64-bit virtual addresses
14 * yet.
15 */
16
17#include <linux/linkage.h>
18#include <asm/msr.h>
19#include <asm/page_types.h>
20#include <asm/processor-flags.h>
21#include <asm/segment.h>
22
23	.code64
24	.text
25/*
26 * When booting in 64-bit mode on 32-bit EFI firmware, startup_64_mixed_mode()
27 * is the first thing that runs after switching to long mode. Depending on
28 * whether the EFI handover protocol or the compat entry point was used to
29 * enter the kernel, it will either branch to the 64-bit EFI handover
30 * entrypoint at offset 0x390 in the image, or to the 64-bit EFI PE/COFF
31 * entrypoint efi_pe_entry(). In the former case, the bootloader must provide a
32 * struct bootparams pointer as the third argument, so the presence of such a
33 * pointer is used to disambiguate.
34 *
35 *                                                             +--------------+
36 *  +------------------+     +------------+            +------>| efi_pe_entry |
37 *  | efi32_pe_entry   |---->|            |            |       +-----------+--+
38 *  +------------------+     |            |     +------+----------------+  |
39 *                           | startup_32 |---->| startup_64_mixed_mode |  |
40 *  +------------------+     |            |     +------+----------------+  V
41 *  | efi32_stub_entry |---->|            |            |     +------------------+
42 *  +------------------+     +------------+            +---->| efi64_stub_entry |
43 *                                                           +-------------+----+
44 *                           +------------+     +----------+               |
45 *                           | startup_64 |<----| efi_main |<--------------+
46 *                           +------------+     +----------+
47 */
48SYM_FUNC_START(startup_64_mixed_mode)
49	lea	efi32_boot_args(%rip), %rdx
50	mov	0(%rdx), %edi
51	mov	4(%rdx), %esi
52	mov	8(%rdx), %edx		// saved bootparams pointer
53	test	%edx, %edx
54	jnz	efi64_stub_entry
55	/*
56	 * efi_pe_entry uses MS calling convention, which requires 32 bytes of
57	 * shadow space on the stack even if all arguments are passed in
58	 * registers. We also need an additional 8 bytes for the space that
59	 * would be occupied by the return address, and this also results in
60	 * the correct stack alignment for entry.
61	 */
62	sub	$40, %rsp
63	mov	%rdi, %rcx		// MS calling convention
64	mov	%rsi, %rdx
65	jmp	efi_pe_entry
66SYM_FUNC_END(startup_64_mixed_mode)
67
68SYM_FUNC_START(__efi64_thunk)
69	push	%rbp
70	push	%rbx
71
72	movl	%ds, %eax
73	push	%rax
74	movl	%es, %eax
75	push	%rax
76	movl	%ss, %eax
77	push	%rax
78
79	/* Copy args passed on stack */
80	movq	0x30(%rsp), %rbp
81	movq	0x38(%rsp), %rbx
82	movq	0x40(%rsp), %rax
83
84	/*
85	 * Convert x86-64 ABI params to i386 ABI
86	 */
87	subq	$64, %rsp
88	movl	%esi, 0x0(%rsp)
89	movl	%edx, 0x4(%rsp)
90	movl	%ecx, 0x8(%rsp)
91	movl	%r8d, 0xc(%rsp)
92	movl	%r9d, 0x10(%rsp)
93	movl	%ebp, 0x14(%rsp)
94	movl	%ebx, 0x18(%rsp)
95	movl	%eax, 0x1c(%rsp)
96
97	leaq	0x20(%rsp), %rbx
98	sgdt	(%rbx)
99	sidt	16(%rbx)
100
101	leaq	1f(%rip), %rbp
102
103	/*
104	 * Switch to IDT and GDT with 32-bit segments. These are the firmware
105	 * GDT and IDT that were installed when the kernel started executing.
106	 * The pointers were saved by the efi32_entry() routine below.
107	 *
108	 * Pass the saved DS selector to the 32-bit code, and use far return to
109	 * restore the saved CS selector.
110	 */
111	lidt	efi32_boot_idt(%rip)
112	lgdt	efi32_boot_gdt(%rip)
113
114	movzwl	efi32_boot_ds(%rip), %edx
115	movzwq	efi32_boot_cs(%rip), %rax
116	pushq	%rax
117	leaq	efi_enter32(%rip), %rax
118	pushq	%rax
119	lretq
120
1211:	addq	$64, %rsp
122	movq	%rdi, %rax
123
124	pop	%rbx
125	movl	%ebx, %ss
126	pop	%rbx
127	movl	%ebx, %es
128	pop	%rbx
129	movl	%ebx, %ds
130	/* Clear out 32-bit selector from FS and GS */
131	xorl	%ebx, %ebx
132	movl	%ebx, %fs
133	movl	%ebx, %gs
134
135	pop	%rbx
136	pop	%rbp
137	RET
138SYM_FUNC_END(__efi64_thunk)
139
140	.code32
141/*
142 * EFI service pointer must be in %edi.
143 *
144 * The stack should represent the 32-bit calling convention.
145 */
146SYM_FUNC_START_LOCAL(efi_enter32)
147	/* Load firmware selector into data and stack segment registers */
148	movl	%edx, %ds
149	movl	%edx, %es
150	movl	%edx, %fs
151	movl	%edx, %gs
152	movl	%edx, %ss
153
154	/* Reload pgtables */
155	movl	%cr3, %eax
156	movl	%eax, %cr3
157
158	/* Disable paging */
159	movl	%cr0, %eax
160	btrl	$X86_CR0_PG_BIT, %eax
161	movl	%eax, %cr0
162
163	/* Disable long mode via EFER */
164	movl	$MSR_EFER, %ecx
165	rdmsr
166	btrl	$_EFER_LME, %eax
167	wrmsr
168
169	call	*%edi
170
171	/* We must preserve return value */
172	movl	%eax, %edi
173
174	/*
175	 * Some firmware will return with interrupts enabled. Be sure to
176	 * disable them before we switch GDTs and IDTs.
177	 */
178	cli
179
180	lidtl	16(%ebx)
181	lgdtl	(%ebx)
182
183	movl	%cr4, %eax
184	btsl	$(X86_CR4_PAE_BIT), %eax
185	movl	%eax, %cr4
186
187	movl	%cr3, %eax
188	movl	%eax, %cr3
189
190	movl	$MSR_EFER, %ecx
191	rdmsr
192	btsl	$_EFER_LME, %eax
193	wrmsr
194
195	xorl	%eax, %eax
196	lldt	%ax
197
198	pushl	$__KERNEL_CS
199	pushl	%ebp
200
201	/* Enable paging */
202	movl	%cr0, %eax
203	btsl	$X86_CR0_PG_BIT, %eax
204	movl	%eax, %cr0
205	lret
206SYM_FUNC_END(efi_enter32)
207
208/*
209 * This is the common EFI stub entry point for mixed mode.
210 *
211 * Arguments:	%ecx	image handle
212 * 		%edx	EFI system table pointer
213 *		%esi	struct bootparams pointer (or NULL when not using
214 *			the EFI handover protocol)
215 *
216 * Since this is the point of no return for ordinary execution, no registers
217 * are considered live except for the function parameters. [Note that the EFI
218 * stub may still exit and return to the firmware using the Exit() EFI boot
219 * service.]
220 */
221SYM_FUNC_START(efi32_entry)
222	call	1f
2231:	pop	%ebx
224
225	/* Save firmware GDTR and code/data selectors */
226	sgdtl	(efi32_boot_gdt - 1b)(%ebx)
227	movw	%cs, (efi32_boot_cs - 1b)(%ebx)
228	movw	%ds, (efi32_boot_ds - 1b)(%ebx)
229
230	/* Store firmware IDT descriptor */
231	sidtl	(efi32_boot_idt - 1b)(%ebx)
232
233	/* Store boot arguments */
234	leal	(efi32_boot_args - 1b)(%ebx), %ebx
235	movl	%ecx, 0(%ebx)
236	movl	%edx, 4(%ebx)
237	movl	%esi, 8(%ebx)
238	movb	$0x0, 12(%ebx)          // efi_is64
239
240	/* Disable paging */
241	movl	%cr0, %eax
242	btrl	$X86_CR0_PG_BIT, %eax
243	movl	%eax, %cr0
244
245	jmp	startup_32
246SYM_FUNC_END(efi32_entry)
247
248#define ST32_boottime		60 // offsetof(efi_system_table_32_t, boottime)
249#define BS32_handle_protocol	88 // offsetof(efi_boot_services_32_t, handle_protocol)
250#define LI32_image_base		32 // offsetof(efi_loaded_image_32_t, image_base)
251
252/*
253 * efi_status_t efi32_pe_entry(efi_handle_t image_handle,
254 *			       efi_system_table_32_t *sys_table)
255 */
256SYM_FUNC_START(efi32_pe_entry)
257	pushl	%ebp
258	movl	%esp, %ebp
259	pushl	%eax				// dummy push to allocate loaded_image
260
261	pushl	%ebx				// save callee-save registers
262	pushl	%edi
263
264	call	verify_cpu			// check for long mode support
265	testl	%eax, %eax
266	movl	$0x80000003, %eax		// EFI_UNSUPPORTED
267	jnz	2f
268
269	call	1f
2701:	pop	%ebx
271
272	/* Get the loaded image protocol pointer from the image handle */
273	leal	-4(%ebp), %eax
274	pushl	%eax				// &loaded_image
275	leal	(loaded_image_proto - 1b)(%ebx), %eax
276	pushl	%eax				// pass the GUID address
277	pushl	8(%ebp)				// pass the image handle
278
279	/*
280	 * Note the alignment of the stack frame.
281	 *   sys_table
282	 *   handle             <-- 16-byte aligned on entry by ABI
283	 *   return address
284	 *   frame pointer
285	 *   loaded_image       <-- local variable
286	 *   saved %ebx		<-- 16-byte aligned here
287	 *   saved %edi
288	 *   &loaded_image
289	 *   &loaded_image_proto
290	 *   handle             <-- 16-byte aligned for call to handle_protocol
291	 */
292
293	movl	12(%ebp), %eax			// sys_table
294	movl	ST32_boottime(%eax), %eax	// sys_table->boottime
295	call	*BS32_handle_protocol(%eax)	// sys_table->boottime->handle_protocol
296	addl	$12, %esp			// restore argument space
297	testl	%eax, %eax
298	jnz	2f
299
300	movl	8(%ebp), %ecx			// image_handle
301	movl	12(%ebp), %edx			// sys_table
302	movl	-4(%ebp), %esi			// loaded_image
303	movl	LI32_image_base(%esi), %esi	// loaded_image->image_base
304	leal	(startup_32 - 1b)(%ebx), %ebp	// runtime address of startup_32
305	/*
306	 * We need to set the image_offset variable here since startup_32() will
307	 * use it before we get to the 64-bit efi_pe_entry() in C code.
308	 */
309	subl	%esi, %ebp			// calculate image_offset
310	movl	%ebp, (image_offset - 1b)(%ebx)	// save image_offset
311	xorl	%esi, %esi
312	jmp	efi32_entry			// pass %ecx, %edx, %esi
313						// no other registers remain live
314
3152:	popl	%edi				// restore callee-save registers
316	popl	%ebx
317	leave
318	RET
319SYM_FUNC_END(efi32_pe_entry)
320
321	.section ".rodata"
322	/* EFI loaded image protocol GUID */
323	.balign 4
324SYM_DATA_START_LOCAL(loaded_image_proto)
325	.long	0x5b1b31a1
326	.word	0x9562, 0x11d2
327	.byte	0x8e, 0x3f, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b
328SYM_DATA_END(loaded_image_proto)
329
330	.data
331	.balign	8
332SYM_DATA_START_LOCAL(efi32_boot_gdt)
333	.word	0
334	.quad	0
335SYM_DATA_END(efi32_boot_gdt)
336
337SYM_DATA_START_LOCAL(efi32_boot_idt)
338	.word	0
339	.quad	0
340SYM_DATA_END(efi32_boot_idt)
341
342SYM_DATA_LOCAL(efi32_boot_cs, .word 0)
343SYM_DATA_LOCAL(efi32_boot_ds, .word 0)
344SYM_DATA_LOCAL(efi32_boot_args, .long 0, 0, 0)
345SYM_DATA(efi_is64, .byte 1)
346