aboutsummaryrefslogtreecommitdiffstats
path: root/arch/i386/boot/compressed
diff options
context:
space:
mode:
Diffstat (limited to 'arch/i386/boot/compressed')
-rw-r--r--arch/i386/boot/compressed/Makefile28
-rw-r--r--arch/i386/boot/compressed/head.S185
-rw-r--r--arch/i386/boot/compressed/misc.c264
-rw-r--r--arch/i386/boot/compressed/relocs.c625
-rw-r--r--arch/i386/boot/compressed/vmlinux.lds43
-rw-r--r--arch/i386/boot/compressed/vmlinux.scr3
6 files changed, 947 insertions, 201 deletions
diff --git a/arch/i386/boot/compressed/Makefile b/arch/i386/boot/compressed/Makefile
index 258ea95224f6..a661217f33ec 100644
--- a/arch/i386/boot/compressed/Makefile
+++ b/arch/i386/boot/compressed/Makefile
@@ -4,22 +4,42 @@
4# create a compressed vmlinux image from the original vmlinux 4# create a compressed vmlinux image from the original vmlinux
5# 5#
6 6
7targets := vmlinux vmlinux.bin vmlinux.bin.gz head.o misc.o piggy.o 7targets := vmlinux vmlinux.bin vmlinux.bin.gz head.o misc.o piggy.o \
8 vmlinux.bin.all vmlinux.relocs
8EXTRA_AFLAGS := -traditional 9EXTRA_AFLAGS := -traditional
9 10
10LDFLAGS_vmlinux := -Ttext $(IMAGE_OFFSET) -e startup_32 11LDFLAGS_vmlinux := -T
12CFLAGS_misc.o += -fPIC
13hostprogs-y := relocs
11 14
12$(obj)/vmlinux: $(obj)/head.o $(obj)/misc.o $(obj)/piggy.o FORCE 15$(obj)/vmlinux: $(src)/vmlinux.lds $(obj)/head.o $(obj)/misc.o $(obj)/piggy.o FORCE
13 $(call if_changed,ld) 16 $(call if_changed,ld)
14 @: 17 @:
15 18
16$(obj)/vmlinux.bin: vmlinux FORCE 19$(obj)/vmlinux.bin: vmlinux FORCE
17 $(call if_changed,objcopy) 20 $(call if_changed,objcopy)
18 21
22quiet_cmd_relocs = RELOCS $@
23 cmd_relocs = $(obj)/relocs $< > $@;$(obj)/relocs --abs-relocs $<
24$(obj)/vmlinux.relocs: vmlinux $(obj)/relocs FORCE
25 $(call if_changed,relocs)
26
27vmlinux.bin.all-y := $(obj)/vmlinux.bin
28vmlinux.bin.all-$(CONFIG_RELOCATABLE) += $(obj)/vmlinux.relocs
29quiet_cmd_relocbin = BUILD $@
30 cmd_relocbin = cat $(filter-out FORCE,$^) > $@
31$(obj)/vmlinux.bin.all: $(vmlinux.bin.all-y) FORCE
32 $(call if_changed,relocbin)
33
34ifdef CONFIG_RELOCATABLE
35$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin.all FORCE
36 $(call if_changed,gzip)
37else
19$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE 38$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE
20 $(call if_changed,gzip) 39 $(call if_changed,gzip)
40endif
21 41
22LDFLAGS_piggy.o := -r --format binary --oformat elf32-i386 -T 42LDFLAGS_piggy.o := -r --format binary --oformat elf32-i386 -T
23 43
24$(obj)/piggy.o: $(obj)/vmlinux.scr $(obj)/vmlinux.bin.gz FORCE 44$(obj)/piggy.o: $(src)/vmlinux.scr $(obj)/vmlinux.bin.gz FORCE
25 $(call if_changed,ld) 45 $(call if_changed,ld)
diff --git a/arch/i386/boot/compressed/head.S b/arch/i386/boot/compressed/head.S
index b5893e4ecd37..f395a4bb38bb 100644
--- a/arch/i386/boot/compressed/head.S
+++ b/arch/i386/boot/compressed/head.S
@@ -26,9 +26,11 @@
26#include <linux/linkage.h> 26#include <linux/linkage.h>
27#include <asm/segment.h> 27#include <asm/segment.h>
28#include <asm/page.h> 28#include <asm/page.h>
29#include <asm/boot.h>
29 30
31.section ".text.head"
30 .globl startup_32 32 .globl startup_32
31 33
32startup_32: 34startup_32:
33 cld 35 cld
34 cli 36 cli
@@ -37,93 +39,142 @@ startup_32:
37 movl %eax,%es 39 movl %eax,%es
38 movl %eax,%fs 40 movl %eax,%fs
39 movl %eax,%gs 41 movl %eax,%gs
42 movl %eax,%ss
40 43
41 lss stack_start,%esp 44/* Calculate the delta between where we were compiled to run
42 xorl %eax,%eax 45 * at and where we were actually loaded at. This can only be done
431: incl %eax # check that A20 really IS enabled 46 * with a short local call on x86. Nothing else will tell us what
44 movl %eax,0x000000 # loop forever if it isn't 47 * address we are running at. The reserved chunk of the real-mode
45 cmpl %eax,0x100000 48 * data at 0x34-0x3f are used as the stack for this calculation.
46 je 1b 49 * Only 4 bytes are needed.
50 */
51 leal 0x40(%esi), %esp
52 call 1f
531: popl %ebp
54 subl $1b, %ebp
55
56/* %ebp contains the address we are loaded at by the boot loader and %ebx
57 * contains the address where we should move the kernel image temporarily
58 * for safe in-place decompression.
59 */
60
61#ifdef CONFIG_RELOCATABLE
62 movl %ebp, %ebx
63 addl $(CONFIG_PHYSICAL_ALIGN - 1), %ebx
64 andl $(~(CONFIG_PHYSICAL_ALIGN - 1)), %ebx
65#else
66 movl $LOAD_PHYSICAL_ADDR, %ebx
67#endif
68
69 /* Replace the compressed data size with the uncompressed size */
70 subl input_len(%ebp), %ebx
71 movl output_len(%ebp), %eax
72 addl %eax, %ebx
73 /* Add 8 bytes for every 32K input block */
74 shrl $12, %eax
75 addl %eax, %ebx
76 /* Add 32K + 18 bytes of extra slack */
77 addl $(32768 + 18), %ebx
78 /* Align on a 4K boundary */
79 addl $4095, %ebx
80 andl $~4095, %ebx
81
82/* Copy the compressed kernel to the end of our buffer
83 * where decompression in place becomes safe.
84 */
85 pushl %esi
86 leal _end(%ebp), %esi
87 leal _end(%ebx), %edi
88 movl $(_end - startup_32), %ecx
89 std
90 rep
91 movsb
92 cld
93 popl %esi
94
95/* Compute the kernel start address.
96 */
97#ifdef CONFIG_RELOCATABLE
98 addl $(CONFIG_PHYSICAL_ALIGN - 1), %ebp
99 andl $(~(CONFIG_PHYSICAL_ALIGN - 1)), %ebp
100#else
101 movl $LOAD_PHYSICAL_ADDR, %ebp
102#endif
47 103
48/* 104/*
49 * Initialize eflags. Some BIOS's leave bits like NT set. This would 105 * Jump to the relocated address.
50 * confuse the debugger if this code is traced.
51 * XXX - best to initialize before switching to protected mode.
52 */ 106 */
53 pushl $0 107 leal relocated(%ebx), %eax
54 popfl 108 jmp *%eax
109.section ".text"
110relocated:
111
55/* 112/*
56 * Clear BSS 113 * Clear BSS
57 */ 114 */
58 xorl %eax,%eax 115 xorl %eax,%eax
59 movl $_edata,%edi 116 leal _edata(%ebx),%edi
60 movl $_end,%ecx 117 leal _end(%ebx), %ecx
61 subl %edi,%ecx 118 subl %edi,%ecx
62 cld 119 cld
63 rep 120 rep
64 stosb 121 stosb
122
123/*
124 * Setup the stack for the decompressor
125 */
126 leal stack_end(%ebx), %esp
127
65/* 128/*
66 * Do the decompression, and jump to the new kernel.. 129 * Do the decompression, and jump to the new kernel..
67 */ 130 */
68 subl $16,%esp # place for structure on the stack 131 movl output_len(%ebx), %eax
69 movl %esp,%eax 132 pushl %eax
133 pushl %ebp # output address
134 movl input_len(%ebx), %eax
135 pushl %eax # input_len
136 leal input_data(%ebx), %eax
137 pushl %eax # input_data
138 leal _end(%ebx), %eax
139 pushl %eax # end of the image as third argument
70 pushl %esi # real mode pointer as second arg 140 pushl %esi # real mode pointer as second arg
71 pushl %eax # address of structure as first arg
72 call decompress_kernel 141 call decompress_kernel
73 orl %eax,%eax 142 addl $20, %esp
74 jnz 3f 143 popl %ecx
75 popl %esi # discard address
76 popl %esi # real mode pointer
77 xorl %ebx,%ebx
78 ljmp $(__BOOT_CS), $__PHYSICAL_START
79 144
145#if CONFIG_RELOCATABLE
146/* Find the address of the relocations.
147 */
148 movl %ebp, %edi
149 addl %ecx, %edi
150
151/* Calculate the delta between where vmlinux was compiled to run
152 * and where it was actually loaded.
153 */
154 movl %ebp, %ebx
155 subl $LOAD_PHYSICAL_ADDR, %ebx
156 jz 2f /* Nothing to be done if loaded at compiled addr. */
80/* 157/*
81 * We come here, if we were loaded high. 158 * Process relocations.
82 * We need to move the move-in-place routine down to 0x1000
83 * and then start it with the buffer addresses in registers,
84 * which we got from the stack.
85 */ 159 */
863: 160
87 movl $move_routine_start,%esi 1611: subl $4, %edi
88 movl $0x1000,%edi 162 movl 0(%edi), %ecx
89 movl $move_routine_end,%ecx 163 testl %ecx, %ecx
90 subl %esi,%ecx 164 jz 2f
91 addl $3,%ecx 165 addl %ebx, -__PAGE_OFFSET(%ebx, %ecx)
92 shrl $2,%ecx 166 jmp 1b
93 cld 1672:
94 rep 168#endif
95 movsl
96
97 popl %esi # discard the address
98 popl %ebx # real mode pointer
99 popl %esi # low_buffer_start
100 popl %ecx # lcount
101 popl %edx # high_buffer_start
102 popl %eax # hcount
103 movl $__PHYSICAL_START,%edi
104 cli # make sure we don't get interrupted
105 ljmp $(__BOOT_CS), $0x1000 # and jump to the move routine
106 169
107/* 170/*
108 * Routine (template) for moving the decompressed kernel in place, 171 * Jump to the decompressed kernel.
109 * if we were high loaded. This _must_ PIC-code !
110 */ 172 */
111move_routine_start:
112 movl %ecx,%ebp
113 shrl $2,%ecx
114 rep
115 movsl
116 movl %ebp,%ecx
117 andl $3,%ecx
118 rep
119 movsb
120 movl %edx,%esi
121 movl %eax,%ecx # NOTE: rep movsb won't move if %ecx == 0
122 addl $3,%ecx
123 shrl $2,%ecx
124 rep
125 movsl
126 movl %ebx,%esi # Restore setup pointer
127 xorl %ebx,%ebx 173 xorl %ebx,%ebx
128 ljmp $(__BOOT_CS), $__PHYSICAL_START 174 jmp *%ebp
129move_routine_end: 175
176.bss
177.balign 4
178stack:
179 .fill 4096, 1, 0
180stack_end:
diff --git a/arch/i386/boot/compressed/misc.c b/arch/i386/boot/compressed/misc.c
index b2ccd543410d..1ce7017fd627 100644
--- a/arch/i386/boot/compressed/misc.c
+++ b/arch/i386/boot/compressed/misc.c
@@ -9,11 +9,94 @@
9 * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996 9 * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996
10 */ 10 */
11 11
12#undef CONFIG_PARAVIRT
12#include <linux/linkage.h> 13#include <linux/linkage.h>
13#include <linux/vmalloc.h> 14#include <linux/vmalloc.h>
14#include <linux/screen_info.h> 15#include <linux/screen_info.h>
15#include <asm/io.h> 16#include <asm/io.h>
16#include <asm/page.h> 17#include <asm/page.h>
18#include <asm/boot.h>
19
20/* WARNING!!
21 * This code is compiled with -fPIC and it is relocated dynamically
22 * at run time, but no relocation processing is performed.
23 * This means that it is not safe to place pointers in static structures.
24 */
25
26/*
27 * Getting to provable safe in place decompression is hard.
28 * Worst case behaviours need to be analized.
29 * Background information:
30 *
31 * The file layout is:
32 * magic[2]
33 * method[1]
34 * flags[1]
35 * timestamp[4]
36 * extraflags[1]
37 * os[1]
38 * compressed data blocks[N]
39 * crc[4] orig_len[4]
40 *
41 * resulting in 18 bytes of non compressed data overhead.
42 *
43 * Files divided into blocks
44 * 1 bit (last block flag)
45 * 2 bits (block type)
46 *
47 * 1 block occurs every 32K -1 bytes or when there 50% compression has been achieved.
48 * The smallest block type encoding is always used.
49 *
50 * stored:
51 * 32 bits length in bytes.
52 *
53 * fixed:
54 * magic fixed tree.
55 * symbols.
56 *
57 * dynamic:
58 * dynamic tree encoding.
59 * symbols.
60 *
61 *
62 * The buffer for decompression in place is the length of the
63 * uncompressed data, plus a small amount extra to keep the algorithm safe.
64 * The compressed data is placed at the end of the buffer. The output
65 * pointer is placed at the start of the buffer and the input pointer
66 * is placed where the compressed data starts. Problems will occur
67 * when the output pointer overruns the input pointer.
68 *
69 * The output pointer can only overrun the input pointer if the input
70 * pointer is moving faster than the output pointer. A condition only
71 * triggered by data whose compressed form is larger than the uncompressed
72 * form.
73 *
74 * The worst case at the block level is a growth of the compressed data
75 * of 5 bytes per 32767 bytes.
76 *
77 * The worst case internal to a compressed block is very hard to figure.
78 * The worst case can at least be boundined by having one bit that represents
79 * 32764 bytes and then all of the rest of the bytes representing the very
80 * very last byte.
81 *
82 * All of which is enough to compute an amount of extra data that is required
83 * to be safe. To avoid problems at the block level allocating 5 extra bytes
84 * per 32767 bytes of data is sufficient. To avoind problems internal to a block
85 * adding an extra 32767 bytes (the worst case uncompressed block size) is
86 * sufficient, to ensure that in the worst case the decompressed data for
87 * block will stop the byte before the compressed data for a block begins.
88 * To avoid problems with the compressed data's meta information an extra 18
89 * bytes are needed. Leading to the formula:
90 *
91 * extra_bytes = (uncompressed_size >> 12) + 32768 + 18 + decompressor_size.
92 *
93 * Adding 8 bytes per 32K is a bit excessive but much easier to calculate.
94 * Adding 32768 instead of 32767 just makes for round numbers.
95 * Adding the decompressor_size is necessary as it musht live after all
96 * of the data as well. Last I measured the decompressor is about 14K.
97 * 10K of actuall data and 4K of bss.
98 *
99 */
17 100
18/* 101/*
19 * gzip declarations 102 * gzip declarations
@@ -30,15 +113,20 @@ typedef unsigned char uch;
30typedef unsigned short ush; 113typedef unsigned short ush;
31typedef unsigned long ulg; 114typedef unsigned long ulg;
32 115
33#define WSIZE 0x8000 /* Window size must be at least 32k, */ 116#define WSIZE 0x80000000 /* Window size must be at least 32k,
34 /* and a power of two */ 117 * and a power of two
118 * We don't actually have a window just
119 * a huge output buffer so I report
120 * a 2G windows size, as that should
121 * always be larger than our output buffer.
122 */
35 123
36static uch *inbuf; /* input buffer */ 124static uch *inbuf; /* input buffer */
37static uch window[WSIZE]; /* Sliding window buffer */ 125static uch *window; /* Sliding window buffer, (and final output buffer) */
38 126
39static unsigned insize = 0; /* valid bytes in inbuf */ 127static unsigned insize; /* valid bytes in inbuf */
40static unsigned inptr = 0; /* index of next byte to be processed in inbuf */ 128static unsigned inptr; /* index of next byte to be processed in inbuf */
41static unsigned outcnt = 0; /* bytes in output buffer */ 129static unsigned outcnt; /* bytes in output buffer */
42 130
43/* gzip flag byte */ 131/* gzip flag byte */
44#define ASCII_FLAG 0x01 /* bit 0 set: file probably ASCII text */ 132#define ASCII_FLAG 0x01 /* bit 0 set: file probably ASCII text */
@@ -89,8 +177,6 @@ extern unsigned char input_data[];
89extern int input_len; 177extern int input_len;
90 178
91static long bytes_out = 0; 179static long bytes_out = 0;
92static uch *output_data;
93static unsigned long output_ptr = 0;
94 180
95static void *malloc(int size); 181static void *malloc(int size);
96static void free(void *where); 182static void free(void *where);
@@ -100,24 +186,17 @@ static void *memcpy(void *dest, const void *src, unsigned n);
100 186
101static void putstr(const char *); 187static void putstr(const char *);
102 188
103extern int end; 189static unsigned long free_mem_ptr;
104static long free_mem_ptr = (long)&end; 190static unsigned long free_mem_end_ptr;
105static long free_mem_end_ptr;
106 191
107#define INPLACE_MOVE_ROUTINE 0x1000
108#define LOW_BUFFER_START 0x2000
109#define LOW_BUFFER_MAX 0x90000
110#define HEAP_SIZE 0x3000 192#define HEAP_SIZE 0x3000
111static unsigned int low_buffer_end, low_buffer_size;
112static int high_loaded =0;
113static uch *high_buffer_start /* = (uch *)(((ulg)&end) + HEAP_SIZE)*/;
114 193
115static char *vidmem = (char *)0xb8000; 194static char *vidmem = (char *)0xb8000;
116static int vidport; 195static int vidport;
117static int lines, cols; 196static int lines, cols;
118 197
119#ifdef CONFIG_X86_NUMAQ 198#ifdef CONFIG_X86_NUMAQ
120static void * xquad_portio = NULL; 199void *xquad_portio;
121#endif 200#endif
122 201
123#include "../../../../lib/inflate.c" 202#include "../../../../lib/inflate.c"
@@ -151,7 +230,7 @@ static void gzip_mark(void **ptr)
151 230
152static void gzip_release(void **ptr) 231static void gzip_release(void **ptr)
153{ 232{
154 free_mem_ptr = (long) *ptr; 233 free_mem_ptr = (unsigned long) *ptr;
155} 234}
156 235
157static void scroll(void) 236static void scroll(void)
@@ -179,7 +258,7 @@ static void putstr(const char *s)
179 y--; 258 y--;
180 } 259 }
181 } else { 260 } else {
182 vidmem [ ( x + cols * y ) * 2 ] = c; 261 vidmem [ ( x + cols * y ) * 2 ] = c;
183 if ( ++x >= cols ) { 262 if ( ++x >= cols ) {
184 x = 0; 263 x = 0;
185 if ( ++y >= lines ) { 264 if ( ++y >= lines ) {
@@ -224,58 +303,31 @@ static void* memcpy(void* dest, const void* src, unsigned n)
224 */ 303 */
225static int fill_inbuf(void) 304static int fill_inbuf(void)
226{ 305{
227 if (insize != 0) { 306 error("ran out of input data");
228 error("ran out of input data"); 307 return 0;
229 }
230
231 inbuf = input_data;
232 insize = input_len;
233 inptr = 1;
234 return inbuf[0];
235} 308}
236 309
237/* =========================================================================== 310/* ===========================================================================
238 * Write the output window window[0..outcnt-1] and update crc and bytes_out. 311 * Write the output window window[0..outcnt-1] and update crc and bytes_out.
239 * (Used for the decompressed data only.) 312 * (Used for the decompressed data only.)
240 */ 313 */
241static void flush_window_low(void)
242{
243 ulg c = crc; /* temporary variable */
244 unsigned n;
245 uch *in, *out, ch;
246
247 in = window;
248 out = &output_data[output_ptr];
249 for (n = 0; n < outcnt; n++) {
250 ch = *out++ = *in++;
251 c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8);
252 }
253 crc = c;
254 bytes_out += (ulg)outcnt;
255 output_ptr += (ulg)outcnt;
256 outcnt = 0;
257}
258
259static void flush_window_high(void)
260{
261 ulg c = crc; /* temporary variable */
262 unsigned n;
263 uch *in, ch;
264 in = window;
265 for (n = 0; n < outcnt; n++) {
266 ch = *output_data++ = *in++;
267 if ((ulg)output_data == low_buffer_end) output_data=high_buffer_start;
268 c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8);
269 }
270 crc = c;
271 bytes_out += (ulg)outcnt;
272 outcnt = 0;
273}
274
275static void flush_window(void) 314static void flush_window(void)
276{ 315{
277 if (high_loaded) flush_window_high(); 316 /* With my window equal to my output buffer
278 else flush_window_low(); 317 * I only need to compute the crc here.
318 */
319 ulg c = crc; /* temporary variable */
320 unsigned n;
321 uch *in, ch;
322
323 in = window;
324 for (n = 0; n < outcnt; n++) {
325 ch = *in++;
326 c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8);
327 }
328 crc = c;
329 bytes_out += (ulg)outcnt;
330 outcnt = 0;
279} 331}
280 332
281static void error(char *x) 333static void error(char *x)
@@ -287,66 +339,8 @@ static void error(char *x)
287 while(1); /* Halt */ 339 while(1); /* Halt */
288} 340}
289 341
290#define STACK_SIZE (4096) 342asmlinkage void decompress_kernel(void *rmode, unsigned long end,
291 343 uch *input_data, unsigned long input_len, uch *output)
292long user_stack [STACK_SIZE];
293
294struct {
295 long * a;
296 short b;
297 } stack_start = { & user_stack [STACK_SIZE] , __BOOT_DS };
298
299static void setup_normal_output_buffer(void)
300{
301#ifdef STANDARD_MEMORY_BIOS_CALL
302 if (RM_EXT_MEM_K < 1024) error("Less than 2MB of memory");
303#else
304 if ((RM_ALT_MEM_K > RM_EXT_MEM_K ? RM_ALT_MEM_K : RM_EXT_MEM_K) < 1024) error("Less than 2MB of memory");
305#endif
306 output_data = (unsigned char *)__PHYSICAL_START; /* Normally Points to 1M */
307 free_mem_end_ptr = (long)real_mode;
308}
309
310struct moveparams {
311 uch *low_buffer_start; int lcount;
312 uch *high_buffer_start; int hcount;
313};
314
315static void setup_output_buffer_if_we_run_high(struct moveparams *mv)
316{
317 high_buffer_start = (uch *)(((ulg)&end) + HEAP_SIZE);
318#ifdef STANDARD_MEMORY_BIOS_CALL
319 if (RM_EXT_MEM_K < (3*1024)) error("Less than 4MB of memory");
320#else
321 if ((RM_ALT_MEM_K > RM_EXT_MEM_K ? RM_ALT_MEM_K : RM_EXT_MEM_K) < (3*1024)) error("Less than 4MB of memory");
322#endif
323 mv->low_buffer_start = output_data = (unsigned char *)LOW_BUFFER_START;
324 low_buffer_end = ((unsigned int)real_mode > LOW_BUFFER_MAX
325 ? LOW_BUFFER_MAX : (unsigned int)real_mode) & ~0xfff;
326 low_buffer_size = low_buffer_end - LOW_BUFFER_START;
327 high_loaded = 1;
328 free_mem_end_ptr = (long)high_buffer_start;
329 if ( (__PHYSICAL_START + low_buffer_size) > ((ulg)high_buffer_start)) {
330 high_buffer_start = (uch *)(__PHYSICAL_START + low_buffer_size);
331 mv->hcount = 0; /* say: we need not to move high_buffer */
332 }
333 else mv->hcount = -1;
334 mv->high_buffer_start = high_buffer_start;
335}
336
337static void close_output_buffer_if_we_run_high(struct moveparams *mv)
338{
339 if (bytes_out > low_buffer_size) {
340 mv->lcount = low_buffer_size;
341 if (mv->hcount)
342 mv->hcount = bytes_out - low_buffer_size;
343 } else {
344 mv->lcount = bytes_out;
345 mv->hcount = 0;
346 }
347}
348
349asmlinkage int decompress_kernel(struct moveparams *mv, void *rmode)
350{ 344{
351 real_mode = rmode; 345 real_mode = rmode;
352 346
@@ -361,13 +355,25 @@ asmlinkage int decompress_kernel(struct moveparams *mv, void *rmode)
361 lines = RM_SCREEN_INFO.orig_video_lines; 355 lines = RM_SCREEN_INFO.orig_video_lines;
362 cols = RM_SCREEN_INFO.orig_video_cols; 356 cols = RM_SCREEN_INFO.orig_video_cols;
363 357
364 if (free_mem_ptr < 0x100000) setup_normal_output_buffer(); 358 window = output; /* Output buffer (Normally at 1M) */
365 else setup_output_buffer_if_we_run_high(mv); 359 free_mem_ptr = end; /* Heap */
360 free_mem_end_ptr = end + HEAP_SIZE;
361 inbuf = input_data; /* Input buffer */
362 insize = input_len;
363 inptr = 0;
364
365 if ((u32)output & (CONFIG_PHYSICAL_ALIGN -1))
366 error("Destination address not CONFIG_PHYSICAL_ALIGN aligned");
367 if (end > ((-__PAGE_OFFSET-(512 <<20)-1) & 0x7fffffff))
368 error("Destination address too large");
369#ifndef CONFIG_RELOCATABLE
370 if ((u32)output != LOAD_PHYSICAL_ADDR)
371 error("Wrong destination address");
372#endif
366 373
367 makecrc(); 374 makecrc();
368 putstr("Uncompressing Linux... "); 375 putstr("Uncompressing Linux... ");
369 gunzip(); 376 gunzip();
370 putstr("Ok, booting the kernel.\n"); 377 putstr("Ok, booting the kernel.\n");
371 if (high_loaded) close_output_buffer_if_we_run_high(mv); 378 return;
372 return high_loaded;
373} 379}
diff --git a/arch/i386/boot/compressed/relocs.c b/arch/i386/boot/compressed/relocs.c
new file mode 100644
index 000000000000..468da89153c4
--- /dev/null
+++ b/arch/i386/boot/compressed/relocs.c
@@ -0,0 +1,625 @@
1#include <stdio.h>
2#include <stdarg.h>
3#include <stdlib.h>
4#include <stdint.h>
5#include <string.h>
6#include <errno.h>
7#include <unistd.h>
8#include <elf.h>
9#include <byteswap.h>
10#define USE_BSD
11#include <endian.h>
12
13#define MAX_SHDRS 100
14static Elf32_Ehdr ehdr;
15static Elf32_Shdr shdr[MAX_SHDRS];
16static Elf32_Sym *symtab[MAX_SHDRS];
17static Elf32_Rel *reltab[MAX_SHDRS];
18static char *strtab[MAX_SHDRS];
19static unsigned long reloc_count, reloc_idx;
20static unsigned long *relocs;
21
22/*
23 * Following symbols have been audited. There values are constant and do
24 * not change if bzImage is loaded at a different physical address than
25 * the address for which it has been compiled. Don't warn user about
26 * absolute relocations present w.r.t these symbols.
27 */
28static const char* safe_abs_relocs[] = {
29 "__kernel_vsyscall",
30 "__kernel_rt_sigreturn",
31 "__kernel_sigreturn",
32 "SYSENTER_RETURN",
33};
34
35static int is_safe_abs_reloc(const char* sym_name)
36{
37 int i, array_size;
38
39 array_size = sizeof(safe_abs_relocs)/sizeof(char*);
40
41 for(i = 0; i < array_size; i++) {
42 if (!strcmp(sym_name, safe_abs_relocs[i]))
43 /* Match found */
44 return 1;
45 }
46 return 0;
47}
48
49static void die(char *fmt, ...)
50{
51 va_list ap;
52 va_start(ap, fmt);
53 vfprintf(stderr, fmt, ap);
54 va_end(ap);
55 exit(1);
56}
57
58static const char *sym_type(unsigned type)
59{
60 static const char *type_name[] = {
61#define SYM_TYPE(X) [X] = #X
62 SYM_TYPE(STT_NOTYPE),
63 SYM_TYPE(STT_OBJECT),
64 SYM_TYPE(STT_FUNC),
65 SYM_TYPE(STT_SECTION),
66 SYM_TYPE(STT_FILE),
67 SYM_TYPE(STT_COMMON),
68 SYM_TYPE(STT_TLS),
69#undef SYM_TYPE
70 };
71 const char *name = "unknown sym type name";
72 if (type < sizeof(type_name)/sizeof(type_name[0])) {
73 name = type_name[type];
74 }
75 return name;
76}
77
78static const char *sym_bind(unsigned bind)
79{
80 static const char *bind_name[] = {
81#define SYM_BIND(X) [X] = #X
82 SYM_BIND(STB_LOCAL),
83 SYM_BIND(STB_GLOBAL),
84 SYM_BIND(STB_WEAK),
85#undef SYM_BIND
86 };
87 const char *name = "unknown sym bind name";
88 if (bind < sizeof(bind_name)/sizeof(bind_name[0])) {
89 name = bind_name[bind];
90 }
91 return name;
92}
93
94static const char *sym_visibility(unsigned visibility)
95{
96 static const char *visibility_name[] = {
97#define SYM_VISIBILITY(X) [X] = #X
98 SYM_VISIBILITY(STV_DEFAULT),
99 SYM_VISIBILITY(STV_INTERNAL),
100 SYM_VISIBILITY(STV_HIDDEN),
101 SYM_VISIBILITY(STV_PROTECTED),
102#undef SYM_VISIBILITY
103 };
104 const char *name = "unknown sym visibility name";
105 if (visibility < sizeof(visibility_name)/sizeof(visibility_name[0])) {
106 name = visibility_name[visibility];
107 }
108 return name;
109}
110
111static const char *rel_type(unsigned type)
112{
113 static const char *type_name[] = {
114#define REL_TYPE(X) [X] = #X
115 REL_TYPE(R_386_NONE),
116 REL_TYPE(R_386_32),
117 REL_TYPE(R_386_PC32),
118 REL_TYPE(R_386_GOT32),
119 REL_TYPE(R_386_PLT32),
120 REL_TYPE(R_386_COPY),
121 REL_TYPE(R_386_GLOB_DAT),
122 REL_TYPE(R_386_JMP_SLOT),
123 REL_TYPE(R_386_RELATIVE),
124 REL_TYPE(R_386_GOTOFF),
125 REL_TYPE(R_386_GOTPC),
126#undef REL_TYPE
127 };
128 const char *name = "unknown type rel type name";
129 if (type < sizeof(type_name)/sizeof(type_name[0])) {
130 name = type_name[type];
131 }
132 return name;
133}
134
135static const char *sec_name(unsigned shndx)
136{
137 const char *sec_strtab;
138 const char *name;
139 sec_strtab = strtab[ehdr.e_shstrndx];
140 name = "<noname>";
141 if (shndx < ehdr.e_shnum) {
142 name = sec_strtab + shdr[shndx].sh_name;
143 }
144 else if (shndx == SHN_ABS) {
145 name = "ABSOLUTE";
146 }
147 else if (shndx == SHN_COMMON) {
148 name = "COMMON";
149 }
150 return name;
151}
152
153static const char *sym_name(const char *sym_strtab, Elf32_Sym *sym)
154{
155 const char *name;
156 name = "<noname>";
157 if (sym->st_name) {
158 name = sym_strtab + sym->st_name;
159 }
160 else {
161 name = sec_name(shdr[sym->st_shndx].sh_name);
162 }
163 return name;
164}
165
166
167
168#if BYTE_ORDER == LITTLE_ENDIAN
169#define le16_to_cpu(val) (val)
170#define le32_to_cpu(val) (val)
171#endif
172#if BYTE_ORDER == BIG_ENDIAN
173#define le16_to_cpu(val) bswap_16(val)
174#define le32_to_cpu(val) bswap_32(val)
175#endif
176
177static uint16_t elf16_to_cpu(uint16_t val)
178{
179 return le16_to_cpu(val);
180}
181
182static uint32_t elf32_to_cpu(uint32_t val)
183{
184 return le32_to_cpu(val);
185}
186
187static void read_ehdr(FILE *fp)
188{
189 if (fread(&ehdr, sizeof(ehdr), 1, fp) != 1) {
190 die("Cannot read ELF header: %s\n",
191 strerror(errno));
192 }
193 if (memcmp(ehdr.e_ident, ELFMAG, 4) != 0) {
194 die("No ELF magic\n");
195 }
196 if (ehdr.e_ident[EI_CLASS] != ELFCLASS32) {
197 die("Not a 32 bit executable\n");
198 }
199 if (ehdr.e_ident[EI_DATA] != ELFDATA2LSB) {
200 die("Not a LSB ELF executable\n");
201 }
202 if (ehdr.e_ident[EI_VERSION] != EV_CURRENT) {
203 die("Unknown ELF version\n");
204 }
205 /* Convert the fields to native endian */
206 ehdr.e_type = elf16_to_cpu(ehdr.e_type);
207 ehdr.e_machine = elf16_to_cpu(ehdr.e_machine);
208 ehdr.e_version = elf32_to_cpu(ehdr.e_version);
209 ehdr.e_entry = elf32_to_cpu(ehdr.e_entry);
210 ehdr.e_phoff = elf32_to_cpu(ehdr.e_phoff);
211 ehdr.e_shoff = elf32_to_cpu(ehdr.e_shoff);
212 ehdr.e_flags = elf32_to_cpu(ehdr.e_flags);
213 ehdr.e_ehsize = elf16_to_cpu(ehdr.e_ehsize);
214 ehdr.e_phentsize = elf16_to_cpu(ehdr.e_phentsize);
215 ehdr.e_phnum = elf16_to_cpu(ehdr.e_phnum);
216 ehdr.e_shentsize = elf16_to_cpu(ehdr.e_shentsize);
217 ehdr.e_shnum = elf16_to_cpu(ehdr.e_shnum);
218 ehdr.e_shstrndx = elf16_to_cpu(ehdr.e_shstrndx);
219
220 if ((ehdr.e_type != ET_EXEC) && (ehdr.e_type != ET_DYN)) {
221 die("Unsupported ELF header type\n");
222 }
223 if (ehdr.e_machine != EM_386) {
224 die("Not for x86\n");
225 }
226 if (ehdr.e_version != EV_CURRENT) {
227 die("Unknown ELF version\n");
228 }
229 if (ehdr.e_ehsize != sizeof(Elf32_Ehdr)) {
230 die("Bad Elf header size\n");
231 }
232 if (ehdr.e_phentsize != sizeof(Elf32_Phdr)) {
233 die("Bad program header entry\n");
234 }
235 if (ehdr.e_shentsize != sizeof(Elf32_Shdr)) {
236 die("Bad section header entry\n");
237 }
238 if (ehdr.e_shstrndx >= ehdr.e_shnum) {
239 die("String table index out of bounds\n");
240 }
241}
242
243static void read_shdrs(FILE *fp)
244{
245 int i;
246 if (ehdr.e_shnum > MAX_SHDRS) {
247 die("%d section headers supported: %d\n",
248 ehdr.e_shnum, MAX_SHDRS);
249 }
250 if (fseek(fp, ehdr.e_shoff, SEEK_SET) < 0) {
251 die("Seek to %d failed: %s\n",
252 ehdr.e_shoff, strerror(errno));
253 }
254 if (fread(&shdr, sizeof(shdr[0]), ehdr.e_shnum, fp) != ehdr.e_shnum) {
255 die("Cannot read ELF section headers: %s\n",
256 strerror(errno));
257 }
258 for(i = 0; i < ehdr.e_shnum; i++) {
259 shdr[i].sh_name = elf32_to_cpu(shdr[i].sh_name);
260 shdr[i].sh_type = elf32_to_cpu(shdr[i].sh_type);
261 shdr[i].sh_flags = elf32_to_cpu(shdr[i].sh_flags);
262 shdr[i].sh_addr = elf32_to_cpu(shdr[i].sh_addr);
263 shdr[i].sh_offset = elf32_to_cpu(shdr[i].sh_offset);
264 shdr[i].sh_size = elf32_to_cpu(shdr[i].sh_size);
265 shdr[i].sh_link = elf32_to_cpu(shdr[i].sh_link);
266 shdr[i].sh_info = elf32_to_cpu(shdr[i].sh_info);
267 shdr[i].sh_addralign = elf32_to_cpu(shdr[i].sh_addralign);
268 shdr[i].sh_entsize = elf32_to_cpu(shdr[i].sh_entsize);
269 }
270
271}
272
273static void read_strtabs(FILE *fp)
274{
275 int i;
276 for(i = 0; i < ehdr.e_shnum; i++) {
277 if (shdr[i].sh_type != SHT_STRTAB) {
278 continue;
279 }
280 strtab[i] = malloc(shdr[i].sh_size);
281 if (!strtab[i]) {
282 die("malloc of %d bytes for strtab failed\n",
283 shdr[i].sh_size);
284 }
285 if (fseek(fp, shdr[i].sh_offset, SEEK_SET) < 0) {
286 die("Seek to %d failed: %s\n",
287 shdr[i].sh_offset, strerror(errno));
288 }
289 if (fread(strtab[i], 1, shdr[i].sh_size, fp) != shdr[i].sh_size) {
290 die("Cannot read symbol table: %s\n",
291 strerror(errno));
292 }
293 }
294}
295
296static void read_symtabs(FILE *fp)
297{
298 int i,j;
299 for(i = 0; i < ehdr.e_shnum; i++) {
300 if (shdr[i].sh_type != SHT_SYMTAB) {
301 continue;
302 }
303 symtab[i] = malloc(shdr[i].sh_size);
304 if (!symtab[i]) {
305 die("malloc of %d bytes for symtab failed\n",
306 shdr[i].sh_size);
307 }
308 if (fseek(fp, shdr[i].sh_offset, SEEK_SET) < 0) {
309 die("Seek to %d failed: %s\n",
310 shdr[i].sh_offset, strerror(errno));
311 }
312 if (fread(symtab[i], 1, shdr[i].sh_size, fp) != shdr[i].sh_size) {
313 die("Cannot read symbol table: %s\n",
314 strerror(errno));
315 }
316 for(j = 0; j < shdr[i].sh_size/sizeof(symtab[i][0]); j++) {
317 symtab[i][j].st_name = elf32_to_cpu(symtab[i][j].st_name);
318 symtab[i][j].st_value = elf32_to_cpu(symtab[i][j].st_value);
319 symtab[i][j].st_size = elf32_to_cpu(symtab[i][j].st_size);
320 symtab[i][j].st_shndx = elf16_to_cpu(symtab[i][j].st_shndx);
321 }
322 }
323}
324
325
326static void read_relocs(FILE *fp)
327{
328 int i,j;
329 for(i = 0; i < ehdr.e_shnum; i++) {
330 if (shdr[i].sh_type != SHT_REL) {
331 continue;
332 }
333 reltab[i] = malloc(shdr[i].sh_size);
334 if (!reltab[i]) {
335 die("malloc of %d bytes for relocs failed\n",
336 shdr[i].sh_size);
337 }
338 if (fseek(fp, shdr[i].sh_offset, SEEK_SET) < 0) {
339 die("Seek to %d failed: %s\n",
340 shdr[i].sh_offset, strerror(errno));
341 }
342 if (fread(reltab[i], 1, shdr[i].sh_size, fp) != shdr[i].sh_size) {
343 die("Cannot read symbol table: %s\n",
344 strerror(errno));
345 }
346 for(j = 0; j < shdr[i].sh_size/sizeof(reltab[0][0]); j++) {
347 reltab[i][j].r_offset = elf32_to_cpu(reltab[i][j].r_offset);
348 reltab[i][j].r_info = elf32_to_cpu(reltab[i][j].r_info);
349 }
350 }
351}
352
353
354static void print_absolute_symbols(void)
355{
356 int i;
357 printf("Absolute symbols\n");
358 printf(" Num: Value Size Type Bind Visibility Name\n");
359 for(i = 0; i < ehdr.e_shnum; i++) {
360 char *sym_strtab;
361 Elf32_Sym *sh_symtab;
362 int j;
363 if (shdr[i].sh_type != SHT_SYMTAB) {
364 continue;
365 }
366 sh_symtab = symtab[i];
367 sym_strtab = strtab[shdr[i].sh_link];
368 for(j = 0; j < shdr[i].sh_size/sizeof(symtab[0][0]); j++) {
369 Elf32_Sym *sym;
370 const char *name;
371 sym = &symtab[i][j];
372 name = sym_name(sym_strtab, sym);
373 if (sym->st_shndx != SHN_ABS) {
374 continue;
375 }
376 printf("%5d %08x %5d %10s %10s %12s %s\n",
377 j, sym->st_value, sym->st_size,
378 sym_type(ELF32_ST_TYPE(sym->st_info)),
379 sym_bind(ELF32_ST_BIND(sym->st_info)),
380 sym_visibility(ELF32_ST_VISIBILITY(sym->st_other)),
381 name);
382 }
383 }
384 printf("\n");
385}
386
387static void print_absolute_relocs(void)
388{
389 int i, printed = 0;
390
391 for(i = 0; i < ehdr.e_shnum; i++) {
392 char *sym_strtab;
393 Elf32_Sym *sh_symtab;
394 unsigned sec_applies, sec_symtab;
395 int j;
396 if (shdr[i].sh_type != SHT_REL) {
397 continue;
398 }
399 sec_symtab = shdr[i].sh_link;
400 sec_applies = shdr[i].sh_info;
401 if (!(shdr[sec_applies].sh_flags & SHF_ALLOC)) {
402 continue;
403 }
404 sh_symtab = symtab[sec_symtab];
405 sym_strtab = strtab[shdr[sec_symtab].sh_link];
406 for(j = 0; j < shdr[i].sh_size/sizeof(reltab[0][0]); j++) {
407 Elf32_Rel *rel;
408 Elf32_Sym *sym;
409 const char *name;
410 rel = &reltab[i][j];
411 sym = &sh_symtab[ELF32_R_SYM(rel->r_info)];
412 name = sym_name(sym_strtab, sym);
413 if (sym->st_shndx != SHN_ABS) {
414 continue;
415 }
416
417 /* Absolute symbols are not relocated if bzImage is
418 * loaded at a non-compiled address. Display a warning
419 * to user at compile time about the absolute
420 * relocations present.
421 *
422 * User need to audit the code to make sure
423 * some symbols which should have been section
424 * relative have not become absolute because of some
425 * linker optimization or wrong programming usage.
426 *
427 * Before warning check if this absolute symbol
428 * relocation is harmless.
429 */
430 if (is_safe_abs_reloc(name))
431 continue;
432
433 if (!printed) {
434 printf("WARNING: Absolute relocations"
435 " present\n");
436 printf("Offset Info Type Sym.Value "
437 "Sym.Name\n");
438 printed = 1;
439 }
440
441 printf("%08x %08x %10s %08x %s\n",
442 rel->r_offset,
443 rel->r_info,
444 rel_type(ELF32_R_TYPE(rel->r_info)),
445 sym->st_value,
446 name);
447 }
448 }
449
450 if (printed)
451 printf("\n");
452}
453
454static void walk_relocs(void (*visit)(Elf32_Rel *rel, Elf32_Sym *sym))
455{
456 int i;
457 /* Walk through the relocations */
458 for(i = 0; i < ehdr.e_shnum; i++) {
459 char *sym_strtab;
460 Elf32_Sym *sh_symtab;
461 unsigned sec_applies, sec_symtab;
462 int j;
463 if (shdr[i].sh_type != SHT_REL) {
464 continue;
465 }
466 sec_symtab = shdr[i].sh_link;
467 sec_applies = shdr[i].sh_info;
468 if (!(shdr[sec_applies].sh_flags & SHF_ALLOC)) {
469 continue;
470 }
471 sh_symtab = symtab[sec_symtab];
472 sym_strtab = strtab[shdr[sec_symtab].sh_link];
473 for(j = 0; j < shdr[i].sh_size/sizeof(reltab[0][0]); j++) {
474 Elf32_Rel *rel;
475 Elf32_Sym *sym;
476 unsigned r_type;
477 rel = &reltab[i][j];
478 sym = &sh_symtab[ELF32_R_SYM(rel->r_info)];
479 r_type = ELF32_R_TYPE(rel->r_info);
480 /* Don't visit relocations to absolute symbols */
481 if (sym->st_shndx == SHN_ABS) {
482 continue;
483 }
484 if (r_type == R_386_PC32) {
485 /* PC relative relocations don't need to be adjusted */
486 }
487 else if (r_type == R_386_32) {
488 /* Visit relocations that need to be adjusted */
489 visit(rel, sym);
490 }
491 else {
492 die("Unsupported relocation type: %d\n", r_type);
493 }
494 }
495 }
496}
497
498static void count_reloc(Elf32_Rel *rel, Elf32_Sym *sym)
499{
500 reloc_count += 1;
501}
502
503static void collect_reloc(Elf32_Rel *rel, Elf32_Sym *sym)
504{
505 /* Remember the address that needs to be adjusted. */
506 relocs[reloc_idx++] = rel->r_offset;
507}
508
509static int cmp_relocs(const void *va, const void *vb)
510{
511 const unsigned long *a, *b;
512 a = va; b = vb;
513 return (*a == *b)? 0 : (*a > *b)? 1 : -1;
514}
515
516static void emit_relocs(int as_text)
517{
518 int i;
519 /* Count how many relocations I have and allocate space for them. */
520 reloc_count = 0;
521 walk_relocs(count_reloc);
522 relocs = malloc(reloc_count * sizeof(relocs[0]));
523 if (!relocs) {
524 die("malloc of %d entries for relocs failed\n",
525 reloc_count);
526 }
527 /* Collect up the relocations */
528 reloc_idx = 0;
529 walk_relocs(collect_reloc);
530
531 /* Order the relocations for more efficient processing */
532 qsort(relocs, reloc_count, sizeof(relocs[0]), cmp_relocs);
533
534 /* Print the relocations */
535 if (as_text) {
536 /* Print the relocations in a form suitable that
537 * gas will like.
538 */
539 printf(".section \".data.reloc\",\"a\"\n");
540 printf(".balign 4\n");
541 for(i = 0; i < reloc_count; i++) {
542 printf("\t .long 0x%08lx\n", relocs[i]);
543 }
544 printf("\n");
545 }
546 else {
547 unsigned char buf[4];
548 buf[0] = buf[1] = buf[2] = buf[3] = 0;
549 /* Print a stop */
550 printf("%c%c%c%c", buf[0], buf[1], buf[2], buf[3]);
551 /* Now print each relocation */
552 for(i = 0; i < reloc_count; i++) {
553 buf[0] = (relocs[i] >> 0) & 0xff;
554 buf[1] = (relocs[i] >> 8) & 0xff;
555 buf[2] = (relocs[i] >> 16) & 0xff;
556 buf[3] = (relocs[i] >> 24) & 0xff;
557 printf("%c%c%c%c", buf[0], buf[1], buf[2], buf[3]);
558 }
559 }
560}
561
562static void usage(void)
563{
564 die("relocs [--abs-syms |--abs-relocs | --text] vmlinux\n");
565}
566
567int main(int argc, char **argv)
568{
569 int show_absolute_syms, show_absolute_relocs;
570 int as_text;
571 const char *fname;
572 FILE *fp;
573 int i;
574
575 show_absolute_syms = 0;
576 show_absolute_relocs = 0;
577 as_text = 0;
578 fname = NULL;
579 for(i = 1; i < argc; i++) {
580 char *arg = argv[i];
581 if (*arg == '-') {
582 if (strcmp(argv[1], "--abs-syms") == 0) {
583 show_absolute_syms = 1;
584 continue;
585 }
586
587 if (strcmp(argv[1], "--abs-relocs") == 0) {
588 show_absolute_relocs = 1;
589 continue;
590 }
591 else if (strcmp(argv[1], "--text") == 0) {
592 as_text = 1;
593 continue;
594 }
595 }
596 else if (!fname) {
597 fname = arg;
598 continue;
599 }
600 usage();
601 }
602 if (!fname) {
603 usage();
604 }
605 fp = fopen(fname, "r");
606 if (!fp) {
607 die("Cannot open %s: %s\n",
608 fname, strerror(errno));
609 }
610 read_ehdr(fp);
611 read_shdrs(fp);
612 read_strtabs(fp);
613 read_symtabs(fp);
614 read_relocs(fp);
615 if (show_absolute_syms) {
616 print_absolute_symbols();
617 return 0;
618 }
619 if (show_absolute_relocs) {
620 print_absolute_relocs();
621 return 0;
622 }
623 emit_relocs(as_text);
624 return 0;
625}
diff --git a/arch/i386/boot/compressed/vmlinux.lds b/arch/i386/boot/compressed/vmlinux.lds
new file mode 100644
index 000000000000..cc4854f6c6c1
--- /dev/null
+++ b/arch/i386/boot/compressed/vmlinux.lds
@@ -0,0 +1,43 @@
1OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
2OUTPUT_ARCH(i386)
3ENTRY(startup_32)
4SECTIONS
5{
6 /* Be careful parts of head.S assume startup_32 is at
7 * address 0.
8 */
9 . = 0 ;
10 .text.head : {
11 _head = . ;
12 *(.text.head)
13 _ehead = . ;
14 }
15 .data.compressed : {
16 *(.data.compressed)
17 }
18 .text : {
19 _text = .; /* Text */
20 *(.text)
21 *(.text.*)
22 _etext = . ;
23 }
24 .rodata : {
25 _rodata = . ;
26 *(.rodata) /* read-only data */
27 *(.rodata.*)
28 _erodata = . ;
29 }
30 .data : {
31 _data = . ;
32 *(.data)
33 *(.data.*)
34 _edata = . ;
35 }
36 .bss : {
37 _bss = . ;
38 *(.bss)
39 *(.bss.*)
40 *(COMMON)
41 _end = . ;
42 }
43}
diff --git a/arch/i386/boot/compressed/vmlinux.scr b/arch/i386/boot/compressed/vmlinux.scr
index 1ed9d791f863..707a88f7f29e 100644
--- a/arch/i386/boot/compressed/vmlinux.scr
+++ b/arch/i386/boot/compressed/vmlinux.scr
@@ -1,9 +1,10 @@
1SECTIONS 1SECTIONS
2{ 2{
3 .data : { 3 .data.compressed : {
4 input_len = .; 4 input_len = .;
5 LONG(input_data_end - input_data) input_data = .; 5 LONG(input_data_end - input_data) input_data = .;
6 *(.data) 6 *(.data)
7 output_len = . - 4;
7 input_data_end = .; 8 input_data_end = .;
8 } 9 }
9} 10}