xref: /openbmc/linux/arch/x86/boot/compressed/head_64.S (revision e721eb06)
1/* SPDX-License-Identifier: GPL-2.0 */
2/*
3 *  linux/boot/head.S
4 *
5 *  Copyright (C) 1991, 1992, 1993  Linus Torvalds
6 */
7
8/*
9 *  head.S contains the 32-bit startup code.
10 *
11 * NOTE!!! Startup happens at absolute address 0x00001000, which is also where
12 * the page directory will exist. The startup code will be overwritten by
13 * the page directory. [According to comments etc elsewhere on a compressed
14 * kernel it will end up at 0x1000 + 1Mb I hope so as I assume this. - AC]
15 *
16 * Page 0 is deliberately kept safe, since System Management Mode code in
17 * laptops may need to access the BIOS data stored there.  This is also
18 * useful for future device drivers that either access the BIOS via VM86
19 * mode.
20 */
21
22/*
23 * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996
24 */
25	.code32
26	.text
27
28#include <linux/init.h>
29#include <linux/linkage.h>
30#include <asm/segment.h>
31#include <asm/boot.h>
32#include <asm/msr.h>
33#include <asm/processor-flags.h>
34#include <asm/asm-offsets.h>
35#include <asm/bootparam.h>
36#include "pgtable.h"
37
38/*
39 * Locally defined symbols should be marked hidden:
40 */
41	.hidden _bss
42	.hidden _ebss
43	.hidden _got
44	.hidden _egot
45	.hidden _end
46
47	__HEAD
48	.code32
49SYM_FUNC_START(startup_32)
50	/*
51	 * 32bit entry is 0 and it is ABI so immutable!
52	 * If we come here directly from a bootloader,
53	 * kernel(text+data+bss+brk) ramdisk, zero_page, command line
54	 * all need to be under the 4G limit.
55	 */
56	cld
57	cli
58
59/*
60 * Calculate the delta between where we were compiled to run
61 * at and where we were actually loaded at.  This can only be done
62 * with a short local call on x86.  Nothing  else will tell us what
63 * address we are running at.  The reserved chunk of the real-mode
64 * data at 0x1e4 (defined as a scratch field) are used as the stack
65 * for this calculation. Only 4 bytes are needed.
66 */
67	leal	(BP_scratch+4)(%esi), %esp
68	call	1f
691:	popl	%ebp
70	subl	$1b, %ebp
71
72	/* Load new GDT with the 64bit segments using 32bit descriptor */
73	leal	gdt(%ebp), %eax
74	movl	%eax, 2(%eax)
75	lgdt	(%eax)
76
77	/* Load segment registers with our descriptors */
78	movl	$__BOOT_DS, %eax
79	movl	%eax, %ds
80	movl	%eax, %es
81	movl	%eax, %fs
82	movl	%eax, %gs
83	movl	%eax, %ss
84
85/* setup a stack and make sure cpu supports long mode. */
86	leal	boot_stack_end(%ebp), %esp
87
88	call	verify_cpu
89	testl	%eax, %eax
90	jnz	.Lno_longmode
91
92/*
93 * Compute the delta between where we were compiled to run at
94 * and where the code will actually run at.
95 *
96 * %ebp contains the address we are loaded at by the boot loader and %ebx
97 * contains the address where we should move the kernel image temporarily
98 * for safe in-place decompression.
99 */
100
101#ifdef CONFIG_RELOCATABLE
102	movl	%ebp, %ebx
103
104#ifdef CONFIG_EFI_STUB
105/*
106 * If we were loaded via the EFI LoadImage service, startup_32 will be at an
107 * offset to the start of the space allocated for the image. efi_pe_entry will
108 * set up image_offset to tell us where the image actually starts, so that we
109 * can use the full available buffer.
110 *	image_offset = startup_32 - image_base
111 * Otherwise image_offset will be zero and has no effect on the calculations.
112 */
113	subl    image_offset(%ebp), %ebx
114#endif
115
116	movl	BP_kernel_alignment(%esi), %eax
117	decl	%eax
118	addl	%eax, %ebx
119	notl	%eax
120	andl	%eax, %ebx
121	cmpl	$LOAD_PHYSICAL_ADDR, %ebx
122	jae	1f
123#endif
124	movl	$LOAD_PHYSICAL_ADDR, %ebx
1251:
126
127	/* Target address to relocate to for decompression */
128	addl	BP_init_size(%esi), %ebx
129	subl	$_end, %ebx
130
131/*
132 * Prepare for entering 64 bit mode
133 */
134
135	/* Enable PAE mode */
136	movl	%cr4, %eax
137	orl	$X86_CR4_PAE, %eax
138	movl	%eax, %cr4
139
140 /*
141  * Build early 4G boot pagetable
142  */
143	/*
144	 * If SEV is active then set the encryption mask in the page tables.
145	 * This will insure that when the kernel is copied and decompressed
146	 * it will be done so encrypted.
147	 */
148	call	get_sev_encryption_bit
149	xorl	%edx, %edx
150	testl	%eax, %eax
151	jz	1f
152	subl	$32, %eax	/* Encryption bit is always above bit 31 */
153	bts	%eax, %edx	/* Set encryption mask for page tables */
1541:
155
156	/* Initialize Page tables to 0 */
157	leal	pgtable(%ebx), %edi
158	xorl	%eax, %eax
159	movl	$(BOOT_INIT_PGT_SIZE/4), %ecx
160	rep	stosl
161
162	/* Build Level 4 */
163	leal	pgtable + 0(%ebx), %edi
164	leal	0x1007 (%edi), %eax
165	movl	%eax, 0(%edi)
166	addl	%edx, 4(%edi)
167
168	/* Build Level 3 */
169	leal	pgtable + 0x1000(%ebx), %edi
170	leal	0x1007(%edi), %eax
171	movl	$4, %ecx
1721:	movl	%eax, 0x00(%edi)
173	addl	%edx, 0x04(%edi)
174	addl	$0x00001000, %eax
175	addl	$8, %edi
176	decl	%ecx
177	jnz	1b
178
179	/* Build Level 2 */
180	leal	pgtable + 0x2000(%ebx), %edi
181	movl	$0x00000183, %eax
182	movl	$2048, %ecx
1831:	movl	%eax, 0(%edi)
184	addl	%edx, 4(%edi)
185	addl	$0x00200000, %eax
186	addl	$8, %edi
187	decl	%ecx
188	jnz	1b
189
190	/* Enable the boot page tables */
191	leal	pgtable(%ebx), %eax
192	movl	%eax, %cr3
193
194	/* Enable Long mode in EFER (Extended Feature Enable Register) */
195	movl	$MSR_EFER, %ecx
196	rdmsr
197	btsl	$_EFER_LME, %eax
198	wrmsr
199
200	/* After gdt is loaded */
201	xorl	%eax, %eax
202	lldt	%ax
203	movl    $__BOOT_TSS, %eax
204	ltr	%ax
205
206	/*
207	 * Setup for the jump to 64bit mode
208	 *
209	 * When the jump is performend we will be in long mode but
210	 * in 32bit compatibility mode with EFER.LME = 1, CS.L = 0, CS.D = 1
211	 * (and in turn EFER.LMA = 1).	To jump into 64bit mode we use
212	 * the new gdt/idt that has __KERNEL_CS with CS.L = 1.
213	 * We place all of the values on our mini stack so lret can
214	 * used to perform that far jump.
215	 */
216	pushl	$__KERNEL_CS
217	leal	startup_64(%ebp), %eax
218#ifdef CONFIG_EFI_MIXED
219	movl	efi32_boot_args(%ebp), %edi
220	cmp	$0, %edi
221	jz	1f
222	leal	efi64_stub_entry(%ebp), %eax
223	movl	efi32_boot_args+4(%ebp), %esi
224	movl	efi32_boot_args+8(%ebp), %edx	// saved bootparams pointer
225	cmpl	$0, %edx
226	jnz	1f
227	leal	efi_pe_entry(%ebp), %eax
228	movl	%edi, %ecx			// MS calling convention
229	movl	%esi, %edx
2301:
231#endif
232	pushl	%eax
233
234	/* Enter paged protected Mode, activating Long Mode */
235	movl	$(X86_CR0_PG | X86_CR0_PE), %eax /* Enable Paging and Protected mode */
236	movl	%eax, %cr0
237
238	/* Jump from 32bit compatibility mode into 64bit mode. */
239	lret
240SYM_FUNC_END(startup_32)
241
242#ifdef CONFIG_EFI_MIXED
243	.org 0x190
244SYM_FUNC_START(efi32_stub_entry)
245	add	$0x4, %esp		/* Discard return address */
246	popl	%ecx
247	popl	%edx
248	popl	%esi
249
250	call	1f
2511:	pop	%ebp
252	subl	$1b, %ebp
253
254	movl	%esi, efi32_boot_args+8(%ebp)
255SYM_INNER_LABEL(efi32_pe_stub_entry, SYM_L_LOCAL)
256	movl	%ecx, efi32_boot_args(%ebp)
257	movl	%edx, efi32_boot_args+4(%ebp)
258	movb	$0, efi_is64(%ebp)
259
260	/* Save firmware GDTR and code/data selectors */
261	sgdtl	efi32_boot_gdt(%ebp)
262	movw	%cs, efi32_boot_cs(%ebp)
263	movw	%ds, efi32_boot_ds(%ebp)
264
265	/* Disable paging */
266	movl	%cr0, %eax
267	btrl	$X86_CR0_PG_BIT, %eax
268	movl	%eax, %cr0
269
270	jmp	startup_32
271SYM_FUNC_END(efi32_stub_entry)
272#endif
273
274	.code64
275	.org 0x200
276SYM_CODE_START(startup_64)
277	/*
278	 * 64bit entry is 0x200 and it is ABI so immutable!
279	 * We come here either from startup_32 or directly from a
280	 * 64bit bootloader.
281	 * If we come here from a bootloader, kernel(text+data+bss+brk),
282	 * ramdisk, zero_page, command line could be above 4G.
283	 * We depend on an identity mapped page table being provided
284	 * that maps our entire kernel(text+data+bss+brk), zero page
285	 * and command line.
286	 */
287
288	cld
289	cli
290
291	/* Setup data segments. */
292	xorl	%eax, %eax
293	movl	%eax, %ds
294	movl	%eax, %es
295	movl	%eax, %ss
296	movl	%eax, %fs
297	movl	%eax, %gs
298
299	/*
300	 * Compute the decompressed kernel start address.  It is where
301	 * we were loaded at aligned to a 2M boundary. %rbp contains the
302	 * decompressed kernel start address.
303	 *
304	 * If it is a relocatable kernel then decompress and run the kernel
305	 * from load address aligned to 2MB addr, otherwise decompress and
306	 * run the kernel from LOAD_PHYSICAL_ADDR
307	 *
308	 * We cannot rely on the calculation done in 32-bit mode, since we
309	 * may have been invoked via the 64-bit entry point.
310	 */
311
312	/* Start with the delta to where the kernel will run at. */
313#ifdef CONFIG_RELOCATABLE
314	leaq	startup_32(%rip) /* - $startup_32 */, %rbp
315
316#ifdef CONFIG_EFI_STUB
317/*
318 * If we were loaded via the EFI LoadImage service, startup_32 will be at an
319 * offset to the start of the space allocated for the image. efi_pe_entry will
320 * set up image_offset to tell us where the image actually starts, so that we
321 * can use the full available buffer.
322 *	image_offset = startup_32 - image_base
323 * Otherwise image_offset will be zero and has no effect on the calculations.
324 */
325	movl    image_offset(%rip), %eax
326	subq	%rax, %rbp
327#endif
328
329	movl	BP_kernel_alignment(%rsi), %eax
330	decl	%eax
331	addq	%rax, %rbp
332	notq	%rax
333	andq	%rax, %rbp
334	cmpq	$LOAD_PHYSICAL_ADDR, %rbp
335	jae	1f
336#endif
337	movq	$LOAD_PHYSICAL_ADDR, %rbp
3381:
339
340	/* Target address to relocate to for decompression */
341	movl	BP_init_size(%rsi), %ebx
342	subl	$_end, %ebx
343	addq	%rbp, %rbx
344
345	/* Set up the stack */
346	leaq	boot_stack_end(%rbx), %rsp
347
348	/*
349	 * paging_prepare() and cleanup_trampoline() below can have GOT
350	 * references. Adjust the table with address we are running at.
351	 *
352	 * Zero RAX for adjust_got: the GOT was not adjusted before;
353	 * there's no adjustment to undo.
354	 */
355	xorq	%rax, %rax
356
357	/*
358	 * Calculate the address the binary is loaded at and use it as
359	 * a GOT adjustment.
360	 */
361	call	1f
3621:	popq	%rdi
363	subq	$1b, %rdi
364
365	call	.Ladjust_got
366
367	/*
368	 * At this point we are in long mode with 4-level paging enabled,
369	 * but we might want to enable 5-level paging or vice versa.
370	 *
371	 * The problem is that we cannot do it directly. Setting or clearing
372	 * CR4.LA57 in long mode would trigger #GP. So we need to switch off
373	 * long mode and paging first.
374	 *
375	 * We also need a trampoline in lower memory to switch over from
376	 * 4- to 5-level paging for cases when the bootloader puts the kernel
377	 * above 4G, but didn't enable 5-level paging for us.
378	 *
379	 * The same trampoline can be used to switch from 5- to 4-level paging
380	 * mode, like when starting 4-level paging kernel via kexec() when
381	 * original kernel worked in 5-level paging mode.
382	 *
383	 * For the trampoline, we need the top page table to reside in lower
384	 * memory as we don't have a way to load 64-bit values into CR3 in
385	 * 32-bit mode.
386	 *
387	 * We go though the trampoline even if we don't have to: if we're
388	 * already in a desired paging mode. This way the trampoline code gets
389	 * tested on every boot.
390	 */
391
392	/* Make sure we have GDT with 32-bit code segment */
393	leaq	gdt64(%rip), %rax
394	addq	%rax, 2(%rax)
395	lgdt	(%rax)
396
397	/* Reload CS so IRET returns to a CS actually in the GDT */
398	pushq	$__KERNEL_CS
399	leaq	.Lon_kernel_cs(%rip), %rax
400	pushq	%rax
401	lretq
402
403.Lon_kernel_cs:
404
405	/*
406	 * paging_prepare() sets up the trampoline and checks if we need to
407	 * enable 5-level paging.
408	 *
409	 * paging_prepare() returns a two-quadword structure which lands
410	 * into RDX:RAX:
411	 *   - Address of the trampoline is returned in RAX.
412	 *   - Non zero RDX means trampoline needs to enable 5-level
413	 *     paging.
414	 *
415	 * RSI holds real mode data and needs to be preserved across
416	 * this function call.
417	 */
418	pushq	%rsi
419	movq	%rsi, %rdi		/* real mode address */
420	call	paging_prepare
421	popq	%rsi
422
423	/* Save the trampoline address in RCX */
424	movq	%rax, %rcx
425
426	/*
427	 * Load the address of trampoline_return() into RDI.
428	 * It will be used by the trampoline to return to the main code.
429	 */
430	leaq	trampoline_return(%rip), %rdi
431
432	/* Switch to compatibility mode (CS.L = 0 CS.D = 1) via far return */
433	pushq	$__KERNEL32_CS
434	leaq	TRAMPOLINE_32BIT_CODE_OFFSET(%rax), %rax
435	pushq	%rax
436	lretq
437trampoline_return:
438	/* Restore the stack, the 32-bit trampoline uses its own stack */
439	leaq	boot_stack_end(%rbx), %rsp
440
441	/*
442	 * cleanup_trampoline() would restore trampoline memory.
443	 *
444	 * RDI is address of the page table to use instead of page table
445	 * in trampoline memory (if required).
446	 *
447	 * RSI holds real mode data and needs to be preserved across
448	 * this function call.
449	 */
450	pushq	%rsi
451	leaq	top_pgtable(%rbx), %rdi
452	call	cleanup_trampoline
453	popq	%rsi
454
455	/* Zero EFLAGS */
456	pushq	$0
457	popfq
458
459	/*
460	 * Previously we've adjusted the GOT with address the binary was
461	 * loaded at. Now we need to re-adjust for relocation address.
462	 *
463	 * Calculate the address the binary is loaded at, so that we can
464	 * undo the previous GOT adjustment.
465	 */
466	call	1f
4671:	popq	%rax
468	subq	$1b, %rax
469
470	/* The new adjustment is the relocation address */
471	movq	%rbx, %rdi
472	call	.Ladjust_got
473
474/*
475 * Copy the compressed kernel to the end of our buffer
476 * where decompression in place becomes safe.
477 */
478	pushq	%rsi
479	leaq	(_bss-8)(%rip), %rsi
480	leaq	(_bss-8)(%rbx), %rdi
481	movq	$_bss /* - $startup_32 */, %rcx
482	shrq	$3, %rcx
483	std
484	rep	movsq
485	cld
486	popq	%rsi
487
488	/*
489	 * The GDT may get overwritten either during the copy we just did or
490	 * during extract_kernel below. To avoid any issues, repoint the GDTR
491	 * to the new copy of the GDT.
492	 */
493	leaq	gdt64(%rbx), %rax
494	leaq	gdt(%rbx), %rdx
495	movq	%rdx, 2(%rax)
496	lgdt	(%rax)
497
498/*
499 * Jump to the relocated address.
500 */
501	leaq	.Lrelocated(%rbx), %rax
502	jmp	*%rax
503SYM_CODE_END(startup_64)
504
505#ifdef CONFIG_EFI_STUB
506	.org 0x390
507SYM_FUNC_START(efi64_stub_entry)
508SYM_FUNC_START_ALIAS(efi_stub_entry)
509	and	$~0xf, %rsp			/* realign the stack */
510	movq	%rdx, %rbx			/* save boot_params pointer */
511	call	efi_main
512	movq	%rbx,%rsi
513	leaq	startup_64(%rax), %rax
514	jmp	*%rax
515SYM_FUNC_END(efi64_stub_entry)
516SYM_FUNC_END_ALIAS(efi_stub_entry)
517#endif
518
519	.text
520SYM_FUNC_START_LOCAL_NOALIGN(.Lrelocated)
521
522/*
523 * Clear BSS (stack is currently empty)
524 */
525	xorl	%eax, %eax
526	leaq    _bss(%rip), %rdi
527	leaq    _ebss(%rip), %rcx
528	subq	%rdi, %rcx
529	shrq	$3, %rcx
530	rep	stosq
531
532/*
533 * Do the extraction, and jump to the new kernel..
534 */
535	pushq	%rsi			/* Save the real mode argument */
536	movq	%rsi, %rdi		/* real mode address */
537	leaq	boot_heap(%rip), %rsi	/* malloc area for uncompression */
538	leaq	input_data(%rip), %rdx  /* input_data */
539	movl	$z_input_len, %ecx	/* input_len */
540	movq	%rbp, %r8		/* output target address */
541	movl	$z_output_len, %r9d	/* decompressed length, end of relocs */
542	call	extract_kernel		/* returns kernel location in %rax */
543	popq	%rsi
544
545/*
546 * Jump to the decompressed kernel.
547 */
548	jmp	*%rax
549SYM_FUNC_END(.Lrelocated)
550
551/*
552 * Adjust the global offset table
553 *
554 * RAX is the previous adjustment of the table to undo (use 0 if it's the
555 * first time we touch GOT).
556 * RDI is the new adjustment to apply.
557 */
558.Ladjust_got:
559	/* Walk through the GOT adding the address to the entries */
560	leaq	_got(%rip), %rdx
561	leaq	_egot(%rip), %rcx
5621:
563	cmpq	%rcx, %rdx
564	jae	2f
565	subq	%rax, (%rdx)	/* Undo previous adjustment */
566	addq	%rdi, (%rdx)	/* Apply the new adjustment */
567	addq	$8, %rdx
568	jmp	1b
5692:
570	ret
571
572	.code32
573/*
574 * This is the 32-bit trampoline that will be copied over to low memory.
575 *
576 * RDI contains the return address (might be above 4G).
577 * ECX contains the base address of the trampoline memory.
578 * Non zero RDX means trampoline needs to enable 5-level paging.
579 */
580SYM_CODE_START(trampoline_32bit_src)
581	/* Set up data and stack segments */
582	movl	$__KERNEL_DS, %eax
583	movl	%eax, %ds
584	movl	%eax, %ss
585
586	/* Set up new stack */
587	leal	TRAMPOLINE_32BIT_STACK_END(%ecx), %esp
588
589	/* Disable paging */
590	movl	%cr0, %eax
591	btrl	$X86_CR0_PG_BIT, %eax
592	movl	%eax, %cr0
593
594	/* Check what paging mode we want to be in after the trampoline */
595	cmpl	$0, %edx
596	jz	1f
597
598	/* We want 5-level paging: don't touch CR3 if it already points to 5-level page tables */
599	movl	%cr4, %eax
600	testl	$X86_CR4_LA57, %eax
601	jnz	3f
602	jmp	2f
6031:
604	/* We want 4-level paging: don't touch CR3 if it already points to 4-level page tables */
605	movl	%cr4, %eax
606	testl	$X86_CR4_LA57, %eax
607	jz	3f
6082:
609	/* Point CR3 to the trampoline's new top level page table */
610	leal	TRAMPOLINE_32BIT_PGTABLE_OFFSET(%ecx), %eax
611	movl	%eax, %cr3
6123:
613	/* Set EFER.LME=1 as a precaution in case hypervsior pulls the rug */
614	pushl	%ecx
615	pushl	%edx
616	movl	$MSR_EFER, %ecx
617	rdmsr
618	btsl	$_EFER_LME, %eax
619	wrmsr
620	popl	%edx
621	popl	%ecx
622
623	/* Enable PAE and LA57 (if required) paging modes */
624	movl	$X86_CR4_PAE, %eax
625	cmpl	$0, %edx
626	jz	1f
627	orl	$X86_CR4_LA57, %eax
6281:
629	movl	%eax, %cr4
630
631	/* Calculate address of paging_enabled() once we are executing in the trampoline */
632	leal	.Lpaging_enabled - trampoline_32bit_src + TRAMPOLINE_32BIT_CODE_OFFSET(%ecx), %eax
633
634	/* Prepare the stack for far return to Long Mode */
635	pushl	$__KERNEL_CS
636	pushl	%eax
637
638	/* Enable paging again */
639	movl	$(X86_CR0_PG | X86_CR0_PE), %eax
640	movl	%eax, %cr0
641
642	lret
643SYM_CODE_END(trampoline_32bit_src)
644
645	.code64
646SYM_FUNC_START_LOCAL_NOALIGN(.Lpaging_enabled)
647	/* Return from the trampoline */
648	jmp	*%rdi
649SYM_FUNC_END(.Lpaging_enabled)
650
651	/*
652         * The trampoline code has a size limit.
653         * Make sure we fail to compile if the trampoline code grows
654         * beyond TRAMPOLINE_32BIT_CODE_SIZE bytes.
655	 */
656	.org	trampoline_32bit_src + TRAMPOLINE_32BIT_CODE_SIZE
657
658	.code32
659SYM_FUNC_START_LOCAL_NOALIGN(.Lno_longmode)
660	/* This isn't an x86-64 CPU, so hang intentionally, we cannot continue */
6611:
662	hlt
663	jmp     1b
664SYM_FUNC_END(.Lno_longmode)
665
666#include "../../kernel/verify_cpu.S"
667
668	.data
669SYM_DATA_START_LOCAL(gdt64)
670	.word	gdt_end - gdt - 1
671	.quad   gdt - gdt64
672SYM_DATA_END(gdt64)
673	.balign	8
674SYM_DATA_START_LOCAL(gdt)
675	.word	gdt_end - gdt - 1
676	.long	0
677	.word	0
678	.quad	0x00cf9a000000ffff	/* __KERNEL32_CS */
679	.quad	0x00af9a000000ffff	/* __KERNEL_CS */
680	.quad	0x00cf92000000ffff	/* __KERNEL_DS */
681	.quad	0x0080890000000000	/* TS descriptor */
682	.quad   0x0000000000000000	/* TS continued */
683SYM_DATA_END_LABEL(gdt, SYM_L_LOCAL, gdt_end)
684
685#ifdef CONFIG_EFI_STUB
686SYM_DATA(image_offset, .long 0)
687#endif
688
689#ifdef CONFIG_EFI_MIXED
690SYM_DATA_LOCAL(efi32_boot_args, .long 0, 0, 0)
691SYM_DATA(efi_is64, .byte 1)
692
693#define ST32_boottime		60 // offsetof(efi_system_table_32_t, boottime)
694#define BS32_handle_protocol	88 // offsetof(efi_boot_services_32_t, handle_protocol)
695#define LI32_image_base		32 // offsetof(efi_loaded_image_32_t, image_base)
696
697	.text
698	.code32
699SYM_FUNC_START(efi32_pe_entry)
700/*
701 * efi_status_t efi32_pe_entry(efi_handle_t image_handle,
702 *			       efi_system_table_32_t *sys_table)
703 */
704
705	pushl	%ebp
706	movl	%esp, %ebp
707	pushl	%eax				// dummy push to allocate loaded_image
708
709	pushl	%ebx				// save callee-save registers
710	pushl	%edi
711
712	call	verify_cpu			// check for long mode support
713	testl	%eax, %eax
714	movl	$0x80000003, %eax		// EFI_UNSUPPORTED
715	jnz	2f
716
717	call	1f
7181:	pop	%ebx
719	subl	$1b, %ebx
720
721	/* Get the loaded image protocol pointer from the image handle */
722	leal	-4(%ebp), %eax
723	pushl	%eax				// &loaded_image
724	leal	loaded_image_proto(%ebx), %eax
725	pushl	%eax				// pass the GUID address
726	pushl	8(%ebp)				// pass the image handle
727
728	/*
729	 * Note the alignment of the stack frame.
730	 *   sys_table
731	 *   handle             <-- 16-byte aligned on entry by ABI
732	 *   return address
733	 *   frame pointer
734	 *   loaded_image       <-- local variable
735	 *   saved %ebx		<-- 16-byte aligned here
736	 *   saved %edi
737	 *   &loaded_image
738	 *   &loaded_image_proto
739	 *   handle             <-- 16-byte aligned for call to handle_protocol
740	 */
741
742	movl	12(%ebp), %eax			// sys_table
743	movl	ST32_boottime(%eax), %eax	// sys_table->boottime
744	call	*BS32_handle_protocol(%eax)	// sys_table->boottime->handle_protocol
745	addl	$12, %esp			// restore argument space
746	testl	%eax, %eax
747	jnz	2f
748
749	movl	8(%ebp), %ecx			// image_handle
750	movl	12(%ebp), %edx			// sys_table
751	movl	-4(%ebp), %esi			// loaded_image
752	movl	LI32_image_base(%esi), %esi	// loaded_image->image_base
753	movl	%ebx, %ebp			// startup_32 for efi32_pe_stub_entry
754	/*
755	 * We need to set the image_offset variable here since startup_32() will
756	 * use it before we get to the 64-bit efi_pe_entry() in C code.
757	 */
758	subl	%esi, %ebx
759	movl	%ebx, image_offset(%ebp)	// save image_offset
760	jmp	efi32_pe_stub_entry
761
7622:	popl	%edi				// restore callee-save registers
763	popl	%ebx
764	leave
765	ret
766SYM_FUNC_END(efi32_pe_entry)
767
768	.section ".rodata"
769	/* EFI loaded image protocol GUID */
770	.balign 4
771SYM_DATA_START_LOCAL(loaded_image_proto)
772	.long	0x5b1b31a1
773	.word	0x9562, 0x11d2
774	.byte	0x8e, 0x3f, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b
775SYM_DATA_END(loaded_image_proto)
776#endif
777
778/*
779 * Stack and heap for uncompression
780 */
781	.bss
782	.balign 4
783SYM_DATA_LOCAL(boot_heap,	.fill BOOT_HEAP_SIZE, 1, 0)
784
785SYM_DATA_START_LOCAL(boot_stack)
786	.fill BOOT_STACK_SIZE, 1, 0
787SYM_DATA_END_LABEL(boot_stack, SYM_L_LOCAL, boot_stack_end)
788
789/*
790 * Space for page tables (not in .bss so not zeroed)
791 */
792	.section ".pgtable","aw",@nobits
793	.balign 4096
794SYM_DATA_LOCAL(pgtable,		.fill BOOT_PGT_SIZE, 1, 0)
795
796/*
797 * The page table is going to be used instead of page table in the trampoline
798 * memory.
799 */
800SYM_DATA_LOCAL(top_pgtable,	.fill PAGE_SIZE, 1, 0)
801