xref: /OK3568_Linux_fs/kernel/arch/x86/boot/compressed/head_32.S (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun/* SPDX-License-Identifier: GPL-2.0 */
2*4882a593Smuzhiyun/*
3*4882a593Smuzhiyun *  linux/boot/head.S
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun *  Copyright (C) 1991, 1992, 1993  Linus Torvalds
6*4882a593Smuzhiyun */
7*4882a593Smuzhiyun
8*4882a593Smuzhiyun/*
9*4882a593Smuzhiyun *  head.S contains the 32-bit startup code.
10*4882a593Smuzhiyun *
11*4882a593Smuzhiyun * NOTE!!! Startup happens at absolute address 0x00001000, which is also where
12*4882a593Smuzhiyun * the page directory will exist. The startup code will be overwritten by
13*4882a593Smuzhiyun * the page directory. [According to comments etc elsewhere on a compressed
14*4882a593Smuzhiyun * kernel it will end up at 0x1000 + 1Mb I hope so as I assume this. - AC]
15*4882a593Smuzhiyun *
16*4882a593Smuzhiyun * Page 0 is deliberately kept safe, since System Management Mode code in
17*4882a593Smuzhiyun * laptops may need to access the BIOS data stored there.  This is also
18*4882a593Smuzhiyun * useful for future device drivers that either access the BIOS via VM86
19*4882a593Smuzhiyun * mode.
20*4882a593Smuzhiyun */
21*4882a593Smuzhiyun
22*4882a593Smuzhiyun/*
23*4882a593Smuzhiyun * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996
24*4882a593Smuzhiyun */
25*4882a593Smuzhiyun	.text
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun#include <linux/init.h>
28*4882a593Smuzhiyun#include <linux/linkage.h>
29*4882a593Smuzhiyun#include <asm/segment.h>
30*4882a593Smuzhiyun#include <asm/page_types.h>
31*4882a593Smuzhiyun#include <asm/boot.h>
32*4882a593Smuzhiyun#include <asm/asm-offsets.h>
33*4882a593Smuzhiyun#include <asm/bootparam.h>
34*4882a593Smuzhiyun
35*4882a593Smuzhiyun/*
36*4882a593Smuzhiyun * These symbols needed to be marked as .hidden to prevent the BFD linker from
37*4882a593Smuzhiyun * generating R_386_32 (rather than R_386_RELATIVE) relocations for them when
38*4882a593Smuzhiyun * the 32-bit compressed kernel is linked as PIE. This is no longer necessary,
39*4882a593Smuzhiyun * but it doesn't hurt to keep them .hidden.
40*4882a593Smuzhiyun */
41*4882a593Smuzhiyun	.hidden _bss
42*4882a593Smuzhiyun	.hidden _ebss
43*4882a593Smuzhiyun	.hidden _end
44*4882a593Smuzhiyun
45*4882a593Smuzhiyun	__HEAD
46*4882a593SmuzhiyunSYM_FUNC_START(startup_32)
47*4882a593Smuzhiyun	cld
48*4882a593Smuzhiyun	cli
49*4882a593Smuzhiyun
50*4882a593Smuzhiyun/*
51*4882a593Smuzhiyun * Calculate the delta between where we were compiled to run
52*4882a593Smuzhiyun * at and where we were actually loaded at.  This can only be done
53*4882a593Smuzhiyun * with a short local call on x86.  Nothing  else will tell us what
54*4882a593Smuzhiyun * address we are running at.  The reserved chunk of the real-mode
55*4882a593Smuzhiyun * data at 0x1e4 (defined as a scratch field) are used as the stack
56*4882a593Smuzhiyun * for this calculation. Only 4 bytes are needed.
57*4882a593Smuzhiyun */
58*4882a593Smuzhiyun	leal	(BP_scratch+4)(%esi), %esp
59*4882a593Smuzhiyun	call	1f
60*4882a593Smuzhiyun1:	popl	%edx
61*4882a593Smuzhiyun	addl	$_GLOBAL_OFFSET_TABLE_+(.-1b), %edx
62*4882a593Smuzhiyun
63*4882a593Smuzhiyun	/* Load new GDT */
64*4882a593Smuzhiyun	leal	gdt@GOTOFF(%edx), %eax
65*4882a593Smuzhiyun	movl	%eax, 2(%eax)
66*4882a593Smuzhiyun	lgdt	(%eax)
67*4882a593Smuzhiyun
68*4882a593Smuzhiyun	/* Load segment registers with our descriptors */
69*4882a593Smuzhiyun	movl	$__BOOT_DS, %eax
70*4882a593Smuzhiyun	movl	%eax, %ds
71*4882a593Smuzhiyun	movl	%eax, %es
72*4882a593Smuzhiyun	movl	%eax, %fs
73*4882a593Smuzhiyun	movl	%eax, %gs
74*4882a593Smuzhiyun	movl	%eax, %ss
75*4882a593Smuzhiyun
76*4882a593Smuzhiyun/*
77*4882a593Smuzhiyun * %edx contains the address we are loaded at by the boot loader (plus the
78*4882a593Smuzhiyun * offset to the GOT).  The below code calculates %ebx to be the address where
79*4882a593Smuzhiyun * we should move the kernel image temporarily for safe in-place decompression
80*4882a593Smuzhiyun * (again, plus the offset to the GOT).
81*4882a593Smuzhiyun *
82*4882a593Smuzhiyun * %ebp is calculated to be the address that the kernel will be decompressed to.
83*4882a593Smuzhiyun */
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun#ifdef CONFIG_RELOCATABLE
86*4882a593Smuzhiyun	leal	startup_32@GOTOFF(%edx), %ebx
87*4882a593Smuzhiyun
88*4882a593Smuzhiyun#ifdef CONFIG_EFI_STUB
89*4882a593Smuzhiyun/*
90*4882a593Smuzhiyun * If we were loaded via the EFI LoadImage service, startup_32() will be at an
91*4882a593Smuzhiyun * offset to the start of the space allocated for the image. efi_pe_entry() will
92*4882a593Smuzhiyun * set up image_offset to tell us where the image actually starts, so that we
93*4882a593Smuzhiyun * can use the full available buffer.
94*4882a593Smuzhiyun *	image_offset = startup_32 - image_base
95*4882a593Smuzhiyun * Otherwise image_offset will be zero and has no effect on the calculations.
96*4882a593Smuzhiyun */
97*4882a593Smuzhiyun	subl    image_offset@GOTOFF(%edx), %ebx
98*4882a593Smuzhiyun#endif
99*4882a593Smuzhiyun
100*4882a593Smuzhiyun	movl	BP_kernel_alignment(%esi), %eax
101*4882a593Smuzhiyun	decl	%eax
102*4882a593Smuzhiyun	addl    %eax, %ebx
103*4882a593Smuzhiyun	notl	%eax
104*4882a593Smuzhiyun	andl    %eax, %ebx
105*4882a593Smuzhiyun	cmpl	$LOAD_PHYSICAL_ADDR, %ebx
106*4882a593Smuzhiyun	jae	1f
107*4882a593Smuzhiyun#endif
108*4882a593Smuzhiyun	movl	$LOAD_PHYSICAL_ADDR, %ebx
109*4882a593Smuzhiyun1:
110*4882a593Smuzhiyun
111*4882a593Smuzhiyun	movl	%ebx, %ebp	// Save the output address for later
112*4882a593Smuzhiyun	/* Target address to relocate to for decompression */
113*4882a593Smuzhiyun	addl    BP_init_size(%esi), %ebx
114*4882a593Smuzhiyun	subl    $_end@GOTOFF, %ebx
115*4882a593Smuzhiyun
116*4882a593Smuzhiyun	/* Set up the stack */
117*4882a593Smuzhiyun	leal	boot_stack_end@GOTOFF(%ebx), %esp
118*4882a593Smuzhiyun
119*4882a593Smuzhiyun	/* Zero EFLAGS */
120*4882a593Smuzhiyun	pushl	$0
121*4882a593Smuzhiyun	popfl
122*4882a593Smuzhiyun
123*4882a593Smuzhiyun/*
124*4882a593Smuzhiyun * Copy the compressed kernel to the end of our buffer
125*4882a593Smuzhiyun * where decompression in place becomes safe.
126*4882a593Smuzhiyun */
127*4882a593Smuzhiyun	pushl	%esi
128*4882a593Smuzhiyun	leal	(_bss@GOTOFF-4)(%edx), %esi
129*4882a593Smuzhiyun	leal	(_bss@GOTOFF-4)(%ebx), %edi
130*4882a593Smuzhiyun	movl	$(_bss - startup_32), %ecx
131*4882a593Smuzhiyun	shrl	$2, %ecx
132*4882a593Smuzhiyun	std
133*4882a593Smuzhiyun	rep	movsl
134*4882a593Smuzhiyun	cld
135*4882a593Smuzhiyun	popl	%esi
136*4882a593Smuzhiyun
137*4882a593Smuzhiyun	/*
138*4882a593Smuzhiyun	 * The GDT may get overwritten either during the copy we just did or
139*4882a593Smuzhiyun	 * during extract_kernel below. To avoid any issues, repoint the GDTR
140*4882a593Smuzhiyun	 * to the new copy of the GDT.
141*4882a593Smuzhiyun	 */
142*4882a593Smuzhiyun	leal	gdt@GOTOFF(%ebx), %eax
143*4882a593Smuzhiyun	movl	%eax, 2(%eax)
144*4882a593Smuzhiyun	lgdt	(%eax)
145*4882a593Smuzhiyun
146*4882a593Smuzhiyun/*
147*4882a593Smuzhiyun * Jump to the relocated address.
148*4882a593Smuzhiyun */
149*4882a593Smuzhiyun	leal	.Lrelocated@GOTOFF(%ebx), %eax
150*4882a593Smuzhiyun	jmp	*%eax
151*4882a593SmuzhiyunSYM_FUNC_END(startup_32)
152*4882a593Smuzhiyun
153*4882a593Smuzhiyun#ifdef CONFIG_EFI_STUB
154*4882a593SmuzhiyunSYM_FUNC_START(efi32_stub_entry)
155*4882a593SmuzhiyunSYM_FUNC_START_ALIAS(efi_stub_entry)
156*4882a593Smuzhiyun	add	$0x4, %esp
157*4882a593Smuzhiyun	movl	8(%esp), %esi	/* save boot_params pointer */
158*4882a593Smuzhiyun	call	efi_main
159*4882a593Smuzhiyun	/* efi_main returns the possibly relocated address of startup_32 */
160*4882a593Smuzhiyun	jmp	*%eax
161*4882a593SmuzhiyunSYM_FUNC_END(efi32_stub_entry)
162*4882a593SmuzhiyunSYM_FUNC_END_ALIAS(efi_stub_entry)
163*4882a593Smuzhiyun#endif
164*4882a593Smuzhiyun
165*4882a593Smuzhiyun	.text
166*4882a593SmuzhiyunSYM_FUNC_START_LOCAL_NOALIGN(.Lrelocated)
167*4882a593Smuzhiyun
168*4882a593Smuzhiyun/*
169*4882a593Smuzhiyun * Clear BSS (stack is currently empty)
170*4882a593Smuzhiyun */
171*4882a593Smuzhiyun	xorl	%eax, %eax
172*4882a593Smuzhiyun	leal	_bss@GOTOFF(%ebx), %edi
173*4882a593Smuzhiyun	leal	_ebss@GOTOFF(%ebx), %ecx
174*4882a593Smuzhiyun	subl	%edi, %ecx
175*4882a593Smuzhiyun	shrl	$2, %ecx
176*4882a593Smuzhiyun	rep	stosl
177*4882a593Smuzhiyun
178*4882a593Smuzhiyun/*
179*4882a593Smuzhiyun * Do the extraction, and jump to the new kernel..
180*4882a593Smuzhiyun */
181*4882a593Smuzhiyun	/* push arguments for extract_kernel: */
182*4882a593Smuzhiyun
183*4882a593Smuzhiyun	pushl	output_len@GOTOFF(%ebx)	/* decompressed length, end of relocs */
184*4882a593Smuzhiyun	pushl	%ebp			/* output address */
185*4882a593Smuzhiyun	pushl	input_len@GOTOFF(%ebx)	/* input_len */
186*4882a593Smuzhiyun	leal	input_data@GOTOFF(%ebx), %eax
187*4882a593Smuzhiyun	pushl	%eax			/* input_data */
188*4882a593Smuzhiyun	leal	boot_heap@GOTOFF(%ebx), %eax
189*4882a593Smuzhiyun	pushl	%eax			/* heap area */
190*4882a593Smuzhiyun	pushl	%esi			/* real mode pointer */
191*4882a593Smuzhiyun	call	extract_kernel		/* returns kernel location in %eax */
192*4882a593Smuzhiyun	addl	$24, %esp
193*4882a593Smuzhiyun
194*4882a593Smuzhiyun/*
195*4882a593Smuzhiyun * Jump to the extracted kernel.
196*4882a593Smuzhiyun */
197*4882a593Smuzhiyun	xorl	%ebx, %ebx
198*4882a593Smuzhiyun	jmp	*%eax
199*4882a593SmuzhiyunSYM_FUNC_END(.Lrelocated)
200*4882a593Smuzhiyun
201*4882a593Smuzhiyun	.data
202*4882a593Smuzhiyun	.balign	8
203*4882a593SmuzhiyunSYM_DATA_START_LOCAL(gdt)
204*4882a593Smuzhiyun	.word	gdt_end - gdt - 1
205*4882a593Smuzhiyun	.long	0
206*4882a593Smuzhiyun	.word	0
207*4882a593Smuzhiyun	.quad	0x0000000000000000	/* Reserved */
208*4882a593Smuzhiyun	.quad	0x00cf9a000000ffff	/* __KERNEL_CS */
209*4882a593Smuzhiyun	.quad	0x00cf92000000ffff	/* __KERNEL_DS */
210*4882a593SmuzhiyunSYM_DATA_END_LABEL(gdt, SYM_L_LOCAL, gdt_end)
211*4882a593Smuzhiyun
212*4882a593Smuzhiyun#ifdef CONFIG_EFI_STUB
213*4882a593SmuzhiyunSYM_DATA(image_offset, .long 0)
214*4882a593Smuzhiyun#endif
215*4882a593Smuzhiyun
216*4882a593Smuzhiyun/*
217*4882a593Smuzhiyun * Stack and heap for uncompression
218*4882a593Smuzhiyun */
219*4882a593Smuzhiyun	.bss
220*4882a593Smuzhiyun	.balign 4
221*4882a593Smuzhiyunboot_heap:
222*4882a593Smuzhiyun	.fill BOOT_HEAP_SIZE, 1, 0
223*4882a593Smuzhiyunboot_stack:
224*4882a593Smuzhiyun	.fill BOOT_STACK_SIZE, 1, 0
225*4882a593Smuzhiyunboot_stack_end:
226