xref: /openbmc/linux/arch/x86/boot/compressed/head_64.S (revision 4bb1eb3c)
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	leal	startup_64(%ebp), %eax
217#ifdef CONFIG_EFI_MIXED
218	movl	efi32_boot_args(%ebp), %edi
219	cmp	$0, %edi
220	jz	1f
221	leal	efi64_stub_entry(%ebp), %eax
222	movl	efi32_boot_args+4(%ebp), %esi
223	movl	efi32_boot_args+8(%ebp), %edx	// saved bootparams pointer
224	cmpl	$0, %edx
225	jnz	1f
226	/*
227	 * efi_pe_entry uses MS calling convention, which requires 32 bytes of
228	 * shadow space on the stack even if all arguments are passed in
229	 * registers. We also need an additional 8 bytes for the space that
230	 * would be occupied by the return address, and this also results in
231	 * the correct stack alignment for entry.
232	 */
233	subl	$40, %esp
234	leal	efi_pe_entry(%ebp), %eax
235	movl	%edi, %ecx			// MS calling convention
236	movl	%esi, %edx
2371:
238#endif
239	pushl	$__KERNEL_CS
240	pushl	%eax
241
242	/* Enter paged protected Mode, activating Long Mode */
243	movl	$(X86_CR0_PG | X86_CR0_PE), %eax /* Enable Paging and Protected mode */
244	movl	%eax, %cr0
245
246	/* Jump from 32bit compatibility mode into 64bit mode. */
247	lret
248SYM_FUNC_END(startup_32)
249
250#ifdef CONFIG_EFI_MIXED
251	.org 0x190
252SYM_FUNC_START(efi32_stub_entry)
253	add	$0x4, %esp		/* Discard return address */
254	popl	%ecx
255	popl	%edx
256	popl	%esi
257
258	call	1f
2591:	pop	%ebp
260	subl	$1b, %ebp
261
262	movl	%esi, efi32_boot_args+8(%ebp)
263SYM_INNER_LABEL(efi32_pe_stub_entry, SYM_L_LOCAL)
264	movl	%ecx, efi32_boot_args(%ebp)
265	movl	%edx, efi32_boot_args+4(%ebp)
266	movb	$0, efi_is64(%ebp)
267
268	/* Save firmware GDTR and code/data selectors */
269	sgdtl	efi32_boot_gdt(%ebp)
270	movw	%cs, efi32_boot_cs(%ebp)
271	movw	%ds, efi32_boot_ds(%ebp)
272
273	/* Disable paging */
274	movl	%cr0, %eax
275	btrl	$X86_CR0_PG_BIT, %eax
276	movl	%eax, %cr0
277
278	jmp	startup_32
279SYM_FUNC_END(efi32_stub_entry)
280#endif
281
282	.code64
283	.org 0x200
284SYM_CODE_START(startup_64)
285	/*
286	 * 64bit entry is 0x200 and it is ABI so immutable!
287	 * We come here either from startup_32 or directly from a
288	 * 64bit bootloader.
289	 * If we come here from a bootloader, kernel(text+data+bss+brk),
290	 * ramdisk, zero_page, command line could be above 4G.
291	 * We depend on an identity mapped page table being provided
292	 * that maps our entire kernel(text+data+bss+brk), zero page
293	 * and command line.
294	 */
295
296	cld
297	cli
298
299	/* Setup data segments. */
300	xorl	%eax, %eax
301	movl	%eax, %ds
302	movl	%eax, %es
303	movl	%eax, %ss
304	movl	%eax, %fs
305	movl	%eax, %gs
306
307	/*
308	 * Compute the decompressed kernel start address.  It is where
309	 * we were loaded at aligned to a 2M boundary. %rbp contains the
310	 * decompressed kernel start address.
311	 *
312	 * If it is a relocatable kernel then decompress and run the kernel
313	 * from load address aligned to 2MB addr, otherwise decompress and
314	 * run the kernel from LOAD_PHYSICAL_ADDR
315	 *
316	 * We cannot rely on the calculation done in 32-bit mode, since we
317	 * may have been invoked via the 64-bit entry point.
318	 */
319
320	/* Start with the delta to where the kernel will run at. */
321#ifdef CONFIG_RELOCATABLE
322	leaq	startup_32(%rip) /* - $startup_32 */, %rbp
323
324#ifdef CONFIG_EFI_STUB
325/*
326 * If we were loaded via the EFI LoadImage service, startup_32 will be at an
327 * offset to the start of the space allocated for the image. efi_pe_entry will
328 * set up image_offset to tell us where the image actually starts, so that we
329 * can use the full available buffer.
330 *	image_offset = startup_32 - image_base
331 * Otherwise image_offset will be zero and has no effect on the calculations.
332 */
333	movl    image_offset(%rip), %eax
334	subq	%rax, %rbp
335#endif
336
337	movl	BP_kernel_alignment(%rsi), %eax
338	decl	%eax
339	addq	%rax, %rbp
340	notq	%rax
341	andq	%rax, %rbp
342	cmpq	$LOAD_PHYSICAL_ADDR, %rbp
343	jae	1f
344#endif
345	movq	$LOAD_PHYSICAL_ADDR, %rbp
3461:
347
348	/* Target address to relocate to for decompression */
349	movl	BP_init_size(%rsi), %ebx
350	subl	$_end, %ebx
351	addq	%rbp, %rbx
352
353	/* Set up the stack */
354	leaq	boot_stack_end(%rbx), %rsp
355
356	/*
357	 * paging_prepare() and cleanup_trampoline() below can have GOT
358	 * references. Adjust the table with address we are running at.
359	 *
360	 * Zero RAX for adjust_got: the GOT was not adjusted before;
361	 * there's no adjustment to undo.
362	 */
363	xorq	%rax, %rax
364
365	/*
366	 * Calculate the address the binary is loaded at and use it as
367	 * a GOT adjustment.
368	 */
369	call	1f
3701:	popq	%rdi
371	subq	$1b, %rdi
372
373	call	.Ladjust_got
374
375	/*
376	 * At this point we are in long mode with 4-level paging enabled,
377	 * but we might want to enable 5-level paging or vice versa.
378	 *
379	 * The problem is that we cannot do it directly. Setting or clearing
380	 * CR4.LA57 in long mode would trigger #GP. So we need to switch off
381	 * long mode and paging first.
382	 *
383	 * We also need a trampoline in lower memory to switch over from
384	 * 4- to 5-level paging for cases when the bootloader puts the kernel
385	 * above 4G, but didn't enable 5-level paging for us.
386	 *
387	 * The same trampoline can be used to switch from 5- to 4-level paging
388	 * mode, like when starting 4-level paging kernel via kexec() when
389	 * original kernel worked in 5-level paging mode.
390	 *
391	 * For the trampoline, we need the top page table to reside in lower
392	 * memory as we don't have a way to load 64-bit values into CR3 in
393	 * 32-bit mode.
394	 *
395	 * We go though the trampoline even if we don't have to: if we're
396	 * already in a desired paging mode. This way the trampoline code gets
397	 * tested on every boot.
398	 */
399
400	/* Make sure we have GDT with 32-bit code segment */
401	leaq	gdt64(%rip), %rax
402	addq	%rax, 2(%rax)
403	lgdt	(%rax)
404
405	/* Reload CS so IRET returns to a CS actually in the GDT */
406	pushq	$__KERNEL_CS
407	leaq	.Lon_kernel_cs(%rip), %rax
408	pushq	%rax
409	lretq
410
411.Lon_kernel_cs:
412
413	/*
414	 * paging_prepare() sets up the trampoline and checks if we need to
415	 * enable 5-level paging.
416	 *
417	 * paging_prepare() returns a two-quadword structure which lands
418	 * into RDX:RAX:
419	 *   - Address of the trampoline is returned in RAX.
420	 *   - Non zero RDX means trampoline needs to enable 5-level
421	 *     paging.
422	 *
423	 * RSI holds real mode data and needs to be preserved across
424	 * this function call.
425	 */
426	pushq	%rsi
427	movq	%rsi, %rdi		/* real mode address */
428	call	paging_prepare
429	popq	%rsi
430
431	/* Save the trampoline address in RCX */
432	movq	%rax, %rcx
433
434	/*
435	 * Load the address of trampoline_return() into RDI.
436	 * It will be used by the trampoline to return to the main code.
437	 */
438	leaq	trampoline_return(%rip), %rdi
439
440	/* Switch to compatibility mode (CS.L = 0 CS.D = 1) via far return */
441	pushq	$__KERNEL32_CS
442	leaq	TRAMPOLINE_32BIT_CODE_OFFSET(%rax), %rax
443	pushq	%rax
444	lretq
445trampoline_return:
446	/* Restore the stack, the 32-bit trampoline uses its own stack */
447	leaq	boot_stack_end(%rbx), %rsp
448
449	/*
450	 * cleanup_trampoline() would restore trampoline memory.
451	 *
452	 * RDI is address of the page table to use instead of page table
453	 * in trampoline memory (if required).
454	 *
455	 * RSI holds real mode data and needs to be preserved across
456	 * this function call.
457	 */
458	pushq	%rsi
459	leaq	top_pgtable(%rbx), %rdi
460	call	cleanup_trampoline
461	popq	%rsi
462
463	/* Zero EFLAGS */
464	pushq	$0
465	popfq
466
467	/*
468	 * Previously we've adjusted the GOT with address the binary was
469	 * loaded at. Now we need to re-adjust for relocation address.
470	 *
471	 * Calculate the address the binary is loaded at, so that we can
472	 * undo the previous GOT adjustment.
473	 */
474	call	1f
4751:	popq	%rax
476	subq	$1b, %rax
477
478	/* The new adjustment is the relocation address */
479	movq	%rbx, %rdi
480	call	.Ladjust_got
481
482/*
483 * Copy the compressed kernel to the end of our buffer
484 * where decompression in place becomes safe.
485 */
486	pushq	%rsi
487	leaq	(_bss-8)(%rip), %rsi
488	leaq	(_bss-8)(%rbx), %rdi
489	movq	$_bss /* - $startup_32 */, %rcx
490	shrq	$3, %rcx
491	std
492	rep	movsq
493	cld
494	popq	%rsi
495
496	/*
497	 * The GDT may get overwritten either during the copy we just did or
498	 * during extract_kernel below. To avoid any issues, repoint the GDTR
499	 * to the new copy of the GDT.
500	 */
501	leaq	gdt64(%rbx), %rax
502	leaq	gdt(%rbx), %rdx
503	movq	%rdx, 2(%rax)
504	lgdt	(%rax)
505
506/*
507 * Jump to the relocated address.
508 */
509	leaq	.Lrelocated(%rbx), %rax
510	jmp	*%rax
511SYM_CODE_END(startup_64)
512
513#ifdef CONFIG_EFI_STUB
514	.org 0x390
515SYM_FUNC_START(efi64_stub_entry)
516SYM_FUNC_START_ALIAS(efi_stub_entry)
517	and	$~0xf, %rsp			/* realign the stack */
518	movq	%rdx, %rbx			/* save boot_params pointer */
519	call	efi_main
520	movq	%rbx,%rsi
521	leaq	startup_64(%rax), %rax
522	jmp	*%rax
523SYM_FUNC_END(efi64_stub_entry)
524SYM_FUNC_END_ALIAS(efi_stub_entry)
525#endif
526
527	.text
528SYM_FUNC_START_LOCAL_NOALIGN(.Lrelocated)
529
530/*
531 * Clear BSS (stack is currently empty)
532 */
533	xorl	%eax, %eax
534	leaq    _bss(%rip), %rdi
535	leaq    _ebss(%rip), %rcx
536	subq	%rdi, %rcx
537	shrq	$3, %rcx
538	rep	stosq
539
540/*
541 * Do the extraction, and jump to the new kernel..
542 */
543	pushq	%rsi			/* Save the real mode argument */
544	movq	%rsi, %rdi		/* real mode address */
545	leaq	boot_heap(%rip), %rsi	/* malloc area for uncompression */
546	leaq	input_data(%rip), %rdx  /* input_data */
547	movl	$z_input_len, %ecx	/* input_len */
548	movq	%rbp, %r8		/* output target address */
549	movl	$z_output_len, %r9d	/* decompressed length, end of relocs */
550	call	extract_kernel		/* returns kernel location in %rax */
551	popq	%rsi
552
553/*
554 * Jump to the decompressed kernel.
555 */
556	jmp	*%rax
557SYM_FUNC_END(.Lrelocated)
558
559/*
560 * Adjust the global offset table
561 *
562 * RAX is the previous adjustment of the table to undo (use 0 if it's the
563 * first time we touch GOT).
564 * RDI is the new adjustment to apply.
565 */
566.Ladjust_got:
567	/* Walk through the GOT adding the address to the entries */
568	leaq	_got(%rip), %rdx
569	leaq	_egot(%rip), %rcx
5701:
571	cmpq	%rcx, %rdx
572	jae	2f
573	subq	%rax, (%rdx)	/* Undo previous adjustment */
574	addq	%rdi, (%rdx)	/* Apply the new adjustment */
575	addq	$8, %rdx
576	jmp	1b
5772:
578	ret
579
580	.code32
581/*
582 * This is the 32-bit trampoline that will be copied over to low memory.
583 *
584 * RDI contains the return address (might be above 4G).
585 * ECX contains the base address of the trampoline memory.
586 * Non zero RDX means trampoline needs to enable 5-level paging.
587 */
588SYM_CODE_START(trampoline_32bit_src)
589	/* Set up data and stack segments */
590	movl	$__KERNEL_DS, %eax
591	movl	%eax, %ds
592	movl	%eax, %ss
593
594	/* Set up new stack */
595	leal	TRAMPOLINE_32BIT_STACK_END(%ecx), %esp
596
597	/* Disable paging */
598	movl	%cr0, %eax
599	btrl	$X86_CR0_PG_BIT, %eax
600	movl	%eax, %cr0
601
602	/* Check what paging mode we want to be in after the trampoline */
603	cmpl	$0, %edx
604	jz	1f
605
606	/* We want 5-level paging: don't touch CR3 if it already points to 5-level page tables */
607	movl	%cr4, %eax
608	testl	$X86_CR4_LA57, %eax
609	jnz	3f
610	jmp	2f
6111:
612	/* We want 4-level paging: don't touch CR3 if it already points to 4-level page tables */
613	movl	%cr4, %eax
614	testl	$X86_CR4_LA57, %eax
615	jz	3f
6162:
617	/* Point CR3 to the trampoline's new top level page table */
618	leal	TRAMPOLINE_32BIT_PGTABLE_OFFSET(%ecx), %eax
619	movl	%eax, %cr3
6203:
621	/* Set EFER.LME=1 as a precaution in case hypervsior pulls the rug */
622	pushl	%ecx
623	pushl	%edx
624	movl	$MSR_EFER, %ecx
625	rdmsr
626	btsl	$_EFER_LME, %eax
627	wrmsr
628	popl	%edx
629	popl	%ecx
630
631	/* Enable PAE and LA57 (if required) paging modes */
632	movl	$X86_CR4_PAE, %eax
633	cmpl	$0, %edx
634	jz	1f
635	orl	$X86_CR4_LA57, %eax
6361:
637	movl	%eax, %cr4
638
639	/* Calculate address of paging_enabled() once we are executing in the trampoline */
640	leal	.Lpaging_enabled - trampoline_32bit_src + TRAMPOLINE_32BIT_CODE_OFFSET(%ecx), %eax
641
642	/* Prepare the stack for far return to Long Mode */
643	pushl	$__KERNEL_CS
644	pushl	%eax
645
646	/* Enable paging again */
647	movl	$(X86_CR0_PG | X86_CR0_PE), %eax
648	movl	%eax, %cr0
649
650	lret
651SYM_CODE_END(trampoline_32bit_src)
652
653	.code64
654SYM_FUNC_START_LOCAL_NOALIGN(.Lpaging_enabled)
655	/* Return from the trampoline */
656	jmp	*%rdi
657SYM_FUNC_END(.Lpaging_enabled)
658
659	/*
660         * The trampoline code has a size limit.
661         * Make sure we fail to compile if the trampoline code grows
662         * beyond TRAMPOLINE_32BIT_CODE_SIZE bytes.
663	 */
664	.org	trampoline_32bit_src + TRAMPOLINE_32BIT_CODE_SIZE
665
666	.code32
667SYM_FUNC_START_LOCAL_NOALIGN(.Lno_longmode)
668	/* This isn't an x86-64 CPU, so hang intentionally, we cannot continue */
6691:
670	hlt
671	jmp     1b
672SYM_FUNC_END(.Lno_longmode)
673
674#include "../../kernel/verify_cpu.S"
675
676	.data
677SYM_DATA_START_LOCAL(gdt64)
678	.word	gdt_end - gdt - 1
679	.quad   gdt - gdt64
680SYM_DATA_END(gdt64)
681	.balign	8
682SYM_DATA_START_LOCAL(gdt)
683	.word	gdt_end - gdt - 1
684	.long	0
685	.word	0
686	.quad	0x00cf9a000000ffff	/* __KERNEL32_CS */
687	.quad	0x00af9a000000ffff	/* __KERNEL_CS */
688	.quad	0x00cf92000000ffff	/* __KERNEL_DS */
689	.quad	0x0080890000000000	/* TS descriptor */
690	.quad   0x0000000000000000	/* TS continued */
691SYM_DATA_END_LABEL(gdt, SYM_L_LOCAL, gdt_end)
692
693#ifdef CONFIG_EFI_STUB
694SYM_DATA(image_offset, .long 0)
695#endif
696
697#ifdef CONFIG_EFI_MIXED
698SYM_DATA_LOCAL(efi32_boot_args, .long 0, 0, 0)
699SYM_DATA(efi_is64, .byte 1)
700
701#define ST32_boottime		60 // offsetof(efi_system_table_32_t, boottime)
702#define BS32_handle_protocol	88 // offsetof(efi_boot_services_32_t, handle_protocol)
703#define LI32_image_base		32 // offsetof(efi_loaded_image_32_t, image_base)
704
705	.text
706	.code32
707SYM_FUNC_START(efi32_pe_entry)
708/*
709 * efi_status_t efi32_pe_entry(efi_handle_t image_handle,
710 *			       efi_system_table_32_t *sys_table)
711 */
712
713	pushl	%ebp
714	movl	%esp, %ebp
715	pushl	%eax				// dummy push to allocate loaded_image
716
717	pushl	%ebx				// save callee-save registers
718	pushl	%edi
719
720	call	verify_cpu			// check for long mode support
721	testl	%eax, %eax
722	movl	$0x80000003, %eax		// EFI_UNSUPPORTED
723	jnz	2f
724
725	call	1f
7261:	pop	%ebx
727	subl	$1b, %ebx
728
729	/* Get the loaded image protocol pointer from the image handle */
730	leal	-4(%ebp), %eax
731	pushl	%eax				// &loaded_image
732	leal	loaded_image_proto(%ebx), %eax
733	pushl	%eax				// pass the GUID address
734	pushl	8(%ebp)				// pass the image handle
735
736	/*
737	 * Note the alignment of the stack frame.
738	 *   sys_table
739	 *   handle             <-- 16-byte aligned on entry by ABI
740	 *   return address
741	 *   frame pointer
742	 *   loaded_image       <-- local variable
743	 *   saved %ebx		<-- 16-byte aligned here
744	 *   saved %edi
745	 *   &loaded_image
746	 *   &loaded_image_proto
747	 *   handle             <-- 16-byte aligned for call to handle_protocol
748	 */
749
750	movl	12(%ebp), %eax			// sys_table
751	movl	ST32_boottime(%eax), %eax	// sys_table->boottime
752	call	*BS32_handle_protocol(%eax)	// sys_table->boottime->handle_protocol
753	addl	$12, %esp			// restore argument space
754	testl	%eax, %eax
755	jnz	2f
756
757	movl	8(%ebp), %ecx			// image_handle
758	movl	12(%ebp), %edx			// sys_table
759	movl	-4(%ebp), %esi			// loaded_image
760	movl	LI32_image_base(%esi), %esi	// loaded_image->image_base
761	movl	%ebx, %ebp			// startup_32 for efi32_pe_stub_entry
762	/*
763	 * We need to set the image_offset variable here since startup_32() will
764	 * use it before we get to the 64-bit efi_pe_entry() in C code.
765	 */
766	subl	%esi, %ebx
767	movl	%ebx, image_offset(%ebp)	// save image_offset
768	jmp	efi32_pe_stub_entry
769
7702:	popl	%edi				// restore callee-save registers
771	popl	%ebx
772	leave
773	ret
774SYM_FUNC_END(efi32_pe_entry)
775
776	.section ".rodata"
777	/* EFI loaded image protocol GUID */
778	.balign 4
779SYM_DATA_START_LOCAL(loaded_image_proto)
780	.long	0x5b1b31a1
781	.word	0x9562, 0x11d2
782	.byte	0x8e, 0x3f, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b
783SYM_DATA_END(loaded_image_proto)
784#endif
785
786/*
787 * Stack and heap for uncompression
788 */
789	.bss
790	.balign 4
791SYM_DATA_LOCAL(boot_heap,	.fill BOOT_HEAP_SIZE, 1, 0)
792
793SYM_DATA_START_LOCAL(boot_stack)
794	.fill BOOT_STACK_SIZE, 1, 0
795	.balign 16
796SYM_DATA_END_LABEL(boot_stack, SYM_L_LOCAL, boot_stack_end)
797
798/*
799 * Space for page tables (not in .bss so not zeroed)
800 */
801	.section ".pgtable","aw",@nobits
802	.balign 4096
803SYM_DATA_LOCAL(pgtable,		.fill BOOT_PGT_SIZE, 1, 0)
804
805/*
806 * The page table is going to be used instead of page table in the trampoline
807 * memory.
808 */
809SYM_DATA_LOCAL(top_pgtable,	.fill PAGE_SIZE, 1, 0)
810