linux/arch/x86/boot/compressed/misc.c
<<
>>
Prefs
   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
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.