linux-old/arch/i386/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#define STANDALONE
  13
  14#include <linux/linkage.h>
  15#include <linux/vmalloc.h>
  16#include <linux/tty.h>
  17#include <asm/io.h>
  18
  19/*
  20 * gzip declarations
  21 */
  22
  23#define OF(args)  args
  24#define STATIC static
  25
  26#undef memset
  27#undef memcpy
  28
  29/*
  30 * Why do we do this? Don't ask me..
  31 *
  32 * Incomprehensible are the ways of bootloaders.
  33 */
  34static void* memset(void *, int, size_t);
  35static void* memcpy(void *, __const void *, size_t);
  36#define memzero(s, n)     memset ((s), 0, (n))
  37
  38typedef unsigned char  uch;
  39typedef unsigned short ush;
  40typedef unsigned long  ulg;
  41
  42#define WSIZE 0x8000            /* Window size must be at least 32k, */
  43                                /* and a power of two */
  44
  45static uch *inbuf;           /* input buffer */
  46static uch window[WSIZE];    /* Sliding window buffer */
  47
  48static unsigned insize = 0;  /* valid bytes in inbuf */
  49static unsigned inptr = 0;   /* index of next byte to be processed in inbuf */
  50static unsigned outcnt = 0;  /* bytes in output buffer */
  51
  52/* gzip flag byte */
  53#define ASCII_FLAG   0x01 /* bit 0 set: file probably ASCII text */
  54#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
  55#define EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
  56#define ORIG_NAME    0x08 /* bit 3 set: original file name present */
  57#define COMMENT      0x10 /* bit 4 set: file comment present */
  58#define ENCRYPTED    0x20 /* bit 5 set: file is encrypted */
  59#define RESERVED     0xC0 /* bit 6,7:   reserved */
  60
  61#define get_byte()  (inptr < insize ? inbuf[inptr++] : fill_inbuf())
  62                
  63/* Diagnostic functions */
  64#ifdef DEBUG
  65#  define Assert(cond,msg) {if(!(cond)) error(msg);}
  66#  define Trace(x) fprintf x
  67#  define Tracev(x) {if (verbose) fprintf x ;}
  68#  define Tracevv(x) {if (verbose>1) fprintf x ;}
  69#  define Tracec(c,x) {if (verbose && (c)) fprintf x ;}
  70#  define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;}
  71#else
  72#  define Assert(cond,msg)
  73#  define Trace(x)
  74#  define Tracev(x)
  75#  define Tracevv(x)
  76#  define Tracec(c,x)
  77#  define Tracecv(c,x)
  78#endif
  79
  80static int  fill_inbuf(void);
  81static void flush_window(void);
  82static void error(char *m);
  83static void gzip_mark(void **);
  84static void gzip_release(void **);
  85  
  86/*
  87 * This is set up by the setup-routine at boot-time
  88 */
  89static unsigned char *real_mode; /* Pointer to real-mode data */
  90
  91#define EXT_MEM_K   (*(unsigned short *)(real_mode + 0x2))
  92#ifndef STANDARD_MEMORY_BIOS_CALL
  93#define ALT_MEM_K   (*(unsigned long *)(real_mode + 0x1e0))
  94#endif
  95#define SCREEN_INFO (*(struct screen_info *)(real_mode+0))
  96
  97extern char input_data[];
  98extern int input_len;
  99
 100static long bytes_out = 0;
 101static uch *output_data;
 102static unsigned long output_ptr = 0;
 103
 104static void *malloc(int size);
 105static void free(void *where);
 106
 107static void putstr(const char *);
 108
 109extern int end;
 110static long free_mem_ptr = (long)&end;
 111static long free_mem_end_ptr;
 112
 113#define INPLACE_MOVE_ROUTINE  0x1000
 114#define LOW_BUFFER_START      0x2000
 115#define LOW_BUFFER_MAX       0x90000
 116#define HEAP_SIZE             0x3000
 117static unsigned int low_buffer_end, low_buffer_size;
 118static int high_loaded =0;
 119static uch *high_buffer_start /* = (uch *)(((ulg)&end) + HEAP_SIZE)*/;
 120
 121static char *vidmem = (char *)0xb8000;
 122static int vidport;
 123static int lines, cols;
 124
 125#include "../../../../lib/inflate.c"
 126
 127static void *malloc(int size)
 128{
 129        void *p;
 130
 131        if (size <0) error("Malloc error\n");
 132        if (free_mem_ptr <= 0) error("Memory error\n");
 133
 134        free_mem_ptr = (free_mem_ptr + 3) & ~3; /* Align */
 135
 136        p = (void *)free_mem_ptr;
 137        free_mem_ptr += size;
 138
 139        if (free_mem_ptr >= free_mem_end_ptr)
 140                error("\nOut of memory\n");
 141
 142        return p;
 143}
 144
 145static void free(void *where)
 146{       /* Don't care */
 147}
 148
 149static void gzip_mark(void **ptr)
 150{
 151        *ptr = (void *) free_mem_ptr;
 152}
 153
 154static void gzip_release(void **ptr)
 155{
 156        free_mem_ptr = (long) *ptr;
 157}
 158 
 159static void scroll(void)
 160{
 161        int i;
 162
 163        memcpy ( vidmem, vidmem + cols * 2, ( lines - 1 ) * cols * 2 );
 164        for ( i = ( lines - 1 ) * cols * 2; i < lines * cols * 2; i += 2 )
 165                vidmem[i] = ' ';
 166}
 167
 168static void putstr(const char *s)
 169{
 170        int x,y,pos;
 171        char c;
 172
 173        x = SCREEN_INFO.orig_x;
 174        y = SCREEN_INFO.orig_y;
 175
 176        while ( ( c = *s++ ) != '\0' ) {
 177                if ( c == '\n' ) {
 178                        x = 0;
 179                        if ( ++y >= lines ) {
 180                                scroll();
 181                                y--;
 182                        }
 183                } else {
 184                        vidmem [ ( x + cols * y ) * 2 ] = c; 
 185                        if ( ++x >= cols ) {
 186                                x = 0;
 187                                if ( ++y >= lines ) {
 188                                        scroll();
 189                                        y--;
 190                                }
 191                        }
 192                }
 193        }
 194
 195        SCREEN_INFO.orig_x = x;
 196        SCREEN_INFO.orig_y = y;
 197
 198        pos = (x + cols * y) * 2;       /* Update cursor position */
 199        outb_p(14, vidport);
 200        outb_p(0xff & (pos >> 9), vidport+1);
 201        outb_p(15, vidport);
 202        outb_p(0xff & (pos >> 1), vidport+1);
 203}
 204
 205static void* memset(void* s, int c, size_t n)
 206{
 207        int i;
 208        char *ss = (char*)s;
 209
 210        for (i=0;i<n;i++) ss[i] = c;
 211        return s;
 212}
 213
 214static void* memcpy(void* __dest, __const void* __src,
 215                            size_t __n)
 216{
 217        int i;
 218        char *d = (char *)__dest, *s = (char *)__src;
 219
 220        for (i=0;i<__n;i++) d[i] = s[i];
 221        return __dest;
 222}
 223
 224/* ===========================================================================
 225 * Fill the input buffer. This is called only when the buffer is empty
 226 * and at least one byte is really needed.
 227 */
 228static int fill_inbuf(void)
 229{
 230        if (insize != 0) {
 231                error("ran out of input data\n");
 232        }
 233
 234        inbuf = input_data;
 235        insize = input_len;
 236        inptr = 1;
 237        return inbuf[0];
 238}
 239
 240/* ===========================================================================
 241 * Write the output window window[0..outcnt-1] and update crc and bytes_out.
 242 * (Used for the decompressed data only.)
 243 */
 244static void flush_window_low(void)
 245{
 246    ulg c = crc;         /* temporary variable */
 247    unsigned n;
 248    uch *in, *out, ch;
 249    
 250    in = window;
 251    out = &output_data[output_ptr]; 
 252    for (n = 0; n < outcnt; n++) {
 253            ch = *out++ = *in++;
 254            c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8);
 255    }
 256    crc = c;
 257    bytes_out += (ulg)outcnt;
 258    output_ptr += (ulg)outcnt;
 259    outcnt = 0;
 260}
 261
 262static void flush_window_high(void)
 263{
 264    ulg c = crc;         /* temporary variable */
 265    unsigned n;
 266    uch *in,  ch;
 267    in = window;
 268    for (n = 0; n < outcnt; n++) {
 269        ch = *output_data++ = *in++;
 270        if ((ulg)output_data == low_buffer_end) output_data=high_buffer_start;
 271        c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8);
 272    }
 273    crc = c;
 274    bytes_out += (ulg)outcnt;
 275    outcnt = 0;
 276}
 277
 278static void flush_window(void)
 279{
 280        if (high_loaded) flush_window_high();
 281        else flush_window_low();
 282}
 283
 284static void error(char *x)
 285{
 286        putstr("\n\n");
 287        putstr(x);
 288        putstr("\n\n -- System halted");
 289
 290        while(1);       /* Halt */
 291}
 292
 293#define STACK_SIZE (4096)
 294
 295long user_stack [STACK_SIZE];
 296
 297struct {
 298        long * a;
 299        short b;
 300        } stack_start = { & user_stack [STACK_SIZE] , __KERNEL_DS };
 301
 302static void setup_normal_output_buffer(void)
 303{
 304#ifdef STANDARD_MEMORY_BIOS_CALL
 305        if (EXT_MEM_K < 1024) error("Less than 2MB of memory.\n");
 306#else
 307        if ((ALT_MEM_K > EXT_MEM_K ? ALT_MEM_K : EXT_MEM_K) < 1024) error("Less than 2MB of memory.\n");
 308#endif
 309        output_data = (char *)0x100000; /* Points to 1M */
 310        free_mem_end_ptr = (long)real_mode;
 311}
 312
 313struct moveparams {
 314        uch *low_buffer_start;  int lcount;
 315        uch *high_buffer_start; int hcount;
 316};
 317
 318static void setup_output_buffer_if_we_run_high(struct moveparams *mv)
 319{
 320        high_buffer_start = (uch *)(((ulg)&end) + HEAP_SIZE);
 321#ifdef STANDARD_MEMORY_BIOS_CALL
 322        if (EXT_MEM_K < (3*1024)) error("Less than 4MB of memory.\n");
 323#else
 324        if ((ALT_MEM_K > EXT_MEM_K ? ALT_MEM_K : EXT_MEM_K) < (3*1024)) error("Less than 4MB of memory.\n");
 325#endif  
 326        mv->low_buffer_start = output_data = (char *)LOW_BUFFER_START;
 327        low_buffer_end = ((unsigned int)real_mode > LOW_BUFFER_MAX
 328          ? LOW_BUFFER_MAX : (unsigned int)real_mode) & ~0xfff;
 329        low_buffer_size = low_buffer_end - LOW_BUFFER_START;
 330        high_loaded = 1;
 331        free_mem_end_ptr = (long)high_buffer_start;
 332        if ( (0x100000 + low_buffer_size) > ((ulg)high_buffer_start)) {
 333                high_buffer_start = (uch *)(0x100000 + low_buffer_size);
 334                mv->hcount = 0; /* say: we need not to move high_buffer */
 335        }
 336        else mv->hcount = -1;
 337        mv->high_buffer_start = high_buffer_start;
 338}
 339
 340static void close_output_buffer_if_we_run_high(struct moveparams *mv)
 341{
 342        if (bytes_out > low_buffer_size) {
 343                mv->lcount = low_buffer_size;
 344                if (mv->hcount)
 345                        mv->hcount = bytes_out - low_buffer_size;
 346        } else {
 347                mv->lcount = bytes_out;
 348                mv->hcount = 0;
 349        }
 350}
 351
 352
 353asmlinkage int decompress_kernel(struct moveparams *mv, void *rmode)
 354{
 355        real_mode = rmode;
 356
 357        if (SCREEN_INFO.orig_video_mode == 7) {
 358                vidmem = (char *) 0xb0000;
 359                vidport = 0x3b4;
 360        } else {
 361                vidmem = (char *) 0xb8000;
 362                vidport = 0x3d4;
 363        }
 364
 365        lines = SCREEN_INFO.orig_video_lines;
 366        cols = SCREEN_INFO.orig_video_cols;
 367
 368        if (free_mem_ptr < 0x100000) setup_normal_output_buffer();
 369        else setup_output_buffer_if_we_run_high(mv);
 370
 371        makecrc();
 372        putstr("Uncompressing Linux... ");
 373        gunzip();
 374        putstr("Ok, booting the kernel.\n");
 375        if (high_loaded) close_output_buffer_if_we_run_high(mv);
 376        return high_loaded;
 377}
 378
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.