diff options
author | H. Peter Anvin <hpa@zytor.com> | 2009-05-08 20:42:16 -0400 |
---|---|---|
committer | H. Peter Anvin <hpa@zytor.com> | 2009-05-08 20:46:34 -0400 |
commit | 02a884c0fe7ec8459d00d34b7d4101af21fc4a86 (patch) | |
tree | 164783f84130482e52290af03d96ff8e887f8605 /arch | |
parent | 36d3793c947f1ef7ba3d24eeeddc1be41adc5ab4 (diff) |
x86, boot: determine compressed code offset at compile time
Determine the compressed code offset (from the kernel runtime address)
at compile time. This allows some minor optimizations in
arch/x86/boot/compressed/head_*.S, but more importantly it makes this
value available to the build process, which will enable a future patch
to export the necessary linear memory footprint into the bzImage
header.
[ Impact: cleanup, future patch enabling ]
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/x86/boot/compressed/Makefile | 11 | ||||
-rw-r--r-- | arch/x86/boot/compressed/head_32.S | 24 | ||||
-rw-r--r-- | arch/x86/boot/compressed/head_64.S | 41 | ||||
-rw-r--r-- | arch/x86/boot/compressed/mkpiggy.c | 97 | ||||
-rw-r--r-- | arch/x86/boot/compressed/vmlinux.scr | 10 |
5 files changed, 123 insertions, 60 deletions
diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile index 7f24fdb584e6..49c8a4c37d7c 100644 --- a/arch/x86/boot/compressed/Makefile +++ b/arch/x86/boot/compressed/Makefile | |||
@@ -19,6 +19,8 @@ KBUILD_AFLAGS := $(KBUILD_CFLAGS) -D__ASSEMBLY__ | |||
19 | LDFLAGS := -m elf_$(UTS_MACHINE) | 19 | LDFLAGS := -m elf_$(UTS_MACHINE) |
20 | LDFLAGS_vmlinux := -T | 20 | LDFLAGS_vmlinux := -T |
21 | 21 | ||
22 | hostprogs-y := mkpiggy | ||
23 | |||
22 | $(obj)/vmlinux: $(obj)/vmlinux.lds $(obj)/head_$(BITS).o $(obj)/misc.o $(obj)/piggy.o FORCE | 24 | $(obj)/vmlinux: $(obj)/vmlinux.lds $(obj)/head_$(BITS).o $(obj)/misc.o $(obj)/piggy.o FORCE |
23 | $(call if_changed,ld) | 25 | $(call if_changed,ld) |
24 | @: | 26 | @: |
@@ -50,6 +52,9 @@ suffix-$(CONFIG_KERNEL_GZIP) := gz | |||
50 | suffix-$(CONFIG_KERNEL_BZIP2) := bz2 | 52 | suffix-$(CONFIG_KERNEL_BZIP2) := bz2 |
51 | suffix-$(CONFIG_KERNEL_LZMA) := lzma | 53 | suffix-$(CONFIG_KERNEL_LZMA) := lzma |
52 | 54 | ||
53 | LDFLAGS_piggy.o := -r --format binary --oformat $(CONFIG_OUTPUT_FORMAT) -T | 55 | quiet_cmd_mkpiggy = MKPIGGY $@ |
54 | $(obj)/piggy.o: $(obj)/vmlinux.scr $(obj)/vmlinux.bin.$(suffix-y) FORCE | 56 | cmd_mkpiggy = $(obj)/mkpiggy $< > $@ || ( rm -f $@ ; false ) |
55 | $(call if_changed,ld) | 57 | |
58 | targets += piggy.S | ||
59 | $(obj)/piggy.S: $(obj)/vmlinux.bin.$(suffix-y) $(obj)/mkpiggy FORCE | ||
60 | $(call if_changed,mkpiggy) | ||
diff --git a/arch/x86/boot/compressed/head_32.S b/arch/x86/boot/compressed/head_32.S index 6710dc78ac59..470474bafc4d 100644 --- a/arch/x86/boot/compressed/head_32.S +++ b/arch/x86/boot/compressed/head_32.S | |||
@@ -75,18 +75,8 @@ ENTRY(startup_32) | |||
75 | movl $LOAD_PHYSICAL_ADDR, %ebx | 75 | movl $LOAD_PHYSICAL_ADDR, %ebx |
76 | #endif | 76 | #endif |
77 | 77 | ||
78 | /* Replace the compressed data size with the uncompressed size */ | 78 | /* Target address to relocate to for decompression */ |
79 | subl input_len(%ebp), %ebx | 79 | addl $z_extract_offset, %ebx |
80 | movl output_len(%ebp), %eax | ||
81 | addl %eax, %ebx | ||
82 | /* Add 8 bytes for every 32K input block */ | ||
83 | shrl $12, %eax | ||
84 | addl %eax, %ebx | ||
85 | /* Add 32K + 18 bytes of extra slack */ | ||
86 | addl $(32768 + 18), %ebx | ||
87 | /* Align on a 4K boundary */ | ||
88 | addl $4095, %ebx | ||
89 | andl $~4095, %ebx | ||
90 | 80 | ||
91 | /* Set up the stack */ | 81 | /* Set up the stack */ |
92 | leal boot_stack_end(%ebx), %esp | 82 | leal boot_stack_end(%ebx), %esp |
@@ -142,12 +132,10 @@ relocated: | |||
142 | /* | 132 | /* |
143 | * Do the decompression, and jump to the new kernel.. | 133 | * Do the decompression, and jump to the new kernel.. |
144 | */ | 134 | */ |
145 | movl output_len(%ebx), %eax | 135 | leal z_extract_offset_negative(%ebx), %ebp |
146 | pushl %eax | ||
147 | /* push arguments for decompress_kernel: */ | 136 | /* push arguments for decompress_kernel: */ |
148 | pushl %ebp /* output address */ | 137 | pushl %ebp /* output address */ |
149 | movl input_len(%ebx), %eax | 138 | pushl $z_input_len /* input_len */ |
150 | pushl %eax /* input_len */ | ||
151 | leal input_data(%ebx), %eax | 139 | leal input_data(%ebx), %eax |
152 | pushl %eax /* input_data */ | 140 | pushl %eax /* input_data */ |
153 | leal boot_heap(%ebx), %eax | 141 | leal boot_heap(%ebx), %eax |
@@ -155,14 +143,12 @@ relocated: | |||
155 | pushl %esi /* real mode pointer */ | 143 | pushl %esi /* real mode pointer */ |
156 | call decompress_kernel | 144 | call decompress_kernel |
157 | addl $20, %esp | 145 | addl $20, %esp |
158 | popl %ecx | ||
159 | 146 | ||
160 | #if CONFIG_RELOCATABLE | 147 | #if CONFIG_RELOCATABLE |
161 | /* | 148 | /* |
162 | * Find the address of the relocations. | 149 | * Find the address of the relocations. |
163 | */ | 150 | */ |
164 | movl %ebp, %edi | 151 | leal z_output_len(%ebp), %edi |
165 | addl %ecx, %edi | ||
166 | 152 | ||
167 | /* | 153 | /* |
168 | * Calculate the delta between where vmlinux was compiled to run | 154 | * Calculate the delta between where vmlinux was compiled to run |
diff --git a/arch/x86/boot/compressed/head_64.S b/arch/x86/boot/compressed/head_64.S index 723c72dfd7bc..2b9f2510507b 100644 --- a/arch/x86/boot/compressed/head_64.S +++ b/arch/x86/boot/compressed/head_64.S | |||
@@ -90,16 +90,8 @@ ENTRY(startup_32) | |||
90 | movl $CONFIG_PHYSICAL_START, %ebx | 90 | movl $CONFIG_PHYSICAL_START, %ebx |
91 | #endif | 91 | #endif |
92 | 92 | ||
93 | /* Replace the compressed data size with the uncompressed size */ | 93 | /* Target address to relocate to for decompression */ |
94 | subl input_len(%ebp), %ebx | 94 | addl $z_extract_offset, %ebx |
95 | movl output_len(%ebp), %eax | ||
96 | addl %eax, %ebx | ||
97 | /* Add 8 bytes for every 32K input block */ | ||
98 | shrl $12, %eax | ||
99 | addl %eax, %ebx | ||
100 | /* Add 32K + 18 bytes of extra slack and align on a 4K boundary */ | ||
101 | addl $(32768 + 18 + 4095), %ebx | ||
102 | andl $~4095, %ebx | ||
103 | 95 | ||
104 | /* | 96 | /* |
105 | * Prepare for entering 64 bit mode | 97 | * Prepare for entering 64 bit mode |
@@ -224,6 +216,9 @@ ENTRY(startup_64) | |||
224 | * If it is a relocatable kernel then decompress and run the kernel | 216 | * If it is a relocatable kernel then decompress and run the kernel |
225 | * from load address aligned to 2MB addr, otherwise decompress and | 217 | * from load address aligned to 2MB addr, otherwise decompress and |
226 | * run the kernel from CONFIG_PHYSICAL_START | 218 | * run the kernel from CONFIG_PHYSICAL_START |
219 | * | ||
220 | * We cannot rely on the calculation done in 32-bit mode, since we | ||
221 | * may have been invoked via the 64-bit entry point. | ||
227 | */ | 222 | */ |
228 | 223 | ||
229 | /* Start with the delta to where the kernel will run at. */ | 224 | /* Start with the delta to where the kernel will run at. */ |
@@ -237,17 +232,8 @@ ENTRY(startup_64) | |||
237 | movq %rbp, %rbx | 232 | movq %rbp, %rbx |
238 | #endif | 233 | #endif |
239 | 234 | ||
240 | /* Replace the compressed data size with the uncompressed size */ | 235 | /* Target address to relocate to for decompression */ |
241 | movl input_len(%rip), %eax | 236 | leaq z_extract_offset(%rbp), %rbx |
242 | subq %rax, %rbx | ||
243 | movl output_len(%rip), %eax | ||
244 | addq %rax, %rbx | ||
245 | /* Add 8 bytes for every 32K input block */ | ||
246 | shrq $12, %rax | ||
247 | addq %rax, %rbx | ||
248 | /* Add 32K + 18 bytes of extra slack and align on a 4K boundary */ | ||
249 | addq $(32768 + 18 + 4095), %rbx | ||
250 | andq $~4095, %rbx | ||
251 | 237 | ||
252 | /* Set up the stack */ | 238 | /* Set up the stack */ |
253 | leaq boot_stack_end(%rbx), %rsp | 239 | leaq boot_stack_end(%rbx), %rsp |
@@ -292,13 +278,12 @@ relocated: | |||
292 | /* | 278 | /* |
293 | * Do the decompression, and jump to the new kernel.. | 279 | * Do the decompression, and jump to the new kernel.. |
294 | */ | 280 | */ |
295 | pushq %rsi # Save the real mode argument | 281 | pushq %rsi /* Save the real mode argument */ |
296 | movq %rsi, %rdi # real mode address | 282 | movq %rsi, %rdi /* real mode address */ |
297 | leaq boot_heap(%rip), %rsi # malloc area for uncompression | 283 | leaq boot_heap(%rip), %rsi /* malloc area for uncompression */ |
298 | leaq input_data(%rip), %rdx # input_data | 284 | leaq input_data(%rip), %rdx /* input_data */ |
299 | movl input_len(%rip), %eax | 285 | movl $z_input_len, %ecx /* input_len */ |
300 | movq %rax, %rcx # input_len | 286 | movq %rbp, %r8 /* output target address */ |
301 | movq %rbp, %r8 # output | ||
302 | call decompress_kernel | 287 | call decompress_kernel |
303 | popq %rsi | 288 | popq %rsi |
304 | 289 | ||
diff --git a/arch/x86/boot/compressed/mkpiggy.c b/arch/x86/boot/compressed/mkpiggy.c new file mode 100644 index 000000000000..bcbd36c41432 --- /dev/null +++ b/arch/x86/boot/compressed/mkpiggy.c | |||
@@ -0,0 +1,97 @@ | |||
1 | /* ----------------------------------------------------------------------- * | ||
2 | * | ||
3 | * Copyright (C) 2009 Intel Corporation. All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU General Public License version | ||
7 | * 2 as published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
17 | * 02110-1301, USA. | ||
18 | * | ||
19 | * H. Peter Anvin <hpa@linux.intel.com> | ||
20 | * | ||
21 | * ----------------------------------------------------------------------- */ | ||
22 | |||
23 | /* | ||
24 | * Compute the desired load offset from a compressed program; outputs | ||
25 | * a small assembly wrapper with the appropriate symbols defined. | ||
26 | */ | ||
27 | |||
28 | #include <stdlib.h> | ||
29 | #include <stdio.h> | ||
30 | #include <string.h> | ||
31 | #include <inttypes.h> | ||
32 | |||
33 | static uint32_t getle32(const void *p) | ||
34 | { | ||
35 | const uint8_t *cp = p; | ||
36 | |||
37 | return (uint32_t)cp[0] + ((uint32_t)cp[1] << 8) + | ||
38 | ((uint32_t)cp[2] << 16) + ((uint32_t)cp[3] << 24); | ||
39 | } | ||
40 | |||
41 | int main(int argc, char *argv[]) | ||
42 | { | ||
43 | uint32_t olen; | ||
44 | long ilen; | ||
45 | unsigned long offs; | ||
46 | FILE *f; | ||
47 | |||
48 | if (argc < 2) { | ||
49 | fprintf(stderr, "Usage: %s compressed_file\n", argv[0]); | ||
50 | return 1; | ||
51 | } | ||
52 | |||
53 | /* Get the information for the compressed kernel image first */ | ||
54 | |||
55 | f = fopen(argv[1], "r"); | ||
56 | if (!f) { | ||
57 | perror(argv[1]); | ||
58 | return 1; | ||
59 | } | ||
60 | |||
61 | |||
62 | if (fseek(f, -4L, SEEK_END)) { | ||
63 | perror(argv[1]); | ||
64 | } | ||
65 | fread(&olen, sizeof olen, 1, f); | ||
66 | ilen = ftell(f); | ||
67 | olen = getle32(&olen); | ||
68 | fclose(f); | ||
69 | |||
70 | /* | ||
71 | * Now we have the input (compressed) and output (uncompressed) | ||
72 | * sizes, compute the necessary decompression offset... | ||
73 | */ | ||
74 | |||
75 | offs = (olen > ilen) ? olen - ilen : 0; | ||
76 | offs += olen >> 12; /* Add 8 bytes for each 32K block */ | ||
77 | offs += 32*1024 + 18; /* Add 32K + 18 bytes slack */ | ||
78 | offs = (offs+4095) & ~4095; /* Round to a 4K boundary */ | ||
79 | |||
80 | printf(".section \".rodata.compressed\",\"a\",@progbits\n"); | ||
81 | printf(".globl z_input_len\n"); | ||
82 | printf("z_input_len = %lu\n", ilen); | ||
83 | printf(".globl z_output_len\n"); | ||
84 | printf("z_output_len = %lu\n", (unsigned long)olen); | ||
85 | printf(".globl z_extract_offset\n"); | ||
86 | printf("z_extract_offset = 0x%lx\n", offs); | ||
87 | /* z_extract_offset_negative allows simplification of head_32.S */ | ||
88 | printf(".globl z_extract_offset_negative\n"); | ||
89 | printf("z_extract_offset_negative = -0x%lx\n", offs); | ||
90 | |||
91 | printf(".globl input_data, input_data_end\n"); | ||
92 | printf("input_data:\n"); | ||
93 | printf(".incbin \"%s\"\n", argv[1]); | ||
94 | printf("input_data_end:\n"); | ||
95 | |||
96 | return 0; | ||
97 | } | ||
diff --git a/arch/x86/boot/compressed/vmlinux.scr b/arch/x86/boot/compressed/vmlinux.scr deleted file mode 100644 index f02382ae5c48..000000000000 --- a/arch/x86/boot/compressed/vmlinux.scr +++ /dev/null | |||
@@ -1,10 +0,0 @@ | |||
1 | SECTIONS | ||
2 | { | ||
3 | .rodata.compressed : { | ||
4 | input_len = .; | ||
5 | LONG(input_data_end - input_data) input_data = .; | ||
6 | *(.data) | ||
7 | output_len = . - 4; | ||
8 | input_data_end = .; | ||
9 | } | ||
10 | } | ||