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