summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorphk <phk@FreeBSD.org>1995-04-15 08:23:55 +0000
committerphk <phk@FreeBSD.org>1995-04-15 08:23:55 +0000
commitd54917fe68724c46f79ba0c6ab1d96735048c4f8 (patch)
treef14954d443fa7d6d6f6d3e4570dc59ce71b73f5a /sys
parent7be871777e399ba0efd634a4197c337bae9cf6fb (diff)
downloadFreeBSD-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/Makefile23
-rw-r--r--sys/i386/boot/kzipboot/README49
-rw-r--r--sys/i386/boot/kzipboot/boot.c142
-rw-r--r--sys/i386/boot/kzipboot/gzip.h84
-rw-r--r--sys/i386/boot/kzipboot/head.S10
-rw-r--r--sys/i386/boot/kzipboot/malloc.c229
-rw-r--r--sys/i386/boot/kzipboot/misc.c211
-rw-r--r--sys/i386/boot/kzipboot/unzip.c175
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");
+}
OpenPOWER on IntegriCloud