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