1/* 2 * misc.c 3 * 4 * This is a collection of several routines from gzip-1.0.3 5 * adapted for Linux. 6 * 7 * malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994 8 * puts by Nick Holloway 1993, better puts by Martin Mares 1995 9 * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996 10 */ 11 12#include "misc.h" 13 14/* WARNING!! 15 * This code is compiled with -fPIC and it is relocated dynamically 16 * at run time, but no relocation processing is performed. 17 * This means that it is not safe to place pointers in static structures. 18 */ 19 20/* 21 * Getting to provable safe in place decompression is hard. 22 * Worst case behaviours need to be analyzed. 23 * Background information: 24 * 25 * The file layout is: 26 * magic[2] 27 * method[1] 28 * flags[1] 29 * timestamp[4] 30 * extraflags[1] 31 * os[1] 32 * compressed data blocks[N] 33 * crc[4] orig_len[4] 34 * 35 * resulting in 18 bytes of non compressed data overhead. 36 * 37 * Files divided into blocks 38 * 1 bit (last block flag) 39 * 2 bits (block type) 40 * 41 * 1 block occurs every 32K -1 bytes or when there 50% compression 42 * has been achieved. The smallest block type encoding is always used. 43 * 44 * stored: 45 * 32 bits length in bytes. 46 * 47 * fixed: 48 * magic fixed tree. 49 * symbols. 50 * 51 * dynamic: 52 * dynamic tree encoding. 53 * symbols. 54 * 55 * 56 * The buffer for decompression in place is the length of the 57 * uncompressed data, plus a small amount extra to keep the algorithm safe. 58 * The compressed data is placed at the end of the buffer. The output 59 * pointer is placed at the start of the buffer and the input pointer 60 * is placed where the compressed data starts. Problems will occur 61 * when the output pointer overruns the input pointer. 62 * 63 * The output pointer can only overrun the input pointer if the input 64 * pointer is moving faster than the output pointer. A condition only 65 * triggered by data whose compressed form is larger than the uncompressed 66 * form. 67 * 68 * The worst case at the block level is a growth of the compressed data 69 * of 5 bytes per 32767 bytes. 70 * 71 * The worst case internal to a compressed block is very hard to figure. 72 * The worst case can at least be boundined by having one bit that represents 73 * 32764 bytes and then all of the rest of the bytes representing the very 74 * very last byte. 75 * 76 * All of which is enough to compute an amount of extra data that is required 77 * to be safe. To avoid problems at the block level allocating 5 extra bytes 78 * per 32767 bytes of data is sufficient. To avoind problems internal to a 79 * block adding an extra 32767 bytes (the worst case uncompressed block size) 80 * is sufficient, to ensure that in the worst case the decompressed data for 81 * block will stop the byte before the compressed data for a block begins. 82 * To avoid problems with the compressed data's meta information an extra 18 83 * bytes are needed. Leading to the formula: 84 * 85 * extra_bytes = (uncompressed_size >> 12) + 32768 + 18 + decompressor_size. 86 * 87 * Adding 8 bytes per 32K is a bit excessive but much easier to calculate. 88 * Adding 32768 instead of 32767 just makes for round numbers. 89 * Adding the decompressor_size is necessary as it musht live after all 90 * of the data as well. Last I measured the decompressor is about 14K. 91 * 10K of actual data and 4K of bss. 92 * 93 */ 94 95/* 96 * gzip declarations 97 */ 98#define STATIC static 99 100#undef memset 101#undef memcpy 102#define memzero(s, n) memset((s), 0, (n)) 103 104 105static void error(char *m); 106 107/* 108 * This is set up by the setup-routine at boot-time 109 */ 110struct boot_params *real_mode; /* Pointer to real-mode data */ 111static int quiet; 112static int debug; 113 114void *memset(void *s, int c, size_t n); 115void *memcpy(void *dest, const void *src, size_t n); 116 117#ifdef CONFIG_X86_64 118#define memptr long 119#else 120#define memptr unsigned 121#endif 122 123static memptr free_mem_ptr; 124static memptr free_mem_end_ptr; 125 126static char *vidmem; 127static int vidport; 128static int lines, cols; 129 130#ifdef CONFIG_KERNEL_GZIP 131#include "../../../../lib/decompress_inflate.c" 132#endif 133 134#ifdef CONFIG_KERNEL_BZIP2 135#include "../../../../lib/decompress_bunzip2.c" 136#endif 137 138#ifdef CONFIG_KERNEL_LZMA 139#include "../../../../lib/decompress_unlzma.c" 140#endif 141 142#ifdef CONFIG_KERNEL_LZO 143#include "../../../../lib/decompress_unlzo.c" 144#endif 145 146static void scroll(void) 147{ 148 int i; 149 150 memcpy(vidmem, vidmem + cols * 2, (lines - 1) * cols * 2); 151 for (i = (lines - 1) * cols * 2; i < lines * cols * 2; i += 2) 152 vidmem[i] = ' '; 153} 154 155#define XMTRDY 0x20 156 157#define TXR 0 /* Transmit register (WRITE) */ 158#define LSR 5 /* Line Status */ 159static void serial_putchar(int ch) 160{ 161 unsigned timeout = 0xffff; 162 163 while ((inb(early_serial_base + LSR) & XMTRDY) == 0 && --timeout) 164 cpu_relax(); 165 166 outb(ch, early_serial_base + TXR); 167} 168 169void __putstr(int error, const char *s) 170{ 171 int x, y, pos; 172 char c; 173 174#ifndef CONFIG_X86_VERBOSE_BOOTUP 175 if (!error) 176 return; 177#endif 178 if (early_serial_base) { 179 const char *str = s; 180 while (*str) { 181 if (*str == '\n') 182 serial_putchar('\r'); 183 serial_putchar(*str++); 184 } 185 } 186 187 if (real_mode->screen_info.orig_video_mode == 0 && 188 lines == 0 && cols == 0) 189 return; 190 191 x = real_mode->screen_info.orig_x; 192 y = real_mode->screen_info.orig_y; 193 194 while ((c = *s++) != '\0') { 195 if (c == '\n') { 196 x = 0; 197 if (++y >= lines) { 198 scroll(); 199 y--; 200 } 201 } else { 202 vidmem[(x + cols * y) * 2] = c; 203 if (++x >= cols) { 204 x = 0; 205 if (++y >= lines) { 206 scroll(); 207 y--; 208 } 209 } 210 } 211 } 212 213 real_mode->screen_info.orig_x = x; 214 real_mode->screen_info.orig_y = y; 215 216 pos = (x + cols * y) * 2; /* Update cursor position */ 217 outb(14, vidport); 218 outb(0xff & (pos >> 9), vidport+1); 219 outb(15, vidport); 220 outb(0xff & (pos >> 1), vidport+1); 221} 222 223void *memset(void *s, int c, size_t n) 224{ 225 int i; 226 char *ss = s; 227 228 for (i = 0; i < n; i++) 229 ss[i] = c; 230 return s; 231} 232 233void *memcpy(void *dest, const void *src, size_t n) 234{ 235 int i; 236 const char *s = src; 237 char *d = dest; 238 239 for (i = 0; i < n; i++) 240 d[i] = s[i]; 241 return dest; 242} 243 244 245static void error(char *x) 246{ 247 __putstr(1, "\n\n"); 248 __putstr(1, x); 249 __putstr(1, "\n\n -- System halted"); 250 251 while (1) 252 asm("hlt"); 253} 254 255static void parse_elf(void *output) 256{ 257#ifdef CONFIG_X86_64 258 Elf64_Ehdr ehdr; 259 Elf64_Phdr *phdrs, *phdr; 260#else 261 Elf32_Ehdr ehdr; 262 Elf32_Phdr *phdrs, *phdr; 263#endif 264 void *dest; 265 int i; 266 267 memcpy(&ehdr, output, sizeof(ehdr)); 268 if (ehdr.e_ident[EI_MAG0] != ELFMAG0 || 269 ehdr.e_ident[EI_MAG1] != ELFMAG1 || 270 ehdr.e_ident[EI_MAG2] != ELFMAG2 || 271 ehdr.e_ident[EI_MAG3] != ELFMAG3) { 272 error("Kernel is not a valid ELF file"); 273 return; 274 } 275 276 if (!quiet) 277 putstr("Parsing ELF... "); 278 279 phdrs = malloc(sizeof(*phdrs) * ehdr.e_phnum); 280 if (!phdrs) 281 error("Failed to allocate space for phdrs"); 282 283 memcpy(phdrs, output + ehdr.e_phoff, sizeof(*phdrs) * ehdr.e_phnum); 284 285 for (i = 0; i < ehdr.e_phnum; i++) { 286 phdr = &phdrs[i]; 287 288 switch (phdr->p_type) { 289 case PT_LOAD: 290#ifdef CONFIG_RELOCATABLE 291 dest = output; 292 dest += (phdr->p_paddr - LOAD_PHYSICAL_ADDR); 293#else 294 dest = (void *)(phdr->p_paddr); 295#endif 296 memcpy(dest, 297 output + phdr->p_offset, 298 phdr->p_filesz); 299 break; 300 default: /* Ignore other PT_* */ break; 301 } 302 } 303} 304 305asmlinkage void decompress_kernel(void *rmode, memptr heap, 306 unsigned char *input_data, 307 unsigned long input_len, 308 unsigned char *output) 309{ 310 real_mode = rmode; 311 312 if (cmdline_find_option_bool("quiet")) 313 quiet = 1; 314 if (cmdline_find_option_bool("debug")) 315 debug = 1; 316 317 if (real_mode->screen_info.orig_video_mode == 7) { 318 vidmem = (char *) 0xb0000; 319 vidport = 0x3b4; 320 } else { 321 vidmem = (char *) 0xb8000; 322 vidport = 0x3d4; 323 } 324 325 lines = real_mode->screen_info.orig_video_lines; 326 cols = real_mode->screen_info.orig_video_cols; 327 328 console_init(); 329 if (debug) 330 putstr("early console in decompress_kernel\n"); 331 332 free_mem_ptr = heap; /* Heap */ 333 free_mem_end_ptr = heap + BOOT_HEAP_SIZE; 334 335 if ((unsigned long)output & (MIN_KERNEL_ALIGN - 1)) 336 error("Destination address inappropriately aligned"); 337#ifdef CONFIG_X86_64 338 if (heap > 0x3fffffffffffUL) 339 error("Destination address too large"); 340#else 341 if (heap > ((-__PAGE_OFFSET-(512<<20)-1) & 0x7fffffff)) 342 error("Destination address too large"); 343#endif 344#ifndef CONFIG_RELOCATABLE 345 if ((unsigned long)output != LOAD_PHYSICAL_ADDR) 346 error("Wrong destination address"); 347#endif 348 349 if (!quiet) 350 putstr("\nDecompressing Linux... "); 351 decompress(input_data, input_len, NULL, NULL, output, NULL, error); 352 parse_elf(output); 353 if (!quiet) 354 putstr("done.\nBooting the kernel.\n"); 355 return; 356} 357