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" 13820e8fecSVivek Goyal #include "../string.h" 14778cb929SIan Campbell 15778cb929SIan Campbell /* WARNING!! 16778cb929SIan Campbell * This code is compiled with -fPIC and it is relocated dynamically 17778cb929SIan Campbell * at run time, but no relocation processing is performed. 18778cb929SIan Campbell * This means that it is not safe to place pointers in static structures. 19778cb929SIan Campbell */ 20778cb929SIan Campbell 21778cb929SIan Campbell /* 22778cb929SIan Campbell * Getting to provable safe in place decompression is hard. 23778cb929SIan Campbell * Worst case behaviours need to be analyzed. 24778cb929SIan Campbell * Background information: 25778cb929SIan Campbell * 26778cb929SIan Campbell * The file layout is: 27778cb929SIan Campbell * magic[2] 28778cb929SIan Campbell * method[1] 29778cb929SIan Campbell * flags[1] 30778cb929SIan Campbell * timestamp[4] 31778cb929SIan Campbell * extraflags[1] 32778cb929SIan Campbell * os[1] 33778cb929SIan Campbell * compressed data blocks[N] 34778cb929SIan Campbell * crc[4] orig_len[4] 35778cb929SIan Campbell * 36778cb929SIan Campbell * resulting in 18 bytes of non compressed data overhead. 37778cb929SIan Campbell * 38778cb929SIan Campbell * Files divided into blocks 39778cb929SIan Campbell * 1 bit (last block flag) 40778cb929SIan Campbell * 2 bits (block type) 41778cb929SIan Campbell * 421180e01dSIngo Molnar * 1 block occurs every 32K -1 bytes or when there 50% compression 431180e01dSIngo Molnar * has been achieved. The smallest block type encoding is always used. 44778cb929SIan Campbell * 45778cb929SIan Campbell * stored: 46778cb929SIan Campbell * 32 bits length in bytes. 47778cb929SIan Campbell * 48778cb929SIan Campbell * fixed: 49778cb929SIan Campbell * magic fixed tree. 50778cb929SIan Campbell * symbols. 51778cb929SIan Campbell * 52778cb929SIan Campbell * dynamic: 53778cb929SIan Campbell * dynamic tree encoding. 54778cb929SIan Campbell * symbols. 55778cb929SIan Campbell * 56778cb929SIan Campbell * 57778cb929SIan Campbell * The buffer for decompression in place is the length of the 58778cb929SIan Campbell * uncompressed data, plus a small amount extra to keep the algorithm safe. 59778cb929SIan Campbell * The compressed data is placed at the end of the buffer. The output 60778cb929SIan Campbell * pointer is placed at the start of the buffer and the input pointer 61778cb929SIan Campbell * is placed where the compressed data starts. Problems will occur 62778cb929SIan Campbell * when the output pointer overruns the input pointer. 63778cb929SIan Campbell * 64778cb929SIan Campbell * The output pointer can only overrun the input pointer if the input 65778cb929SIan Campbell * pointer is moving faster than the output pointer. A condition only 66778cb929SIan Campbell * triggered by data whose compressed form is larger than the uncompressed 67778cb929SIan Campbell * form. 68778cb929SIan Campbell * 69778cb929SIan Campbell * The worst case at the block level is a growth of the compressed data 70778cb929SIan Campbell * of 5 bytes per 32767 bytes. 71778cb929SIan Campbell * 72778cb929SIan Campbell * The worst case internal to a compressed block is very hard to figure. 73778cb929SIan Campbell * The worst case can at least be boundined by having one bit that represents 74778cb929SIan Campbell * 32764 bytes and then all of the rest of the bytes representing the very 75778cb929SIan Campbell * very last byte. 76778cb929SIan Campbell * 77778cb929SIan Campbell * All of which is enough to compute an amount of extra data that is required 78778cb929SIan Campbell * to be safe. To avoid problems at the block level allocating 5 extra bytes 791180e01dSIngo Molnar * per 32767 bytes of data is sufficient. To avoind problems internal to a 801180e01dSIngo Molnar * block adding an extra 32767 bytes (the worst case uncompressed block size) 811180e01dSIngo Molnar * is sufficient, to ensure that in the worst case the decompressed data for 82778cb929SIan Campbell * block will stop the byte before the compressed data for a block begins. 83778cb929SIan Campbell * To avoid problems with the compressed data's meta information an extra 18 84778cb929SIan Campbell * bytes are needed. Leading to the formula: 85778cb929SIan Campbell * 86778cb929SIan Campbell * extra_bytes = (uncompressed_size >> 12) + 32768 + 18 + decompressor_size. 87778cb929SIan Campbell * 88778cb929SIan Campbell * Adding 8 bytes per 32K is a bit excessive but much easier to calculate. 89778cb929SIan Campbell * Adding 32768 instead of 32767 just makes for round numbers. 90778cb929SIan Campbell * Adding the decompressor_size is necessary as it musht live after all 91778cb929SIan Campbell * of the data as well. Last I measured the decompressor is about 14K. 92778cb929SIan Campbell * 10K of actual data and 4K of bss. 93778cb929SIan Campbell * 94778cb929SIan Campbell */ 95778cb929SIan Campbell 96778cb929SIan Campbell /* 97778cb929SIan Campbell * gzip declarations 98778cb929SIan Campbell */ 99778cb929SIan Campbell #define STATIC static 100778cb929SIan Campbell 101778cb929SIan Campbell #undef memcpy 10204999550SVivek Goyal 10304999550SVivek Goyal /* 10404999550SVivek Goyal * Use a normal definition of memset() from string.c. There are already 10504999550SVivek Goyal * included header files which expect a definition of memset() and by 10604999550SVivek Goyal * the time we define memset macro, it is too late. 10704999550SVivek Goyal */ 10804999550SVivek Goyal #undef memset 109778cb929SIan Campbell #define memzero(s, n) memset((s), 0, (n)) 110778cb929SIan Campbell 111778cb929SIan Campbell 112778cb929SIan Campbell static void error(char *m); 113778cb929SIan Campbell 114778cb929SIan Campbell /* 115778cb929SIan Campbell * This is set up by the setup-routine at boot-time 116778cb929SIan Campbell */ 1178fee13a4SYinghai Lu struct boot_params *real_mode; /* Pointer to real-mode data */ 118778cb929SIan Campbell 11982fa9637SKees Cook memptr free_mem_ptr; 12082fa9637SKees Cook memptr free_mem_end_ptr; 121778cb929SIan Campbell 12203056c88SAlexander van Heukelum static char *vidmem; 123778cb929SIan Campbell static int vidport; 124778cb929SIan Campbell static int lines, cols; 125778cb929SIan Campbell 126ae03c499SAlain Knaff #ifdef CONFIG_KERNEL_GZIP 127ae03c499SAlain Knaff #include "../../../../lib/decompress_inflate.c" 128ae03c499SAlain Knaff #endif 129ae03c499SAlain Knaff 130ae03c499SAlain Knaff #ifdef CONFIG_KERNEL_BZIP2 131ae03c499SAlain Knaff #include "../../../../lib/decompress_bunzip2.c" 132ae03c499SAlain Knaff #endif 133ae03c499SAlain Knaff 134ae03c499SAlain Knaff #ifdef CONFIG_KERNEL_LZMA 135ae03c499SAlain Knaff #include "../../../../lib/decompress_unlzma.c" 136ae03c499SAlain Knaff #endif 137778cb929SIan Campbell 13830314804SLasse Collin #ifdef CONFIG_KERNEL_XZ 13930314804SLasse Collin #include "../../../../lib/decompress_unxz.c" 14030314804SLasse Collin #endif 14130314804SLasse Collin 14213510997SAlbin Tonnerre #ifdef CONFIG_KERNEL_LZO 14313510997SAlbin Tonnerre #include "../../../../lib/decompress_unlzo.c" 14413510997SAlbin Tonnerre #endif 14513510997SAlbin Tonnerre 146f9b493acSKyungsik Lee #ifdef CONFIG_KERNEL_LZ4 147f9b493acSKyungsik Lee #include "../../../../lib/decompress_unlz4.c" 148f9b493acSKyungsik Lee #endif 149f9b493acSKyungsik Lee 150778cb929SIan Campbell static void scroll(void) 151778cb929SIan Campbell { 152778cb929SIan Campbell int i; 153778cb929SIan Campbell 154778cb929SIan Campbell memcpy(vidmem, vidmem + cols * 2, (lines - 1) * cols * 2); 155778cb929SIan Campbell for (i = (lines - 1) * cols * 2; i < lines * cols * 2; i += 2) 156778cb929SIan Campbell vidmem[i] = ' '; 157778cb929SIan Campbell } 158778cb929SIan Campbell 1598fee13a4SYinghai Lu #define XMTRDY 0x20 1608fee13a4SYinghai Lu 1618fee13a4SYinghai Lu #define TXR 0 /* Transmit register (WRITE) */ 1628fee13a4SYinghai Lu #define LSR 5 /* Line Status */ 1638fee13a4SYinghai Lu static void serial_putchar(int ch) 1648fee13a4SYinghai Lu { 1658fee13a4SYinghai Lu unsigned timeout = 0xffff; 1668fee13a4SYinghai Lu 1678fee13a4SYinghai Lu while ((inb(early_serial_base + LSR) & XMTRDY) == 0 && --timeout) 1688fee13a4SYinghai Lu cpu_relax(); 1698fee13a4SYinghai Lu 1708fee13a4SYinghai Lu outb(ch, early_serial_base + TXR); 1718fee13a4SYinghai Lu } 1728fee13a4SYinghai Lu 1737aac3015SJoe Millenbach void __putstr(const char *s) 174778cb929SIan Campbell { 175778cb929SIan Campbell int x, y, pos; 176778cb929SIan Campbell char c; 177778cb929SIan Campbell 1788fee13a4SYinghai Lu if (early_serial_base) { 1798fee13a4SYinghai Lu const char *str = s; 1808fee13a4SYinghai Lu while (*str) { 1818fee13a4SYinghai Lu if (*str == '\n') 1828fee13a4SYinghai Lu serial_putchar('\r'); 1838fee13a4SYinghai Lu serial_putchar(*str++); 1848fee13a4SYinghai Lu } 1858fee13a4SYinghai Lu } 1866bcb13b3SBen Collins 18723968f71SKristian Høgsberg if (real_mode->screen_info.orig_video_mode == 0 && 18823968f71SKristian Høgsberg lines == 0 && cols == 0) 189778cb929SIan Campbell return; 190778cb929SIan Campbell 19123968f71SKristian Høgsberg x = real_mode->screen_info.orig_x; 19223968f71SKristian Høgsberg y = real_mode->screen_info.orig_y; 193778cb929SIan Campbell 194778cb929SIan Campbell while ((c = *s++) != '\0') { 195778cb929SIan Campbell if (c == '\n') { 196778cb929SIan Campbell x = 0; 197778cb929SIan Campbell if (++y >= lines) { 198778cb929SIan Campbell scroll(); 199778cb929SIan Campbell y--; 200778cb929SIan Campbell } 201778cb929SIan Campbell } else { 202778cb929SIan Campbell vidmem[(x + cols * y) * 2] = c; 203778cb929SIan Campbell if (++x >= cols) { 204778cb929SIan Campbell x = 0; 205778cb929SIan Campbell if (++y >= lines) { 206778cb929SIan Campbell scroll(); 207778cb929SIan Campbell y--; 208778cb929SIan Campbell } 209778cb929SIan Campbell } 210778cb929SIan Campbell } 211778cb929SIan Campbell } 212778cb929SIan Campbell 21323968f71SKristian Høgsberg real_mode->screen_info.orig_x = x; 21423968f71SKristian Høgsberg real_mode->screen_info.orig_y = y; 215778cb929SIan Campbell 216778cb929SIan Campbell pos = (x + cols * y) * 2; /* Update cursor position */ 217778cb929SIan Campbell outb(14, vidport); 218778cb929SIan Campbell outb(0xff & (pos >> 9), vidport+1); 219778cb929SIan Campbell outb(15, vidport); 220778cb929SIan Campbell outb(0xff & (pos >> 1), vidport+1); 221778cb929SIan Campbell } 222778cb929SIan Campbell 223778cb929SIan Campbell static void error(char *x) 224778cb929SIan Campbell { 225cb454fe1SJoe Millenbach error_putstr("\n\n"); 226cb454fe1SJoe Millenbach error_putstr(x); 227cb454fe1SJoe Millenbach error_putstr("\n\n -- System halted"); 228778cb929SIan Campbell 229778cb929SIan Campbell while (1) 230778cb929SIan Campbell asm("hlt"); 231778cb929SIan Campbell } 232778cb929SIan Campbell 233a0215061SKees Cook #if CONFIG_X86_NEED_RELOCS 234a0215061SKees Cook static void handle_relocations(void *output, unsigned long output_len) 235a0215061SKees Cook { 236a0215061SKees Cook int *reloc; 237a0215061SKees Cook unsigned long delta, map, ptr; 238a0215061SKees Cook unsigned long min_addr = (unsigned long)output; 239a0215061SKees Cook unsigned long max_addr = min_addr + output_len; 240a0215061SKees Cook 241a0215061SKees Cook /* 242a0215061SKees Cook * Calculate the delta between where vmlinux was linked to load 243a0215061SKees Cook * and where it was actually loaded. 244a0215061SKees Cook */ 245a0215061SKees Cook delta = min_addr - LOAD_PHYSICAL_ADDR; 246a0215061SKees Cook if (!delta) { 247a0215061SKees Cook debug_putstr("No relocation needed... "); 248a0215061SKees Cook return; 249a0215061SKees Cook } 250a0215061SKees Cook debug_putstr("Performing relocations... "); 251a0215061SKees Cook 252a0215061SKees Cook /* 253a0215061SKees Cook * The kernel contains a table of relocation addresses. Those 254a0215061SKees Cook * addresses have the final load address of the kernel in virtual 255a0215061SKees Cook * memory. We are currently working in the self map. So we need to 256a0215061SKees Cook * create an adjustment for kernel memory addresses to the self map. 257a0215061SKees Cook * This will involve subtracting out the base address of the kernel. 258a0215061SKees Cook */ 259a0215061SKees Cook map = delta - __START_KERNEL_map; 260a0215061SKees Cook 261a0215061SKees Cook /* 262a0215061SKees Cook * Process relocations: 32 bit relocations first then 64 bit after. 2636d24c5f7SJan Beulich * Three sets of binary relocations are added to the end of the kernel 264a0215061SKees Cook * before compression. Each relocation table entry is the kernel 265a0215061SKees Cook * address of the location which needs to be updated stored as a 266a0215061SKees Cook * 32-bit value which is sign extended to 64 bits. 267a0215061SKees Cook * 268a0215061SKees Cook * Format is: 269a0215061SKees Cook * 270a0215061SKees Cook * kernel bits... 271a0215061SKees Cook * 0 - zero terminator for 64 bit relocations 272a0215061SKees Cook * 64 bit relocation repeated 2736d24c5f7SJan Beulich * 0 - zero terminator for inverse 32 bit relocations 2746d24c5f7SJan Beulich * 32 bit inverse relocation repeated 275a0215061SKees Cook * 0 - zero terminator for 32 bit relocations 276a0215061SKees Cook * 32 bit relocation repeated 277a0215061SKees Cook * 278a0215061SKees Cook * So we work backwards from the end of the decompressed image. 279a0215061SKees Cook */ 280a0215061SKees Cook for (reloc = output + output_len - sizeof(*reloc); *reloc; reloc--) { 281a0215061SKees Cook int extended = *reloc; 282a0215061SKees Cook extended += map; 283a0215061SKees Cook 284a0215061SKees Cook ptr = (unsigned long)extended; 285a0215061SKees Cook if (ptr < min_addr || ptr > max_addr) 286a0215061SKees Cook error("32-bit relocation outside of kernel!\n"); 287a0215061SKees Cook 288a0215061SKees Cook *(uint32_t *)ptr += delta; 289a0215061SKees Cook } 290a0215061SKees Cook #ifdef CONFIG_X86_64 2916d24c5f7SJan Beulich while (*--reloc) { 2926d24c5f7SJan Beulich long extended = *reloc; 2936d24c5f7SJan Beulich extended += map; 2946d24c5f7SJan Beulich 2956d24c5f7SJan Beulich ptr = (unsigned long)extended; 2966d24c5f7SJan Beulich if (ptr < min_addr || ptr > max_addr) 2976d24c5f7SJan Beulich error("inverse 32-bit relocation outside of kernel!\n"); 2986d24c5f7SJan Beulich 2996d24c5f7SJan Beulich *(int32_t *)ptr -= delta; 3006d24c5f7SJan Beulich } 301a0215061SKees Cook for (reloc--; *reloc; reloc--) { 302a0215061SKees Cook long extended = *reloc; 303a0215061SKees Cook extended += map; 304a0215061SKees Cook 305a0215061SKees Cook ptr = (unsigned long)extended; 306a0215061SKees Cook if (ptr < min_addr || ptr > max_addr) 307a0215061SKees Cook error("64-bit relocation outside of kernel!\n"); 308a0215061SKees Cook 309a0215061SKees Cook *(uint64_t *)ptr += delta; 310a0215061SKees Cook } 311a0215061SKees Cook #endif 312a0215061SKees Cook } 313a0215061SKees Cook #else 314a0215061SKees Cook static inline void handle_relocations(void *output, unsigned long output_len) 315a0215061SKees Cook { } 316a0215061SKees Cook #endif 317a0215061SKees Cook 318099e1377SIan Campbell static void parse_elf(void *output) 319099e1377SIan Campbell { 320099e1377SIan Campbell #ifdef CONFIG_X86_64 321099e1377SIan Campbell Elf64_Ehdr ehdr; 322099e1377SIan Campbell Elf64_Phdr *phdrs, *phdr; 323099e1377SIan Campbell #else 324099e1377SIan Campbell Elf32_Ehdr ehdr; 325099e1377SIan Campbell Elf32_Phdr *phdrs, *phdr; 326099e1377SIan Campbell #endif 327099e1377SIan Campbell void *dest; 328099e1377SIan Campbell int i; 329099e1377SIan Campbell 330099e1377SIan Campbell memcpy(&ehdr, output, sizeof(ehdr)); 331099e1377SIan Campbell if (ehdr.e_ident[EI_MAG0] != ELFMAG0 || 332099e1377SIan Campbell ehdr.e_ident[EI_MAG1] != ELFMAG1 || 333099e1377SIan Campbell ehdr.e_ident[EI_MAG2] != ELFMAG2 || 334fd77c7caSPaolo Ciarrocchi ehdr.e_ident[EI_MAG3] != ELFMAG3) { 335099e1377SIan Campbell error("Kernel is not a valid ELF file"); 336099e1377SIan Campbell return; 337099e1377SIan Campbell } 338099e1377SIan Campbell 339e605a425SJoe Millenbach debug_putstr("Parsing ELF... "); 340099e1377SIan Campbell 341099e1377SIan Campbell phdrs = malloc(sizeof(*phdrs) * ehdr.e_phnum); 342099e1377SIan Campbell if (!phdrs) 343099e1377SIan Campbell error("Failed to allocate space for phdrs"); 344099e1377SIan Campbell 345099e1377SIan Campbell memcpy(phdrs, output + ehdr.e_phoff, sizeof(*phdrs) * ehdr.e_phnum); 346099e1377SIan Campbell 347099e1377SIan Campbell for (i = 0; i < ehdr.e_phnum; i++) { 348099e1377SIan Campbell phdr = &phdrs[i]; 349099e1377SIan Campbell 350099e1377SIan Campbell switch (phdr->p_type) { 351099e1377SIan Campbell case PT_LOAD: 352099e1377SIan Campbell #ifdef CONFIG_RELOCATABLE 353099e1377SIan Campbell dest = output; 354099e1377SIan Campbell dest += (phdr->p_paddr - LOAD_PHYSICAL_ADDR); 355099e1377SIan Campbell #else 356099e1377SIan Campbell dest = (void *)(phdr->p_paddr); 357099e1377SIan Campbell #endif 358099e1377SIan Campbell memcpy(dest, 359099e1377SIan Campbell output + phdr->p_offset, 360099e1377SIan Campbell phdr->p_filesz); 361099e1377SIan Campbell break; 362099e1377SIan Campbell default: /* Ignore other PT_* */ break; 363099e1377SIan Campbell } 364099e1377SIan Campbell } 3655067cf53SJesper Juhl 3665067cf53SJesper Juhl free(phdrs); 367099e1377SIan Campbell } 368099e1377SIan Campbell 3692605fc21SAndi Kleen asmlinkage __visible void *decompress_kernel(void *rmode, memptr heap, 3701180e01dSIngo Molnar unsigned char *input_data, 3711180e01dSIngo Molnar unsigned long input_len, 372a0215061SKees Cook unsigned char *output, 373e6023367SJunjie Mao unsigned long output_len, 374e6023367SJunjie Mao unsigned long run_size) 375778cb929SIan Campbell { 376*f285f4a2SKees Cook unsigned char *output_orig = output; 377*f285f4a2SKees Cook 378778cb929SIan Campbell real_mode = rmode; 379778cb929SIan Campbell 3805dcd14ecSH. Peter Anvin sanitize_boot_params(real_mode); 3815dcd14ecSH. Peter Anvin 38223968f71SKristian Høgsberg if (real_mode->screen_info.orig_video_mode == 7) { 383778cb929SIan Campbell vidmem = (char *) 0xb0000; 384778cb929SIan Campbell vidport = 0x3b4; 385778cb929SIan Campbell } else { 386778cb929SIan Campbell vidmem = (char *) 0xb8000; 387778cb929SIan Campbell vidport = 0x3d4; 388778cb929SIan Campbell } 389778cb929SIan Campbell 39023968f71SKristian Høgsberg lines = real_mode->screen_info.orig_video_lines; 39123968f71SKristian Høgsberg cols = real_mode->screen_info.orig_video_cols; 392778cb929SIan Campbell 3938fee13a4SYinghai Lu console_init(); 394e605a425SJoe Millenbach debug_putstr("early console in decompress_kernel\n"); 3958fee13a4SYinghai Lu 396778cb929SIan Campbell free_mem_ptr = heap; /* Heap */ 3977c539764SAlexander van Heukelum free_mem_end_ptr = heap + BOOT_HEAP_SIZE; 398778cb929SIan Campbell 399e6023367SJunjie Mao /* 400e6023367SJunjie Mao * The memory hole needed for the kernel is the larger of either 401e6023367SJunjie Mao * the entire decompressed kernel plus relocation table, or the 402e6023367SJunjie Mao * entire decompressed kernel plus .bss and .brk sections. 403e6023367SJunjie Mao */ 404e6023367SJunjie Mao output = choose_kernel_location(input_data, input_len, output, 405e6023367SJunjie Mao output_len > run_size ? output_len 406e6023367SJunjie Mao : run_size); 4078ab3820fSKees Cook 4088ab3820fSKees Cook /* Validate memory location choices. */ 4097ed42a28SH. Peter Anvin if ((unsigned long)output & (MIN_KERNEL_ALIGN - 1)) 4107ed42a28SH. Peter Anvin error("Destination address inappropriately aligned"); 411778cb929SIan Campbell #ifdef CONFIG_X86_64 4127ed42a28SH. Peter Anvin if (heap > 0x3fffffffffffUL) 413778cb929SIan Campbell error("Destination address too large"); 414778cb929SIan Campbell #else 415147dd561SH. Peter Anvin if (heap > ((-__PAGE_OFFSET-(128<<20)-1) & 0x7fffffff)) 416778cb929SIan Campbell error("Destination address too large"); 417778cb929SIan Campbell #endif 4187ed42a28SH. Peter Anvin #ifndef CONFIG_RELOCATABLE 4197ed42a28SH. Peter Anvin if ((unsigned long)output != LOAD_PHYSICAL_ADDR) 4207ed42a28SH. Peter Anvin error("Wrong destination address"); 421778cb929SIan Campbell #endif 422778cb929SIan Campbell 423e605a425SJoe Millenbach debug_putstr("\nDecompressing Linux... "); 424ae03c499SAlain Knaff decompress(input_data, input_len, NULL, NULL, output, NULL, error); 425099e1377SIan Campbell parse_elf(output); 426*f285f4a2SKees Cook /* 427*f285f4a2SKees Cook * 32-bit always performs relocations. 64-bit relocations are only 428*f285f4a2SKees Cook * needed if kASLR has chosen a different load address. 429*f285f4a2SKees Cook */ 430*f285f4a2SKees Cook if (!IS_ENABLED(CONFIG_X86_64) || output != output_orig) 431a0215061SKees Cook handle_relocations(output, output_len); 432e605a425SJoe Millenbach debug_putstr("done.\nBooting the kernel.\n"); 4338ab3820fSKees Cook return output; 434778cb929SIan Campbell } 435