diff options
author | phk <phk@FreeBSD.org> | 1995-04-15 08:23:55 +0000 |
---|---|---|
committer | phk <phk@FreeBSD.org> | 1995-04-15 08:23:55 +0000 |
commit | d54917fe68724c46f79ba0c6ab1d96735048c4f8 (patch) | |
tree | f14954d443fa7d6d6f6d3e4570dc59ce71b73f5a /sys | |
parent | 7be871777e399ba0efd634a4197c337bae9cf6fb (diff) | |
download | FreeBSD-src-d54917fe68724c46f79ba0c6ab1d96735048c4f8.zip FreeBSD-src-d54917fe68724c46f79ba0c6ab1d96735048c4f8.tar.gz |
The magic code to uncompress a kernel.
Reviewed by: phk
Obtained from: Linux via 386BSD.
Diffstat (limited to 'sys')
-rw-r--r-- | sys/i386/boot/kzipboot/Makefile | 23 | ||||
-rw-r--r-- | sys/i386/boot/kzipboot/README | 49 | ||||
-rw-r--r-- | sys/i386/boot/kzipboot/boot.c | 142 | ||||
-rw-r--r-- | sys/i386/boot/kzipboot/gzip.h | 84 | ||||
-rw-r--r-- | sys/i386/boot/kzipboot/head.S | 10 | ||||
-rw-r--r-- | sys/i386/boot/kzipboot/malloc.c | 229 | ||||
-rw-r--r-- | sys/i386/boot/kzipboot/misc.c | 211 | ||||
-rw-r--r-- | sys/i386/boot/kzipboot/unzip.c | 175 |
8 files changed, 923 insertions, 0 deletions
diff --git a/sys/i386/boot/kzipboot/Makefile b/sys/i386/boot/kzipboot/Makefile new file mode 100644 index 0000000..3ed6f52 --- /dev/null +++ b/sys/i386/boot/kzipboot/Makefile @@ -0,0 +1,23 @@ +# $Id$ + +PROG= kzip.o +SRCS= head.S boot.c unzip.c misc.c malloc.c inflate.c +BINDIR= /usr/lib +.PATH: ${.CURDIR}/../../../kern +NOMAN= toobad + +# Where to load the kernel +KADDR = 0x100000 + +# What segment our code lives in +CSEG = 0x8 + +STRIP= # very important!! don't let kzip.o be stripped + +CFLAGS+= -DKADDR=$(KADDR) -DCSEG=$(CSEG) +CFLAGS+= -DUSE_KERNEL_INFLATE -DKZIP -DCOMCONSOLE=0x3F8 + +kzip.o: ${OBJS} + $(LD) -r -x -o kzip.o $(OBJS) + +.include <bsd.prog.mk> diff --git a/sys/i386/boot/kzipboot/README b/sys/i386/boot/kzipboot/README new file mode 100644 index 0000000..2845cbe --- /dev/null +++ b/sys/i386/boot/kzipboot/README @@ -0,0 +1,49 @@ +/* Beware: mostly obsolete info */ + +This is the first (alpha) release of kernel packer/unpacker +for FreeBSD. It is based on xBoot from Linux, but +hardly rewritten. + +It assumes that: +1) The kernel should be loaded at 0x100000 phys address. +2) The CS selector is equal to 8, which is OK for all + current secondary boot programs. + +Run "make install" to install it. It will place +"kzip" shell script into /usr/sbin, and several files +into /usr/libexec/kzip directory. + +Then try to zip your kernel, for example: + + % kzip /kernel + System size is 462848 + Compressed size 247027 + +It will create file /kernel.kz: + + % ls -l /kernel /kernel.kz + -rwxr-xr-x 1 root 497297 Oct 8 12:41 /386bsd + -rwxrwxr-x 1 root 262144 Oct 8 13:37 /386bsd.kz + +Then rename /kernel.kz to /kernel and reboot. + + % mv /kernel /o3kernel + % mv /kernel.kz /kernel + % sync + % reboot + +During booting, you will see the message: + + Uncompressing kernel...done + Booting the kernel + +The packed kernel should load and run. + +The main problem with packed kernel is the lack of symbol table, +so all commands that require it, will not run. +Among them: ps, savecore, *stat, etc. + +Packed kernels are good for install and fixit floppies. + +Serge Vakulenko, <vak@zebub.msk.su> +Opdated for FreeBSD 2.1 by Gary Jennejohn 12FEB95 diff --git a/sys/i386/boot/kzipboot/boot.c b/sys/i386/boot/kzipboot/boot.c new file mode 100644 index 0000000..16ccefd --- /dev/null +++ b/sys/i386/boot/kzipboot/boot.c @@ -0,0 +1,142 @@ +/* + * FreeBSD kernel unpacker. + * 1993 by Serge Vakulenko + * modified for FreeBSD 2.1 by Gary Jennejohn - 12FEB95 + */ + +#include <machine/cpufunc.h> /* for inb/outb */ +#include <sys/reboot.h> /* for RB_SERIAL */ + +short *videomem; +int curs; +int cols; +int lines; +unsigned int port; + +unsigned char bios[0x100]; + +extern int end, edata; + +void decompress_kernel (void *dest); + +#if 0 +inline void outb (unsigned short x, unsigned char y) +{ + asm volatile ("outb %0, %1" : : "a" (y) , "d" (x)); +} + +inline unsigned char inb (unsigned short x, unsigned char y) +{ + asm volatile ("inb %0, %1" : : "a" (y) , "d" (x)); +} +#endif + +int memcmp (const void *arg1, const void *arg2, unsigned len) +{ + unsigned char *a = (unsigned char*) arg1; + unsigned char *b = (unsigned char*) arg2; + + for (; len-- > 0; ++a, ++b) + if (*a < *b) + return (-1); + else if (*a > *b) + return (1); + return (0); +} + +void *memcpy (void *to, const void *from, unsigned len) +{ + char *f = (char*) from; + char *t = (char*) to; + + while (len-- > 0) + *t++ = *f++; + return (to); +} + +void serial_putchar (unsigned char c) +{ + unsigned char stat; + + do { + stat = inb (COMCONSOLE+5); + } while (stat & 0x20); + + outb (COMCONSOLE, c); +} + +void putchar (unsigned char c) +{ + switch (c) { + case '\n': curs = (curs + cols) / cols * cols; break; + default: videomem[curs++] = 0x0700 | c; break; + } + while (curs >= cols*lines) { + memcpy (videomem, videomem+cols, (lines-1) * cols * 2); + curs -= cols; + } + /* set cursor position */ + outb (port, 0x0e); outb (port+1, curs>>8); + outb (port, 0x0f); outb (port+1, curs); +} + +int use_serial; + +void putstr (char *s) +{ + while (*s) { + if (use_serial) + serial_putchar (*s++); + else + putchar (*s++); + } +} + +void error (char *s) +{ + putstr ("\n\n"); + putstr (s); + putstr ("\n\n -- System halted"); + while (1); /* Halt */ +} + +void boot (int howto) +{ + int l, c, *p; + + /* clear bss */ + for (p = &edata; p < &end; ++p) + *p = 0; + + if (!(use_serial = (howto & RB_SERIAL))) { + /* Test for monochrome video adapter */ + if ((*((unsigned char*) 0x410) & 0x30) == 0x30) + videomem = (void*) 0xb0000; /* monochrome */ + else + videomem = (void*) 0xb8000; /* color */ + + port = *(unsigned short*) 0x463; + cols = *(unsigned short*) 0x44a; + lines = 1 + *(unsigned char*) 0x484; + c = *(unsigned char*) 0x450; + l = *(unsigned char*) 0x451; + + if (lines < 25) + lines = 25; + curs = l*cols + c; + if (curs > lines*cols) + curs = (lines-1) * cols; + } + + /* save bios area */ + memcpy (bios, (void*) 0x400, sizeof (bios)); + + putstr ("Uncompressing kernel..."); + decompress_kernel ((void*) KADDR); + putstr ("done\n"); + + /* restore bios area */ + memcpy ((void*) 0x400, bios, sizeof (bios)); + + putstr ("Booting the kernel\n"); +} diff --git a/sys/i386/boot/kzipboot/gzip.h b/sys/i386/boot/kzipboot/gzip.h new file mode 100644 index 0000000..0ad5ce35 --- /dev/null +++ b/sys/i386/boot/kzipboot/gzip.h @@ -0,0 +1,84 @@ +/* + * gzip.h -- common declarations for all gzip modules + * Copyright (C) 1992-1993 Jean-loup Gailly. + * Adapted for FreeBSD boot unpacker by Serge Vakulenko. + * This is free software; you can redistribute it and/or modify it under the + * terms of the GNU General Public License, see the file COPYING. + */ + +typedef unsigned char uchar; +#ifndef USE_KERNEL_INFLATE +typedef unsigned short ushort; +#endif +typedef unsigned long ulong; + +#define NULL 0 + +#define STORED 0 /* Compression methods */ +#define COMPRESSED 1 +#define PACKED 2 +#define DEFLATED 8 /* methods 3 to 7 reserved */ + +#define INBUFSIZ 0x8000 /* input buffer size */ + +#define OUTBUFSIZ 16384 /* output buffer size */ +#define OUTBUF_EXTRA 2048 /* required by unlzw() */ + +#define GZIP_MAGIC "\037\213" /* gzip files, 1F 8B */ +#define OLD_GZIP_MAGIC "\037\236" /* gzip 0.5 = freeze 1.x */ +#define PKZIP_MAGIC "PK\003\004" /* pkzip files */ +#define PACK_MAGIC "\037\036" /* packed files */ +#define LZW_MAGIC "\037\235" /* lzw files, 1F 9D */ + +/* gzip flag byte */ +#define ASCII_FLAG 0x01 /* file probably ascii text */ +#define CONTINUATION 0x02 /* cont. of multi-part gzip file */ +#define EXTRA_FIELD 0x04 /* extra field present */ +#define ORIG_NAME 0x08 /* original file name present */ +#define COMMENT 0x10 /* file comment present */ +#define ENCRYPTED 0x20 /* file is encrypted */ +#define RESERVED 0xC0 /* reserved */ + +/* window size--must be a power of two, and */ +/* at least 32K for zip's deflate method */ +#define WSIZE 0x8000 + +extern int method; /* compression method */ + +extern uchar inbuf[]; /* input buffer */ +extern uchar outbuf[]; /* output buffer */ +extern uchar window[]; /* Sliding window and suffix table (unlzw) */ + +extern unsigned insize; /* valid bytes in inbuf */ +extern unsigned inptr; /* index of next byte to be processed in inbuf */ +extern unsigned outcnt; /* bytes in output buffer */ + +extern int pkzip; /* set for a pkzip file */ +extern int extended; /* set if extended local header */ +extern ulong crc; /* shift register contents */ +extern ulong output_ptr; /* total output bytes */ + +extern void unzip (void); +extern void check_zipfile (void); +extern void updcrc (uchar *s, unsigned n); +extern void clear_bufs (void); +extern void fill_inbuf (void); +extern void flush_window (void); +extern void error (char *m); +#ifndef USE_KERNEL_INFLATE +extern int inflate (void); +#endif + +static inline uchar get_byte () +{ + if (inptr >= insize) + fill_inbuf (); + return (inbuf[inptr++]); +} + +static inline void put_char (uchar c) +{ + window[outcnt++] = c; + if (outcnt == WSIZE) + flush_window(); +} diff --git a/sys/i386/boot/kzipboot/head.S b/sys/i386/boot/kzipboot/head.S new file mode 100644 index 0000000..a3e8e6d --- /dev/null +++ b/sys/i386/boot/kzipboot/head.S @@ -0,0 +1,10 @@ +/* + * Boot unpacker startup routine. + * Copyright (C) Serge Vakulenko + */ + .text +start: + cli # disable interrupts + call _boot # unpack the kernel image + ljmp $CSEG, $KADDR # jump to unpacked kernel + . = start + 0x500 # skip over warm boot shit diff --git a/sys/i386/boot/kzipboot/malloc.c b/sys/i386/boot/kzipboot/malloc.c new file mode 100644 index 0000000..ef57458 --- /dev/null +++ b/sys/i386/boot/kzipboot/malloc.c @@ -0,0 +1,229 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * malloc.c (Caltech) 2/21/82 + * Chris Kingsley, kingsley@cit-20. + * + * This is a very fast storage allocator. It allocates blocks of a small + * number of different sizes, and keeps free lists of each size. Blocks that + * don't exactly fit are passed up to the next larger size. In this + * implementation, the available sizes are 2^n-4 (or 2^n-10) bytes long. + * This is designed for use in a virtual memory environment. + * + * Modified for stand-alone use (for kzip) by Gary Jennejohn - 12FEB95 + */ +#ifdef USE_KERNEL_INFLATE + +#include <sys/types.h> + +#define NULL 0 + +/* + * The overhead on a block is at least 4 bytes. When free, this space + * contains a pointer to the next free block, and the bottom two bits must + * be zero. When in use, the first byte is set to MAGIC, and the second + * byte is the size index. The remaining bytes are for alignment. + * If range checking is enabled then a second word holds the size of the + * requested block, less 1, rounded up to a multiple of sizeof(RMAGIC). + * The order of elements is critical: ov_magic must overlay the low order + * bits of ov_next, and ov_magic can not be a valid ov_next bit pattern. + */ +union overhead { + union overhead *ov_next; /* when free */ + struct { + u_char ovu_magic; /* magic number */ + u_char ovu_index; /* bucket # */ + } ovu; +#define ov_magic ovu.ovu_magic +#define ov_index ovu.ovu_index +#define ov_rmagic ovu.ovu_rmagic +#define ov_size ovu.ovu_size +}; + +#define MAGIC 0xef /* magic # on accounting info */ +#define RMAGIC 0x5555 /* magic # on range info */ + +#define RSLOP 0 + +/* + * nextf[i] is the pointer to the next free block of size 2^(i+3). The + * smallest allocatable block is 8 bytes. The overhead information + * precedes the data area returned to the user. + */ +#define NBUCKETS 30 +static union overhead *nextf[NBUCKETS]; + +static int pagesz; /* page size */ +static int pagebucket; /* page size bucket */ + +#define STORAGE 40960 /* must be at least this big to handle GENERIC */ +unsigned char storage [STORAGE]; +int next_free; /* need this to emulate sbrk() */ + +#define ASSERT(p) + +static void morecore (int); + +void * +malloc(nbytes, junk1, junk2) /* junk? not used */ + size_t nbytes; + int junk1, junk2; +{ + register union overhead *op; + register int bucket, n; + register unsigned amt; + + /* + * First time malloc is called, setup page size and + * align break pointer so all data will be page aligned. + */ + if (pagesz == 0) { + pagesz = n = 4096; + op = (union overhead *)storage; + n = n - sizeof (*op) - ((int)op & (n - 1)); + if (n < 0) + n += pagesz; + if (n > STORAGE) + return (NULL); + + next_free = n; + + bucket = 0; + amt = 8; + while (pagesz > amt) { + amt <<= 1; + bucket++; + } + pagebucket = bucket; + } + /* + * Convert amount of memory requested into closest block size + * stored in hash buckets which satisfies request. + * Account for space used per block for accounting. + */ + if (nbytes <= (n = pagesz - sizeof (*op) - RSLOP)) { + amt = 8; /* size of first bucket */ + bucket = 0; + n = -(sizeof (*op) + RSLOP); + } else { + amt = pagesz; + bucket = pagebucket; + } + while (nbytes > amt + n) { + amt <<= 1; + if (amt == 0) + return (NULL); + bucket++; + } + /* + * If nothing in hash bucket right now, + * request more memory from the system. + */ + if ((op = nextf[bucket]) == NULL) { + morecore(bucket); + if ((op = nextf[bucket]) == NULL) + return (NULL); + } + + /* remove from linked list */ + nextf[bucket] = op->ov_next; + op->ov_magic = MAGIC; + op->ov_index = bucket; + return ((char *)(op + 1)); +} + +/* + * Allocate more memory to the indicated bucket. + */ +static void +morecore(bucket) + int bucket; +{ + register union overhead *op; + register int sz; /* size of desired block */ + int amt; /* amount to allocate */ + int nblks; /* how many blocks we get */ + + /* + * sbrk_size <= 0 only for big, FLUFFY, requests (about + * 2^30 bytes on a VAX, I think) or for a negative arg. + */ + sz = 1 << (bucket + 3); + + if (sz <= 0) + return; + + if (sz < pagesz) { + amt = pagesz; + nblks = amt / sz; + } else { + amt = sz + pagesz; + nblks = 1; + } + /* no more room! */ + if (amt > (STORAGE - next_free)) + return; + op = (union overhead *)&storage [next_free]; + next_free += amt; + /* + * Add new memory allocated to that on + * free list for this hash bucket. + */ + nextf[bucket] = op; + while (--nblks > 0) { + op->ov_next = (union overhead *)((caddr_t)op + sz); + op = (union overhead *)((caddr_t)op + sz); + } +} + +void +free(cp, junk) /* junk not used */ + void *cp; + int junk; +{ + register int size; + register union overhead *op; + + if (cp == NULL) + return; + op = (union overhead *)((caddr_t)cp - sizeof (union overhead)); + if (op->ov_magic != MAGIC) + return; /* sanity */ + size = op->ov_index; + ASSERT(size < NBUCKETS); + op->ov_next = nextf[size]; /* also clobbers ov_magic */ + nextf[size] = op; +} + +#endif /* USE_KERNEL_INFLATE */ diff --git a/sys/i386/boot/kzipboot/misc.c b/sys/i386/boot/kzipboot/misc.c new file mode 100644 index 0000000..13396f4 --- /dev/null +++ b/sys/i386/boot/kzipboot/misc.c @@ -0,0 +1,211 @@ +/* + * misc.c + * + * This is a collection of several routines from gzip-1.0.3 + * adapted for Linux. + * + * Ported to 386bsd by Serge Vakulenko + */ + +#include "gzip.h" + +uchar inbuf [INBUFSIZ]; +uchar outbuf [OUTBUFSIZ+OUTBUF_EXTRA]; +uchar window [WSIZE]; + +unsigned outcnt; +unsigned insize; +unsigned inptr; + +extern const char input_data[]; +extern const int input_len; + +int input_ptr; + +int method; + +char *output_data; +ulong output_ptr; + +void makecrc (void); +void putstr (char *c); +void *memcpy (void *to, const void *from, unsigned len); +int memcmp (const void *arg1, const void *arg2, unsigned len); + +ulong crc; /* shift register contents */ +ulong crc_32_tab[256]; /* 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. + */ +void updcrc(s, n) +uchar *s; /* pointer to bytes to pump through */ +unsigned n; /* number of bytes in s[] */ +{ + while (n--) + crc = crc_32_tab[(uchar)crc ^ (*s++)] ^ (crc >> 8); +} + +/* + * Clear input and output buffers + */ +void clear_bufs() +{ + outcnt = 0; + insize = inptr = 0; +} + +/* + * Fill the input buffer. This is called only when the buffer is empty + * and at least one byte is really needed. + */ +void 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) + 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"); + inptr = 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); + + output_ptr += outcnt; + outcnt = 0; +} + +/* + * Code to compute the CRC-32 table. Borrowed from + * gzip-1.0.3/makecrc.c. + * Not copyrighted 1990 Mark Adler + */ +void makecrc(void) +{ + ulong c; /* crc shift register */ + ulong 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 const uchar poly[] = { 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(poly)/sizeof(*poly); i++) + e |= 1L << (31 - poly[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; + } +} + +/* + * Check the magic number of the input file and update ofname if an + * original name was given and to_stdout is not set. + * Set inptr to the offset of the next byte to be processed. + */ +static void get_method() +{ + uchar flags; + char magic[2]; /* magic header */ + + magic[0] = get_byte(); + magic[1] = get_byte(); + + method = -1; /* unknown yet */ + extended = pkzip = 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) { + method = get_byte(); + flags = get_byte(); + if (flags & ENCRYPTED) + error("Input is encrypted"); + if (flags & CONTINUATION) + error("Multi part input"); + if (flags & RESERVED) + error("Input has invalid flags"); + + (void) get_byte(); /* Get timestamp */ + (void) get_byte(); + (void) get_byte(); + (void) get_byte(); + + (void) get_byte(); /* Ignore extra flags for the moment */ + (void) get_byte(); /* Ignore OS type for the moment */ + + if (flags & EXTRA_FIELD) { + unsigned len = get_byte(); + len |= get_byte() << 8; + while (len--) + (void) get_byte(); + } + + /* Discard file comment if any */ + if (flags & COMMENT) + while (get_byte()) + continue; + + } 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; + check_zipfile(); + + } else if (memcmp(magic, PACK_MAGIC, 2) == 0) + error("packed input"); + else if (memcmp(magic, LZW_MAGIC, 2) == 0) + error("compressed input"); + if (method == -1) + error("Corrupted input"); +} + +void +decompress_kernel (void *dest) +{ + output_data = dest; + output_ptr = 0; + + input_ptr = 0; + + clear_bufs (); + makecrc (); + get_method (); + unzip (); +} diff --git a/sys/i386/boot/kzipboot/unzip.c b/sys/i386/boot/kzipboot/unzip.c new file mode 100644 index 0000000..b3a9b5a --- /dev/null +++ b/sys/i386/boot/kzipboot/unzip.c @@ -0,0 +1,175 @@ +/* + * unzip.c -- decompress files in gzip or pkzip format. + * Copyright (C) 1992-1993 Jean-loup Gailly + * + * Adapted for Linux booting by Hannu Savolainen 1993 + * Adapted for FreeBSD booting by Serge Vakulenko + * + * This is free software; you can redistribute it and/or modify it under the + * terms of the GNU General Public License, see the file COPYING. + * + * The code in this file is derived from the file funzip.c written + * and put in the public domain by Mark Adler. + */ + +/* + * This version can extract files in gzip or pkzip format. + * For the latter, only the first entry is extracted, and it has to be + * either deflated or stored. + */ + +#include "gzip.h" + +#ifdef USE_KERNEL_INFLATE +#include <sys/types.h> +#include <sys/inflate.h> +#endif + +/* PKZIP header definitions */ +#define LOCSIG 0x04034b50L /* four-byte lead-in (lsb first) */ +#define LOCFLG 6 /* offset of bit flag */ +#define CRPFLG 1 /* bit for encrypted entry */ +#define EXTFLG 8 /* bit for extended local header */ +#define LOCHOW 8 /* offset of compression method */ +#define LOCTIM 10 /* file mod time (for decryption) */ +#define LOCCRC 14 /* offset of crc */ +#define LOCSIZ 18 /* offset of compressed size */ +#define LOCLEN 22 /* offset of uncompressed length */ +#define LOCFIL 26 /* offset of file name field length */ +#define LOCEXT 28 /* offset of extra field length */ +#define LOCHDR 30 /* size of local header, including sig */ +#define EXTHDR 16 /* size of extended local header, inc sig */ + +int pkzip; /* set for a pkzip file */ +int extended; /* set if extended local header */ + +/* Macros for getting two-byte and four-byte header values */ +#define SH(p) ((ushort)(uchar)((p)[0]) | ((ushort)(uchar)((p)[1]) << 8)) +#define LG(p) ((ulong)(SH(p)) | ((ulong)(SH((p)+2)) << 16)) + +/* + * Check zip file and advance inptr to the start of the compressed data. + * Get ofname from the local header if necessary. + */ +void check_zipfile() +{ + uchar *h = inbuf + inptr; /* first local header */ + + /* Check validity of local header, and skip name and extra fields */ + inptr += LOCHDR + SH(h + LOCFIL) + SH(h + LOCEXT); + + if (inptr > insize || LG(h) != LOCSIG) + error("input not a zip"); + + method = h[LOCHOW]; + if (method != STORED && method != DEFLATED) + error("first entry not deflated or stored--can't extract"); + + /* If entry encrypted, decrypt and validate encryption header */ + if (h[LOCFLG] & CRPFLG) + error("encrypted file"); + + /* Save flags for unzip() */ + extended = (h[LOCFLG] & EXTFLG) != 0; + pkzip = 1; +} + +#ifdef USE_KERNEL_INFLATE +int +Flush (void *nu, u_char *buf, u_long cnt) +{ + outcnt = cnt; + flush_window(); + return 0; +} + +int +NextByte (void *nu) +{ + return ((int) get_byte ()); +} + +struct inflate infl; /* put it into the BSS */ + +#endif + +/* + * Unzip in to out. This routine works on both gzip and pkzip files. + * + * IN assertions: the buffer inbuf contains already the beginning of + * the compressed data, from offsets inptr to insize-1 included. + * The magic header has already been checked. The output buffer is cleared. + */ + +void unzip() +{ + ulong orig_crc = 0; /* original crc */ + ulong orig_len = 0; /* original uncompressed length */ + uchar buf[EXTHDR]; /* extended local header */ + int n; + + crc = 0xffffffffL; /* initialize crc */ + + if (pkzip && !extended) { /* crc and length at the end otherwise */ + orig_crc = LG(inbuf + LOCCRC); + orig_len = LG(inbuf + LOCLEN); + } + + /* Decompress */ + if (method == DEFLATED) { +#ifdef USE_KERNEL_INFLATE + int res; + infl.gz_input = NextByte; + infl.gz_output = Flush; + infl.gz_slide = window; + res = inflate (&infl); +#else + int res = inflate(); +#endif + if (res == 3) + error("out of memory"); + else if (res != 0) + error("invalid compressed format"); + + } else if (pkzip && method == STORED) { + register ulong n = LG(inbuf + LOCLEN); + + if (n != LG(inbuf + LOCSIZ)) + error("length mismatch"); + while (n--) + put_char(get_byte()); + } else + error("internal error, invalid method"); + + /* Get the crc and original length */ + if (!pkzip) { + /* crc32 (see algorithm.doc) + * uncompressed input size modulo 2^32 + */ + for (n = 0; n < 8; n++) + buf[n] = get_byte(); /* may cause an error if EOF */ + orig_crc = LG(buf); + orig_len = LG(buf+4); + + } else if (extended) { /* If extended header, check it */ + /* signature - 4bytes: 0x50 0x4b 0x07 0x08 + * CRC-32 value + * compressed size 4-bytes + * uncompressed size 4-bytes + */ + for (n = 0; n < EXTHDR; n++) + buf[n] = get_byte(); /* may cause an error if EOF */ + orig_crc = LG(buf+4); + orig_len = LG(buf+12); + } + + /* Validate decompression */ + if (orig_crc != (crc ^ 0xffffffffL)) + error("crc error"); + if (orig_len != output_ptr) + error("length error"); + + /* Check if there are more entries in a pkzip file */ + if (pkzip && inptr+4 < insize && LG(inbuf+inptr) == LOCSIG) + error("zip file has more than one entry"); +} |