diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1995-11-14 08:00:00 +0000 |
---|---|---|
committer | <ralf@linux-mips.org> | 1995-11-14 08:00:00 +0000 |
commit | e7c2a72e2680827d6a733931273a93461c0d8d1b (patch) | |
tree | c9abeda78ef7504062bb2e816bcf3e3c9d680112 /arch/mips/boot | |
parent | ec6044459060a8c9ce7f64405c465d141898548c (diff) |
Import of Linux/MIPS 1.3.0
Diffstat (limited to 'arch/mips/boot')
-rw-r--r-- | arch/mips/boot/Makefile | 47 | ||||
-rw-r--r-- | arch/mips/boot/a.out.c | 254 | ||||
-rw-r--r-- | arch/mips/boot/compressed/Makefile | 45 | ||||
-rw-r--r-- | arch/mips/boot/compressed/cache.S | 162 | ||||
-rw-r--r-- | arch/mips/boot/compressed/crypt.h | 12 | ||||
-rw-r--r-- | arch/mips/boot/compressed/gzip.h | 284 | ||||
-rw-r--r-- | arch/mips/boot/compressed/head.S | 52 | ||||
-rw-r--r-- | arch/mips/boot/compressed/inflate.c | 810 | ||||
-rw-r--r-- | arch/mips/boot/compressed/lzw.h | 42 | ||||
-rw-r--r-- | arch/mips/boot/compressed/misc.c | 438 | ||||
-rw-r--r-- | arch/mips/boot/compressed/piggyback.c | 81 | ||||
-rw-r--r-- | arch/mips/boot/compressed/unzip.c | 180 | ||||
-rw-r--r-- | arch/mips/boot/compressed/xtract.c | 86 | ||||
-rw-r--r-- | arch/mips/boot/head.S | 387 | ||||
-rw-r--r-- | arch/mips/boot/loader.h | 24 | ||||
-rw-r--r-- | arch/mips/boot/milo.c | 316 |
16 files changed, 2833 insertions, 387 deletions
diff --git a/arch/mips/boot/Makefile b/arch/mips/boot/Makefile new file mode 100644 index 000000000..93784137d --- /dev/null +++ b/arch/mips/boot/Makefile @@ -0,0 +1,47 @@ +# +# arch/mips/boot/Makefile +# +# This file is subject to the terms and conditions of the GNU General Public +# License. See the file "COPYING" in the main directory of this archive +# for more details. +# +# Copyright (C) 1995 by Ralf Baechle +# + +.c.s: + $(CC) $(CFLAGS) -S $< +.s.o: + $(AS) $(ASFLAGS) -o $*.o $< +.c.o: + $(CC) $(CFLAGS) -c $< +.S.s: + $(CPP) $(CFLAGS) $< -o $*.s +.S.o: + $(CC) $(CFLAGS) -c $< -o $*.o + +OBJS = milo.o a.out.o + +# +# Fake compressed boot +# +zImage: $(CONFIGURE) $(TOPDIR)/vmlinux + cp $(TOPDIR)/vmlinux $@ + $(STRIP) --discard-all $@ + +zdisk: zImage + mcopy -n zImage a:vmlinux + +dep: + $(CPP) -M *.[cS] > .depend + +clean: + rm -f zImage + +dummy: + +# +# include a dependency file if one exists +# +ifeq (.depend,$(wildcard .depend)) +include .depend +endif diff --git a/arch/mips/boot/a.out.c b/arch/mips/boot/a.out.c new file mode 100644 index 000000000..15515b219 --- /dev/null +++ b/arch/mips/boot/a.out.c @@ -0,0 +1,254 @@ +/* + * arch/mips/boot/milo.c + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1994, 1995 by Ralf Baechle + * Copyright (C) 1993 by Hamish Macdonald + */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/file.h> + +#include "loader.h" + +static int kfd; +static struct exec kexec; +static off_t filesize; +static struct nlist *syms; +static char *strs; +static long strsize, numsyms; + +/* + * Read a symbol from the kernel executable + */ +static struct nlist *aout_get_nlist(char *symbol) +{ + struct nlist *nl, *p = NULL; + + for (nl = syms; nl < syms + numsyms; nl++) { + /* + * We accept only extern visible .text, .data and .bss symbols. + */ + if (strcmp (symbol, strs + nl->n_un.n_strx) == 0 + && ((nl->n_type == N_TEXT | N_EXT) || + (nl->n_type == N_DATA | N_EXT) || + (nl->n_type == N_BSS | N_EXT))) { + p = (struct nlist *)malloc (sizeof (struct nlist) + + strlen(strs + nl->n_un.n_strx) + 1); + if (!p) + break; + *p = *nl; + p->n_un.n_name = (char *)(p+1); + strcpy (p->n_un.n_name, strs + nl->n_un.n_strx); + } + } + return p; +} + +/* + * Return a pointer to the internal symbol + */ +static char *aout_ld_isymbol(char *symbol) +{ + static char isymbol[64]; + + strcpy(isymbol, STR(C_LABEL_PREFIX)); + strcat(isymbol, symbol); + + return isymbol; +} + +/* + * Return base address for the loaded kernel + */ +static u_long aout_get_kbase(void) +{ + return (u_long) kexec.a_entry; +} + +/* + * Return size of kernel code + data + */ +static u_long aout_get_ksize(void) +{ + return (u_long) (kexec.a_text + kexec.a_data); +} + +/* + * Load a.out kernel into memory + */ +static int aout_load_kernel(void *mem) +{ + if (lseek (kfd, N_TXTOFF(kexec), L_SET) == -1) + { + fprintf (stderr, "Failed to seek to text\n\r"); + exit (EXIT_FAILURE); + } + if (read (kfd, mem, kexec.a_text) != kexec.a_text) + { + fprintf (stderr, "Failed to read text\n\r"); + exit (EXIT_FAILURE); + } + if (lseek (kfd, N_DATOFF(kexec), L_SET) == -1) + { + fprintf (stderr, "Failed to seek to data\n\r"); + exit (EXIT_FAILURE); + } + if (read (kfd, mem + kexec.a_text, kexec.a_data) != kexec.a_data) + { + fprintf (stderr, "Failed to read data\n\r"); + exit (EXIT_FAILURE); + } + close (kfd); + + return 0; +} + +/* + * Print some statistics about the kernel + */ +static void aout_print_stats(void) +{ + printf("Kernel text at 0x%08lx, size %d bytes\n\r", + kexec.a_entry + N_TXTADDR(kexec), kexec.a_text); + printf("Kernel data at 0x%08lx, size %d bytes\n\r", + kexec.a_entry + N_DATADDR(kexec), kexec.a_data ); + printf("Kernel bss at 0x%08lx, size %d bytes\n\r", + kexec.a_entry + N_BSSADDR(kexec), kexec.a_bss ); +} + +static int aout_open_kernel(char *kernel) +{ + int sfd; + + /* + * open kernel executable and read exec header + */ + if (debuglevel >= 2) + { + printf("aout_open_kernel(): Open kernel file\r\n"); + fflush(stdout); + } + if ((kfd = open (kernel, O_RDONLY)) == -1) + { + printf ("Unable to open kernel file %s\r\n", kernel); + exit (EXIT_FAILURE); + } + if (debuglevel >= 2) + { + printf("aout_open_kernel(): Reading exec header\r\n"); + fflush(stdout); + } + if (read (kfd, (void *)&kexec, sizeof(kexec)) != sizeof(kexec)) + { + printf ("Unable to read exec header from %s\n\r", kernel); + exit (EXIT_FAILURE); + } + + /* + * Is this really a kernel??? + * (My Mips docs mention SMAGIC, too, but don't tell about what + * a SMAGIC file exactly is. If someone knows, please tell me -Ralf) + * + * FIXME: QMAGIC doesn't work yet. + */ + if(N_MAGIC(kexec) != OMAGIC && + N_MAGIC(kexec) != NMAGIC && + N_MAGIC(kexec) != ZMAGIC && + N_MAGIC(kexec) != QMAGIC) + { + fprintf(stderr, "Kernel %s is no MIPS binary.\r\n", kernel); + exit (EXIT_FAILURE); + } + if(N_MACHTYPE(kexec) != M_MIPS1 && + N_MACHTYPE(kexec) != M_MIPS2) + { + fprintf(stderr, "Kernel %s is no MIPS binary.\r\n", kernel); + exit (EXIT_FAILURE); + } + + /* + * Read file's symbol table + */ + /* + * Open kernel executable and read exec header - we need to + * use a second open file since the ARC standard doesn't + * support reverse seeking on files which might run us in + * trouble later on. + */ + if (debuglevel >= 2) + { + printf("aout_open_kernel(): Open kernel file\r\n"); + fflush(stdout); + } + if ((sfd = open (kernel, O_RDONLY)) == -1) + { + printf ("Unable to open kernel %s for reading symbols.\r\n", kernel); + exit (EXIT_FAILURE); + } + syms = (struct nlist *)malloc (kexec.a_syms); + if (!syms) + { + return 0; + } + + if (debuglevel >= 2) + { + printf("aout_open_kernel(): Seeking to symbol table\r\n"); + fflush(stdout); + } + lseek (sfd, N_SYMOFF(kexec), L_SET); + if (debuglevel >= 2) + { + printf("aout_open_kernel(): Reading symbol table\r\n"); + fflush(stdout); + } + read (sfd, syms, kexec.a_syms); + numsyms = kexec.a_syms / sizeof (struct nlist); + filesize = lseek (sfd, 0L, L_XTND); + strsize = filesize - N_STROFF(kexec); + strs = (char *)malloc (strsize); + + if (!strs) + { + free (syms); + syms = NULL; + return 0; + } + + lseek (sfd, N_STROFF(kexec), L_SET); + read (sfd, strs, strsize); + close(sfd); + + return 0; +} + +static void aout_close_kernel(void) +{ + if (strs) + { + free (strs); + strs = NULL; + } + if (syms) + { + free (syms); + syms = NULL; + } + close(kfd); +} + +struct loader loader_aout = { + aout_get_nlist, + aout_ld_isymbol, + aout_get_kbase, + aout_get_ksize, + aout_load_kernel, + aout_print_stats, + aout_open_kernel, + aout_close_kernel +}; diff --git a/arch/mips/boot/compressed/Makefile b/arch/mips/boot/compressed/Makefile new file mode 100644 index 000000000..228ee83bc --- /dev/null +++ b/arch/mips/boot/compressed/Makefile @@ -0,0 +1,45 @@ +# +# linux/arch/i386/boot/compressed/Makefile +# +# create a compressed vmlinux image from the original vmlinux +# + +HEAD = head.o +SYSTEM = $(TOPDIR)/vmlinux + +OBJECTS = $(HEAD) inflate.o unzip.o misc.o + +CFLAGS = -O2 -DSTDC_HEADERS + +.c.s: + $(CC) $(CFLAGS) -S $< +.s.o: + $(AS) $(ASFLAGS) -o $*.o $< +.c.o: + $(CC) $(CFLAGS) -c $< +.S.s: + $(CPP) $(CFLAGS) $< -o $*.s +.S.o: + $(CC) $(CFLAGS) -c $< -o $*.o + +all: vmlinux + +vmlinux: piggy.o $(OBJECTS) + $(LD) $(ZLINKFLAGS) -o vmlinux $(OBJECTS) piggy.o + +head.o: head.s + +head.s: head.S $(TOPDIR)/include/linux/tasks.h + $(CPP) -traditional head.S -o head.s + +piggy.o: $(SYSTEM) xtract piggyback + ./xtract $(SYSTEM) | gzip -9 | ./piggyback > piggy.o + +xtract: xtract.c + $(HOSTCC) $(CFLAGS) -o xtract xtract.c + +piggyback: piggyback.c + $(HOSTCC) $(CFLAGS) -o piggyback piggyback.c + +clean: + rm -f xtract piggyback vmlinux diff --git a/arch/mips/boot/compressed/cache.S b/arch/mips/boot/compressed/cache.S new file mode 100644 index 000000000..8e7fff0c1 --- /dev/null +++ b/arch/mips/boot/compressed/cache.S @@ -0,0 +1,162 @@ +/* + * arch/mips/boot/compressed/cache.S + * + * Copyright (C) 1994, 1995 Waldorf Electronics + * Written by Ralf Baechle + * + * Flush instruction/data caches + * + * Parameters: a0 - starting address to flush + * a1 - size of area to be flushed + * a2 - which caches to be flushed + * + * FIXME: - ignores parameters in a0/a1 + * - doesn't know about second level caches + */ +#include <linux/autoconf.h> + +#include <asm/asm.h> +#include <asm/cachectl.h> +#include <asm/mipsregs.h> +#include <asm/segment.h> + +#ifdef __R4000__ + +/* + * Some bits in the config register + */ +#define CONFIG_IB (1<<5) +#define CONFIG_DB (1<<4) + + /* + * Flush instruction/data caches + * + * Parameters: a0 - starting address to flush + * a1 - size of area to be flushed + * a2 - which caches to be flushed + * + */ + + .text + + .set noreorder + LEAF(cacheflush) + andi t1,a2,DCACHE + beqz t1,do_icache + li t0,KSEG0 # delay slot + + /* + * Writeback data cache, even lines + */ + li t1,CACHELINES-1 +1: cache Index_Writeback_Inv_D,0(t0) + cache Index_Writeback_Inv_D,32(t0) + cache Index_Writeback_Inv_D,64(t0) + cache Index_Writeback_Inv_D,96(t0) + cache Index_Writeback_Inv_D,128(t0) + cache Index_Writeback_Inv_D,160(t0) + cache Index_Writeback_Inv_D,192(t0) + cache Index_Writeback_Inv_D,224(t0) + cache Index_Writeback_Inv_D,256(t0) + cache Index_Writeback_Inv_D,288(t0) + cache Index_Writeback_Inv_D,320(t0) + cache Index_Writeback_Inv_D,352(t0) + cache Index_Writeback_Inv_D,384(t0) + cache Index_Writeback_Inv_D,416(t0) + cache Index_Writeback_Inv_D,448(t0) + cache Index_Writeback_Inv_D,480(t0) + addiu t0,512 + bnez t1,1b + subu t1,1 + + /* + * Writeback data cache, odd lines + * Only needed for 16 byte line size + */ + mfc0 t1,CP0_CONFIG + andi t1,CONFIG_IB + bnez t1,do_icache + li t1,CACHELINES-1 +1: cache Index_Writeback_Inv_D,16(t0) + cache Index_Writeback_Inv_D,48(t0) + cache Index_Writeback_Inv_D,80(t0) + cache Index_Writeback_Inv_D,112(t0) + cache Index_Writeback_Inv_D,144(t0) + cache Index_Writeback_Inv_D,176(t0) + cache Index_Writeback_Inv_D,208(t0) + cache Index_Writeback_Inv_D,240(t0) + cache Index_Writeback_Inv_D,272(t0) + cache Index_Writeback_Inv_D,304(t0) + cache Index_Writeback_Inv_D,336(t0) + cache Index_Writeback_Inv_D,368(t0) + cache Index_Writeback_Inv_D,400(t0) + cache Index_Writeback_Inv_D,432(t0) + cache Index_Writeback_Inv_D,464(t0) + cache Index_Writeback_Inv_D,496(t0) + addiu t0,512 + bnez t1,1b + subu t1,1 + +do_icache: andi t1,a2,ICACHE + beqz t1,done + + /* + * Flush instruction cache, even lines + */ + lui t0,0x8000 + li t1,CACHELINES-1 +1: cache Index_Invalidate_I,0(t0) + cache Index_Invalidate_I,32(t0) + cache Index_Invalidate_I,64(t0) + cache Index_Invalidate_I,96(t0) + cache Index_Invalidate_I,128(t0) + cache Index_Invalidate_I,160(t0) + cache Index_Invalidate_I,192(t0) + cache Index_Invalidate_I,224(t0) + cache Index_Invalidate_I,256(t0) + cache Index_Invalidate_I,288(t0) + cache Index_Invalidate_I,320(t0) + cache Index_Invalidate_I,352(t0) + cache Index_Invalidate_I,384(t0) + cache Index_Invalidate_I,416(t0) + cache Index_Invalidate_I,448(t0) + cache Index_Invalidate_I,480(t0) + addiu t0,512 + bnez t1,1b + subu t1,1 + + /* + * Flush instruction cache, even lines + * Only needed for 16 byte line size + */ + mfc0 t1,CP0_CONFIG + andi t1,CONFIG_DB + bnez t1,done + li t1,CACHELINES-1 +1: cache Index_Invalidate_I,16(t0) + cache Index_Invalidate_I,48(t0) + cache Index_Invalidate_I,80(t0) + cache Index_Invalidate_I,112(t0) + cache Index_Invalidate_I,144(t0) + cache Index_Invalidate_I,176(t0) + cache Index_Invalidate_I,208(t0) + cache Index_Invalidate_I,240(t0) + cache Index_Invalidate_I,272(t0) + cache Index_Invalidate_I,304(t0) + cache Index_Invalidate_I,336(t0) + cache Index_Invalidate_I,368(t0) + cache Index_Invalidate_I,400(t0) + cache Index_Invalidate_I,432(t0) + cache Index_Invalidate_I,464(t0) + cache Index_Invalidate_I,496(t0) + addiu t0,512 + bnez t1,1b + subu t1,1 + +done: j ra + nop + END(sys_cacheflush) + +#else /* !defined (__R4000__) */ +#error "No R3000 cacheflushing implemented yet!" +#endif /* !defined (__R4000__) */ diff --git a/arch/mips/boot/compressed/crypt.h b/arch/mips/boot/compressed/crypt.h new file mode 100644 index 000000000..2a4c203ca --- /dev/null +++ b/arch/mips/boot/compressed/crypt.h @@ -0,0 +1,12 @@ +/* crypt.h (dummy version) -- do not perform encryption + * Hardly worth copyrighting :-) + */ + +#ifdef CRYPT +# undef CRYPT /* dummy version */ +#endif + +#define RAND_HEAD_LEN 12 /* length of encryption random header */ + +#define zencode +#define zdecode diff --git a/arch/mips/boot/compressed/gzip.h b/arch/mips/boot/compressed/gzip.h new file mode 100644 index 000000000..2f738b945 --- /dev/null +++ b/arch/mips/boot/compressed/gzip.h @@ -0,0 +1,284 @@ +/* gzip.h -- common declarations for all gzip modules + * Copyright (C) 1992-1993 Jean-loup Gailly. + * 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. + */ + +#if defined(__STDC__) || defined(PROTO) +# define OF(args) args +#else +# define OF(args) () +#endif + +#ifdef __STDC__ + typedef void *voidp; +#else + typedef char *voidp; +#endif + +/* I don't like nested includes, but the string functions are used too often */ +#if defined(HAVE_STRING_H) || defined(STDC_HEADERS) +# include <string.h> +# define memzero(s, n) memset ((s), 0, (n)) +#else +# include <strings.h> +# define strchr index +# define strrchr rindex +# define memcpy(d, s, n) bcopy((s), (d), (n)) +# define memcmp(s1, s2, n) bcmp((s1), (s2), (n)) +# define memzero(s, n) bzero((s), (n)) +#endif + +#if !defined(STDC_HEADERS) && defined(HAVE_MEMORY_H) +# include <memory.h> +#endif + +#ifndef RETSIGTYPE +# define RETSIGTYPE void +#endif + +#define local static + +typedef unsigned char uch; +typedef unsigned short ush; +typedef unsigned long ulg; + +/* Return codes from gzip */ +#define OK 0 +#define ERROR 1 +#define WARNING 2 + +/* Compression methods (see algorithm.doc) */ +#define STORED 0 +#define COMPRESSED 1 +#define PACKED 2 +/* methods 3 to 7 reserved */ +#define DEFLATED 8 +extern int method; /* compression method */ + +/* To save memory for 16 bit systems, some arrays are overlayed between + * the various modules: + * deflate: prev+head window d_buf l_buf outbuf + * unlzw: tab_prefix tab_suffix stack inbuf outbuf + * inflate: window inbuf + * unpack: window inbuf + * For compression, input is done in window[]. For decompression, output + * is done in window except for unlzw. + */ + +#ifndef INBUFSIZ +# define INBUFSIZ 0x8000 /* input buffer size */ +#endif +#define INBUF_EXTRA 64 /* required by unlzw() */ + +#ifndef OUTBUFSIZ +# define OUTBUFSIZ 16384 /* output buffer size */ +#endif +#define OUTBUF_EXTRA 2048 /* required by unlzw() */ + +#define DIST_BUFSIZE 0x8000 /* buffer for distances, see trees.c */ + +#ifdef DYN_ALLOC +# define EXTERN(type, array) extern type * near array +# define DECLARE(type, array, size) type * near array +# define ALLOC(type, array, size) { \ + array = (type*)fcalloc((unsigned)(((size)+1L)/2), 2*sizeof(type)); \ + if (array == NULL) error("insufficient memory"); \ + } +# define FREE(array) {if (array != NULL) fcfree(array), array=NULL;} +#else +# define EXTERN(type, array) extern type array[] +# define DECLARE(type, array, size) type array[size] +# define ALLOC(type, array, size) +# define FREE(array) +#endif + +EXTERN(uch, inbuf); /* input buffer */ +EXTERN(uch, outbuf); /* output buffer */ +EXTERN(ush, d_buf); /* buffer for distances, see trees.c */ +EXTERN(uch, window); /* Sliding window and suffix table (unlzw) */ +#define tab_suffix window +#ifndef MAXSEG_64K +# define tab_prefix prev /* hash link (see deflate.c) */ +# define head (prev+WSIZE) /* hash head (see deflate.c) */ + EXTERN(ush, tab_prefix); /* prefix code (see unlzw.c) */ +#else +# define tab_prefix0 prev +# define head tab_prefix1 + EXTERN(ush, tab_prefix0); /* prefix for even codes */ + EXTERN(ush, tab_prefix1); /* prefix for odd codes */ +#endif + +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 long bytes_in; /* number of input bytes */ +extern long bytes_out; /* number of output bytes */ +extern long overhead; /* number of bytes in gzip header */ + +#define isize bytes_in +/* for compatibility with old zip sources (to be cleaned) */ + +extern int ifd; /* input file descriptor */ +extern int ofd; /* output file descriptor */ +extern char ifname[]; /* input filename or "stdin" */ +extern char ofname[]; /* output filename or "stdout" */ + +extern ulg time_stamp; /* original time stamp (modification time) */ +extern long ifile_size; /* input file size, -1 for devices (debug only) */ + +extern int exit_code; /* program exit code */ + +typedef int file_t; /* Do not use stdio */ +#define NO_FILE (-1) /* in memory compression */ + + +#define GZIP_MAGIC "\037\213" /* Magic header for gzip files, 1F 8B */ +#define OLD_GZIP_MAGIC "\037\236" /* Magic header for gzip 0.5 = freeze 1.x */ +#define PKZIP_MAGIC "PK\003\004" /* Magic header for pkzip files */ +#define PACK_MAGIC "\037\036" /* Magic header for packed files */ + +/* gzip flag byte */ +#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ +#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */ +#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ +#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ +#define COMMENT 0x10 /* bit 4 set: file comment present */ +#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */ +#define RESERVED 0xC0 /* bit 6,7: reserved */ + +/* internal file attribute */ +#define UNKNOWN (-1) +#define BINARY 0 +#define ASCII 1 + +#ifndef WSIZE +# define WSIZE 0x8000 /* window size--must be a power of two, and */ +#endif /* at least 32K for zip's deflate method */ + +#define MIN_MATCH 3 +#define MAX_MATCH 258 +/* The minimum and maximum match lengths */ + +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) +/* Minimum amount of lookahead, except at the end of the input file. + * See deflate.c for comments about the MIN_MATCH+1. + */ + +#define MAX_DIST (WSIZE-MIN_LOOKAHEAD) +/* In order to simplify the code, particularly on 16 bit machines, match + * distances are limited to MAX_DIST instead of WSIZE. + */ + +extern int decrypt; /* flag to turn on decryption */ +extern int save_orig_name; /* set if original name must be saved */ +extern int verbose; /* be verbose (-v) */ +extern int level; /* compression level */ +extern int test; /* check .z file integrity */ +extern int to_stdout; /* output to stdout (-c) */ + +#define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf()) + +/* put_byte is used for the compressed output, put_char for the + * uncompressed output. However unlzw() uses window for its + * suffix table instead of its output buffer, so it does not use put_char. + * (to be cleaned up). + */ +#define put_byte(c) {outbuf[outcnt++]=(uch)(c); if (outcnt==OUTBUFSIZ)\ + flush_outbuf();} +#define put_char(c) {window[outcnt++]=(uch)(c); if (outcnt==WSIZE)\ + flush_window();} + +/* Output a 16 bit value, lsb first */ +#define put_short(w) \ +{ if (outcnt < OUTBUFSIZ-2) { \ + outbuf[outcnt++] = (uch) ((w) & 0xff); \ + outbuf[outcnt++] = (uch) ((ush)(w) >> 8); \ + } else { \ + put_byte((uch)((w) & 0xff)); \ + put_byte((uch)((ush)(w) >> 8)); \ + } \ +} + +/* Output a 32 bit value to the bit stream, lsb first */ +#define put_long(n) { \ + put_short((n) & 0xffff); \ + put_short(((ulg)(n)) >> 16); \ +} + +#define seekable() 0 /* force sequential output */ +#define translate_eol 0 /* no option -a yet */ + +#define tolow(c) (isupper(c) ? (c)-'A'+'a' : (c)) /* force to lower case */ + +/* Macros for getting two-byte and four-byte header values */ +#define SH(p) ((ush)(uch)((p)[0]) | ((ush)(uch)((p)[1]) << 8)) +#define LG(p) ((ulg)(SH(p)) | ((ulg)(SH((p)+2)) << 16)) + +/* Diagnostic functions */ +#ifdef DEBUG +# define Assert(cond,msg) {if(!(cond)) error(msg);} +# define Trace(x) fprintf x +# define Tracev(x) {if (verbose) fprintf x ;} +# define Tracevv(x) {if (verbose>1) fprintf x ;} +# define Tracec(c,x) {if (verbose && (c)) fprintf x ;} +# define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;} +#else +# define Assert(cond,msg) +# define Trace(x) +# define Tracev(x) +# define Tracevv(x) +# define Tracec(c,x) +# define Tracecv(c,x) +#endif + + /* in zip.c: */ +extern void zip OF((int in, int out)); +extern int file_read OF((char *buf, unsigned size)); + + /* in unzip.c */ +extern void unzip OF((int in, int out)); +extern int check_zipfile OF((int in)); + + /* in unpack.c */ +extern void unpack OF((int in, int out)); + + /* in gzip.c */ +RETSIGTYPE abort_gzip OF((void)); + + /* in deflate.c */ +void lm_init OF((int pack_level, ush *flags)); +ulg deflate OF((void)); + + /* in trees.c */ +void ct_init OF((ush *attr, int *method)); +int ct_tally OF((int dist, int lc)); +ulg flush_block OF((char *buf, ulg stored_len, int eof)); + + /* in bits.c */ +void bi_init OF((file_t zipfile)); +void send_bits OF((int value, int length)); +unsigned bi_reverse OF((unsigned value, int length)); +void bi_windup OF((void)); +void copy_block OF((char *buf, unsigned len, int header)); +extern int (*read_buf) OF((char *buf, unsigned size)); + + /* in util.c: */ +extern ulg updcrc OF((uch *s, unsigned n)); +extern void clear_bufs OF((void)); +extern int fill_inbuf OF((void)); +extern void flush_outbuf OF((void)); +extern void flush_window OF((void)); +extern char *strlwr OF((char *s)); +extern char *basename OF((char *fname)); +extern char *add_envopt OF((int *argcp, char ***argvp, char *env)); +extern void error OF((char *m)); +extern void warn OF((char *a, char *b)); +extern void read_error OF((void)); +extern void write_error OF((void)); +extern void display_ratio OF((long num, long den)); +extern voidp xmalloc OF((unsigned int size)); + + /* in inflate.c */ +extern int inflate OF((void)); diff --git a/arch/mips/boot/compressed/head.S b/arch/mips/boot/compressed/head.S new file mode 100644 index 000000000..0ca599563 --- /dev/null +++ b/arch/mips/boot/compressed/head.S @@ -0,0 +1,52 @@ +/* + * arch/mips/boot/compressed/head.S + * + * Copyright (C) 1995 by Ralf Baechle + * + * Head.S contains the MIPS exception handler and startup code. + */ + +#include <asm/asm.h> + + .text + .set noreorder +/* + * Compressed kernel entry + */ + NESTED(kernel_entry, 16, sp) + /* + * Set EXL in c0_status. The results in the lowest two + * gigabytes identity mapped. + */ + mfc0 t0,CP0_STATUS + ori t0,4 + mtc0 t0,CP0_STATUS + + /* + * Clear BSS first so that there are no surprises... + */ + la t0,_edata + la t1,_end + sw zero,(t0) +1: addiu t0,4 + bnel t0,t1,1b + sw zero,(t0) + END(kernel_entry) + + /* + * Do the decompression, and jump to the new kernel.. + */ + jal C_LABEL(decompress_kernel) + nop + + /* + * Flush caches + */ + jal C_LABEL(cacheflush) + + /* + * Jump into the decompressed kernel + */ + la t0,KSEG0 + jr t0 + nop diff --git a/arch/mips/boot/compressed/inflate.c b/arch/mips/boot/compressed/inflate.c new file mode 100644 index 000000000..848fef6ae --- /dev/null +++ b/arch/mips/boot/compressed/inflate.c @@ -0,0 +1,810 @@ +#define DEBG(x) +#define DEBG1(x) +/* inflate.c -- Not copyrighted 1992 by Mark Adler + version c10p1, 10 January 1993 */ + +/* + * Adapted for booting Linux by Hannu Savolainen 1993 + * based on gzip-1.0.3 + */ + +#ifndef lint +static char rcsid[] = "$Id: inflate.c,v 0.10 1993/02/04 13:21:06 jloup Exp $"; +#endif + +#include "gzip.h" +#define slide window + +#if defined(STDC_HEADERS) || defined(HAVE_STDLIB_H) +# include <sys/types.h> +# include <stdlib.h> +#endif + +struct huft { + uch e; /* number of extra bits or operation */ + uch b; /* number of bits in this code or subcode */ + union { + ush n; /* literal, length base, or distance base */ + struct huft *t; /* pointer to next level of table */ + } v; +}; + + +/* Function prototypes */ +int huft_build OF((unsigned *, unsigned, unsigned, ush *, ush *, + struct huft **, int *)); +int huft_free OF((struct huft *)); +int inflate_codes OF((struct huft *, struct huft *, int, int)); +int inflate_stored OF((void)); +int inflate_fixed OF((void)); +int inflate_dynamic OF((void)); +int inflate_block OF((int *)); +int inflate OF((void)); + + +#define wp outcnt +#define flush_output(w) (wp=(w),flush_window()) + +/* Tables for deflate from PKZIP's appnote.txt. */ +static unsigned border[] = { /* Order of the bit length code lengths */ + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; +static ush cplens[] = { /* Copy lengths for literal codes 257..285 */ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; + /* note: see note #13 above about the 258 in this list. */ +static ush cplext[] = { /* Extra bits for literal codes 257..285 */ + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, + 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99}; /* 99==invalid */ +static ush cpdist[] = { /* Copy offsets for distance codes 0..29 */ + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577}; +static ush cpdext[] = { /* Extra bits for distance codes */ + 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, + 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, + 12, 12, 13, 13}; + + +ulg bb; /* bit buffer */ +unsigned bk; /* bits in bit buffer */ + +ush mask_bits[] = { + 0x0000, + 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, + 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff +}; + +#ifdef CRYPT + uch cc; +# define NEXTBYTE() \ + (decrypt ? (cc = get_byte(), zdecode(cc), cc) : get_byte()) +#else +# define NEXTBYTE() (uch)get_byte() +#endif +#define NEEDBITS(n) {while(k<(n)){b|=((ulg)NEXTBYTE())<<k;k+=8;}} +#define DUMPBITS(n) {b>>=(n);k-=(n);} + +int lbits = 9; /* bits in base literal/length lookup table */ +int dbits = 6; /* bits in base distance lookup table */ + + +/* If BMAX needs to be larger than 16, then h and x[] should be ulg. */ +#define BMAX 16 /* maximum bit length of any code (16 for explode) */ +#define N_MAX 288 /* maximum number of codes in any set */ + + +unsigned hufts; /* track memory usage */ + + +int huft_build(b, n, s, d, e, t, m) +unsigned *b; /* code lengths in bits (all assumed <= BMAX) */ +unsigned n; /* number of codes (assumed <= N_MAX) */ +unsigned s; /* number of simple-valued codes (0..s-1) */ +ush *d; /* list of base values for non-simple codes */ +ush *e; /* list of extra bits for non-simple codes */ +struct huft **t; /* result: starting table */ +int *m; /* maximum lookup bits, returns actual */ +/* Given a list of code lengths and a maximum table size, make a set of + tables to decode that set of codes. Return zero on success, one if + the given code set is incomplete (the tables are still built in this + case), two if the input is invalid (all zero length codes or an + oversubscribed set of lengths), and three if not enough memory. */ +{ + unsigned a; /* counter for codes of length k */ + unsigned c[BMAX+1]; /* bit length count table */ + unsigned f; /* i repeats in table every f entries */ + int g; /* maximum code length */ + int h; /* table level */ + register unsigned i; /* counter, current code */ + register unsigned j; /* counter */ + register int k; /* number of bits in current code */ + int l; /* bits per table (returned in m) */ + register unsigned *p; /* pointer into c[], b[], or v[] */ + register struct huft *q; /* points to current table */ + struct huft r; /* table entry for structure assignment */ + struct huft *u[BMAX]; /* table stack */ + unsigned v[N_MAX]; /* values in order of bit length */ + register int w; /* bits before this table == (l * h) */ + unsigned x[BMAX+1]; /* bit offsets, then code stack */ + unsigned *xp; /* pointer into x */ + int y; /* number of dummy codes added */ + unsigned z; /* number of entries in current table */ + +DEBG("huft1 "); + + /* Generate counts for each bit length */ + memzero(c, sizeof(c)); + p = b; i = n; + do { + c[*p++]++; /* assume all entries <= BMAX */ + } while (--i); + if (c[0] == n) /* null input--all zero length codes */ + { + *t = (struct huft *)NULL; + *m = 0; + return 0; + } + +DEBG("huft2 "); + + /* Find minimum and maximum length, bound *m by those */ + l = *m; + for (j = 1; j <= BMAX; j++) + if (c[j]) + break; + k = j; /* minimum code length */ + if ((unsigned)l < j) + l = j; + for (i = BMAX; i; i--) + if (c[i]) + break; + g = i; /* maximum code length */ + if ((unsigned)l > i) + l = i; + *m = l; + +DEBG("huft3 "); + + /* Adjust last length count to fill out codes, if needed */ + for (y = 1 << j; j < i; j++, y <<= 1) + if ((y -= c[j]) < 0) + return 2; /* bad input: more codes than bits */ + if ((y -= c[i]) < 0) + return 2; + c[i] += y; + +DEBG("huft4 "); + + /* Generate starting offsets into the value table for each length */ + x[1] = j = 0; + p = c + 1; xp = x + 2; + while (--i) { /* note that i == g from above */ + *xp++ = (j += *p++); + } + +DEBG("huft5 "); + + /* Make a table of values in order of bit lengths */ + p = b; i = 0; + do { + if ((j = *p++) != 0) + v[x[j]++] = i; + } while (++i < n); + +DEBG("h6 "); + + /* Generate the Huffman codes and for each, make the table entries */ + x[0] = i = 0; /* first Huffman code is zero */ + p = v; /* grab values in bit order */ + h = -1; /* no tables yet--level -1 */ + w = -l; /* bits decoded == (l * h) */ + u[0] = (struct huft *)NULL; /* just to keep compilers happy */ + q = (struct huft *)NULL; /* ditto */ + z = 0; /* ditto */ +DEBG("h6a "); + + /* go through the bit lengths (k already is bits in shortest code) */ + for (; k <= g; k++) + { +DEBG("h6b "); + a = c[k]; + while (a--) + { +DEBG("h6b1 "); + /* here i is the Huffman code of length k bits for value *p */ + /* make tables up to required level */ + while (k > w + l) + { +DEBG1("1 "); + h++; + w += l; /* previous table always l bits */ + + /* compute minimum size table less than or equal to l bits */ + z = (z = g - w) > (unsigned)l ? l : z; /* upper limit on table size */ + if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */ + { /* too few codes for k-w bit table */ +DEBG1("2 "); + f -= a + 1; /* deduct codes from patterns left */ + xp = c + k; + while (++j < z) /* try smaller tables up to z bits */ + { + if ((f <<= 1) <= *++xp) + break; /* enough codes to use up j bits */ + f -= *xp; /* else deduct codes from patterns */ + } + } +DEBG1("3 "); + z = 1 << j; /* table entries for j-bit table */ + + /* allocate and link in new table */ + q = (struct huft *)malloc((z + 1)*sizeof(struct huft)); +DEBG1("4 "); + hufts += z + 1; /* track memory usage */ + *t = q + 1; /* link to list for huft_free() */ + *(t = &(q->v.t)) = (struct huft *)NULL; + u[h] = ++q; /* table starts after link */ + +DEBG1("5 "); + /* connect to last table, if there is one */ + if (h) + { + x[h] = i; /* save pattern for backing up */ + r.b = (uch)l; /* bits to dump before this table */ + r.e = (uch)(16 + j); /* bits in this table */ + r.v.t = q; /* pointer to this table */ + j = i >> (w - l); /* (get around Turbo C bug) */ + u[h-1][j] = r; /* connect to last table */ + } +DEBG1("6 "); + } +DEBG("h6c "); + + /* set up table entry in r */ + r.b = (uch)(k - w); + if (p >= v + n) + r.e = 99; /* out of values--invalid code */ + else if (*p < s) + { + r.e = (uch)(*p < 256 ? 16 : 15); /* 256 is end-of-block code */ + r.v.n = *p++; /* simple code is just the value */ + } + else + { + r.e = (uch)e[*p - s]; /* non-simple--look up in lists */ + r.v.n = d[*p++ - s]; + } +DEBG("h6d "); + + /* fill code-like entries with r */ + f = 1 << (k - w); + for (j = i >> w; j < z; j += f) + q[j] = r; + + /* backwards increment the k-bit code i */ + for (j = 1 << (k - 1); i & j; j >>= 1) + i ^= j; + i ^= j; + + /* backup over finished tables */ + while ((i & ((1 << w) - 1)) != x[h]) + { + h--; /* don't need to update q */ + w -= l; + } +DEBG("h6e "); + } +DEBG("h6f "); + } + +DEBG("huft7 "); + + /* Return true (1) if we were given an incomplete table */ + return y != 0 && g != 1; +} + + + +int huft_free(t) +struct huft *t; /* table to free */ +/* Free the malloc'ed tables built by huft_build(), which makes a linked + list of the tables it made, with the links in a dummy first entry of + each table. */ +{ + register struct huft *p, *q; + + + /* Go through linked list, freeing from the malloced (t[-1]) address. */ + p = t; + while (p != (struct huft *)NULL) + { + q = (--p)->v.t; + free(p); + p = q; + } + return 0; +} + + +int inflate_codes(tl, td, bl, bd) +struct huft *tl, *td; /* literal/length and distance decoder tables */ +int bl, bd; /* number of bits decoded by tl[] and td[] */ +/* inflate (decompress) the codes in a deflated (compressed) block. + Return an error code or zero if it all goes ok. */ +{ + register unsigned e; /* table entry flag/number of extra bits */ + unsigned n, d; /* length and index for copy */ + unsigned w; /* current window position */ + struct huft *t; /* pointer to table entry */ + unsigned ml, md; /* masks for bl and bd bits */ + register ulg b; /* bit buffer */ + register unsigned k; /* number of bits in bit buffer */ + + + /* make local copies of globals */ + b = bb; /* initialize bit buffer */ + k = bk; + w = wp; /* initialize window position */ + + /* inflate the coded data */ + ml = mask_bits[bl]; /* precompute masks for speed */ + md = mask_bits[bd]; + for (;;) /* do until end of block */ + { + NEEDBITS((unsigned)bl) + if ((e = (t = tl + ((unsigned)b & ml))->e) > 16) + do { + if (e == 99) + return 1; + DUMPBITS(t->b) + e -= 16; + NEEDBITS(e) + } while ((e = (t = t->v.t + ((unsigned)b & mask_bits[e]))->e) > 16); + DUMPBITS(t->b) + if (e == 16) /* then it's a literal */ + { + slide[w++] = (uch)t->v.n; + if (w == WSIZE) + { + flush_output(w); + w = 0; + } + } + else /* it's an EOB or a length */ + { + /* exit if end of block */ + if (e == 15) + break; + + /* get length of block to copy */ + NEEDBITS(e) + n = t->v.n + ((unsigned)b & mask_bits[e]); + DUMPBITS(e); + + /* decode distance of block to copy */ + NEEDBITS((unsigned)bd) + if ((e = (t = td + ((unsigned)b & md))->e) > 16) + do { + if (e == 99) + return 1; + DUMPBITS(t->b) + e -= 16; + NEEDBITS(e) + } while ((e = (t = t->v.t + ((unsigned)b & mask_bits[e]))->e) > 16); + DUMPBITS(t->b) + NEEDBITS(e) + d = w - t->v.n - ((unsigned)b & mask_bits[e]); + DUMPBITS(e) + + /* do the copy */ + do { + n -= (e = (e = WSIZE - ((d &= WSIZE-1) > w ? d : w)) > n ? n : e); +#if !defined(NOMEMCPY) && !defined(DEBUG) + if (w - d >= e) /* (this test assumes unsigned comparison) */ + { + memcpy(slide + w, slide + d, e); + w += e; + d += e; + } + else /* do it slow to avoid memcpy() overlap */ +#endif /* !NOMEMCPY */ + do { + slide[w++] = slide[d++]; + } while (--e); + if (w == WSIZE) + { + flush_output(w); + w = 0; + } + } while (n); + } + } + + + /* restore the globals from the locals */ + wp = w; /* restore global window pointer */ + bb = b; /* restore global bit buffer */ + bk = k; + + /* done */ + return 0; +} + + + +int inflate_stored() +/* "decompress" an inflated type 0 (stored) block. */ +{ + unsigned n; /* number of bytes in block */ + unsigned w; /* current window position */ + register ulg b; /* bit buffer */ + register unsigned k; /* number of bits in bit buffer */ + +DEBG("<stor"); + + /* make local copies of globals */ + b = bb; /* initialize bit buffer */ + k = bk; + w = wp; /* initialize window position */ + + + /* go to byte boundary */ + n = k & 7; + DUMPBITS(n); + + + /* get the length and its complement */ + NEEDBITS(16) + n = ((unsigned)b & 0xffff); + DUMPBITS(16) + NEEDBITS(16) + if (n != (unsigned)((~b) & 0xffff)) + return 1; /* error in compressed data */ + DUMPBITS(16) + + + /* read and output the compressed data */ + while (n--) + { + NEEDBITS(8) + slide[w++] = (uch)b; + if (w == WSIZE) + { + flush_output(w); + w = 0; + } + DUMPBITS(8) + } + + + /* restore the globals from the locals */ + wp = w; /* restore global window pointer */ + bb = b; /* restore global bit buffer */ + bk = k; + + DEBG(">"); + return 0; +} + + + +int inflate_fixed() +/* decompress an inflated type 1 (fixed Huffman codes) block. We should + either replace this with a custom decoder, or at least precompute the + Huffman tables. */ +{ + int i; /* temporary variable */ + struct huft *tl; /* literal/length code table */ + struct huft *td; /* distance code table */ + int bl; /* lookup bits for tl */ + int bd; /* lookup bits for td */ + unsigned l[288]; /* length list for huft_build */ + +DEBG("<fix"); + + /* set up literal table */ + for (i = 0; i < 144; i++) + l[i] = 8; + for (; i < 256; i++) + l[i] = 9; + for (; i < 280; i++) + l[i] = 7; + for (; i < 288; i++) /* make a complete, but wrong code set */ + l[i] = 8; + bl = 7; + if ((i = huft_build(l, 288, 257, cplens, cplext, &tl, &bl)) != 0) + return i; + + + /* set up distance table */ + for (i = 0; i < 30; i++) /* make an incomplete code set */ + l[i] = 5; + bd = 5; + if ((i = huft_build(l, 30, 0, cpdist, cpdext, &td, &bd)) > 1) + { + huft_free(tl); + + DEBG(">"); + return i; + } + + + /* decompress until an end-of-block code */ + if (inflate_codes(tl, td, bl, bd)) + return 1; + + + /* free the decoding tables, return */ + huft_free(tl); + huft_free(td); + return 0; +} + + + +int inflate_dynamic() +/* decompress an inflated type 2 (dynamic Huffman codes) block. */ +{ + int i; /* temporary variables */ + unsigned j; + unsigned l; /* last length */ + unsigned m; /* mask for bit lengths table */ + unsigned n; /* number of lengths to get */ + struct huft *tl; /* literal/length code table */ + struct huft *td; /* distance code table */ + int bl; /* lookup bits for tl */ + int bd; /* lookup bits for td */ + unsigned nb; /* number of bit length codes */ + unsigned nl; /* number of literal/length codes */ + unsigned nd; /* number of distance codes */ +#ifdef PKZIP_BUG_WORKAROUND + unsigned ll[288+32]; /* literal/length and distance code lengths */ +#else + unsigned ll[286+30]; /* literal/length and distance code lengths */ +#endif + register ulg b; /* bit buffer */ + register unsigned k; /* number of bits in bit buffer */ + +DEBG("<dyn"); + + /* make local bit buffer */ + b = bb; + k = bk; + + + /* read in table lengths */ + NEEDBITS(5) + nl = 257 + ((unsigned)b & 0x1f); /* number of literal/length codes */ + DUMPBITS(5) + NEEDBITS(5) + nd = 1 + ((unsigned)b & 0x1f); /* number of distance codes */ + DUMPBITS(5) + NEEDBITS(4) + nb = 4 + ((unsigned)b & 0xf); /* number of bit length codes */ + DUMPBITS(4) +#ifdef PKZIP_BUG_WORKAROUND + if (nl > 288 || nd > 32) +#else + if (nl > 286 || nd > 30) +#endif + return 1; /* bad lengths */ + +DEBG("dyn1 "); + + /* read in bit-length-code lengths */ + for (j = 0; j < nb; j++) + { + NEEDBITS(3) + ll[border[j]] = (unsigned)b & 7; + DUMPBITS(3) + } + for (; j < 19; j++) + ll[border[j]] = 0; + +DEBG("dyn2 "); + + /* build decoding table for trees--single level, 7 bit lookup */ + bl = 7; + if ((i = huft_build(ll, 19, 19, NULL, NULL, &tl, &bl)) != 0) + { + if (i == 1) + huft_free(tl); + return i; /* incomplete code set */ + } + +DEBG("dyn3 "); + + /* read in literal and distance code lengths */ + n = nl + nd; + m = mask_bits[bl]; + i = l = 0; + while ((unsigned)i < n) + { + NEEDBITS((unsigned)bl) + j = (td = tl + ((unsigned)b & m))->b; + DUMPBITS(j) + j = td->v.n; + if (j < 16) /* length of code in bits (0..15) */ + ll[i++] = l = j; /* save last length in l */ + else if (j == 16) /* repeat last length 3 to 6 times */ + { + NEEDBITS(2) + j = 3 + ((unsigned)b & 3); + DUMPBITS(2) + if ((unsigned)i + j > n) + return 1; + while (j--) + ll[i++] = l; + } + else if (j == 17) /* 3 to 10 zero length codes */ + { + NEEDBITS(3) + j = 3 + ((unsigned)b & 7); + DUMPBITS(3) + if ((unsigned)i + j > n) + return 1; + while (j--) + ll[i++] = 0; + l = 0; + } + else /* j == 18: 11 to 138 zero length codes */ + { + NEEDBITS(7) + j = 11 + ((unsigned)b & 0x7f); + DUMPBITS(7) + if ((unsigned)i + j > n) + return 1; + while (j--) + ll[i++] = 0; + l = 0; + } + } + +DEBG("dyn4 "); + + /* free decoding table for trees */ + huft_free(tl); + +DEBG("dyn5 "); + + /* restore the global bit buffer */ + bb = b; + bk = k; + +DEBG("dyn5a "); + + /* build the decoding tables for literal/length and distance codes */ + bl = lbits; + if ((i = huft_build(ll, nl, 257, cplens, cplext, &tl, &bl)) != 0) + { +DEBG("dyn5b "); + if (i == 1) { + error(" incomplete literal tree\n"); + huft_free(tl); + } + return i; /* incomplete code set */ + } +DEBG("dyn5c "); + bd = dbits; + if ((i = huft_build(ll + nl, nd, 0, cpdist, cpdext, &td, &bd)) != 0) + { +DEBG("dyn5d "); + if (i == 1) { + error(" incomplete distance tree\n"); +#ifdef PKZIP_BUG_WORKAROUND + i = 0; + } +#else + huft_free(td); + } + huft_free(tl); + return i; /* incomplete code set */ +#endif + } + +DEBG("dyn6 "); + + /* decompress until an end-of-block code */ + if (inflate_codes(tl, td, bl, bd)) + return 1; + +DEBG("dyn7 "); + + /* free the decoding tables, return */ + huft_free(tl); + huft_free(td); + + DEBG(">"); + return 0; +} + + + +int inflate_block(e) +int *e; /* last block flag */ +/* decompress an inflated block */ +{ + unsigned t; /* block type */ + register ulg b; /* bit buffer */ + register unsigned k; /* number of bits in bit buffer */ + + DEBG("<blk"); + + /* make local bit buffer */ + b = bb; + k = bk; + + + /* read in last block bit */ + NEEDBITS(1) + *e = (int)b & 1; + DUMPBITS(1) + + + /* read in block type */ + NEEDBITS(2) + t = (unsigned)b & 3; + DUMPBITS(2) + + + /* restore the global bit buffer */ + bb = b; + bk = k; + + /* inflate that block type */ + if (t == 2) + return inflate_dynamic(); + if (t == 0) + return inflate_stored(); + if (t == 1) + return inflate_fixed(); + + DEBG(">"); + + /* bad block type */ + return 2; +} + + + +int inflate() +/* decompress an inflated entry */ +{ + int e; /* last block flag */ + int r; /* result code */ + unsigned h; /* maximum struct huft's malloc'ed */ + + + /* initialize window, bit buffer */ + wp = 0; + bk = 0; + bb = 0; + + + /* decompress until the last block */ + h = 0; + do { + hufts = 0; + if ((r = inflate_block(&e)) != 0) + return r; + if (hufts > h) + h = hufts; + } while (!e); + + /* Undo too much lookahead. The next read will be byte aligned so we + * can discard unused bits in the last meaningful byte. + */ + while (bk >= 8) { + bk -= 8; + inptr--; + } + + /* flush out slide */ + flush_output(wp); + + + /* return success */ +#ifdef DEBUG + fprintf(stderr, "<%u> ", h); +#endif /* DEBUG */ + return 0; +} diff --git a/arch/mips/boot/compressed/lzw.h b/arch/mips/boot/compressed/lzw.h new file mode 100644 index 000000000..4e640f5a2 --- /dev/null +++ b/arch/mips/boot/compressed/lzw.h @@ -0,0 +1,42 @@ +/* lzw.h -- define the lzw functions. + * Copyright (C) 1992-1993 Jean-loup Gailly. + * 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. + */ + +#if !defined(OF) && defined(lint) +# include "gzip.h" +#endif + +#ifndef BITS +# define BITS 16 +#endif +#define INIT_BITS 9 /* Initial number of bits per code */ + +#define LZW_MAGIC "\037\235" /* Magic header for lzw files, 1F 9D */ + +#define BIT_MASK 0x1f /* Mask for 'number of compression bits' */ +/* Mask 0x20 is reserved to mean a fourth header byte, and 0x40 is free. + * It's a pity that old uncompress does not check bit 0x20. That makes + * extension of the format actually undesirable because old compress + * would just crash on the new format instead of giving a meaningful + * error message. It does check the number of bits, but it's more + * helpful to say "unsupported format, get a new version" than + * "can only handle 16 bits". + */ + +#define BLOCK_MODE 0x80 +/* Block compression: if table is full and compression rate is dropping, + * clear the dictionary. + */ + +#define LZW_RESERVED 0x60 /* reserved bits */ + +#define CLEAR 256 /* flush the dictionary */ +#define FIRST (CLEAR+1) /* first free entry */ + +extern int maxbits; /* max bits per code for LZW */ +extern int block_mode; /* block compress mode -C compatible with 2.0 */ + +extern void lzw OF((int in, int out)); +extern void unlzw OF((int in, int out)); diff --git a/arch/mips/boot/compressed/misc.c b/arch/mips/boot/compressed/misc.c new file mode 100644 index 000000000..1e3bb5f82 --- /dev/null +++ b/arch/mips/boot/compressed/misc.c @@ -0,0 +1,438 @@ +/* + * misc.c + * + * This is a collection of several routines from gzip-1.0.3 + * adapted for Linux. + * + * Modified for Linux/MIPS 1995 by Ralf Baechle + * malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994 + * puts by Nick Holloway 1993 + */ + +#include "gzip.h" +#include "lzw.h" + +#include <asm/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; +int graphmode; + +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 lines, cols; + +static void puts(const char *); + +void *malloc(int size) +{ + void *p; + + if (size <0) error("Malloc error\n"); + if (free_mem_ptr <= 0) error("Memory error\n"); + + while(1) { + free_mem_ptr = (free_mem_ptr + 3) & ~3; /* Align */ + + p = (void *)free_mem_ptr; + free_mem_ptr += size; + + /* + * The part of the compressed kernel which has already been expanded + * is no longer needed. Therefore we can reuse it for malloc. + * With bigger kernels, this is necessary. + */ + + if (free_mem_ptr < (long)&end) { + if (free_mem_ptr > (long)&input_data[input_ptr]) + error("\nOut of memory\n"); + + return p; + } + if (free_mem_ptr < 0x90000) + return p; + puts("large kernel, low 1M tight..."); + free_mem_ptr = (long)input_data; + } +} + +void free(void *where) +{ /* Don't care */ +} + +static void scroll() +{ + int i; + + memcpy ( vidmem, vidmem + cols * 2, ( lines - 1 ) * cols * 2 ); + for ( i = ( lines - 1 ) * cols * 2; i < lines * cols * 2; i += 2 ) + vidmem[i] = ' '; +} + +static void puts(const char *s) +{ + int x,y; + char c; + + if (graphmode) + { + /* + * No support for graphic console. We'd need a font + * and that would render the compression somewhat senseless... + */ + return; + } + + x = SCREEN_INFO.orig_x; + y = SCREEN_INFO.orig_y; + + while ( ( c = *s++ ) != '\0' ) { + if ( c == '\n' ) { + x = 0; + if ( ++y >= lines ) { + scroll(); + y--; + } + } else { + vidmem [ ( x + cols * y ) * 2 ] = c; + if ( ++x >= cols ) { + x = 0; + if ( ++y >= lines ) { + scroll(); + y--; + } + } + } + } + + SCREEN_INFO.orig_x = x; + SCREEN_INFO.orig_y = y; +} + +__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 4096UL + +long user_stack [STACK_SIZE]; + +void decompress_kernel(void) +{ + if (boot_info.machtype == MACH_MIPS_MAGNUM_4000) + { + /* + * We don't have a font for graphic console so this means silence... + */ + graphmode = 1; + } + else if (boot_info.machtype = MACH_ACER_PICA_61) + { + vidmem = boot_info.vram_base; + vidmem = vidmem + 0x8000; + } + else + { + if (SCREEN_INFO.orig_video_mode == 7) + vidmem = SLOTSPACE + 0xb0000; + else + vidmem = SLOTSPACE + 0xb8000; + } + + 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 *)0x100000; /* 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"); + + 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(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"); + if ((flags & CONTINUATION) != 0) + error("Multi part input\n"); + 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 & 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 + error("unknown compression method"); + return method; +} diff --git a/arch/mips/boot/compressed/piggyback.c b/arch/mips/boot/compressed/piggyback.c new file mode 100644 index 000000000..40284118b --- /dev/null +++ b/arch/mips/boot/compressed/piggyback.c @@ -0,0 +1,81 @@ +/* + * linux/zBoot/piggyback.c + * + * (C) 1993 Hannu Savolainen + */ + +/* + * This program reads the compressed system image from stdin and + * encapsulates it into an object file written to the stdout. + */ + +#include <stdio.h> +#include <unistd.h> +#include <a.out.h> + +int main(int argc, char *argv[]) +{ + int c, n=0, len=0; + char tmp_buf[512*1024]; + + struct exec obj = {0x00640107}; /* object header */ + char string_names[] = {"_input_data\0_input_len\0"}; + + struct nlist var_names[2] = /* Symbol table */ + { + { /* _input_data */ + (char *)4, 7, 0, 0, 0 + }, + { /* _input_len */ + (char *)16, 7, 0, 0, 0 + } + }; + + + len = 0; + while ((n = read(0, &tmp_buf[len], sizeof(tmp_buf)-len+1)) > 0) + len += n; + + if (n==-1) + { + perror("stdin"); + exit(-1); + } + + if (len >= sizeof(tmp_buf)) + { + fprintf(stderr, "%s: Input too large\n", argv[0]); + exit(-1); + } + + fprintf(stderr, "Compressed size %d.\n", len); + +/* + * Output object header + */ + obj.a_data = len + sizeof(long); + obj.a_syms = sizeof(var_names); + write(1, (char *)&obj, sizeof(obj)); + +/* + * Output data segment (compressed system & len) + */ + write(1, tmp_buf, len); + write(1, (char *)&len, sizeof(len)); + +/* + * Output symbol table + */ + var_names[1].n_value = len; + write(1, (char *)&var_names, sizeof(var_names)); + +/* + * Output string table + */ + len = sizeof(string_names) + sizeof(len); + write(1, (char *)&len, sizeof(len)); + write(1, string_names, sizeof(string_names)); + + exit(0); + +} diff --git a/arch/mips/boot/compressed/unzip.c b/arch/mips/boot/compressed/unzip.c new file mode 100644 index 000000000..d4a6617cd --- /dev/null +++ b/arch/mips/boot/compressed/unzip.c @@ -0,0 +1,180 @@ +/* unzip.c -- decompress files in gzip or pkzip format. + * Copyright (C) 1992-1993 Jean-loup Gailly + * + * Adapted for Linux booting by Hannu Savolainen 1993 + * + * 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. + */ + +#ifndef lint +static char rcsid[] = "$Id: unzip.c,v 0.9 1993/02/10 16:07:22 jloup Exp $"; +#endif + +#include "gzip.h" +#include "crypt.h" + +#include <stdio.h> + +/* 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 */ + + +/* Globals */ + +int decrypt; /* flag to turn on decryption */ +char *key; /* not used--needed to link crypt.c */ +int pkzip = 0; /* set for a pkzip file */ +int extended = 0; /* set if extended local header */ + +/* =========================================================================== + * Check zip file and advance inptr to the start of the compressed data. + * Get ofname from the local header if necessary. + */ +int check_zipfile(in) + int in; /* input file descriptors */ +{ + uch *h = inbuf + inptr; /* first local header */ + + /* ifd = in; */ + + /* 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 ((decrypt = h[LOCFLG] & CRPFLG) != 0) { + error("encrypted file\n"); + exit_code = ERROR; + return -1; + } + + /* Save flags for unzip() */ + extended = (h[LOCFLG] & EXTFLG) != 0; + pkzip = 1; + + /* Get ofname and time stamp from local header (to be done) */ + return 0; +} + +/* =========================================================================== + * 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(in, out) + int in, out; /* input and output file descriptors */ +{ + ulg orig_crc = 0; /* original crc */ + ulg orig_len = 0; /* original uncompressed length */ + int n; + uch buf[EXTHDR]; /* extended local header */ + + /* ifd = in; + ofd = out; */ + + updcrc(NULL, 0); /* 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) { + + int res = inflate(); + + if (res == 3) { + error("out of memory"); + } else if (res != 0) { + error("invalid compressed format"); + } + + } else if (pkzip && method == STORED) { + + register ulg n = LG(inbuf + LOCLEN); + + if (n != LG(inbuf + LOCSIZ) - (decrypt ? RAND_HEAD_LEN : 0)) { + + error("length mismatch"); + } + while (n--) { + uch c = (uch)get_byte(); +#ifdef CRYPT + if (decrypt) zdecode(c); +#endif + if (!test) put_char(c); + } + } 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] = (uch)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] = (uch)get_byte(); /* may cause an error if EOF */ + } + orig_crc = LG(buf+4); + orig_len = LG(buf+12); + } + + /* Validate decompression */ + if (orig_crc != updcrc(outbuf, 0)) { + error("crc error"); + } + if (orig_len != bytes_out) { + 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"); + } + extended = pkzip = 0; /* for next file */ +} diff --git a/arch/mips/boot/compressed/xtract.c b/arch/mips/boot/compressed/xtract.c new file mode 100644 index 000000000..91de49ca7 --- /dev/null +++ b/arch/mips/boot/compressed/xtract.c @@ -0,0 +1,86 @@ +/* + * linux/zBoot/xtract.c + * + * Copyright (C) 1993 Hannu Savolainen + * + * Extracts the system image and writes it to the stdout. + * based on tools/build.c by Linus Torvalds + */ + +#include <stdio.h> /* fprintf */ +#include <string.h> +#include <stdlib.h> /* contains exit */ +#include <sys/types.h> /* unistd.h needs this */ +#include <sys/stat.h> +#include <sys/sysmacros.h> +#include <unistd.h> /* contains read/write */ +#include <fcntl.h> +#include <a.out.h> + +#define N_MAGIC_OFFSET 1024 + +static int GCC_HEADER = sizeof(struct exec); + +#define STRINGIFY(x) #x + +void die(char * str) +{ + fprintf(stderr,"%s\n",str); + exit(1); +} + +void usage(void) +{ + die("Usage: xtract system [ | gzip | piggyback > piggy.s]"); +} + +int main(int argc, char ** argv) +{ + int i,c,id, sz; + char buf[1024]; + char major_root, minor_root; + struct stat sb; + + struct exec *ex = (struct exec *)buf; + + if (argc != 2) + usage(); + + if ((id=open(argv[1],O_RDONLY,0))<0) + die("Unable to open 'system'"); + if (read(id,buf,GCC_HEADER) != GCC_HEADER) + die("Unable to read header of 'system'"); + if (N_MAGIC(*ex) == ZMAGIC) { + GCC_HEADER = N_MAGIC_OFFSET; + lseek(id, GCC_HEADER, SEEK_SET); + } else if (N_MAGIC(*ex) != QMAGIC) + die("Non-GCC header of 'system'"); + + sz = N_SYMOFF(*ex) - GCC_HEADER + 4; /* +4 to get the same result than tools/build */ + + fprintf(stderr, "System size is %d\n", sz); + + while (sz) + { + int l, n; + + l = sz; + if (l > sizeof(buf)) l = sizeof(buf); + + if ((n=read(id, buf, l)) !=l) + { + if (n == -1) + perror(argv[1]); + else + fprintf(stderr, "Unexpected EOF\n"); + + die("Can't read system"); + } + + write(1, buf, l); + sz -= l; + } + + close(id); + return(0); +} diff --git a/arch/mips/boot/head.S b/arch/mips/boot/head.S deleted file mode 100644 index 73e9d2cf9..000000000 --- a/arch/mips/boot/head.S +++ /dev/null @@ -1,387 +0,0 @@ -/* - * mips/head.S - * - * Copyright (C) 1994 Ralf Baechle - * - * Head.S contains the MIPS 32-bit startup code. - */ - -/* - * prevent prototypes from being imported - */ -#define __ASSEMBLY__ - -#include <asm/segment.h> -#include <asm/cachectl.h> -#include <asm/mipsregs.h> -#include <asm/mipsconfig.h> -#include <asm/stackframe.h> -#include <asm/regdef.h> -#include <linux/tasks.h> - - - .globl _empty_bad_page - .globl _empty_bad_page_table - .globl _invalid_pg_table - .globl _empty_zero_page - .globl _tmp_floppy_area - .globl _floppy_track_buffer - .globl _swapper_pg_dir - - .set noreorder - - .text -/* - * This is space for the interrupt handlers. - * They are located at virtual address 0x80000000 (physical 0x0) - */ - /* - * TLB refill, EXL == 0 - */ -except_vec0: - .set noreorder - .set noat - /* - * This TLB-refill handler is supposed never to cause - * another tlb-refill exception. Unmapped pages will - * cause another type of exception. - */ - dmfc0 k0,CP0_CONTEXT - dsrl k0,k0,1 - lwu k0,(k1) - lwu k1,4(k1) - dmtc0 k0,CP0_ENTRYLO0 - dmtc0 k0,CP0_ENTRYLO1 - tlbwr - eret - - /* - * XTLB refill, EXL == 0 (X == 64-bit TLB) - */ - .org except_vec0+0x80 -except_vec1: - /* - * Not used yet... - */ - eret - - /* - * Cache Error - */ - .org except_vec1+0x80 -except_vec2: - /* - * Not used yet... - */ - eret - - /* - * General exception vector. - */ - .org except_vec2+0x80 -except_vec3: - SAVE_ALL - mfc0 t0,CP0_STATUS - ori t0,t0,0x1f - xori t0,t0,0x1f - mtc0 t0,CP0_STATUS - .set at - la k0,_exception_handlers - mfc0 k1,CP0_CAUSE - andi k1,k1,0x7c - addu k0,k0,k1 - lw k0,(k0) - FILL_LDS - jr k0 - nop - - -/******************************************************************************/ - - /* - * The following data is expected to be at certain absolute - * addresses, which are hardwired in - * include/asm-mips/mipsconfig.h - * If the following offset is to short, the assembler will - * break with an assertion failure. You then will have to - * increase it and to fix the address in - * include/asm-mips/mipsconfig.h - */ - - .org except_vec3+0x100 - .globl _kernelsp -_kernelsp: .word 0 - -kernel_entry: - -/* - * Flush the TLB - */ - dmtc0 zero,CP0_ENTRYHI - dmtc0 zero,CP0_ENTRYLO0 - dmtc0 zero,CP0_ENTRYLO1 - li t0,NUMBER_OF_TLB_ENTRIES-1 -1: mtc0 t0,CP0_INDEX - tlbwi - bne zero,t0,1b - subu t0,t0,1 - -/* - * Initialize memory management. - * Wire mapping for port i/o space 0xe0000000 -> 0x9000000900000000 - */ - li t0,3 - mtc0 t0,CP0_WIRED - li t0,PM_64K - mtc0 t0,CP0_PAGEMASK - la t3,map0 - ld t1,0(t3) - ld t2,8(t3) - mtc0 zero,CP0_INDEX - dmtc0 t1,CP0_ENTRYHI - dmtc0 t2,CP0_ENTRYLO0 - dmtc0 zero,CP0_ENTRYLO1 /* Invalid page */ - tlbwi - li t0,PM_1M - mtc0 t0,CP0_PAGEMASK - ld t1,16(t3) - ld t2,24(t3) - li t0,1 - mtc0 t0,CP0_INDEX - dmtc0 t1,CP0_ENTRYHI - dmtc0 t2,CP0_ENTRYLO0 - tlbwi - ld t1,32(t3) - ld t2,40(t3) - li t0,2 - mtc0 t0,CP0_INDEX - dmtc0 t1,CP0_ENTRYHI - dmtc0 t2,CP0_ENTRYLO0 - tlbwi - -/* - * We always use 4k pages. Therefore the PageMask register - * is expected to be setup for 4k pages. - */ - li t0,PM_4K - mtc0 t0,CP0_PAGEMASK - -/* - * Clear BSS first so that there are no surprises... - */ - la t0,__edata - la t1,__end - sw zero,(t0) -1: addiu t0,t0,4 - bnel t0,t1,1b - sw zero,(t0) - -/* - * Copy bootup parameters out of the way. First 2kB of - * _empty_zero_page is for boot parameters, second 2kB - * is for the command line. - */ -#if 0 - movl $0x90000,%esi - movl $_empty_zero_page,%edi - movl $512,%ecx - cld - rep - movsl - xorl %eax,%eax - movl $512,%ecx - rep - stosl - cmpw $(CL_MAGIC),CL_MAGIC_ADDR - jne 1f - movl $_empty_zero_page+2048,%edi - movzwl CL_OFFSET,%esi - addl $(CL_BASE_ADDR),%esi - movl $2048,%ecx - rep - movsb -#endif - - /* - * Preliminary stack... - */ - la sp,0x80700000 - sw sp,_kernelsp -6: - jal _start_kernel - nop - j 6b # main should never return here, but - # just in case, we know what happens. - -#if 0 -/* This is the default interrupt "handler" :-) */ -int_msg: - .asciz "Unknown interrupt\n" -.align 2 -ignore_int: - cld - pushl %eax - pushl %ecx - pushl %edx - push %ds - push %es - push %fs - movl $(KERNEL_DS),%eax - mov %ax,%ds - mov %ax,%es - mov %ax,%fs - pushl $int_msg - call _printk - popl %eax - pop %fs - pop %es - pop %ds - popl %edx - popl %ecx - popl %eax - iret -#endif - -#define CACHELINES 512 /* number of cachelines */ - -/* - * Flush instruction/data caches - * - * Parameters: a0 - starting address to flush - * a1 - size of area to be flushed - * a2 - which caches to be flushed - * - * FIXME: - ignores parameters - * - doesn't know about second level caches - */ - - .set noreorder - .globl _cacheflush - .text -_cacheflush: - /* - * Flush the instruction cache - */ - lui t0,0x8000 - li t1,CACHELINES-1 -1: cache 0,0(t0) - cache 0,32(t0) - cache 0,64(t0) - cache 0,96(t0) - cache 0,128(t0) - cache 0,160(t0) - cache 0,192(t0) - cache 0,224(t0) - cache 0,256(t0) - cache 0,288(t0) - cache 0,320(t0) - cache 0,352(t0) - cache 0,384(t0) - cache 0,416(t0) - cache 0,448(t0) - cache 0,480(t0) - addiu t0,t0,512 - bne zero,t1,1b - subu t1,t1,1 - /* - * Flush the data cache - */ - lui t0,0x8000 - li t1,CACHELINES-1 -1: cache 1,0(t0) - cache 1,32(t0) - cache 1,64(t0) - cache 1,96(t0) - cache 1,128(t0) - cache 1,160(t0) - cache 1,192(t0) - cache 1,224(t0) - cache 1,256(t0) - cache 1,288(t0) - cache 1,320(t0) - cache 1,352(t0) - cache 1,384(t0) - cache 1,416(t0) - cache 1,448(t0) - cache 1,480(t0) - addiu t0,t0,512 - bne zero,t1,1b - subu t1,t1,1 - - j ra - nop - - .globl _beep -_beep: lbu t0,0xe0000061 - xori t0,t0,3 - sb t0,0xe0000061 - jr ra - nop - -/* - * Instead of Intel's strage and unportable segment descriptor magic - * we difference user and kernel space by their address. - * Kernel space (== physical memory) is mapped at 0x80000000, - * User space is mapped at 0x0. - */ - - .data - - .globl _segment_fs - /* - * Inital wired mappings - */ -map0: .quad 0xc00000ffe0000000,0x24000017 - .quad 0xc00000ffe1000000,0x04000017 - .quad 0xc00000ffe2000000,0x04020017 - -/* - * page 0 is made non-existent, so that kernel NULL pointer references get - * caught. Thus the swapper page directory has been moved to 0x1000 - * - * XXX Actually, the swapper page directory is at 0x1000 plus 1 megabyte, - * with the introduction of the compressed boot code. Theoretically, - * the original design of overlaying the startup code with the swapper - * page directory is still possible --- it would reduce the size of the kernel - * by 2-3k. This would be a good thing to do at some point..... - */ - .text - - .org 0x1000 -_swapper_pg_dir: -/* - * The page tables are initialized to only 4MB here - the final page - * tables are set up later depending on memory size. - */ - .org 0x2000 -_pg0: - - .org 0x3000 -_empty_bad_page: - - .org 0x4000 -_empty_bad_page_table: - - .org 0x5000 -_invalid_pg_table: - - .org 0x6000 -_empty_zero_page: - - .org 0x7000 - -/* - * tmp_floppy_area is used by the floppy-driver when DMA cannot - * reach to a buffer-block. It needs to be aligned, so that it isn't - * on a 64kB border. - */ -_tmp_floppy_area: .fill 1024,1,0 -/* - * floppy_track_buffer is used to buffer one track of floppy data: it - * has to be separate from the tmp_floppy area, as otherwise a single- - * sector read/write can mess it up. It can contain one full cylinder (sic) of - * data (36*2*512 bytes). - */ -_floppy_track_buffer: .fill 512*2*36,1,0 - -_segment_fs: .word KERNEL_DS diff --git a/arch/mips/boot/loader.h b/arch/mips/boot/loader.h new file mode 100644 index 000000000..610111b9a --- /dev/null +++ b/arch/mips/boot/loader.h @@ -0,0 +1,24 @@ +/* + * Defines for Linux/MIPS executable loaders + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1995 by Ralf Baechle + */ +#ifndef __STAND_LOADER +#define __STAND_LOADER + +struct loader { + struct nlist *(*ld_get_nlist)(char *symbol); + char *(*ld_isymbol)(char *); + u_long (*ld_get_kbase)(void); + u_long (*ld_get_ksize)(void); + int (*ld_load_kernel)(void *mem); + void (*ld_print_stats)(void); + int (*ld_open_kernel)(char *kernel); + void (*ld_close_kernel)(void); +}; + +#endif /* __STAND_LOADER */ diff --git a/arch/mips/boot/milo.c b/arch/mips/boot/milo.c new file mode 100644 index 000000000..a8a25dd91 --- /dev/null +++ b/arch/mips/boot/milo.c @@ -0,0 +1,316 @@ +/* + * Load and launch Linux/MIPS kernel. + * + * Copyright (C) 1994, 1995 by Waldorf Electronics, + * written by Ralf Baechle and Andreas Busse + * + * Loosly based on bootstrap.c for Linux/68k, + * Copyright (C) 1993 by Hamish Macdonald, Greg Harp + * + * This file is subject to the terms and conditions of the + * GNU General Public License. See the file COPYING in the + * main directory of this archive for more details. + */ +#include <stdio.h> +#include <stddef.h> +#include <stdlib.h> +#include <unistd.h> + +#include <sys/file.h> +#include <sys/types.h> + +#include <linux/string.h> +#include <linux/tty.h> +#include <linux/a.out.h> + +/* + * Prototypes + */ +void usage(void); + +/* + * Defaults, may be overiden by option or environment. + */ +static char *kernel_name = KERNEL_NAME; +static char *ramdisk_name = NULL; +int option_debuglevel = 0; +int option_verbose = 1; +int behaviour = BEHAVE_MILO; + +extern char *optarg; + +extern volatile void launch(char *kptr, char *rdptr, + u_long kernel_size, u_long rd_size); + +static char *kptr; /* kernel will be loaded there */ +static char *rdptr; /* ramdisk will be loaded there */ + +u_long loadaddr = LOADADDR; /* mallocinit() needs that */ +u_long kernel_base = KERNELBASE; /* whereever that is... */ +u_long start_mem; /* always true on an ARC system */ +u_long mem_size; +u_long rd_size; +u_long kernel_entry; +u_long kernel_size; +u_long kernel_bss_end; + +struct bootinfo bi; /* Linux boot info */ +struct screen_info si; /* Linux screen info */ +struct DisplayInfo *di; /* ARC display info */ + + +/* + * For now we just use the aout loader + */ +extern struct loader loader_aout; +struct loader *kld = &loader_aout; + +/* + * main() + */ +int main(int argc, char *argv[]) +{ + int ch; + + /* + * Print the greet message + */ + printf("Linux/MIPS ARC Standalone Shell "); + printf("V" STR(VERSION) "\r\n"); + printf("Copyright (C) Waldorf Electronics and others 1994, 1995\r\n\r\n"); + + /* + * Analyse arguments + */ + if(argc > 1) + { + while ((ch = getopt(argc, argv, "dik:r:v")) != EOF) + switch (ch) + { + case 'd': + option_debuglevel++; + option_verbose = 1; + break; + case 'i': + interactive = 1; + break; + case 'k': + kernel_name = optarg; + break; + case 'r': + ramdisk_name = optarg; + break; + case 'v': + option_verbose = 1; + break; + case '?': + default: + usage(); + } + } +} + +/* + * Do the actual boot + */ +int do_boot(char *kernel_name, char *ramdisk_name) +{ + int kfd, rfd = -1, i; + u_long memreq; + struct nlist *nl; + u_long kbi_offset, ksi_offset; + + /* + * Verify that there is enough RAM + */ + mem_size = bi.memupper - bi.memlower; + if (mem_size < 0x800000) + { + fprintf(stderr, + "Insufficient Memory to load Linux/MIPS, aborting\n\r"); + return(5); + } + + if (behaviour == BEHAVE_ARCDB) + { + printf("%s: kernel file is `%s'\r\n", NAMEOF_ARCDB, kernel_name); + if (ramdisk_name) + printf("%s: ramdisk file is `%s'\r\n", NAMEOF_ARCDB, ramdisk_name); + } + + /* + * Open kernel and gather some data from the executable + */ + if (kld->ld_open_kernel(kernel_name) < 0) + { + fprintf(stderr, "Error opening kernel file %s.\n\r", kernel_name); + return 5; + } + kernel_base = kld->ld_get_kbase(); + kernel_size = kld->ld_get_ksize(); + + bi.ramdisk_size = 0; /* default: no ramdisk */ + if (ramdisk_name) + { + if ((rfd = open (ramdisk_name, O_RDONLY)) == -1) + { + fprintf (stderr, + "Unable to open ramdisk file %s\n\r", ramdisk_name); + } + else + { + /* + * record ramdisk size + */ + bi.ramdisk_size = (lseek (rfd, 0, L_XTND) + 1023) >> 10; + + rd_size = lseek (rfd, 0, L_XTND); + if (rd_size & ((1<<10)-1)) + { + /* + * Most probably the file is no image at all or has been + * corrupted, so print a warning message. + */ + printf("Warning: Ramdisk size is not multiple of 1024 bytes.\r\n"); + } + bi.ramdisk_size = rd_size >> 10; + } + } + bi.ramdisk_base = (u_long)start_mem + mem_size - rd_size; + + /* + * find offset to boot_info structure + */ + if (!(nl = kld->ld_get_nlist (kld->ld_isymbol("boot_info")))) + { + perror("get_nlist1"); + return 1; + } + else + { + kbi_offset = nl->n_value - kernel_base; + free(nl); + } + + /* + * Find offset to screen_info structure + */ + if (!(nl = kld->ld_get_nlist (kld->ld_isymbol("screen_info")))) + { + perror("get_nlist2"); + return 1; + } + else + { + ksi_offset = nl->n_value - kernel_base; + free(nl); + } + + /* + * Find kernel entry point + */ + if (!(nl = kld->ld_get_nlist (kld->ld_isymbol("kernel_entry")))) + { + perror("get_nlist3"); + return 1; + } + else + { + kernel_entry = nl->n_value; + free(nl); + } + + /* + * End of bss segment - ramdisk will be placed there + */ + if (!(nl = kld->ld_get_nlist (kld->ld_isymbol("_end")))) + { + perror("get_nlist3"); + return 1; + } + else + { + kernel_bss_end = nl->n_value; + free(nl); + } + + /* + * allocate buffers for kernel and ramdisk + */ + if (!(kptr = (char *) malloc(kernel_size))) + { + fprintf (stderr, "Unable to allocate %d bytes of memory\n\r", memreq); + return 1; + } + memset (kptr, 0, kernel_size); + + if (rd_size) + { + if (!(rdptr = (char *) malloc(rd_size))) + { + fprintf (stderr, + "Unable to allocate %d bytes of memory\n\r", memreq); + return 1; + } + memset (rdptr, 0, rd_size); + } + + /* + * Should check whether kernel & RAMdisk moving doesn't overwrite + * the bootstraper during startup. + */ + if (option_verbose) + { + /* + * The following text should be printed by the loader module + */ + printf ("\r\n"); + kld->ld_print_stats(); + printf ("Kernel entry at 0x%08lx\n\r", kernel_entry); + } + + /* + * Now do the real loading + */ + if (kld->ld_load_kernel(kptr) < 0) + { + fprintf (stderr, "Failed to load kernel executable\r\n"); + free(kptr); + exit (EXIT_FAILURE); + } + kld->ld_close_kernel(); + + /* + * copy the boot and screen info structures to the kernel image, + * then execute the copy-and-go code + */ + memcpy ((void *)(kptr + kbi_offset), &bi, sizeof(bi)); + memcpy ((void *)(kptr + ksi_offset), &si, sizeof(si)); + + /* + * Write the manipulated kernel back + */ + + /* + * Success... + */ + return 0; +} + +/* + * usage() + * + * Options: + * -d - enable debugging (default is no debugging) + * -i - interactive (default is noninteractive) + * -k - kernel executable (default multi(0)disk(0)fdisk(0)\VMLINUX) + * -r - ramdisk image (default is no ramdisk) + * -v - verbose output + */ +void usage(void) +{ + fprintf (stderr, "Usage:\r\n" + "\tmilo [-d] [-i] [-k kernel_executable] [-r ramdisk_file] [-v]" + " [option...]\r\n"); + exit (EXIT_FAILURE); +} |