1778cb929SIan Campbell /* 2778cb929SIan Campbell * misc.c 3778cb929SIan Campbell * 4778cb929SIan Campbell * This is a collection of several routines from gzip-1.0.3 5778cb929SIan Campbell * adapted for Linux. 6778cb929SIan Campbell * 7778cb929SIan Campbell * malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994 8778cb929SIan Campbell * puts by Nick Holloway 1993, better puts by Martin Mares 1995 9778cb929SIan Campbell * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996 10778cb929SIan Campbell */ 11778cb929SIan Campbell 128fee13a4SYinghai Lu #include "misc.h" 13778cb929SIan Campbell 14778cb929SIan Campbell /* WARNING!! 15778cb929SIan Campbell * This code is compiled with -fPIC and it is relocated dynamically 16778cb929SIan Campbell * at run time, but no relocation processing is performed. 17778cb929SIan Campbell * This means that it is not safe to place pointers in static structures. 18778cb929SIan Campbell */ 19778cb929SIan Campbell 20778cb929SIan Campbell /* 21778cb929SIan Campbell * Getting to provable safe in place decompression is hard. 22778cb929SIan Campbell * Worst case behaviours need to be analyzed. 23778cb929SIan Campbell * Background information: 24778cb929SIan Campbell * 25778cb929SIan Campbell * The file layout is: 26778cb929SIan Campbell * magic[2] 27778cb929SIan Campbell * method[1] 28778cb929SIan Campbell * flags[1] 29778cb929SIan Campbell * timestamp[4] 30778cb929SIan Campbell * extraflags[1] 31778cb929SIan Campbell * os[1] 32778cb929SIan Campbell * compressed data blocks[N] 33778cb929SIan Campbell * crc[4] orig_len[4] 34778cb929SIan Campbell * 35778cb929SIan Campbell * resulting in 18 bytes of non compressed data overhead. 36778cb929SIan Campbell * 37778cb929SIan Campbell * Files divided into blocks 38778cb929SIan Campbell * 1 bit (last block flag) 39778cb929SIan Campbell * 2 bits (block type) 40778cb929SIan Campbell * 411180e01dSIngo Molnar * 1 block occurs every 32K -1 bytes or when there 50% compression 421180e01dSIngo Molnar * has been achieved. The smallest block type encoding is always used. 43778cb929SIan Campbell * 44778cb929SIan Campbell * stored: 45778cb929SIan Campbell * 32 bits length in bytes. 46778cb929SIan Campbell * 47778cb929SIan Campbell * fixed: 48778cb929SIan Campbell * magic fixed tree. 49778cb929SIan Campbell * symbols. 50778cb929SIan Campbell * 51778cb929SIan Campbell * dynamic: 52778cb929SIan Campbell * dynamic tree encoding. 53778cb929SIan Campbell * symbols. 54778cb929SIan Campbell * 55778cb929SIan Campbell * 56778cb929SIan Campbell * The buffer for decompression in place is the length of the 57778cb929SIan Campbell * uncompressed data, plus a small amount extra to keep the algorithm safe. 58778cb929SIan Campbell * The compressed data is placed at the end of the buffer. The output 59778cb929SIan Campbell * pointer is placed at the start of the buffer and the input pointer 60778cb929SIan Campbell * is placed where the compressed data starts. Problems will occur 61778cb929SIan Campbell * when the output pointer overruns the input pointer. 62778cb929SIan Campbell * 63778cb929SIan Campbell * The output pointer can only overrun the input pointer if the input 64778cb929SIan Campbell * pointer is moving faster than the output pointer. A condition only 65778cb929SIan Campbell * triggered by data whose compressed form is larger than the uncompressed 66778cb929SIan Campbell * form. 67778cb929SIan Campbell * 68778cb929SIan Campbell * The worst case at the block level is a growth of the compressed data 69778cb929SIan Campbell * of 5 bytes per 32767 bytes. 70778cb929SIan Campbell * 71778cb929SIan Campbell * The worst case internal to a compressed block is very hard to figure. 72778cb929SIan Campbell * The worst case can at least be boundined by having one bit that represents 73778cb929SIan Campbell * 32764 bytes and then all of the rest of the bytes representing the very 74778cb929SIan Campbell * very last byte. 75778cb929SIan Campbell * 76778cb929SIan Campbell * All of which is enough to compute an amount of extra data that is required 77778cb929SIan Campbell * to be safe. To avoid problems at the block level allocating 5 extra bytes 781180e01dSIngo Molnar * per 32767 bytes of data is sufficient. To avoind problems internal to a 791180e01dSIngo Molnar * block adding an extra 32767 bytes (the worst case uncompressed block size) 801180e01dSIngo Molnar * is sufficient, to ensure that in the worst case the decompressed data for 81778cb929SIan Campbell * block will stop the byte before the compressed data for a block begins. 82778cb929SIan Campbell * To avoid problems with the compressed data's meta information an extra 18 83778cb929SIan Campbell * bytes are needed. Leading to the formula: 84778cb929SIan Campbell * 85778cb929SIan Campbell * extra_bytes = (uncompressed_size >> 12) + 32768 + 18 + decompressor_size. 86778cb929SIan Campbell * 87778cb929SIan Campbell * Adding 8 bytes per 32K is a bit excessive but much easier to calculate. 88778cb929SIan Campbell * Adding 32768 instead of 32767 just makes for round numbers. 89778cb929SIan Campbell * Adding the decompressor_size is necessary as it musht live after all 90778cb929SIan Campbell * of the data as well. Last I measured the decompressor is about 14K. 91778cb929SIan Campbell * 10K of actual data and 4K of bss. 92778cb929SIan Campbell * 93778cb929SIan Campbell */ 94778cb929SIan Campbell 95778cb929SIan Campbell /* 96778cb929SIan Campbell * gzip declarations 97778cb929SIan Campbell */ 98778cb929SIan Campbell #define STATIC static 99778cb929SIan Campbell 100778cb929SIan Campbell #undef memset 101778cb929SIan Campbell #undef memcpy 102778cb929SIan Campbell #define memzero(s, n) memset((s), 0, (n)) 103778cb929SIan Campbell 104778cb929SIan Campbell 105778cb929SIan Campbell static void error(char *m); 106778cb929SIan Campbell 107778cb929SIan Campbell /* 108778cb929SIan Campbell * This is set up by the setup-routine at boot-time 109778cb929SIan Campbell */ 1108fee13a4SYinghai Lu struct boot_params *real_mode; /* Pointer to real-mode data */ 111778cb929SIan Campbell 1126175ddf0SBrian Gerst void *memset(void *s, int c, size_t n); 1136175ddf0SBrian Gerst void *memcpy(void *dest, const void *src, size_t n); 114778cb929SIan Campbell 115778cb929SIan Campbell #ifdef CONFIG_X86_64 116778cb929SIan Campbell #define memptr long 117778cb929SIan Campbell #else 118778cb929SIan Campbell #define memptr unsigned 119778cb929SIan Campbell #endif 120778cb929SIan Campbell 121778cb929SIan Campbell static memptr free_mem_ptr; 122778cb929SIan Campbell static memptr free_mem_end_ptr; 123778cb929SIan Campbell 12403056c88SAlexander van Heukelum static char *vidmem; 125778cb929SIan Campbell static int vidport; 126778cb929SIan Campbell static int lines, cols; 127778cb929SIan Campbell 128ae03c499SAlain Knaff #ifdef CONFIG_KERNEL_GZIP 129ae03c499SAlain Knaff #include "../../../../lib/decompress_inflate.c" 130ae03c499SAlain Knaff #endif 131ae03c499SAlain Knaff 132ae03c499SAlain Knaff #ifdef CONFIG_KERNEL_BZIP2 133ae03c499SAlain Knaff #include "../../../../lib/decompress_bunzip2.c" 134ae03c499SAlain Knaff #endif 135ae03c499SAlain Knaff 136ae03c499SAlain Knaff #ifdef CONFIG_KERNEL_LZMA 137ae03c499SAlain Knaff #include "../../../../lib/decompress_unlzma.c" 138ae03c499SAlain Knaff #endif 139778cb929SIan Campbell 14030314804SLasse Collin #ifdef CONFIG_KERNEL_XZ 14130314804SLasse Collin #include "../../../../lib/decompress_unxz.c" 14230314804SLasse Collin #endif 14330314804SLasse Collin 14413510997SAlbin Tonnerre #ifdef CONFIG_KERNEL_LZO 14513510997SAlbin Tonnerre #include "../../../../lib/decompress_unlzo.c" 14613510997SAlbin Tonnerre #endif 14713510997SAlbin Tonnerre 148f9b493acSKyungsik Lee #ifdef CONFIG_KERNEL_LZ4 149f9b493acSKyungsik Lee #include "../../../../lib/decompress_unlz4.c" 150f9b493acSKyungsik Lee #endif 151f9b493acSKyungsik Lee 152778cb929SIan Campbell static void scroll(void) 153778cb929SIan Campbell { 154778cb929SIan Campbell int i; 155778cb929SIan Campbell 156778cb929SIan Campbell memcpy(vidmem, vidmem + cols * 2, (lines - 1) * cols * 2); 157778cb929SIan Campbell for (i = (lines - 1) * cols * 2; i < lines * cols * 2; i += 2) 158778cb929SIan Campbell vidmem[i] = ' '; 159778cb929SIan Campbell } 160778cb929SIan Campbell 1618fee13a4SYinghai Lu #define XMTRDY 0x20 1628fee13a4SYinghai Lu 1638fee13a4SYinghai Lu #define TXR 0 /* Transmit register (WRITE) */ 1648fee13a4SYinghai Lu #define LSR 5 /* Line Status */ 1658fee13a4SYinghai Lu static void serial_putchar(int ch) 1668fee13a4SYinghai Lu { 1678fee13a4SYinghai Lu unsigned timeout = 0xffff; 1688fee13a4SYinghai Lu 1698fee13a4SYinghai Lu while ((inb(early_serial_base + LSR) & XMTRDY) == 0 && --timeout) 1708fee13a4SYinghai Lu cpu_relax(); 1718fee13a4SYinghai Lu 1728fee13a4SYinghai Lu outb(ch, early_serial_base + TXR); 1738fee13a4SYinghai Lu } 1748fee13a4SYinghai Lu 1757aac3015SJoe Millenbach void __putstr(const char *s) 176778cb929SIan Campbell { 177778cb929SIan Campbell int x, y, pos; 178778cb929SIan Campbell char c; 179778cb929SIan Campbell 1808fee13a4SYinghai Lu if (early_serial_base) { 1818fee13a4SYinghai Lu const char *str = s; 1828fee13a4SYinghai Lu while (*str) { 1838fee13a4SYinghai Lu if (*str == '\n') 1848fee13a4SYinghai Lu serial_putchar('\r'); 1858fee13a4SYinghai Lu serial_putchar(*str++); 1868fee13a4SYinghai Lu } 1878fee13a4SYinghai Lu } 1886bcb13b3SBen Collins 18923968f71SKristian Høgsberg if (real_mode->screen_info.orig_video_mode == 0 && 19023968f71SKristian Høgsberg lines == 0 && cols == 0) 191778cb929SIan Campbell return; 192778cb929SIan Campbell 19323968f71SKristian Høgsberg x = real_mode->screen_info.orig_x; 19423968f71SKristian Høgsberg y = real_mode->screen_info.orig_y; 195778cb929SIan Campbell 196778cb929SIan Campbell while ((c = *s++) != '\0') { 197778cb929SIan Campbell if (c == '\n') { 198778cb929SIan Campbell x = 0; 199778cb929SIan Campbell if (++y >= lines) { 200778cb929SIan Campbell scroll(); 201778cb929SIan Campbell y--; 202778cb929SIan Campbell } 203778cb929SIan Campbell } else { 204778cb929SIan Campbell vidmem[(x + cols * y) * 2] = c; 205778cb929SIan Campbell if (++x >= cols) { 206778cb929SIan Campbell x = 0; 207778cb929SIan Campbell if (++y >= lines) { 208778cb929SIan Campbell scroll(); 209778cb929SIan Campbell y--; 210778cb929SIan Campbell } 211778cb929SIan Campbell } 212778cb929SIan Campbell } 213778cb929SIan Campbell } 214778cb929SIan Campbell 21523968f71SKristian Høgsberg real_mode->screen_info.orig_x = x; 21623968f71SKristian Høgsberg real_mode->screen_info.orig_y = y; 217778cb929SIan Campbell 218778cb929SIan Campbell pos = (x + cols * y) * 2; /* Update cursor position */ 219778cb929SIan Campbell outb(14, vidport); 220778cb929SIan Campbell outb(0xff & (pos >> 9), vidport+1); 221778cb929SIan Campbell outb(15, vidport); 222778cb929SIan Campbell outb(0xff & (pos >> 1), vidport+1); 223778cb929SIan Campbell } 224778cb929SIan Campbell 2256175ddf0SBrian Gerst void *memset(void *s, int c, size_t n) 226778cb929SIan Campbell { 227778cb929SIan Campbell int i; 228778cb929SIan Campbell char *ss = s; 229778cb929SIan Campbell 230020878acSPaolo Ciarrocchi for (i = 0; i < n; i++) 231020878acSPaolo Ciarrocchi ss[i] = c; 232778cb929SIan Campbell return s; 233778cb929SIan Campbell } 23468f4d5a0SZhao Yakui #ifdef CONFIG_X86_32 2356175ddf0SBrian Gerst void *memcpy(void *dest, const void *src, size_t n) 236778cb929SIan Campbell { 23768f4d5a0SZhao Yakui int d0, d1, d2; 23868f4d5a0SZhao Yakui asm volatile( 23968f4d5a0SZhao Yakui "rep ; movsl\n\t" 24068f4d5a0SZhao Yakui "movl %4,%%ecx\n\t" 24168f4d5a0SZhao Yakui "rep ; movsb\n\t" 24268f4d5a0SZhao Yakui : "=&c" (d0), "=&D" (d1), "=&S" (d2) 24368f4d5a0SZhao Yakui : "0" (n >> 2), "g" (n & 3), "1" (dest), "2" (src) 24468f4d5a0SZhao Yakui : "memory"); 245778cb929SIan Campbell 246778cb929SIan Campbell return dest; 247778cb929SIan Campbell } 24868f4d5a0SZhao Yakui #else 24968f4d5a0SZhao Yakui void *memcpy(void *dest, const void *src, size_t n) 25068f4d5a0SZhao Yakui { 25168f4d5a0SZhao Yakui long d0, d1, d2; 25268f4d5a0SZhao Yakui asm volatile( 25368f4d5a0SZhao Yakui "rep ; movsq\n\t" 25468f4d5a0SZhao Yakui "movq %4,%%rcx\n\t" 25568f4d5a0SZhao Yakui "rep ; movsb\n\t" 25668f4d5a0SZhao Yakui : "=&c" (d0), "=&D" (d1), "=&S" (d2) 25768f4d5a0SZhao Yakui : "0" (n >> 3), "g" (n & 7), "1" (dest), "2" (src) 25868f4d5a0SZhao Yakui : "memory"); 259778cb929SIan Campbell 26068f4d5a0SZhao Yakui return dest; 26168f4d5a0SZhao Yakui } 26268f4d5a0SZhao Yakui #endif 263778cb929SIan Campbell 264778cb929SIan Campbell static void error(char *x) 265778cb929SIan Campbell { 266cb454fe1SJoe Millenbach error_putstr("\n\n"); 267cb454fe1SJoe Millenbach error_putstr(x); 268cb454fe1SJoe Millenbach error_putstr("\n\n -- System halted"); 269778cb929SIan Campbell 270778cb929SIan Campbell while (1) 271778cb929SIan Campbell asm("hlt"); 272778cb929SIan Campbell } 273778cb929SIan Campbell 274*a0215061SKees Cook #if CONFIG_X86_NEED_RELOCS 275*a0215061SKees Cook static void handle_relocations(void *output, unsigned long output_len) 276*a0215061SKees Cook { 277*a0215061SKees Cook int *reloc; 278*a0215061SKees Cook unsigned long delta, map, ptr; 279*a0215061SKees Cook unsigned long min_addr = (unsigned long)output; 280*a0215061SKees Cook unsigned long max_addr = min_addr + output_len; 281*a0215061SKees Cook 282*a0215061SKees Cook /* 283*a0215061SKees Cook * Calculate the delta between where vmlinux was linked to load 284*a0215061SKees Cook * and where it was actually loaded. 285*a0215061SKees Cook */ 286*a0215061SKees Cook delta = min_addr - LOAD_PHYSICAL_ADDR; 287*a0215061SKees Cook if (!delta) { 288*a0215061SKees Cook debug_putstr("No relocation needed... "); 289*a0215061SKees Cook return; 290*a0215061SKees Cook } 291*a0215061SKees Cook debug_putstr("Performing relocations... "); 292*a0215061SKees Cook 293*a0215061SKees Cook /* 294*a0215061SKees Cook * The kernel contains a table of relocation addresses. Those 295*a0215061SKees Cook * addresses have the final load address of the kernel in virtual 296*a0215061SKees Cook * memory. We are currently working in the self map. So we need to 297*a0215061SKees Cook * create an adjustment for kernel memory addresses to the self map. 298*a0215061SKees Cook * This will involve subtracting out the base address of the kernel. 299*a0215061SKees Cook */ 300*a0215061SKees Cook map = delta - __START_KERNEL_map; 301*a0215061SKees Cook 302*a0215061SKees Cook /* 303*a0215061SKees Cook * Process relocations: 32 bit relocations first then 64 bit after. 304*a0215061SKees Cook * Two sets of binary relocations are added to the end of the kernel 305*a0215061SKees Cook * before compression. Each relocation table entry is the kernel 306*a0215061SKees Cook * address of the location which needs to be updated stored as a 307*a0215061SKees Cook * 32-bit value which is sign extended to 64 bits. 308*a0215061SKees Cook * 309*a0215061SKees Cook * Format is: 310*a0215061SKees Cook * 311*a0215061SKees Cook * kernel bits... 312*a0215061SKees Cook * 0 - zero terminator for 64 bit relocations 313*a0215061SKees Cook * 64 bit relocation repeated 314*a0215061SKees Cook * 0 - zero terminator for 32 bit relocations 315*a0215061SKees Cook * 32 bit relocation repeated 316*a0215061SKees Cook * 317*a0215061SKees Cook * So we work backwards from the end of the decompressed image. 318*a0215061SKees Cook */ 319*a0215061SKees Cook for (reloc = output + output_len - sizeof(*reloc); *reloc; reloc--) { 320*a0215061SKees Cook int extended = *reloc; 321*a0215061SKees Cook extended += map; 322*a0215061SKees Cook 323*a0215061SKees Cook ptr = (unsigned long)extended; 324*a0215061SKees Cook if (ptr < min_addr || ptr > max_addr) 325*a0215061SKees Cook error("32-bit relocation outside of kernel!\n"); 326*a0215061SKees Cook 327*a0215061SKees Cook *(uint32_t *)ptr += delta; 328*a0215061SKees Cook } 329*a0215061SKees Cook #ifdef CONFIG_X86_64 330*a0215061SKees Cook for (reloc--; *reloc; reloc--) { 331*a0215061SKees Cook long extended = *reloc; 332*a0215061SKees Cook extended += map; 333*a0215061SKees Cook 334*a0215061SKees Cook ptr = (unsigned long)extended; 335*a0215061SKees Cook if (ptr < min_addr || ptr > max_addr) 336*a0215061SKees Cook error("64-bit relocation outside of kernel!\n"); 337*a0215061SKees Cook 338*a0215061SKees Cook *(uint64_t *)ptr += delta; 339*a0215061SKees Cook } 340*a0215061SKees Cook #endif 341*a0215061SKees Cook } 342*a0215061SKees Cook #else 343*a0215061SKees Cook static inline void handle_relocations(void *output, unsigned long output_len) 344*a0215061SKees Cook { } 345*a0215061SKees Cook #endif 346*a0215061SKees Cook 347099e1377SIan Campbell static void parse_elf(void *output) 348099e1377SIan Campbell { 349099e1377SIan Campbell #ifdef CONFIG_X86_64 350099e1377SIan Campbell Elf64_Ehdr ehdr; 351099e1377SIan Campbell Elf64_Phdr *phdrs, *phdr; 352099e1377SIan Campbell #else 353099e1377SIan Campbell Elf32_Ehdr ehdr; 354099e1377SIan Campbell Elf32_Phdr *phdrs, *phdr; 355099e1377SIan Campbell #endif 356099e1377SIan Campbell void *dest; 357099e1377SIan Campbell int i; 358099e1377SIan Campbell 359099e1377SIan Campbell memcpy(&ehdr, output, sizeof(ehdr)); 360099e1377SIan Campbell if (ehdr.e_ident[EI_MAG0] != ELFMAG0 || 361099e1377SIan Campbell ehdr.e_ident[EI_MAG1] != ELFMAG1 || 362099e1377SIan Campbell ehdr.e_ident[EI_MAG2] != ELFMAG2 || 363fd77c7caSPaolo Ciarrocchi ehdr.e_ident[EI_MAG3] != ELFMAG3) { 364099e1377SIan Campbell error("Kernel is not a valid ELF file"); 365099e1377SIan Campbell return; 366099e1377SIan Campbell } 367099e1377SIan Campbell 368e605a425SJoe Millenbach debug_putstr("Parsing ELF... "); 369099e1377SIan Campbell 370099e1377SIan Campbell phdrs = malloc(sizeof(*phdrs) * ehdr.e_phnum); 371099e1377SIan Campbell if (!phdrs) 372099e1377SIan Campbell error("Failed to allocate space for phdrs"); 373099e1377SIan Campbell 374099e1377SIan Campbell memcpy(phdrs, output + ehdr.e_phoff, sizeof(*phdrs) * ehdr.e_phnum); 375099e1377SIan Campbell 376099e1377SIan Campbell for (i = 0; i < ehdr.e_phnum; i++) { 377099e1377SIan Campbell phdr = &phdrs[i]; 378099e1377SIan Campbell 379099e1377SIan Campbell switch (phdr->p_type) { 380099e1377SIan Campbell case PT_LOAD: 381099e1377SIan Campbell #ifdef CONFIG_RELOCATABLE 382099e1377SIan Campbell dest = output; 383099e1377SIan Campbell dest += (phdr->p_paddr - LOAD_PHYSICAL_ADDR); 384099e1377SIan Campbell #else 385099e1377SIan Campbell dest = (void *)(phdr->p_paddr); 386099e1377SIan Campbell #endif 387099e1377SIan Campbell memcpy(dest, 388099e1377SIan Campbell output + phdr->p_offset, 389099e1377SIan Campbell phdr->p_filesz); 390099e1377SIan Campbell break; 391099e1377SIan Campbell default: /* Ignore other PT_* */ break; 392099e1377SIan Campbell } 393099e1377SIan Campbell } 3945067cf53SJesper Juhl 3955067cf53SJesper Juhl free(phdrs); 396099e1377SIan Campbell } 397099e1377SIan Campbell 398778cb929SIan Campbell asmlinkage void decompress_kernel(void *rmode, memptr heap, 3991180e01dSIngo Molnar unsigned char *input_data, 4001180e01dSIngo Molnar unsigned long input_len, 401*a0215061SKees Cook unsigned char *output, 402*a0215061SKees Cook unsigned long output_len) 403778cb929SIan Campbell { 404778cb929SIan Campbell real_mode = rmode; 405778cb929SIan Campbell 4065dcd14ecSH. Peter Anvin sanitize_boot_params(real_mode); 4075dcd14ecSH. Peter Anvin 40823968f71SKristian Høgsberg if (real_mode->screen_info.orig_video_mode == 7) { 409778cb929SIan Campbell vidmem = (char *) 0xb0000; 410778cb929SIan Campbell vidport = 0x3b4; 411778cb929SIan Campbell } else { 412778cb929SIan Campbell vidmem = (char *) 0xb8000; 413778cb929SIan Campbell vidport = 0x3d4; 414778cb929SIan Campbell } 415778cb929SIan Campbell 41623968f71SKristian Høgsberg lines = real_mode->screen_info.orig_video_lines; 41723968f71SKristian Høgsberg cols = real_mode->screen_info.orig_video_cols; 418778cb929SIan Campbell 4198fee13a4SYinghai Lu console_init(); 420e605a425SJoe Millenbach debug_putstr("early console in decompress_kernel\n"); 4218fee13a4SYinghai Lu 422778cb929SIan Campbell free_mem_ptr = heap; /* Heap */ 4237c539764SAlexander van Heukelum free_mem_end_ptr = heap + BOOT_HEAP_SIZE; 424778cb929SIan Campbell 4257ed42a28SH. Peter Anvin if ((unsigned long)output & (MIN_KERNEL_ALIGN - 1)) 4267ed42a28SH. Peter Anvin error("Destination address inappropriately aligned"); 427778cb929SIan Campbell #ifdef CONFIG_X86_64 4287ed42a28SH. Peter Anvin if (heap > 0x3fffffffffffUL) 429778cb929SIan Campbell error("Destination address too large"); 430778cb929SIan Campbell #else 431147dd561SH. Peter Anvin if (heap > ((-__PAGE_OFFSET-(128<<20)-1) & 0x7fffffff)) 432778cb929SIan Campbell error("Destination address too large"); 433778cb929SIan Campbell #endif 4347ed42a28SH. Peter Anvin #ifndef CONFIG_RELOCATABLE 4357ed42a28SH. Peter Anvin if ((unsigned long)output != LOAD_PHYSICAL_ADDR) 4367ed42a28SH. Peter Anvin error("Wrong destination address"); 437778cb929SIan Campbell #endif 438778cb929SIan Campbell 439e605a425SJoe Millenbach debug_putstr("\nDecompressing Linux... "); 440ae03c499SAlain Knaff decompress(input_data, input_len, NULL, NULL, output, NULL, error); 441099e1377SIan Campbell parse_elf(output); 442*a0215061SKees Cook handle_relocations(output, output_len); 443e605a425SJoe Millenbach debug_putstr("done.\nBooting the kernel.\n"); 444778cb929SIan Campbell return; 445778cb929SIan Campbell } 446