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 "miscsetup.h" 13#include <asm/io.h> 14 15/* 16 * gzip declarations 17 */ 18 19#define OF(args) args 20#define STATIC static 21 22#undef memset 23#undef memcpy 24#define memzero(s, n) memset ((s), 0, (n)) 25 26typedef unsigned char uch; 27typedef unsigned short ush; 28typedef unsigned long ulg; 29 30#define WSIZE 0x8000 /* Window size must be at least 32k, */ 31 /* and a power of two */ 32 33static uch *inbuf; /* input buffer */ 34static uch window[WSIZE]; /* Sliding window buffer */ 35 36static unsigned insize = 0; /* valid bytes in inbuf */ 37static unsigned inptr = 0; /* index of next byte to be processed in inbuf */ 38static unsigned outcnt = 0; /* bytes in output buffer */ 39 40/* gzip flag byte */ 41#define ASCII_FLAG 0x01 /* bit 0 set: file probably ASCII text */ 42#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */ 43#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ 44#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ 45#define COMMENT 0x10 /* bit 4 set: file comment present */ 46#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */ 47#define RESERVED 0xC0 /* bit 6,7: reserved */ 48 49#define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf()) 50 51/* Diagnostic functions */ 52#ifdef DEBUG 53# define Assert(cond,msg) {if(!(cond)) error(msg);} 54# define Trace(x) fprintf x 55# define Tracev(x) {if (verbose) fprintf x ;} 56# define Tracevv(x) {if (verbose>1) fprintf x ;} 57# define Tracec(c,x) {if (verbose && (c)) fprintf x ;} 58# define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;} 59#else 60# define Assert(cond,msg) 61# define Trace(x) 62# define Tracev(x) 63# define Tracevv(x) 64# define Tracec(c,x) 65# define Tracecv(c,x) 66#endif 67 68static int fill_inbuf(void); 69static void flush_window(void); 70static void error(char *m); 71static void gzip_mark(void **); 72static void gzip_release(void **); 73 74/* 75 * This is set up by the setup-routine at boot-time 76 */ 77static unsigned char *real_mode; /* Pointer to real-mode data */ 78 79#define EXT_MEM_K (*(unsigned short *)(real_mode + 0x2)) 80#ifndef STANDARD_MEMORY_BIOS_CALL 81#define ALT_MEM_K (*(unsigned long *)(real_mode + 0x1e0)) 82#endif 83#define SCREEN_INFO (*(struct screen_info *)(real_mode+0)) 84 85extern char input_data[]; 86extern int input_len; 87 88static long bytes_out = 0; 89static uch *output_data; 90static unsigned long output_ptr = 0; 91 92 93static void *malloc(int size); 94static void free(void *where); 95static void error(char *m); 96static void gzip_mark(void **); 97static void gzip_release(void **); 98 99static void puts(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\n"); 124 if (free_mem_ptr <= 0) error("Memory error\n"); 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("\nOut of memory\n"); 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 puts(const char *s) 161{ 162 int x,y,pos; 163 char c; 164 165 x = SCREEN_INFO.orig_x; 166 y = 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 SCREEN_INFO.orig_x = x; 188 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 197void* memset(void* s, int c, size_t 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 206void* memcpy(void* __dest, __const void* __src, 207 size_t __n) 208{ 209 int i; 210 char *d = (char *)__dest, *s = (char *)__src; 211 212 for (i=0;i<__n;i++) d[i] = s[i]; 213 return __dest; 214} 215 216/* =========================================================================== 217 * Fill the input buffer. This is called only when the buffer is empty 218 * and at least one byte is really needed. 219 */ 220static int fill_inbuf(void) 221{ 222 if (insize != 0) { 223 error("ran out of input data\n"); 224 } 225 226 inbuf = input_data; 227 insize = input_len; 228 inptr = 1; 229 return inbuf[0]; 230} 231 232/* =========================================================================== 233 * Write the output window window[0..outcnt-1] and update crc and bytes_out. 234 * (Used for the decompressed data only.) 235 */ 236static void flush_window_low(void) 237{ 238 ulg c = crc; /* temporary variable */ 239 unsigned n; 240 uch *in, *out, ch; 241 242 in = window; 243 out = &output_data[output_ptr]; 244 for (n = 0; n < outcnt; n++) { 245 ch = *out++ = *in++; 246 c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8); 247 } 248 crc = c; 249 bytes_out += (ulg)outcnt; 250 output_ptr += (ulg)outcnt; 251 outcnt = 0; 252} 253 254static void flush_window_high(void) 255{ 256 ulg c = crc; /* temporary variable */ 257 unsigned n; 258 uch *in, ch; 259 in = window; 260 for (n = 0; n < outcnt; n++) { 261 ch = *output_data++ = *in++; 262 if ((ulg)output_data == low_buffer_end) output_data=high_buffer_start; 263 c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8); 264 } 265 crc = c; 266 bytes_out += (ulg)outcnt; 267 outcnt = 0; 268} 269 270static void flush_window(void) 271{ 272 if (high_loaded) flush_window_high(); 273 else flush_window_low(); 274} 275 276static void error(char *x) 277{ 278 puts("\n\n"); 279 puts(x); 280 puts("\n\n -- System halted"); 281 282 while(1); /* Halt */ 283} 284 285void setup_normal_output_buffer(void) 286{ 287#ifdef STANDARD_MEMORY_BIOS_CALL 288 if (EXT_MEM_K < 1024) error("Less than 2MB of memory.\n"); 289#else 290 if ((ALT_MEM_K > EXT_MEM_K ? ALT_MEM_K : EXT_MEM_K) < 1024) error("Less than 2MB of memory.\n"); 291#endif 292 output_data = (char *)0x100000; /* Points to 1M */ 293 free_mem_end_ptr = (long)real_mode; 294} 295 296struct moveparams { 297 uch *low_buffer_start; int lcount; 298 uch *high_buffer_start; int hcount; 299}; 300 301void setup_output_buffer_if_we_run_high(struct moveparams *mv) 302{ 303 high_buffer_start = (uch *)(((ulg)&end) + HEAP_SIZE); 304#ifdef STANDARD_MEMORY_BIOS_CALL 305 if (EXT_MEM_K < (3*1024)) error("Less than 4MB of memory.\n"); 306#else 307 if ((ALT_MEM_K > EXT_MEM_K ? ALT_MEM_K : EXT_MEM_K) < (3*1024)) error("Less than 4MB of memory.\n"); 308#endif 309 mv->low_buffer_start = output_data = (char *)LOW_BUFFER_START; 310 low_buffer_end = ((unsigned int)real_mode > LOW_BUFFER_MAX 311 ? LOW_BUFFER_MAX : (unsigned int)real_mode) & ~0xfff; 312 low_buffer_size = low_buffer_end - LOW_BUFFER_START; 313 high_loaded = 1; 314 free_mem_end_ptr = (long)high_buffer_start; 315 if ( (0x100000 + low_buffer_size) > ((ulg)high_buffer_start)) { 316 high_buffer_start = (uch *)(0x100000 + low_buffer_size); 317 mv->hcount = 0; /* say: we need not to move high_buffer */ 318 } 319 else mv->hcount = -1; 320 mv->high_buffer_start = high_buffer_start; 321} 322 323void close_output_buffer_if_we_run_high(struct moveparams *mv) 324{ 325 if (bytes_out > low_buffer_size) { 326 mv->lcount = low_buffer_size; 327 if (mv->hcount) 328 mv->hcount = bytes_out - low_buffer_size; 329 } else { 330 mv->lcount = bytes_out; 331 mv->hcount = 0; 332 } 333} 334 335void check_cpu(void) 336{ 337 int res = 0; 338 asm volatile( " \n\ 339 movl $3,%%edx # at least 386 \n\ 340 pushfl # push EFLAGS \n\ 341 popl %%eax # get EFLAGS \n\ 342 movl %%eax,%%ecx # save original EFLAGS \n\ 343 xorl $0x40000,%%eax # flip AC bit in EFLAGS \n\ 344 pushl %%eax # copy to EFLAGS \n\ 345 popfl # set EFLAGS \n\ 346 pushfl # get new EFLAGS \n\ 347 popl %%eax # put it in eax \n\ 348 xorl %%ecx,%%eax # change in flags \n\ 349 andl $0x40000,%%eax # check if AC bit changed \n\ 350 je 1f \n\ 351\n\ 352 movl $4,%%edx # at least 486 \n\ 353 movl %%ecx,%%eax \n\ 354 xorl $0x200000,%%eax # check ID flag \n\ 355 pushl %%eax \n\ 356 popfl # if we are on a straight 486DX, SX, or \n\ 357 pushfl # 487SX we can't change it \n\ 358 popl %%eax \n\ 359 xorl %%ecx,%%eax \n\ 360 pushl %%ecx # restore original EFLAGS \n\ 361 popfl \n\ 362 andl $0x200000,%%eax \n\ 363 je 1f \n\ 364\n\ 365 /* get vendor info */ \n\ 366# xorl %%eax,%%eax # call CPUID with 0 -> return vendor ID \n\ 367# cpuid \n\ 368# movl $5, %%edx \n\ 369# cmpl $0x41757468,%%ebx # check thats amd \n\ 370# jne 1f \n\ 371\n\ 372 mov $0x80000000,%%eax # Is extended cpuid supported?\n\ 373 cpuid\n\ 374 test $0x80000000,%%eax\n\ 375 movl $5, %%edx \n\ 376 jz 1f\n\ 377\n\ 378 movl $0x80000001,%%eax \n\ 379 cpuid \n\ 380 andl $0x20000000,%%edx \n\ 381 movl $6, %%edx \n\ 382 jz 1f \n\ 383\n\ 384 movl $7, %%edx \n\ 3851:" : "=d" (res) : : "eax", "ebx", "ecx" ); 386 387 switch (res) { 388 case 3: puts( "386" ); 389 break; 390 case 4: puts( "486" ); 391 break; 392 case 5: puts( "no extended cpuid" ); 393 break; 394 case 6: puts( "non-64bit 586+" ); 395 break; 396 case 7: puts( "64bit" ); 397 break; 398 default:puts( "internal error" ); 399 break; 400 } 401 if (res !=7) 402 error( "Sorry, your CPU is not capable of running 64-bit kernel." ); 403} 404 405int decompress_kernel(struct moveparams *mv, void *rmode) 406{ 407 real_mode = rmode; 408 409 if (SCREEN_INFO.orig_video_mode == 7) { 410 vidmem = (char *) 0xb0000; 411 vidport = 0x3b4; 412 } else { 413 vidmem = (char *) 0xb8000; 414 vidport = 0x3d4; 415 } 416 417 lines = SCREEN_INFO.orig_video_lines; 418 cols = SCREEN_INFO.orig_video_cols; 419 420 if (free_mem_ptr < 0x100000) setup_normal_output_buffer(); 421 else setup_output_buffer_if_we_run_high(mv); 422 423 makecrc(); 424 puts("Checking CPU type..."); 425 check_cpu(); 426 puts(".\nDecompressing Linux..."); 427 gunzip(); 428 puts("done.\nBooting the kernel.\n"); 429 if (high_loaded) close_output_buffer_if_we_run_high(mv); 430 return high_loaded; 431} 432