| /* |
| * misc.c |
| * |
| * This is a collection of several routines from gzip-1.0.3 |
| * adapted for Linux. |
| * |
| * malloc and puts by Hannu Savolainen 1993 |
| */ |
| |
| #include "gzip.h" |
| #include "lzw.h" |
| |
| #include <linux/segment.h> |
| |
| /* |
| * These are set up by the setup-routine at boot-time: |
| */ |
| |
| struct screen_info { |
| unsigned char orig_x; |
| unsigned char orig_y; |
| unsigned char unused1[2]; |
| unsigned short orig_video_page; |
| unsigned char orig_video_mode; |
| unsigned char orig_video_cols; |
| unsigned short orig_video_ega_ax; |
| unsigned short orig_video_ega_bx; |
| unsigned short orig_video_ega_cx; |
| unsigned char orig_video_lines; |
| }; |
| |
| /* |
| * This is set up by the setup-routine at boot-time |
| */ |
| #define EXT_MEM_K (*(unsigned short *)0x90002) |
| #define DRIVE_INFO (*(struct drive_info *)0x90080) |
| #define SCREEN_INFO (*(struct screen_info *)0x90000) |
| #define RAMDISK_SIZE (*(unsigned short *)0x901F8) |
| #define ORIG_ROOT_DEV (*(unsigned short *)0x901FC) |
| #define AUX_DEVICE_INFO (*(unsigned char *)0x901FF) |
| |
| #define EOF -1 |
| |
| DECLARE(uch, inbuf, INBUFSIZ); |
| DECLARE(uch, outbuf, OUTBUFSIZ+OUTBUF_EXTRA); |
| DECLARE(uch, window, WSIZE); |
| |
| unsigned outcnt; |
| unsigned insize; |
| unsigned inptr; |
| |
| extern char input_data[]; |
| extern int input_len; |
| |
| int input_ptr; |
| |
| int method, exit_code, part_nb, last_member; |
| int test = 0; |
| int force = 0; |
| int verbose = 1; |
| long bytes_in, bytes_out; |
| |
| char *output_data; |
| unsigned long output_ptr; |
| |
| extern int end; |
| long free_mem_ptr = (long)&end; |
| |
| int to_stdout = 0; |
| int hard_math = 0; |
| |
| void (*work)(int inf, int outf); |
| void makecrc(void); |
| |
| local int get_method(int); |
| |
| char *vidmem = (char *)0xb8000; |
| int vidp = 0; |
| int lines, cols; |
| |
| void *malloc(int size) |
| { |
| void *p; |
| |
| if (size <0) error("Malloc error\n"); |
| if (free_mem_ptr <= 0) error("Memory error\n"); |
| |
| free_mem_ptr = (free_mem_ptr + 3) & ~3; /* Align */ |
| |
| p = (void *)free_mem_ptr; |
| |
| free_mem_ptr += size; |
| |
| if (free_mem_ptr > 0x90000) error("\nOut of memory\n"); |
| |
| if (p == NULL) error("malloc = NULL\n"); |
| return p; |
| } |
| |
| void free(void *where) |
| { /* Don't care */ |
| } |
| |
| static void puts(char *s) |
| { |
| int i,n; |
| for (n = 0; s [n] != '\0'; n++); |
| if (!n) n = 10; |
| |
| for (i=0;i<n;i++) |
| if (s[i] == '\n') |
| { |
| vidp = ((vidp / (cols*2)) + 1) * cols * 2; |
| } else { |
| vidmem[vidp] = s[i]; |
| vidp = vidp + 2; |
| } |
| } |
| |
| __ptr_t memset(__ptr_t s, int c, size_t n) |
| { |
| int i; |
| char *ss = (char*)s; |
| |
| for (i=0;i<n;i++) ss[i] = c; |
| } |
| |
| __ptr_t memcpy(__ptr_t __dest, __const __ptr_t __src, |
| size_t __n) |
| { |
| int i; |
| char *d = (char *)__dest, *s = (char *)__src; |
| |
| for (i=0;i<__n;i++) d[i] = s[i]; |
| } |
| |
| extern ulg crc_32_tab[]; /* crc table, defined below */ |
| |
| /* =========================================================================== |
| * Run a set of bytes through the crc shift register. If s is a NULL |
| * pointer, then initialize the crc shift register contents instead. |
| * Return the current crc in either case. |
| */ |
| ulg updcrc(s, n) |
| uch *s; /* pointer to bytes to pump through */ |
| unsigned n; /* number of bytes in s[] */ |
| { |
| register ulg c; /* temporary variable */ |
| |
| static ulg crc = (ulg)0xffffffffL; /* shift register contents */ |
| |
| if (s == NULL) { |
| c = 0xffffffffL; |
| } else { |
| c = crc; |
| while (n--) { |
| c = crc_32_tab[((int)c ^ (*s++)) & 0xff] ^ (c >> 8); |
| } |
| } |
| crc = c; |
| return c ^ 0xffffffffL; /* (instead of ~c for 64-bit machines) */ |
| } |
| |
| /* =========================================================================== |
| * Clear input and output buffers |
| */ |
| void clear_bufs() |
| { |
| outcnt = 0; |
| insize = inptr = 0; |
| bytes_in = bytes_out = 0L; |
| } |
| |
| /* =========================================================================== |
| * Fill the input buffer. This is called only when the buffer is empty |
| * and at least one byte is really needed. |
| */ |
| int fill_inbuf() |
| { |
| int len, i; |
| |
| /* Read as much as possible */ |
| insize = 0; |
| do { |
| len = INBUFSIZ-insize; |
| if (len > (input_len-input_ptr+1)) len=input_len-input_ptr+1; |
| if (len == 0 || len == EOF) break; |
| |
| for (i=0;i<len;i++) inbuf[insize+i] = input_data[input_ptr+i]; |
| insize += len; |
| input_ptr += len; |
| } while (insize < INBUFSIZ); |
| |
| if (insize == 0) { |
| error("unable to fill buffer\n"); |
| } |
| bytes_in += (ulg)insize; |
| inptr = 1; |
| return inbuf[0]; |
| } |
| |
| /* =========================================================================== |
| * Write the output window window[0..outcnt-1] and update crc and bytes_out. |
| * (Used for the decompressed data only.) |
| */ |
| void flush_window() |
| { |
| if (outcnt == 0) return; |
| updcrc(window, outcnt); |
| |
| memcpy(&output_data[output_ptr], (char *)window, outcnt); |
| |
| bytes_out += (ulg)outcnt; |
| output_ptr += (ulg)outcnt; |
| outcnt = 0; |
| } |
| |
| /* |
| * Code to compute the CRC-32 table. Borrowed from |
| * gzip-1.0.3/makecrc.c. |
| */ |
| |
| ulg crc_32_tab[256]; |
| |
| void |
| makecrc(void) |
| { |
| /* Not copyrighted 1990 Mark Adler */ |
| |
| unsigned long c; /* crc shift register */ |
| unsigned long e; /* polynomial exclusive-or pattern */ |
| int i; /* counter for all possible eight bit values */ |
| int k; /* byte being shifted into crc apparatus */ |
| |
| /* terms of polynomial defining this crc (except x^32): */ |
| static int p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; |
| |
| /* Make exclusive-or pattern from polynomial */ |
| e = 0; |
| for (i = 0; i < sizeof(p)/sizeof(int); i++) |
| e |= 1L << (31 - p[i]); |
| |
| crc_32_tab[0] = 0; |
| |
| for (i = 1; i < 256; i++) |
| { |
| c = 0; |
| for (k = i | 256; k != 1; k >>= 1) |
| { |
| c = c & 1 ? (c >> 1) ^ e : c >> 1; |
| if (k & 1) |
| c ^= e; |
| } |
| crc_32_tab[i] = c; |
| } |
| } |
| |
| void error(char *x) |
| { |
| puts("\n\n"); |
| puts(x); |
| puts("\n\n -- System halted"); |
| |
| while(1); /* Halt */ |
| } |
| |
| #define STACK_SIZE (4096) |
| |
| long user_stack [STACK_SIZE]; |
| |
| struct { |
| long * a; |
| short b; |
| } stack_start = { & user_stack [STACK_SIZE] , KERNEL_DS }; |
| |
| void decompress_kernel() |
| { |
| if (SCREEN_INFO.orig_video_mode == 7) |
| vidmem = (char *) 0xb0000; |
| else |
| vidmem = (char *) 0xb8000; |
| vidp = 0; |
| vidmem[0] = '0'; |
| |
| lines = SCREEN_INFO.orig_video_lines; |
| cols = SCREEN_INFO.orig_video_cols; |
| |
| if (EXT_MEM_K < 1024) error("<2M of mem\n"); |
| |
| output_data = (char *)1048576; /* Points to 1M */ |
| output_ptr = 0; |
| |
| exit_code = 0; |
| test = 0; |
| input_ptr = 0; |
| part_nb = 0; |
| |
| clear_bufs(); |
| makecrc(); |
| |
| puts("Uncompressing Linux..."); |
| |
| method = get_method(0); |
| |
| work(0, 0); |
| |
| puts("done.\n\n"); |
| |
| puts("Now booting the kernel\n"); |
| } |
| |
| /* ======================================================================== |
| * Check the magic number of the input file and update ofname if an |
| * original name was given and to_stdout is not set. |
| * Return the compression method, -1 for error, -2 for warning. |
| * Set inptr to the offset of the next byte to be processed. |
| * This function may be called repeatedly for an input file consisting |
| * of several contiguous gzip'ed members. |
| * IN assertions: there is at least one remaining compressed member. |
| * If the member is a zip file, it must be the only one. |
| */ |
| local int get_method(in) |
| int in; /* input file descriptor */ |
| { |
| uch flags; |
| char magic[2]; /* magic header */ |
| |
| magic[0] = (char)get_byte(); |
| magic[1] = (char)get_byte(); |
| |
| method = -1; /* unknown yet */ |
| part_nb++; /* number of parts in gzip file */ |
| last_member = 0; |
| /* assume multiple members in gzip file except for record oriented I/O */ |
| |
| if (memcmp(magic, GZIP_MAGIC, 2) == 0 |
| || memcmp(magic, OLD_GZIP_MAGIC, 2) == 0) { |
| |
| work = unzip; |
| method = (int)get_byte(); |
| flags = (uch)get_byte(); |
| if ((flags & ENCRYPTED) != 0) { |
| error("Input is encrypted\n"); |
| exit_code = ERROR; |
| return -1; |
| } |
| if ((flags & CONTINUATION) != 0) { |
| error("Multi part input\n"); |
| exit_code = ERROR; |
| if (force <= 1) return -1; |
| } |
| if ((flags & RESERVED) != 0) { |
| error("Input has invalid flags\n"); |
| exit_code = ERROR; |
| if (force <= 1) return -1; |
| } |
| (ulg)get_byte(); /* Get timestamp */ |
| ((ulg)get_byte()) << 8; |
| ((ulg)get_byte()) << 16; |
| ((ulg)get_byte()) << 24; |
| |
| (void)get_byte(); /* Ignore extra flags for the moment */ |
| (void)get_byte(); /* Ignore OS type for the moment */ |
| |
| if ((flags & CONTINUATION) != 0) { |
| unsigned part = (unsigned)get_byte(); |
| part |= ((unsigned)get_byte())<<8; |
| if (verbose) { |
| error("Input is not part number 1\n"); |
| } |
| } |
| if ((flags & EXTRA_FIELD) != 0) { |
| unsigned len = (unsigned)get_byte(); |
| len |= ((unsigned)get_byte())<<8; |
| while (len--) (void)get_byte(); |
| } |
| |
| /* Get original file name if it was truncated */ |
| if ((flags & ORIG_NAME) != 0) { |
| if (to_stdout || part_nb > 1) { |
| /* Discard the old name */ |
| while (get_byte() != 0) /* null */ ; |
| } else { |
| } /* to_stdout */ |
| } /* orig_name */ |
| |
| /* Discard file comment if any */ |
| if ((flags & COMMENT) != 0) { |
| while (get_byte() != 0) /* null */ ; |
| } |
| |
| } else if (memcmp(magic, PKZIP_MAGIC, 2) == 0 && inptr == 2 |
| && memcmp(inbuf, PKZIP_MAGIC, 4) == 0) { |
| /* To simplify the code, we support a zip file when alone only. |
| * We are thus guaranteed that the entire local header fits in inbuf. |
| */ |
| inptr = 0; |
| work = unzip; |
| if (check_zipfile(in) == -1) return -1; |
| /* check_zipfile may get ofname from the local header */ |
| last_member = 1; |
| |
| } else if (memcmp(magic, PACK_MAGIC, 2) == 0) { |
| error("packed input"); |
| } else if (memcmp(magic, LZW_MAGIC, 2) == 0) { |
| error("compressed input"); |
| last_member = 1; |
| } |
| if (method == -1) { |
| error("Corrupted input\n"); |
| if (exit_code != ERROR) exit_code = part_nb == 1 ? ERROR : WARNING; |
| return part_nb == 1 ? -1 : -2; |
| } |
| return method; |
| } |