Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
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 | * | |
5f64ec64 | 15 | * Page 0 is deliberately kept safe, since System Management Mode code in |
1da177e4 | 16 | * laptops may need to access the BIOS data stored there. This is also |
5f64ec64 | 17 | * useful for future device drivers that either access the BIOS via VM86 |
1da177e4 LT |
18 | * mode. |
19 | */ | |
20 | ||
21 | /* | |
22 | * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996 | |
23 | */ | |
5f64ec64 | 24 | .text |
1da177e4 | 25 | |
1dc818c1 | 26 | #include <linux/init.h> |
1da177e4 LT |
27 | #include <linux/linkage.h> |
28 | #include <asm/segment.h> | |
0341c14d | 29 | #include <asm/page_types.h> |
e69f202d | 30 | #include <asm/boot.h> |
a24e7851 | 31 | #include <asm/asm-offsets.h> |
1da177e4 | 32 | |
1dc818c1 | 33 | __HEAD |
cb425afd | 34 | ENTRY(startup_32) |
291f3632 | 35 | #ifdef CONFIG_EFI_STUB |
b1994304 MF |
36 | jmp preferred_addr |
37 | ||
38 | .balign 0x10 | |
291f3632 MF |
39 | /* |
40 | * We don't need the return address, so set up the stack so | |
41 | * efi_main() can find its arugments. | |
42 | */ | |
43 | add $0x4, %esp | |
44 | ||
9ca8f72a MF |
45 | call make_boot_params |
46 | cmpl $0, %eax | |
47 | je 1f | |
48 | movl 0x4(%esp), %esi | |
49 | movl (%esp), %ecx | |
50 | pushl %eax | |
51 | pushl %esi | |
52 | pushl %ecx | |
53 | ||
54 | .org 0x30,0x90 | |
291f3632 MF |
55 | call efi_main |
56 | cmpl $0, %eax | |
291f3632 | 57 | movl %eax, %esi |
b1994304 | 58 | jne 2f |
291f3632 | 59 | 1: |
b1994304 MF |
60 | /* EFI init failed, so hang. */ |
61 | hlt | |
62 | jmp 1b | |
63 | 2: | |
64 | call 3f | |
65 | 3: | |
291f3632 | 66 | popl %eax |
b1994304 | 67 | subl $3b, %eax |
291f3632 MF |
68 | subl BP_pref_address(%esi), %eax |
69 | add BP_code32_start(%esi), %eax | |
70 | leal preferred_addr(%eax), %eax | |
71 | jmp *%eax | |
72 | ||
73 | preferred_addr: | |
74 | #endif | |
bd53147d | 75 | cld |
5f64ec64 PA |
76 | /* |
77 | * Test KEEP_SEGMENTS flag to see if the bootloader is asking | |
78 | * us to not reload segments | |
79 | */ | |
80 | testb $(1<<6), BP_loadflags(%esi) | |
81 | jnz 1f | |
a24e7851 | 82 | |
bd53147d | 83 | cli |
5f64ec64 PA |
84 | movl $__BOOT_DS, %eax |
85 | movl %eax, %ds | |
86 | movl %eax, %es | |
87 | movl %eax, %fs | |
88 | movl %eax, %gs | |
89 | movl %eax, %ss | |
bd53147d | 90 | 1: |
a24e7851 | 91 | |
5f64ec64 PA |
92 | /* |
93 | * Calculate the delta between where we were compiled to run | |
968de4f0 EB |
94 | * at and where we were actually loaded at. This can only be done |
95 | * with a short local call on x86. Nothing else will tell us what | |
96 | * address we are running at. The reserved chunk of the real-mode | |
85414b69 PA |
97 | * data at 0x1e4 (defined as a scratch field) are used as the stack |
98 | * for this calculation. Only 4 bytes are needed. | |
968de4f0 | 99 | */ |
5f64ec64 PA |
100 | leal (BP_scratch+4)(%esi), %esp |
101 | call 1f | |
102 | 1: popl %ebp | |
103 | subl $1b, %ebp | |
968de4f0 | 104 | |
5f64ec64 PA |
105 | /* |
106 | * %ebp contains the address we are loaded at by the boot loader and %ebx | |
e69f202d VG |
107 | * contains the address where we should move the kernel image temporarily |
108 | * for safe in-place decompression. | |
968de4f0 | 109 | */ |
e69f202d | 110 | |
968de4f0 | 111 | #ifdef CONFIG_RELOCATABLE |
5f64ec64 | 112 | movl %ebp, %ebx |
37ba7ab5 PA |
113 | movl BP_kernel_alignment(%esi), %eax |
114 | decl %eax | |
115 | addl %eax, %ebx | |
116 | notl %eax | |
117 | andl %eax, %ebx | |
968de4f0 | 118 | #else |
5f64ec64 | 119 | movl $LOAD_PHYSICAL_ADDR, %ebx |
968de4f0 EB |
120 | #endif |
121 | ||
02a884c0 PA |
122 | /* Target address to relocate to for decompression */ |
123 | addl $z_extract_offset, %ebx | |
968de4f0 | 124 | |
0a137736 PA |
125 | /* Set up the stack */ |
126 | leal boot_stack_end(%ebx), %esp | |
127 | ||
97541912 PA |
128 | /* Zero EFLAGS */ |
129 | pushl $0 | |
130 | popfl | |
131 | ||
5f64ec64 PA |
132 | /* |
133 | * Copy the compressed kernel to the end of our buffer | |
968de4f0 EB |
134 | * where decompression in place becomes safe. |
135 | */ | |
5f64ec64 | 136 | pushl %esi |
36d3793c PA |
137 | leal (_bss-4)(%ebp), %esi |
138 | leal (_bss-4)(%ebx), %edi | |
5b11f1ce | 139 | movl $(_bss - startup_32), %ecx |
36d3793c | 140 | shrl $2, %ecx |
968de4f0 | 141 | std |
36d3793c | 142 | rep movsl |
968de4f0 | 143 | cld |
5f64ec64 | 144 | popl %esi |
968de4f0 | 145 | |
1da177e4 | 146 | /* |
968de4f0 | 147 | * Jump to the relocated address. |
1da177e4 | 148 | */ |
5f64ec64 PA |
149 | leal relocated(%ebx), %eax |
150 | jmp *%eax | |
cb425afd CG |
151 | ENDPROC(startup_32) |
152 | ||
5f64ec64 | 153 | .text |
968de4f0 EB |
154 | relocated: |
155 | ||
1da177e4 | 156 | /* |
0a137736 | 157 | * Clear BSS (stack is currently empty) |
1da177e4 | 158 | */ |
5f64ec64 | 159 | xorl %eax, %eax |
5b11f1ce | 160 | leal _bss(%ebx), %edi |
5f64ec64 PA |
161 | leal _ebss(%ebx), %ecx |
162 | subl %edi, %ecx | |
36d3793c PA |
163 | shrl $2, %ecx |
164 | rep stosl | |
968de4f0 | 165 | |
22a57f58 PA |
166 | /* |
167 | * Adjust our own GOT | |
168 | */ | |
169 | leal _got(%ebx), %edx | |
170 | leal _egot(%ebx), %ecx | |
171 | 1: | |
172 | cmpl %ecx, %edx | |
173 | jae 2f | |
174 | addl %ebx, (%edx) | |
175 | addl $4, %edx | |
176 | jmp 1b | |
177 | 2: | |
178 | ||
1da177e4 LT |
179 | /* |
180 | * Do the decompression, and jump to the new kernel.. | |
181 | */ | |
02a884c0 | 182 | leal z_extract_offset_negative(%ebx), %ebp |
5f64ec64 PA |
183 | /* push arguments for decompress_kernel: */ |
184 | pushl %ebp /* output address */ | |
02a884c0 | 185 | pushl $z_input_len /* input_len */ |
5f64ec64 PA |
186 | leal input_data(%ebx), %eax |
187 | pushl %eax /* input_data */ | |
188 | leal boot_heap(%ebx), %eax | |
189 | pushl %eax /* heap area */ | |
190 | pushl %esi /* real mode pointer */ | |
191 | call decompress_kernel | |
192 | addl $20, %esp | |
968de4f0 EB |
193 | |
194 | #if CONFIG_RELOCATABLE | |
5f64ec64 PA |
195 | /* |
196 | * Find the address of the relocations. | |
968de4f0 | 197 | */ |
02a884c0 | 198 | leal z_output_len(%ebp), %edi |
968de4f0 | 199 | |
5f64ec64 PA |
200 | /* |
201 | * Calculate the delta between where vmlinux was compiled to run | |
968de4f0 EB |
202 | * and where it was actually loaded. |
203 | */ | |
5f64ec64 PA |
204 | movl %ebp, %ebx |
205 | subl $LOAD_PHYSICAL_ADDR, %ebx | |
206 | jz 2f /* Nothing to be done if loaded at compiled addr. */ | |
1da177e4 | 207 | /* |
968de4f0 | 208 | * Process relocations. |
1da177e4 | 209 | */ |
968de4f0 | 210 | |
5f64ec64 PA |
211 | 1: subl $4, %edi |
212 | movl (%edi), %ecx | |
213 | testl %ecx, %ecx | |
214 | jz 2f | |
215 | addl %ebx, -__PAGE_OFFSET(%ebx, %ecx) | |
216 | jmp 1b | |
968de4f0 EB |
217 | 2: |
218 | #endif | |
1da177e4 LT |
219 | |
220 | /* | |
968de4f0 | 221 | * Jump to the decompressed kernel. |
1da177e4 | 222 | */ |
5f64ec64 PA |
223 | xorl %ebx, %ebx |
224 | jmp *%ebp | |
968de4f0 | 225 | |
5f64ec64 PA |
226 | /* |
227 | * Stack and heap for uncompression | |
228 | */ | |
229 | .bss | |
230 | .balign 4 | |
7c539764 AH |
231 | boot_heap: |
232 | .fill BOOT_HEAP_SIZE, 1, 0 | |
233 | boot_stack: | |
234 | .fill BOOT_STACK_SIZE, 1, 0 | |
235 | boot_stack_end: |