diff options
Diffstat (limited to 'arch/x86/boot/compressed/head_64.S')
-rw-r--r-- | arch/x86/boot/compressed/head_64.S | 169 |
1 files changed, 88 insertions, 81 deletions
diff --git a/arch/x86/boot/compressed/head_64.S b/arch/x86/boot/compressed/head_64.S index ed4a82948002..f62c284db9eb 100644 --- a/arch/x86/boot/compressed/head_64.S +++ b/arch/x86/boot/compressed/head_64.S | |||
@@ -21,8 +21,8 @@ | |||
21 | /* | 21 | /* |
22 | * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996 | 22 | * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996 |
23 | */ | 23 | */ |
24 | .code32 | 24 | .code32 |
25 | .text | 25 | .text |
26 | 26 | ||
27 | #include <linux/linkage.h> | 27 | #include <linux/linkage.h> |
28 | #include <asm/segment.h> | 28 | #include <asm/segment.h> |
@@ -33,12 +33,14 @@ | |||
33 | #include <asm/processor-flags.h> | 33 | #include <asm/processor-flags.h> |
34 | #include <asm/asm-offsets.h> | 34 | #include <asm/asm-offsets.h> |
35 | 35 | ||
36 | .section ".text.head" | 36 | .section ".text.head" |
37 | .code32 | 37 | .code32 |
38 | ENTRY(startup_32) | 38 | ENTRY(startup_32) |
39 | cld | 39 | cld |
40 | /* test KEEP_SEGMENTS flag to see if the bootloader is asking | 40 | /* |
41 | * us to not reload segments */ | 41 | * Test KEEP_SEGMENTS flag to see if the bootloader is asking |
42 | * us to not reload segments | ||
43 | */ | ||
42 | testb $(1<<6), BP_loadflags(%esi) | 44 | testb $(1<<6), BP_loadflags(%esi) |
43 | jnz 1f | 45 | jnz 1f |
44 | 46 | ||
@@ -49,14 +51,15 @@ ENTRY(startup_32) | |||
49 | movl %eax, %ss | 51 | movl %eax, %ss |
50 | 1: | 52 | 1: |
51 | 53 | ||
52 | /* Calculate the delta between where we were compiled to run | 54 | /* |
55 | * Calculate the delta between where we were compiled to run | ||
53 | * at and where we were actually loaded at. This can only be done | 56 | * at and where we were actually loaded at. This can only be done |
54 | * with a short local call on x86. Nothing else will tell us what | 57 | * with a short local call on x86. Nothing else will tell us what |
55 | * address we are running at. The reserved chunk of the real-mode | 58 | * address we are running at. The reserved chunk of the real-mode |
56 | * data at 0x1e4 (defined as a scratch field) are used as the stack | 59 | * data at 0x1e4 (defined as a scratch field) are used as the stack |
57 | * for this calculation. Only 4 bytes are needed. | 60 | * for this calculation. Only 4 bytes are needed. |
58 | */ | 61 | */ |
59 | leal (0x1e4+4)(%esi), %esp | 62 | leal (BP_scratch+4)(%esi), %esp |
60 | call 1f | 63 | call 1f |
61 | 1: popl %ebp | 64 | 1: popl %ebp |
62 | subl $1b, %ebp | 65 | subl $1b, %ebp |
@@ -70,32 +73,28 @@ ENTRY(startup_32) | |||
70 | testl %eax, %eax | 73 | testl %eax, %eax |
71 | jnz no_longmode | 74 | jnz no_longmode |
72 | 75 | ||
73 | /* Compute the delta between where we were compiled to run at | 76 | /* |
77 | * Compute the delta between where we were compiled to run at | ||
74 | * and where the code will actually run at. | 78 | * and where the code will actually run at. |
75 | */ | 79 | * |
76 | /* %ebp contains the address we are loaded at by the boot loader and %ebx | 80 | * %ebp contains the address we are loaded at by the boot loader and %ebx |
77 | * contains the address where we should move the kernel image temporarily | 81 | * contains the address where we should move the kernel image temporarily |
78 | * for safe in-place decompression. | 82 | * for safe in-place decompression. |
79 | */ | 83 | */ |
80 | 84 | ||
81 | #ifdef CONFIG_RELOCATABLE | 85 | #ifdef CONFIG_RELOCATABLE |
82 | movl %ebp, %ebx | 86 | movl %ebp, %ebx |
83 | addl $(PMD_PAGE_SIZE -1), %ebx | 87 | movl BP_kernel_alignment(%esi), %eax |
84 | andl $PMD_PAGE_MASK, %ebx | 88 | decl %eax |
89 | addl %eax, %ebx | ||
90 | notl %eax | ||
91 | andl %eax, %ebx | ||
85 | #else | 92 | #else |
86 | movl $CONFIG_PHYSICAL_START, %ebx | 93 | movl $LOAD_PHYSICAL_ADDR, %ebx |
87 | #endif | 94 | #endif |
88 | 95 | ||
89 | /* Replace the compressed data size with the uncompressed size */ | 96 | /* Target address to relocate to for decompression */ |
90 | subl input_len(%ebp), %ebx | 97 | addl $z_extract_offset, %ebx |
91 | movl output_len(%ebp), %eax | ||
92 | addl %eax, %ebx | ||
93 | /* Add 8 bytes for every 32K input block */ | ||
94 | shrl $12, %eax | ||
95 | addl %eax, %ebx | ||
96 | /* Add 32K + 18 bytes of extra slack and align on a 4K boundary */ | ||
97 | addl $(32768 + 18 + 4095), %ebx | ||
98 | andl $~4095, %ebx | ||
99 | 98 | ||
100 | /* | 99 | /* |
101 | * Prepare for entering 64 bit mode | 100 | * Prepare for entering 64 bit mode |
@@ -114,7 +113,7 @@ ENTRY(startup_32) | |||
114 | /* | 113 | /* |
115 | * Build early 4G boot pagetable | 114 | * Build early 4G boot pagetable |
116 | */ | 115 | */ |
117 | /* Initialize Page tables to 0*/ | 116 | /* Initialize Page tables to 0 */ |
118 | leal pgtable(%ebx), %edi | 117 | leal pgtable(%ebx), %edi |
119 | xorl %eax, %eax | 118 | xorl %eax, %eax |
120 | movl $((4096*6)/4), %ecx | 119 | movl $((4096*6)/4), %ecx |
@@ -155,7 +154,8 @@ ENTRY(startup_32) | |||
155 | btsl $_EFER_LME, %eax | 154 | btsl $_EFER_LME, %eax |
156 | wrmsr | 155 | wrmsr |
157 | 156 | ||
158 | /* Setup for the jump to 64bit mode | 157 | /* |
158 | * Setup for the jump to 64bit mode | ||
159 | * | 159 | * |
160 | * When the jump is performend we will be in long mode but | 160 | * When the jump is performend we will be in long mode but |
161 | * in 32bit compatibility mode with EFER.LME = 1, CS.L = 0, CS.D = 1 | 161 | * in 32bit compatibility mode with EFER.LME = 1, CS.L = 0, CS.D = 1 |
@@ -184,7 +184,8 @@ no_longmode: | |||
184 | 184 | ||
185 | #include "../../kernel/verify_cpu_64.S" | 185 | #include "../../kernel/verify_cpu_64.S" |
186 | 186 | ||
187 | /* Be careful here startup_64 needs to be at a predictable | 187 | /* |
188 | * Be careful here startup_64 needs to be at a predictable | ||
188 | * address so I can export it in an ELF header. Bootloaders | 189 | * address so I can export it in an ELF header. Bootloaders |
189 | * should look at the ELF header to find this address, as | 190 | * should look at the ELF header to find this address, as |
190 | * it may change in the future. | 191 | * it may change in the future. |
@@ -192,7 +193,8 @@ no_longmode: | |||
192 | .code64 | 193 | .code64 |
193 | .org 0x200 | 194 | .org 0x200 |
194 | ENTRY(startup_64) | 195 | ENTRY(startup_64) |
195 | /* We come here either from startup_32 or directly from a | 196 | /* |
197 | * We come here either from startup_32 or directly from a | ||
196 | * 64bit bootloader. If we come here from a bootloader we depend on | 198 | * 64bit bootloader. If we come here from a bootloader we depend on |
197 | * an identity mapped page table being provied that maps our | 199 | * an identity mapped page table being provied that maps our |
198 | * entire text+data+bss and hopefully all of memory. | 200 | * entire text+data+bss and hopefully all of memory. |
@@ -209,50 +211,54 @@ ENTRY(startup_64) | |||
209 | movl $0x20, %eax | 211 | movl $0x20, %eax |
210 | ltr %ax | 212 | ltr %ax |
211 | 213 | ||
212 | /* Compute the decompressed kernel start address. It is where | 214 | /* |
215 | * Compute the decompressed kernel start address. It is where | ||
213 | * we were loaded at aligned to a 2M boundary. %rbp contains the | 216 | * we were loaded at aligned to a 2M boundary. %rbp contains the |
214 | * decompressed kernel start address. | 217 | * decompressed kernel start address. |
215 | * | 218 | * |
216 | * If it is a relocatable kernel then decompress and run the kernel | 219 | * If it is a relocatable kernel then decompress and run the kernel |
217 | * from load address aligned to 2MB addr, otherwise decompress and | 220 | * from load address aligned to 2MB addr, otherwise decompress and |
218 | * run the kernel from CONFIG_PHYSICAL_START | 221 | * run the kernel from LOAD_PHYSICAL_ADDR |
222 | * | ||
223 | * We cannot rely on the calculation done in 32-bit mode, since we | ||
224 | * may have been invoked via the 64-bit entry point. | ||
219 | */ | 225 | */ |
220 | 226 | ||
221 | /* Start with the delta to where the kernel will run at. */ | 227 | /* Start with the delta to where the kernel will run at. */ |
222 | #ifdef CONFIG_RELOCATABLE | 228 | #ifdef CONFIG_RELOCATABLE |
223 | leaq startup_32(%rip) /* - $startup_32 */, %rbp | 229 | leaq startup_32(%rip) /* - $startup_32 */, %rbp |
224 | addq $(PMD_PAGE_SIZE - 1), %rbp | 230 | movl BP_kernel_alignment(%rsi), %eax |
225 | andq $PMD_PAGE_MASK, %rbp | 231 | decl %eax |
226 | movq %rbp, %rbx | 232 | addq %rax, %rbp |
233 | notq %rax | ||
234 | andq %rax, %rbp | ||
227 | #else | 235 | #else |
228 | movq $CONFIG_PHYSICAL_START, %rbp | 236 | movq $LOAD_PHYSICAL_ADDR, %rbp |
229 | movq %rbp, %rbx | ||
230 | #endif | 237 | #endif |
231 | 238 | ||
232 | /* Replace the compressed data size with the uncompressed size */ | 239 | /* Target address to relocate to for decompression */ |
233 | movl input_len(%rip), %eax | 240 | leaq z_extract_offset(%rbp), %rbx |
234 | subq %rax, %rbx | 241 | |
235 | movl output_len(%rip), %eax | 242 | /* Set up the stack */ |
236 | addq %rax, %rbx | 243 | leaq boot_stack_end(%rbx), %rsp |
237 | /* Add 8 bytes for every 32K input block */ | 244 | |
238 | shrq $12, %rax | 245 | /* Zero EFLAGS */ |
239 | addq %rax, %rbx | 246 | pushq $0 |
240 | /* Add 32K + 18 bytes of extra slack and align on a 4K boundary */ | 247 | popfq |
241 | addq $(32768 + 18 + 4095), %rbx | 248 | |
242 | andq $~4095, %rbx | 249 | /* |
243 | 250 | * Copy the compressed kernel to the end of our buffer | |
244 | /* Copy the compressed kernel to the end of our buffer | ||
245 | * where decompression in place becomes safe. | 251 | * where decompression in place becomes safe. |
246 | */ | 252 | */ |
247 | leaq _end_before_pgt(%rip), %r8 | 253 | pushq %rsi |
248 | leaq _end_before_pgt(%rbx), %r9 | 254 | leaq (_bss-8)(%rip), %rsi |
249 | movq $_end_before_pgt /* - $startup_32 */, %rcx | 255 | leaq (_bss-8)(%rbx), %rdi |
250 | 1: subq $8, %r8 | 256 | movq $_bss /* - $startup_32 */, %rcx |
251 | subq $8, %r9 | 257 | shrq $3, %rcx |
252 | movq 0(%r8), %rax | 258 | std |
253 | movq %rax, 0(%r9) | 259 | rep movsq |
254 | subq $8, %rcx | 260 | cld |
255 | jnz 1b | 261 | popq %rsi |
256 | 262 | ||
257 | /* | 263 | /* |
258 | * Jump to the relocated address. | 264 | * Jump to the relocated address. |
@@ -260,37 +266,28 @@ ENTRY(startup_64) | |||
260 | leaq relocated(%rbx), %rax | 266 | leaq relocated(%rbx), %rax |
261 | jmp *%rax | 267 | jmp *%rax |
262 | 268 | ||
263 | .section ".text" | 269 | .text |
264 | relocated: | 270 | relocated: |
265 | 271 | ||
266 | /* | 272 | /* |
267 | * Clear BSS | 273 | * Clear BSS (stack is currently empty) |
268 | */ | 274 | */ |
269 | xorq %rax, %rax | 275 | xorl %eax, %eax |
270 | leaq _edata(%rbx), %rdi | 276 | leaq _bss(%rip), %rdi |
271 | leaq _end_before_pgt(%rbx), %rcx | 277 | leaq _ebss(%rip), %rcx |
272 | subq %rdi, %rcx | 278 | subq %rdi, %rcx |
273 | cld | 279 | shrq $3, %rcx |
274 | rep | 280 | rep stosq |
275 | stosb | ||
276 | |||
277 | /* Setup the stack */ | ||
278 | leaq boot_stack_end(%rip), %rsp | ||
279 | |||
280 | /* zero EFLAGS after setting rsp */ | ||
281 | pushq $0 | ||
282 | popfq | ||
283 | 281 | ||
284 | /* | 282 | /* |
285 | * Do the decompression, and jump to the new kernel.. | 283 | * Do the decompression, and jump to the new kernel.. |
286 | */ | 284 | */ |
287 | pushq %rsi # Save the real mode argument | 285 | pushq %rsi /* Save the real mode argument */ |
288 | movq %rsi, %rdi # real mode address | 286 | movq %rsi, %rdi /* real mode address */ |
289 | leaq boot_heap(%rip), %rsi # malloc area for uncompression | 287 | leaq boot_heap(%rip), %rsi /* malloc area for uncompression */ |
290 | leaq input_data(%rip), %rdx # input_data | 288 | leaq input_data(%rip), %rdx /* input_data */ |
291 | movl input_len(%rip), %eax | 289 | movl $z_input_len, %ecx /* input_len */ |
292 | movq %rax, %rcx # input_len | 290 | movq %rbp, %r8 /* output target address */ |
293 | movq %rbp, %r8 # output | ||
294 | call decompress_kernel | 291 | call decompress_kernel |
295 | popq %rsi | 292 | popq %rsi |
296 | 293 | ||
@@ -311,11 +308,21 @@ gdt: | |||
311 | .quad 0x0000000000000000 /* TS continued */ | 308 | .quad 0x0000000000000000 /* TS continued */ |
312 | gdt_end: | 309 | gdt_end: |
313 | 310 | ||
314 | .bss | 311 | /* |
315 | /* Stack and heap for uncompression */ | 312 | * Stack and heap for uncompression |
316 | .balign 4 | 313 | */ |
314 | .bss | ||
315 | .balign 4 | ||
317 | boot_heap: | 316 | boot_heap: |
318 | .fill BOOT_HEAP_SIZE, 1, 0 | 317 | .fill BOOT_HEAP_SIZE, 1, 0 |
319 | boot_stack: | 318 | boot_stack: |
320 | .fill BOOT_STACK_SIZE, 1, 0 | 319 | .fill BOOT_STACK_SIZE, 1, 0 |
321 | boot_stack_end: | 320 | boot_stack_end: |
321 | |||
322 | /* | ||
323 | * Space for page tables (not in .bss so not zeroed) | ||
324 | */ | ||
325 | .section ".pgtable","a",@nobits | ||
326 | .balign 4096 | ||
327 | pgtable: | ||
328 | .fill 6*4096, 1, 0 | ||