blob: fd0b6a272dd5bf252b4aad12be6b961789cc2404 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/boot/head.S
3 *
4 * Copyright (C) 1991, 1992, 1993 Linus Torvalds
5 */
6
7/*
8 * head.S contains the 32-bit startup code.
9 *
10 * NOTE!!! Startup happens at absolute address 0x00001000, which is also where
11 * the page directory will exist. The startup code will be overwritten by
12 * the page directory. [According to comments etc elsewhere on a compressed
13 * kernel it will end up at 0x1000 + 1Mb I hope so as I assume this. - AC]
14 *
H. Peter Anvin5f64ec62009-05-08 15:45:17 -070015 * Page 0 is deliberately kept safe, since System Management Mode code in
Linus Torvalds1da177e2005-04-16 15:20:36 -070016 * laptops may need to access the BIOS data stored there. This is also
H. Peter Anvin5f64ec62009-05-08 15:45:17 -070017 * useful for future device drivers that either access the BIOS via VM86
Linus Torvalds1da177e2005-04-16 15:20:36 -070018 * mode.
19 */
20
21/*
22 * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996
23 */
H. Peter Anvin5f64ec62009-05-08 15:45:17 -070024 .text
Linus Torvalds1da177e2005-04-16 15:20:36 -070025
Tim Abbott1dc818c2009-09-16 16:44:27 -040026#include <linux/init.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070027#include <linux/linkage.h>
28#include <asm/segment.h>
Jeremy Fitzhardinge0341c142009-02-13 11:14:01 -080029#include <asm/page_types.h>
Vivek Goyale69f2022006-12-07 02:14:04 +010030#include <asm/boot.h>
Rusty Russella24e7852007-10-21 16:41:35 -070031#include <asm/asm-offsets.h>
Alexander Kuleshovfb148d82015-02-19 13:34:58 +060032#include <asm/bootparam.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070033
H.J. Lu6d92bc92016-03-16 20:04:35 -070034/*
35 * The 32-bit x86 assembler in binutils 2.26 will generate R_386_GOT32X
36 * relocation to get the symbol address in PIC. When the compressed x86
37 * kernel isn't built as PIC, the linker optimizes R_386_GOT32X
38 * relocations to their fixed symbol addresses. However, when the
39 * compressed x86 kernel is loaded at a different address, it leads
40 * to the following load failure:
41 *
42 * Failed to allocate space for phdrs
43 *
44 * during the decompression stage.
45 *
46 * If the compressed x86 kernel is relocatable at run-time, it should be
47 * compiled with -fPIE, instead of -fPIC, if possible and should be built as
48 * Position Independent Executable (PIE) so that linker won't optimize
49 * R_386_GOT32X relocation to its fixed symbol address. Older
50 * linkers generate R_386_32 relocations against locally defined symbols,
51 * _bss, _ebss, _got and _egot, in PIE. It isn't wrong, just less
52 * optimal than R_386_RELATIVE. But the x86 kernel fails to properly handle
53 * R_386_32 relocations when relocating the kernel. To generate
54 * R_386_RELATIVE relocations, we mark _bss, _ebss, _got and _egot as
55 * hidden:
56 */
57 .hidden _bss
58 .hidden _ebss
59 .hidden _got
60 .hidden _egot
61
Tim Abbott1dc818c2009-09-16 16:44:27 -040062 __HEAD
Cyrill Gorcunovcb425af2009-02-14 00:50:23 +030063ENTRY(startup_32)
Matt Fleming291f3632011-12-12 21:27:52 +000064#ifdef CONFIG_EFI_STUB
Matt Flemingb1994302012-04-15 16:06:04 +010065 jmp preferred_addr
66
Matt Fleming291f3632011-12-12 21:27:52 +000067 /*
68 * We don't need the return address, so set up the stack so
David Woodhouse99f857d2013-01-10 14:31:59 +000069 * efi_main() can find its arguments.
Matt Fleming291f3632011-12-12 21:27:52 +000070 */
David Woodhouse99f857d2013-01-10 14:31:59 +000071ENTRY(efi_pe_entry)
Matt Fleming291f3632011-12-12 21:27:52 +000072 add $0x4, %esp
73
Matt Fleming54b52d82014-01-10 15:27:14 +000074 call 1f
751: popl %esi
76 subl $1b, %esi
77
78 popl %ecx
79 movl %ecx, efi32_config(%esi) /* Handle */
80 popl %ecx
81 movl %ecx, efi32_config+8(%esi) /* EFI System table pointer */
82
83 /* Relocate efi_config->call() */
84 leal efi32_config(%esi), %eax
Lukas Wunner0a637ee2016-08-22 12:01:21 +020085 add %esi, 32(%eax)
Matt Fleming54b52d82014-01-10 15:27:14 +000086 pushl %eax
87
Matt Fleming9ca8f722012-07-19 10:23:48 +010088 call make_boot_params
89 cmpl $0, %eax
Matt Fleming54b52d82014-01-10 15:27:14 +000090 je fail
Matt Fleming7e8213c2014-04-08 13:14:00 +010091 movl %esi, BP_code32_start(%eax)
Matt Fleming54b52d82014-01-10 15:27:14 +000092 popl %ecx
Matt Fleming9ca8f722012-07-19 10:23:48 +010093 pushl %eax
Matt Fleming9ca8f722012-07-19 10:23:48 +010094 pushl %ecx
Matt Fleming54b52d82014-01-10 15:27:14 +000095 jmp 2f /* Skip efi_config initialization */
Matt Fleming9ca8f722012-07-19 10:23:48 +010096
Matt Flemingb8ff87a2014-01-10 15:54:31 +000097ENTRY(efi32_stub_entry)
David Woodhousef7916202013-01-07 22:01:50 +000098 add $0x4, %esp
Matt Fleming54b52d82014-01-10 15:27:14 +000099 popl %ecx
100 popl %edx
101
102 call 1f
1031: popl %esi
104 subl $1b, %esi
105
106 movl %ecx, efi32_config(%esi) /* Handle */
107 movl %edx, efi32_config+8(%esi) /* EFI System table pointer */
108
109 /* Relocate efi_config->call() */
110 leal efi32_config(%esi), %eax
Lukas Wunner0a637ee2016-08-22 12:01:21 +0200111 add %esi, 32(%eax)
Matt Fleming54b52d82014-01-10 15:27:14 +0000112 pushl %eax
1132:
Matt Fleming291f3632011-12-12 21:27:52 +0000114 call efi_main
115 cmpl $0, %eax
Matt Fleming291f3632011-12-12 21:27:52 +0000116 movl %eax, %esi
Matt Flemingb1994302012-04-15 16:06:04 +0100117 jne 2f
Matt Fleming54b52d82014-01-10 15:27:14 +0000118fail:
Matt Flemingb1994302012-04-15 16:06:04 +0100119 /* EFI init failed, so hang. */
120 hlt
Matt Fleming54b52d82014-01-10 15:27:14 +0000121 jmp fail
Matt Flemingb1994302012-04-15 16:06:04 +01001222:
Matt Fleming7e8213c2014-04-08 13:14:00 +0100123 movl BP_code32_start(%esi), %eax
Matt Fleming291f3632011-12-12 21:27:52 +0000124 leal preferred_addr(%eax), %eax
125 jmp *%eax
126
127preferred_addr:
128#endif
Eric W. Biedermanbd531472007-10-26 11:29:04 -0600129 cld
H. Peter Anvin5f64ec62009-05-08 15:45:17 -0700130 /*
131 * Test KEEP_SEGMENTS flag to see if the bootloader is asking
132 * us to not reload segments
133 */
Alexander Kuleshovfb148d82015-02-19 13:34:58 +0600134 testb $KEEP_SEGMENTS, BP_loadflags(%esi)
H. Peter Anvin5f64ec62009-05-08 15:45:17 -0700135 jnz 1f
Rusty Russella24e7852007-10-21 16:41:35 -0700136
Eric W. Biedermanbd531472007-10-26 11:29:04 -0600137 cli
H. Peter Anvin5f64ec62009-05-08 15:45:17 -0700138 movl $__BOOT_DS, %eax
139 movl %eax, %ds
140 movl %eax, %es
141 movl %eax, %fs
142 movl %eax, %gs
143 movl %eax, %ss
Eric W. Biedermanbd531472007-10-26 11:29:04 -06001441:
Rusty Russella24e7852007-10-21 16:41:35 -0700145
H. Peter Anvin5f64ec62009-05-08 15:45:17 -0700146/*
147 * Calculate the delta between where we were compiled to run
Eric W. Biederman968de4f2006-12-07 02:14:04 +0100148 * at and where we were actually loaded at. This can only be done
149 * with a short local call on x86. Nothing else will tell us what
150 * address we are running at. The reserved chunk of the real-mode
H. Peter Anvin85414b62007-07-11 12:18:33 -0700151 * data at 0x1e4 (defined as a scratch field) are used as the stack
152 * for this calculation. Only 4 bytes are needed.
Eric W. Biederman968de4f2006-12-07 02:14:04 +0100153 */
H. Peter Anvin5f64ec62009-05-08 15:45:17 -0700154 leal (BP_scratch+4)(%esi), %esp
155 call 1f
1561: popl %ebp
157 subl $1b, %ebp
Eric W. Biederman968de4f2006-12-07 02:14:04 +0100158
H. Peter Anvin5f64ec62009-05-08 15:45:17 -0700159/*
160 * %ebp contains the address we are loaded at by the boot loader and %ebx
Vivek Goyale69f2022006-12-07 02:14:04 +0100161 * contains the address where we should move the kernel image temporarily
162 * for safe in-place decompression.
Eric W. Biederman968de4f2006-12-07 02:14:04 +0100163 */
Vivek Goyale69f2022006-12-07 02:14:04 +0100164
Eric W. Biederman968de4f2006-12-07 02:14:04 +0100165#ifdef CONFIG_RELOCATABLE
H. Peter Anvin5f64ec62009-05-08 15:45:17 -0700166 movl %ebp, %ebx
H. Peter Anvin37ba7ab2009-05-11 15:56:08 -0700167 movl BP_kernel_alignment(%esi), %eax
168 decl %eax
169 addl %eax, %ebx
170 notl %eax
171 andl %eax, %ebx
Kees Cook8ab38202013-10-10 17:18:14 -0700172 cmpl $LOAD_PHYSICAL_ADDR, %ebx
173 jge 1f
Eric W. Biederman968de4f2006-12-07 02:14:04 +0100174#endif
Kees Cook8ab38202013-10-10 17:18:14 -0700175 movl $LOAD_PHYSICAL_ADDR, %ebx
1761:
Eric W. Biederman968de4f2006-12-07 02:14:04 +0100177
H. Peter Anvin02a884c2009-05-08 17:42:16 -0700178 /* Target address to relocate to for decompression */
Yinghai Lu974f2212016-04-28 17:09:04 -0700179 movl BP_init_size(%esi), %eax
180 subl $_end, %eax
181 addl %eax, %ebx
Eric W. Biederman968de4f2006-12-07 02:14:04 +0100182
H. Peter Anvin0a137732009-05-08 16:27:41 -0700183 /* Set up the stack */
184 leal boot_stack_end(%ebx), %esp
185
H. Peter Anvin97541912009-05-06 17:56:51 -0700186 /* Zero EFLAGS */
187 pushl $0
188 popfl
189
H. Peter Anvin5f64ec62009-05-08 15:45:17 -0700190/*
191 * Copy the compressed kernel to the end of our buffer
Eric W. Biederman968de4f2006-12-07 02:14:04 +0100192 * where decompression in place becomes safe.
193 */
H. Peter Anvin5f64ec62009-05-08 15:45:17 -0700194 pushl %esi
H. Peter Anvin36d37932009-05-08 16:45:15 -0700195 leal (_bss-4)(%ebp), %esi
196 leal (_bss-4)(%ebx), %edi
H. Peter Anvin5b11f1c2009-05-08 16:20:34 -0700197 movl $(_bss - startup_32), %ecx
H. Peter Anvin36d37932009-05-08 16:45:15 -0700198 shrl $2, %ecx
Eric W. Biederman968de4f2006-12-07 02:14:04 +0100199 std
H. Peter Anvin36d37932009-05-08 16:45:15 -0700200 rep movsl
Eric W. Biederman968de4f2006-12-07 02:14:04 +0100201 cld
H. Peter Anvin5f64ec62009-05-08 15:45:17 -0700202 popl %esi
Eric W. Biederman968de4f2006-12-07 02:14:04 +0100203
H. Peter Anvin5f64ec62009-05-08 15:45:17 -0700204/*
Eric W. Biederman968de4f2006-12-07 02:14:04 +0100205 * Jump to the relocated address.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206 */
H. Peter Anvin5f64ec62009-05-08 15:45:17 -0700207 leal relocated(%ebx), %eax
208 jmp *%eax
Cyrill Gorcunovcb425af2009-02-14 00:50:23 +0300209ENDPROC(startup_32)
210
H. Peter Anvin5f64ec62009-05-08 15:45:17 -0700211 .text
Eric W. Biederman968de4f2006-12-07 02:14:04 +0100212relocated:
213
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214/*
H. Peter Anvin0a137732009-05-08 16:27:41 -0700215 * Clear BSS (stack is currently empty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216 */
H. Peter Anvin5f64ec62009-05-08 15:45:17 -0700217 xorl %eax, %eax
H. Peter Anvin5b11f1c2009-05-08 16:20:34 -0700218 leal _bss(%ebx), %edi
H. Peter Anvin5f64ec62009-05-08 15:45:17 -0700219 leal _ebss(%ebx), %ecx
220 subl %edi, %ecx
H. Peter Anvin36d37932009-05-08 16:45:15 -0700221 shrl $2, %ecx
222 rep stosl
Eric W. Biederman968de4f2006-12-07 02:14:04 +0100223
Linus Torvaldsf3670392014-09-22 23:05:49 -0700224/*
225 * Adjust our own GOT
226 */
227 leal _got(%ebx), %edx
228 leal _egot(%ebx), %ecx
2291:
230 cmpl %ecx, %edx
231 jae 2f
232 addl %ebx, (%edx)
233 addl $4, %edx
234 jmp 1b
2352:
236
H. Peter Anvin22a57f52010-08-02 15:34:44 -0700237/*
Kees Cookc0402882016-04-18 09:42:13 -0700238 * Do the extraction, and jump to the new kernel..
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239 */
Kees Cookc0402882016-04-18 09:42:13 -0700240 /* push arguments for extract_kernel: */
Junjie Maoe6023362014-10-31 21:40:38 +0800241 pushl $z_output_len /* decompressed length, end of relocs */
Yinghai Lu974f2212016-04-28 17:09:04 -0700242
243 movl BP_init_size(%esi), %eax
244 subl $_end, %eax
245 movl %ebx, %ebp
246 subl %eax, %ebp
H. Peter Anvin5f64ec62009-05-08 15:45:17 -0700247 pushl %ebp /* output address */
Yinghai Lu974f2212016-04-28 17:09:04 -0700248
H. Peter Anvin02a884c2009-05-08 17:42:16 -0700249 pushl $z_input_len /* input_len */
H. Peter Anvin5f64ec62009-05-08 15:45:17 -0700250 leal input_data(%ebx), %eax
251 pushl %eax /* input_data */
252 leal boot_heap(%ebx), %eax
253 pushl %eax /* heap area */
254 pushl %esi /* real mode pointer */
Kees Cookc0402882016-04-18 09:42:13 -0700255 call extract_kernel /* returns kernel location in %eax */
Yinghai Lu4d2d5422016-04-28 17:09:07 -0700256 addl $24, %esp
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257
258/*
Kees Cookc0402882016-04-18 09:42:13 -0700259 * Jump to the extracted kernel.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260 */
H. Peter Anvin5f64ec62009-05-08 15:45:17 -0700261 xorl %ebx, %ebx
Kees Cook8ab38202013-10-10 17:18:14 -0700262 jmp *%eax
Eric W. Biederman968de4f2006-12-07 02:14:04 +0100263
Matt Fleming9cb0e392014-09-05 14:52:26 +0100264#ifdef CONFIG_EFI_STUB
Linus Torvaldsf3670392014-09-22 23:05:49 -0700265 .data
Matt Fleming54b52d82014-01-10 15:27:14 +0000266efi32_config:
Lukas Wunner0a637ee2016-08-22 12:01:21 +0200267 .fill 4,8,0
Matt Fleming54b52d82014-01-10 15:27:14 +0000268 .long efi_call_phys
269 .long 0
270 .byte 0
Matt Fleming3db4caf2014-03-05 10:15:55 +0000271#endif
Matt Fleming54b52d82014-01-10 15:27:14 +0000272
H. Peter Anvin5f64ec62009-05-08 15:45:17 -0700273/*
274 * Stack and heap for uncompression
275 */
276 .bss
277 .balign 4
Alexander van Heukelum7c539762008-04-08 12:54:30 +0200278boot_heap:
279 .fill BOOT_HEAP_SIZE, 1, 0
280boot_stack:
281 .fill BOOT_STACK_SIZE, 1, 0
282boot_stack_end: