mirror of
https://github.com/freebsd/freebsd-src
synced 2024-09-27 04:05:10 +00:00
The magic code to uncompress a kernel.
Reviewed by: phk Obtained from: Linux via 386BSD.
This commit is contained in:
parent
3e4ece9108
commit
7970b29866
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=7845
23
sys/i386/boot/kzipboot/Makefile
Normal file
23
sys/i386/boot/kzipboot/Makefile
Normal file
|
@ -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>
|
49
sys/i386/boot/kzipboot/README
Normal file
49
sys/i386/boot/kzipboot/README
Normal file
|
@ -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
|
142
sys/i386/boot/kzipboot/boot.c
Normal file
142
sys/i386/boot/kzipboot/boot.c
Normal file
|
@ -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");
|
||||
}
|
84
sys/i386/boot/kzipboot/gzip.h
Normal file
84
sys/i386/boot/kzipboot/gzip.h
Normal file
|
@ -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();
|
||||
}
|
10
sys/i386/boot/kzipboot/head.S
Normal file
10
sys/i386/boot/kzipboot/head.S
Normal file
|
@ -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
|
229
sys/i386/boot/kzipboot/malloc.c
Normal file
229
sys/i386/boot/kzipboot/malloc.c
Normal file
|
@ -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 */
|
211
sys/i386/boot/kzipboot/misc.c
Normal file
211
sys/i386/boot/kzipboot/misc.c
Normal file
|
@ -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 ();
|
||||
}
|
175
sys/i386/boot/kzipboot/unzip.c
Normal file
175
sys/i386/boot/kzipboot/unzip.c
Normal file
|
@ -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");
|
||||
}
|
Loading…
Reference in a new issue