diff options
Diffstat (limited to 'arch/x86/boot/compressed')
-rw-r--r-- | arch/x86/boot/compressed/Makefile | 2 | ||||
-rw-r--r-- | arch/x86/boot/compressed/misc.c | 202 |
2 files changed, 135 insertions, 69 deletions
diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile index d2b9f3bb87c0..92fdd35bd93e 100644 --- a/arch/x86/boot/compressed/Makefile +++ b/arch/x86/boot/compressed/Makefile | |||
@@ -22,7 +22,7 @@ $(obj)/vmlinux: $(src)/vmlinux_$(BITS).lds $(obj)/head_$(BITS).o $(obj)/misc.o $ | |||
22 | $(call if_changed,ld) | 22 | $(call if_changed,ld) |
23 | @: | 23 | @: |
24 | 24 | ||
25 | OBJCOPYFLAGS_vmlinux.bin := -O binary -R .note -R .comment -S | 25 | OBJCOPYFLAGS_vmlinux.bin := -R .comment -S |
26 | $(obj)/vmlinux.bin: vmlinux FORCE | 26 | $(obj)/vmlinux.bin: vmlinux FORCE |
27 | $(call if_changed,objcopy) | 27 | $(call if_changed,objcopy) |
28 | 28 | ||
diff --git a/arch/x86/boot/compressed/misc.c b/arch/x86/boot/compressed/misc.c index 8182e32c1b42..dad4e699f5a3 100644 --- a/arch/x86/boot/compressed/misc.c +++ b/arch/x86/boot/compressed/misc.c | |||
@@ -15,6 +15,10 @@ | |||
15 | * we just keep it from happening | 15 | * we just keep it from happening |
16 | */ | 16 | */ |
17 | #undef CONFIG_PARAVIRT | 17 | #undef CONFIG_PARAVIRT |
18 | #ifdef CONFIG_X86_32 | ||
19 | #define _ASM_DESC_H_ 1 | ||
20 | #endif | ||
21 | |||
18 | #ifdef CONFIG_X86_64 | 22 | #ifdef CONFIG_X86_64 |
19 | #define _LINUX_STRING_H_ 1 | 23 | #define _LINUX_STRING_H_ 1 |
20 | #define __LINUX_BITMAP_H 1 | 24 | #define __LINUX_BITMAP_H 1 |
@@ -22,6 +26,7 @@ | |||
22 | 26 | ||
23 | #include <linux/linkage.h> | 27 | #include <linux/linkage.h> |
24 | #include <linux/screen_info.h> | 28 | #include <linux/screen_info.h> |
29 | #include <linux/elf.h> | ||
25 | #include <asm/io.h> | 30 | #include <asm/io.h> |
26 | #include <asm/page.h> | 31 | #include <asm/page.h> |
27 | #include <asm/boot.h> | 32 | #include <asm/boot.h> |
@@ -53,8 +58,8 @@ | |||
53 | * 1 bit (last block flag) | 58 | * 1 bit (last block flag) |
54 | * 2 bits (block type) | 59 | * 2 bits (block type) |
55 | * | 60 | * |
56 | * 1 block occurs every 32K -1 bytes or when there 50% compression has been achieved. | 61 | * 1 block occurs every 32K -1 bytes or when there 50% compression |
57 | * The smallest block type encoding is always used. | 62 | * has been achieved. The smallest block type encoding is always used. |
58 | * | 63 | * |
59 | * stored: | 64 | * stored: |
60 | * 32 bits length in bytes. | 65 | * 32 bits length in bytes. |
@@ -90,9 +95,9 @@ | |||
90 | * | 95 | * |
91 | * All of which is enough to compute an amount of extra data that is required | 96 | * All of which is enough to compute an amount of extra data that is required |
92 | * to be safe. To avoid problems at the block level allocating 5 extra bytes | 97 | * to be safe. To avoid problems at the block level allocating 5 extra bytes |
93 | * per 32767 bytes of data is sufficient. To avoind problems internal to a block | 98 | * per 32767 bytes of data is sufficient. To avoind problems internal to a |
94 | * adding an extra 32767 bytes (the worst case uncompressed block size) is | 99 | * block adding an extra 32767 bytes (the worst case uncompressed block size) |
95 | * sufficient, to ensure that in the worst case the decompressed data for | 100 | * is sufficient, to ensure that in the worst case the decompressed data for |
96 | * block will stop the byte before the compressed data for a block begins. | 101 | * block will stop the byte before the compressed data for a block begins. |
97 | * To avoid problems with the compressed data's meta information an extra 18 | 102 | * To avoid problems with the compressed data's meta information an extra 18 |
98 | * bytes are needed. Leading to the formula: | 103 | * bytes are needed. Leading to the formula: |
@@ -111,58 +116,66 @@ | |||
111 | * gzip declarations | 116 | * gzip declarations |
112 | */ | 117 | */ |
113 | 118 | ||
114 | #define OF(args) args | 119 | #define OF(args) args |
115 | #define STATIC static | 120 | #define STATIC static |
116 | 121 | ||
117 | #undef memset | 122 | #undef memset |
118 | #undef memcpy | 123 | #undef memcpy |
119 | #define memzero(s, n) memset ((s), 0, (n)) | 124 | #define memzero(s, n) memset((s), 0, (n)) |
125 | |||
126 | typedef unsigned char uch; | ||
127 | typedef unsigned short ush; | ||
128 | typedef unsigned long ulg; | ||
129 | |||
130 | /* | ||
131 | * Window size must be at least 32k, and a power of two. | ||
132 | * We don't actually have a window just a huge output buffer, | ||
133 | * so we report a 2G window size, as that should always be | ||
134 | * larger than our output buffer: | ||
135 | */ | ||
136 | #define WSIZE 0x80000000 | ||
137 | |||
138 | /* Input buffer: */ | ||
139 | static unsigned char *inbuf; | ||
120 | 140 | ||
121 | typedef unsigned char uch; | 141 | /* Sliding window buffer (and final output buffer): */ |
122 | typedef unsigned short ush; | 142 | static unsigned char *window; |
123 | typedef unsigned long ulg; | ||
124 | 143 | ||
125 | #define WSIZE 0x80000000 /* Window size must be at least 32k, | 144 | /* Valid bytes in inbuf: */ |
126 | * and a power of two | 145 | static unsigned insize; |
127 | * We don't actually have a window just | ||
128 | * a huge output buffer so I report | ||
129 | * a 2G windows size, as that should | ||
130 | * always be larger than our output buffer. | ||
131 | */ | ||
132 | 146 | ||
133 | static uch *inbuf; /* input buffer */ | 147 | /* Index of next byte to be processed in inbuf: */ |
134 | static uch *window; /* Sliding window buffer, (and final output buffer) */ | 148 | static unsigned inptr; |
135 | 149 | ||
136 | static unsigned insize; /* valid bytes in inbuf */ | 150 | /* Bytes in output buffer: */ |
137 | static unsigned inptr; /* index of next byte to be processed in inbuf */ | 151 | static unsigned outcnt; |
138 | static unsigned outcnt; /* bytes in output buffer */ | ||
139 | 152 | ||
140 | /* gzip flag byte */ | 153 | /* gzip flag byte */ |
141 | #define ASCII_FLAG 0x01 /* bit 0 set: file probably ASCII text */ | 154 | #define ASCII_FLAG 0x01 /* bit 0 set: file probably ASCII text */ |
142 | #define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */ | 155 | #define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gz file */ |
143 | #define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ | 156 | #define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ |
144 | #define ORIG_NAME 0x08 /* bit 3 set: original file name present */ | 157 | #define ORIG_NAM 0x08 /* bit 3 set: original file name present */ |
145 | #define COMMENT 0x10 /* bit 4 set: file comment present */ | 158 | #define COMMENT 0x10 /* bit 4 set: file comment present */ |
146 | #define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */ | 159 | #define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */ |
147 | #define RESERVED 0xC0 /* bit 6,7: reserved */ | 160 | #define RESERVED 0xC0 /* bit 6, 7: reserved */ |
148 | 161 | ||
149 | #define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf()) | 162 | #define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf()) |
150 | 163 | ||
151 | /* Diagnostic functions */ | 164 | /* Diagnostic functions */ |
152 | #ifdef DEBUG | 165 | #ifdef DEBUG |
153 | # define Assert(cond,msg) {if(!(cond)) error(msg);} | 166 | # define Assert(cond, msg) do { if (!(cond)) error(msg); } while (0) |
154 | # define Trace(x) fprintf x | 167 | # define Trace(x) do { fprintf x; } while (0) |
155 | # define Tracev(x) {if (verbose) fprintf x ;} | 168 | # define Tracev(x) do { if (verbose) fprintf x ; } while (0) |
156 | # define Tracevv(x) {if (verbose>1) fprintf x ;} | 169 | # define Tracevv(x) do { if (verbose > 1) fprintf x ; } while (0) |
157 | # define Tracec(c,x) {if (verbose && (c)) fprintf x ;} | 170 | # define Tracec(c, x) do { if (verbose && (c)) fprintf x ; } while (0) |
158 | # define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;} | 171 | # define Tracecv(c, x) do { if (verbose > 1 && (c)) fprintf x ; } while (0) |
159 | #else | 172 | #else |
160 | # define Assert(cond,msg) | 173 | # define Assert(cond, msg) |
161 | # define Trace(x) | 174 | # define Trace(x) |
162 | # define Tracev(x) | 175 | # define Tracev(x) |
163 | # define Tracevv(x) | 176 | # define Tracevv(x) |
164 | # define Tracec(c,x) | 177 | # define Tracec(c, x) |
165 | # define Tracecv(c,x) | 178 | # define Tracecv(c, x) |
166 | #endif | 179 | #endif |
167 | 180 | ||
168 | static int fill_inbuf(void); | 181 | static int fill_inbuf(void); |
@@ -170,7 +183,7 @@ static void flush_window(void); | |||
170 | static void error(char *m); | 183 | static void error(char *m); |
171 | static void gzip_mark(void **); | 184 | static void gzip_mark(void **); |
172 | static void gzip_release(void **); | 185 | static void gzip_release(void **); |
173 | 186 | ||
174 | /* | 187 | /* |
175 | * This is set up by the setup-routine at boot-time | 188 | * This is set up by the setup-routine at boot-time |
176 | */ | 189 | */ |
@@ -185,7 +198,7 @@ static unsigned char *real_mode; /* Pointer to real-mode data */ | |||
185 | extern unsigned char input_data[]; | 198 | extern unsigned char input_data[]; |
186 | extern int input_len; | 199 | extern int input_len; |
187 | 200 | ||
188 | static long bytes_out = 0; | 201 | static long bytes_out; |
189 | 202 | ||
190 | static void *malloc(int size); | 203 | static void *malloc(int size); |
191 | static void free(void *where); | 204 | static void free(void *where); |
@@ -210,7 +223,7 @@ static memptr free_mem_end_ptr; | |||
210 | #define HEAP_SIZE 0x4000 | 223 | #define HEAP_SIZE 0x4000 |
211 | #endif | 224 | #endif |
212 | 225 | ||
213 | static char *vidmem = (char *)0xb8000; | 226 | static char *vidmem; |
214 | static int vidport; | 227 | static int vidport; |
215 | static int lines, cols; | 228 | static int lines, cols; |
216 | 229 | ||
@@ -224,8 +237,10 @@ static void *malloc(int size) | |||
224 | { | 237 | { |
225 | void *p; | 238 | void *p; |
226 | 239 | ||
227 | if (size <0) error("Malloc error"); | 240 | if (size < 0) |
228 | if (free_mem_ptr <= 0) error("Memory error"); | 241 | error("Malloc error"); |
242 | if (free_mem_ptr <= 0) | ||
243 | error("Memory error"); | ||
229 | 244 | ||
230 | free_mem_ptr = (free_mem_ptr + 3) & ~3; /* Align */ | 245 | free_mem_ptr = (free_mem_ptr + 3) & ~3; /* Align */ |
231 | 246 | ||
@@ -251,19 +266,19 @@ static void gzip_release(void **ptr) | |||
251 | { | 266 | { |
252 | free_mem_ptr = (memptr) *ptr; | 267 | free_mem_ptr = (memptr) *ptr; |
253 | } | 268 | } |
254 | 269 | ||
255 | static void scroll(void) | 270 | static void scroll(void) |
256 | { | 271 | { |
257 | int i; | 272 | int i; |
258 | 273 | ||
259 | memcpy ( vidmem, vidmem + cols * 2, ( lines - 1 ) * cols * 2 ); | 274 | memcpy(vidmem, vidmem + cols * 2, (lines - 1) * cols * 2); |
260 | for ( i = ( lines - 1 ) * cols * 2; i < lines * cols * 2; i += 2 ) | 275 | for (i = (lines - 1) * cols * 2; i < lines * cols * 2; i += 2) |
261 | vidmem[i] = ' '; | 276 | vidmem[i] = ' '; |
262 | } | 277 | } |
263 | 278 | ||
264 | static void putstr(const char *s) | 279 | static void putstr(const char *s) |
265 | { | 280 | { |
266 | int x,y,pos; | 281 | int x, y, pos; |
267 | char c; | 282 | char c; |
268 | 283 | ||
269 | #ifdef CONFIG_X86_32 | 284 | #ifdef CONFIG_X86_32 |
@@ -274,18 +289,18 @@ static void putstr(const char *s) | |||
274 | x = RM_SCREEN_INFO.orig_x; | 289 | x = RM_SCREEN_INFO.orig_x; |
275 | y = RM_SCREEN_INFO.orig_y; | 290 | y = RM_SCREEN_INFO.orig_y; |
276 | 291 | ||
277 | while ( ( c = *s++ ) != '\0' ) { | 292 | while ((c = *s++) != '\0') { |
278 | if ( c == '\n' ) { | 293 | if (c == '\n') { |
279 | x = 0; | 294 | x = 0; |
280 | if ( ++y >= lines ) { | 295 | if (++y >= lines) { |
281 | scroll(); | 296 | scroll(); |
282 | y--; | 297 | y--; |
283 | } | 298 | } |
284 | } else { | 299 | } else { |
285 | vidmem [(x + cols * y) * 2] = c; | 300 | vidmem [(x + cols * y) * 2] = c; |
286 | if ( ++x >= cols ) { | 301 | if (++x >= cols) { |
287 | x = 0; | 302 | x = 0; |
288 | if ( ++y >= lines ) { | 303 | if (++y >= lines) { |
289 | scroll(); | 304 | scroll(); |
290 | y--; | 305 | y--; |
291 | } | 306 | } |
@@ -303,22 +318,22 @@ static void putstr(const char *s) | |||
303 | outb(0xff & (pos >> 1), vidport+1); | 318 | outb(0xff & (pos >> 1), vidport+1); |
304 | } | 319 | } |
305 | 320 | ||
306 | static void* memset(void* s, int c, unsigned n) | 321 | static void *memset(void *s, int c, unsigned n) |
307 | { | 322 | { |
308 | int i; | 323 | int i; |
309 | char *ss = s; | 324 | char *ss = s; |
310 | 325 | ||
311 | for (i=0;i<n;i++) ss[i] = c; | 326 | for (i = 0; i < n; i++) ss[i] = c; |
312 | return s; | 327 | return s; |
313 | } | 328 | } |
314 | 329 | ||
315 | static void* memcpy(void* dest, const void* src, unsigned n) | 330 | static void *memcpy(void *dest, const void *src, unsigned n) |
316 | { | 331 | { |
317 | int i; | 332 | int i; |
318 | const char *s = src; | 333 | const char *s = src; |
319 | char *d = dest; | 334 | char *d = dest; |
320 | 335 | ||
321 | for (i=0;i<n;i++) d[i] = s[i]; | 336 | for (i = 0; i < n; i++) d[i] = s[i]; |
322 | return dest; | 337 | return dest; |
323 | } | 338 | } |
324 | 339 | ||
@@ -341,9 +356,9 @@ static void flush_window(void) | |||
341 | /* With my window equal to my output buffer | 356 | /* With my window equal to my output buffer |
342 | * I only need to compute the crc here. | 357 | * I only need to compute the crc here. |
343 | */ | 358 | */ |
344 | ulg c = crc; /* temporary variable */ | 359 | unsigned long c = crc; /* temporary variable */ |
345 | unsigned n; | 360 | unsigned n; |
346 | uch *in, ch; | 361 | unsigned char *in, ch; |
347 | 362 | ||
348 | in = window; | 363 | in = window; |
349 | for (n = 0; n < outcnt; n++) { | 364 | for (n = 0; n < outcnt; n++) { |
@@ -351,7 +366,7 @@ static void flush_window(void) | |||
351 | c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8); | 366 | c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8); |
352 | } | 367 | } |
353 | crc = c; | 368 | crc = c; |
354 | bytes_out += (ulg)outcnt; | 369 | bytes_out += (unsigned long)outcnt; |
355 | outcnt = 0; | 370 | outcnt = 0; |
356 | } | 371 | } |
357 | 372 | ||
@@ -365,9 +380,59 @@ static void error(char *x) | |||
365 | asm("hlt"); | 380 | asm("hlt"); |
366 | } | 381 | } |
367 | 382 | ||
383 | static void parse_elf(void *output) | ||
384 | { | ||
385 | #ifdef CONFIG_X86_64 | ||
386 | Elf64_Ehdr ehdr; | ||
387 | Elf64_Phdr *phdrs, *phdr; | ||
388 | #else | ||
389 | Elf32_Ehdr ehdr; | ||
390 | Elf32_Phdr *phdrs, *phdr; | ||
391 | #endif | ||
392 | void *dest; | ||
393 | int i; | ||
394 | |||
395 | memcpy(&ehdr, output, sizeof(ehdr)); | ||
396 | if (ehdr.e_ident[EI_MAG0] != ELFMAG0 || | ||
397 | ehdr.e_ident[EI_MAG1] != ELFMAG1 || | ||
398 | ehdr.e_ident[EI_MAG2] != ELFMAG2 || | ||
399 | ehdr.e_ident[EI_MAG3] != ELFMAG3) { | ||
400 | error("Kernel is not a valid ELF file"); | ||
401 | return; | ||
402 | } | ||
403 | |||
404 | putstr("Parsing ELF... "); | ||
405 | |||
406 | phdrs = malloc(sizeof(*phdrs) * ehdr.e_phnum); | ||
407 | if (!phdrs) | ||
408 | error("Failed to allocate space for phdrs"); | ||
409 | |||
410 | memcpy(phdrs, output + ehdr.e_phoff, sizeof(*phdrs) * ehdr.e_phnum); | ||
411 | |||
412 | for (i = 0; i < ehdr.e_phnum; i++) { | ||
413 | phdr = &phdrs[i]; | ||
414 | |||
415 | switch (phdr->p_type) { | ||
416 | case PT_LOAD: | ||
417 | #ifdef CONFIG_RELOCATABLE | ||
418 | dest = output; | ||
419 | dest += (phdr->p_paddr - LOAD_PHYSICAL_ADDR); | ||
420 | #else | ||
421 | dest = (void *)(phdr->p_paddr); | ||
422 | #endif | ||
423 | memcpy(dest, | ||
424 | output + phdr->p_offset, | ||
425 | phdr->p_filesz); | ||
426 | break; | ||
427 | default: /* Ignore other PT_* */ break; | ||
428 | } | ||
429 | } | ||
430 | } | ||
431 | |||
368 | asmlinkage void decompress_kernel(void *rmode, memptr heap, | 432 | asmlinkage void decompress_kernel(void *rmode, memptr heap, |
369 | uch *input_data, unsigned long input_len, | 433 | unsigned char *input_data, |
370 | uch *output) | 434 | unsigned long input_len, |
435 | unsigned char *output) | ||
371 | { | 436 | { |
372 | real_mode = rmode; | 437 | real_mode = rmode; |
373 | 438 | ||
@@ -390,12 +455,12 @@ asmlinkage void decompress_kernel(void *rmode, memptr heap, | |||
390 | inptr = 0; | 455 | inptr = 0; |
391 | 456 | ||
392 | #ifdef CONFIG_X86_64 | 457 | #ifdef CONFIG_X86_64 |
393 | if ((ulg)output & (__KERNEL_ALIGN - 1)) | 458 | if ((unsigned long)output & (__KERNEL_ALIGN - 1)) |
394 | error("Destination address not 2M aligned"); | 459 | error("Destination address not 2M aligned"); |
395 | if ((ulg)output >= 0xffffffffffUL) | 460 | if ((unsigned long)output >= 0xffffffffffUL) |
396 | error("Destination address too large"); | 461 | error("Destination address too large"); |
397 | #else | 462 | #else |
398 | if ((u32)output & (CONFIG_PHYSICAL_ALIGN -1)) | 463 | if ((u32)output & (CONFIG_PHYSICAL_ALIGN - 1)) |
399 | error("Destination address not CONFIG_PHYSICAL_ALIGN aligned"); | 464 | error("Destination address not CONFIG_PHYSICAL_ALIGN aligned"); |
400 | if (heap > ((-__PAGE_OFFSET-(512<<20)-1) & 0x7fffffff)) | 465 | if (heap > ((-__PAGE_OFFSET-(512<<20)-1) & 0x7fffffff)) |
401 | error("Destination address too large"); | 466 | error("Destination address too large"); |
@@ -408,6 +473,7 @@ asmlinkage void decompress_kernel(void *rmode, memptr heap, | |||
408 | makecrc(); | 473 | makecrc(); |
409 | putstr("\nDecompressing Linux... "); | 474 | putstr("\nDecompressing Linux... "); |
410 | gunzip(); | 475 | gunzip(); |
476 | parse_elf(output); | ||
411 | putstr("done.\nBooting the kernel.\n"); | 477 | putstr("done.\nBooting the kernel.\n"); |
412 | return; | 478 | return; |
413 | } | 479 | } |