aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2009-05-08 20:42:16 -0400
committerH. Peter Anvin <hpa@zytor.com>2009-05-08 20:46:34 -0400
commit02a884c0fe7ec8459d00d34b7d4101af21fc4a86 (patch)
tree164783f84130482e52290af03d96ff8e887f8605 /arch
parent36d3793c947f1ef7ba3d24eeeddc1be41adc5ab4 (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/Makefile11
-rw-r--r--arch/x86/boot/compressed/head_32.S24
-rw-r--r--arch/x86/boot/compressed/head_64.S41
-rw-r--r--arch/x86/boot/compressed/mkpiggy.c97
-rw-r--r--arch/x86/boot/compressed/vmlinux.scr10
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__
19LDFLAGS := -m elf_$(UTS_MACHINE) 19LDFLAGS := -m elf_$(UTS_MACHINE)
20LDFLAGS_vmlinux := -T 20LDFLAGS_vmlinux := -T
21 21
22hostprogs-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
50suffix-$(CONFIG_KERNEL_BZIP2) := bz2 52suffix-$(CONFIG_KERNEL_BZIP2) := bz2
51suffix-$(CONFIG_KERNEL_LZMA) := lzma 53suffix-$(CONFIG_KERNEL_LZMA) := lzma
52 54
53LDFLAGS_piggy.o := -r --format binary --oformat $(CONFIG_OUTPUT_FORMAT) -T 55quiet_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
58targets += 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
33static 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
41int 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 @@
1SECTIONS
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}