head_32.S 6.1 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14
/*
 *  linux/boot/head.S
 *
 *  Copyright (C) 1991, 1992, 1993  Linus Torvalds
 */

/*
 *  head.S contains the 32-bit startup code.
 *
 * NOTE!!! Startup happens at absolute address 0x00001000, which is also where
 * the page directory will exist. The startup code will be overwritten by
 * the page directory. [According to comments etc elsewhere on a compressed
 * kernel it will end up at 0x1000 + 1Mb I hope so as I assume this. - AC]
 *
15
 * Page 0 is deliberately kept safe, since System Management Mode code in
L
Linus Torvalds 已提交
16
 * laptops may need to access the BIOS data stored there.  This is also
17
 * useful for future device drivers that either access the BIOS via VM86
L
Linus Torvalds 已提交
18 19 20 21 22 23
 * mode.
 */

/*
 * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996
 */
24
	.text
L
Linus Torvalds 已提交
25

26
#include <linux/init.h>
L
Linus Torvalds 已提交
27 28
#include <linux/linkage.h>
#include <asm/segment.h>
29
#include <asm/page_types.h>
30
#include <asm/boot.h>
R
Rusty Russell 已提交
31
#include <asm/asm-offsets.h>
32
#include <asm/bootparam.h>
L
Linus Torvalds 已提交
33

34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
/*
 * The 32-bit x86 assembler in binutils 2.26 will generate R_386_GOT32X
 * relocation to get the symbol address in PIC.  When the compressed x86
 * kernel isn't built as PIC, the linker optimizes R_386_GOT32X
 * relocations to their fixed symbol addresses.  However, when the
 * compressed x86 kernel is loaded at a different address, it leads
 * to the following load failure:
 *
 *   Failed to allocate space for phdrs
 *
 * during the decompression stage.
 *
 * If the compressed x86 kernel is relocatable at run-time, it should be
 * compiled with -fPIE, instead of -fPIC, if possible and should be built as
 * Position Independent Executable (PIE) so that linker won't optimize
 * R_386_GOT32X relocation to its fixed symbol address.  Older
 * linkers generate R_386_32 relocations against locally defined symbols,
 * _bss, _ebss, _got and _egot, in PIE.  It isn't wrong, just less
 * optimal than R_386_RELATIVE.  But the x86 kernel fails to properly handle
 * R_386_32 relocations when relocating the kernel.  To generate
 * R_386_RELATIVE relocations, we mark _bss, _ebss, _got and _egot as
 * hidden:
 */
	.hidden _bss
	.hidden _ebss
	.hidden _got
	.hidden _egot

62
	__HEAD
63
ENTRY(startup_32)
M
Matt Fleming 已提交
64
#ifdef CONFIG_EFI_STUB
65 66
	jmp	preferred_addr

M
Matt Fleming 已提交
67 68
	/*
	 * We don't need the return address, so set up the stack so
69
	 * efi_main() can find its arguments.
M
Matt Fleming 已提交
70
	 */
71
ENTRY(efi_pe_entry)
M
Matt Fleming 已提交
72 73
	add	$0x4, %esp

74 75 76 77 78 79 80 81 82 83 84 85 86 87
	call	1f
1:	popl	%esi
	subl	$1b, %esi

	popl	%ecx
	movl	%ecx, efi32_config(%esi)	/* Handle */
	popl	%ecx
	movl	%ecx, efi32_config+8(%esi)	/* EFI System table pointer */

	/* Relocate efi_config->call() */
	leal	efi32_config(%esi), %eax
	add	%esi, 88(%eax)
	pushl	%eax

M
Matt Fleming 已提交
88 89
	call	make_boot_params
	cmpl	$0, %eax
90
	je	fail
91
	movl	%esi, BP_code32_start(%eax)
92
	popl	%ecx
M
Matt Fleming 已提交
93 94
	pushl	%eax
	pushl	%ecx
95
	jmp	2f		/* Skip efi_config initialization */
M
Matt Fleming 已提交
96

97
ENTRY(efi32_stub_entry)
98
	add	$0x4, %esp
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
	popl	%ecx
	popl	%edx

	call	1f
1:	popl	%esi
	subl	$1b, %esi

	movl	%ecx, efi32_config(%esi)	/* Handle */
	movl	%edx, efi32_config+8(%esi)	/* EFI System table pointer */

	/* Relocate efi_config->call() */
	leal	efi32_config(%esi), %eax
	add	%esi, 88(%eax)
	pushl	%eax
2:
M
Matt Fleming 已提交
114 115 116
	call	efi_main
	cmpl	$0, %eax
	movl	%eax, %esi
117
	jne	2f
118
fail:
119 120
	/* EFI init failed, so hang. */
	hlt
121
	jmp	fail
122
2:
123
	movl	BP_code32_start(%esi), %eax
M
Matt Fleming 已提交
124 125 126 127 128
	leal	preferred_addr(%eax), %eax
	jmp	*%eax

preferred_addr:
#endif
129
	cld
130 131 132 133
	/*
	 * Test KEEP_SEGMENTS flag to see if the bootloader is asking
	 * us to not reload segments
	 */
134
	testb	$KEEP_SEGMENTS, BP_loadflags(%esi)
135
	jnz	1f
R
Rusty Russell 已提交
136

137
	cli
138 139 140 141 142 143
	movl	$__BOOT_DS, %eax
	movl	%eax, %ds
	movl	%eax, %es
	movl	%eax, %fs
	movl	%eax, %gs
	movl	%eax, %ss
144
1:
R
Rusty Russell 已提交
145

146 147
/*
 * Calculate the delta between where we were compiled to run
148 149 150
 * at and where we were actually loaded at.  This can only be done
 * with a short local call on x86.  Nothing  else will tell us what
 * address we are running at.  The reserved chunk of the real-mode
151 152
 * data at 0x1e4 (defined as a scratch field) are used as the stack
 * for this calculation. Only 4 bytes are needed.
153
 */
154 155 156 157
	leal	(BP_scratch+4)(%esi), %esp
	call	1f
1:	popl	%ebp
	subl	$1b, %ebp
158

159 160
/*
 * %ebp contains the address we are loaded at by the boot loader and %ebx
161 162
 * contains the address where we should move the kernel image temporarily
 * for safe in-place decompression.
163
 */
164

165
#ifdef CONFIG_RELOCATABLE
166
	movl	%ebp, %ebx
167 168 169 170 171
	movl	BP_kernel_alignment(%esi), %eax
	decl	%eax
	addl    %eax, %ebx
	notl	%eax
	andl    %eax, %ebx
172 173
	cmpl	$LOAD_PHYSICAL_ADDR, %ebx
	jge	1f
174
#endif
175 176
	movl	$LOAD_PHYSICAL_ADDR, %ebx
1:
177

178
	/* Target address to relocate to for decompression */
179 180 181
	movl    BP_init_size(%esi), %eax
	subl    $_end, %eax
	addl    %eax, %ebx
182

183 184 185
	/* Set up the stack */
	leal	boot_stack_end(%ebx), %esp

186 187 188 189
	/* Zero EFLAGS */
	pushl	$0
	popfl

190 191
/*
 * Copy the compressed kernel to the end of our buffer
192 193
 * where decompression in place becomes safe.
 */
194
	pushl	%esi
195 196
	leal	(_bss-4)(%ebp), %esi
	leal	(_bss-4)(%ebx), %edi
197
	movl	$(_bss - startup_32), %ecx
198
	shrl	$2, %ecx
199
	std
200
	rep	movsl
201
	cld
202
	popl	%esi
203

L
Linus Torvalds 已提交
204
/*
205
 * Jump to the relocated address.
L
Linus Torvalds 已提交
206
 */
207 208
	leal	relocated(%ebx), %eax
	jmp	*%eax
209 210
ENDPROC(startup_32)

211
	.text
212 213
relocated:

L
Linus Torvalds 已提交
214
/*
215
 * Clear BSS (stack is currently empty)
L
Linus Torvalds 已提交
216
 */
217
	xorl	%eax, %eax
218
	leal	_bss(%ebx), %edi
219 220
	leal	_ebss(%ebx), %ecx
	subl	%edi, %ecx
221 222
	shrl	$2, %ecx
	rep	stosl
223

224 225 226 227 228 229 230 231 232 233 234 235 236
/*
 * Adjust our own GOT
 */
	leal	_got(%ebx), %edx
	leal	_egot(%ebx), %ecx
1:
	cmpl	%ecx, %edx
	jae	2f
	addl	%ebx, (%edx)
	addl	$4, %edx
	jmp	1b
2:

L
Linus Torvalds 已提交
237
/*
238
 * Do the extraction, and jump to the new kernel..
L
Linus Torvalds 已提交
239
 */
240
				/* push arguments for extract_kernel: */
241
	pushl	$z_output_len	/* decompressed length, end of relocs */
242 243 244 245 246

	movl    BP_init_size(%esi), %eax
	subl    $_end, %eax
	movl    %ebx, %ebp
	subl    %eax, %ebp
247
	pushl	%ebp		/* output address */
248

249
	pushl	$z_input_len	/* input_len */
250 251 252 253 254
	leal	input_data(%ebx), %eax
	pushl	%eax		/* input_data */
	leal	boot_heap(%ebx), %eax
	pushl	%eax		/* heap area */
	pushl	%esi		/* real mode pointer */
255
	call	extract_kernel	/* returns kernel location in %eax */
256
	addl	$24, %esp
L
Linus Torvalds 已提交
257 258

/*
259
 * Jump to the extracted kernel.
L
Linus Torvalds 已提交
260
 */
261
	xorl	%ebx, %ebx
262
	jmp	*%eax
263

264
#ifdef CONFIG_EFI_STUB
265
	.data
266 267 268 269 270
efi32_config:
	.fill 11,8,0
	.long efi_call_phys
	.long 0
	.byte 0
M
Matt Fleming 已提交
271
#endif
272

273 274 275 276 277
/*
 * Stack and heap for uncompression
 */
	.bss
	.balign 4
278 279 280 281 282
boot_heap:
	.fill BOOT_HEAP_SIZE, 1, 0
boot_stack:
	.fill BOOT_STACK_SIZE, 1, 0
boot_stack_end: