patch-2.1.36 linux/arch/m68k/boot/atari/bootstrap.c
Next file: linux/arch/m68k/config.in
Previous file: linux/arch/m68k/boot/atari/bootp.h
Back to the patch index
Back to the overall index
- Lines: 579
- Date:
Thu Apr 17 13:20:42 1997
- Orig file:
v2.1.35/linux/arch/m68k/boot/atari/bootstrap.c
- Orig date:
Fri Dec 20 01:19:58 1996
diff -u --recursive --new-file v2.1.35/linux/arch/m68k/boot/atari/bootstrap.c linux/arch/m68k/boot/atari/bootstrap.c
@@ -8,6 +8,8 @@
** for more details.
**
** History:
+** 01 Feb 1997 Implemented kernel decompression (Roman)
+** 28 Nov 1996 Fixed and tested previous change (James)
** 27 Nov 1996 Compatibility with bootinfo interface version 1.0 (Geert)
** 12 Nov 1996 Fixed and tested previous change (Andreas)
** 18 Aug 1996 Updated for the new boot information structure (untested!)
@@ -32,6 +34,8 @@
#define BOOTINFO_COMPAT_1_0 /* bootinfo interface version 1.0 compatible */
+/* support compressed kernels? */
+#define ZKERNEL
#include <stdio.h>
#include <stdlib.h>
@@ -159,6 +163,9 @@
* ...err! On the Afterburner040 (for the Falcon) it's the same... So we do
* another test with 0x00ff82fe, that gives a bus error on the Falcon, but is
* in the range where the Medusa always asserts DTACK.
+ * On the Hades address 0 is writeable as well and it asserts DTACK on
+ * address 0x00ff82fe. To test if the machine is a Hades, address 0xb0000000
+ * is tested. On the Medusa this gives a bus error.
*/
int test_medusa( void )
@@ -177,7 +184,10 @@
"nop \n\t"
"tstb 0x00ff82fe\n\t"
"nop \n\t"
- "moveq #1,%0\n"
+ "moveq #1,%0\n\t"
+ "tstb 0xb0000000\n\t"
+ "nop \n\t"
+ "moveq #0,%0\n"
"Lberr:\t"
"movel a1,sp\n\t"
"movel a0,0x8"
@@ -357,11 +367,21 @@
#ifdef USE_BOOTP
# include "bootp.h"
#else
-# define kread read
-# define klseek lseek
-# define kclose close
+# define ll_read read
+# define ll_lseek lseek
+# define ll_close close
#endif
+#ifdef ZKERNEL
+static int load_zkernel( int fd );
+static int kread( int fd, void *buf, unsigned cnt );
+static int klseek( int fd, int where, int whence );
+static int kclose( int fd );
+#else
+# define kread read
+# define klseek lseek
+# define kclose close
+#endif
/* ++andreas: this must be inline due to Super */
static inline void boot_exit (int) __attribute__ ((noreturn));
@@ -385,16 +405,18 @@
Elf32_Ehdr kexec_elf;
Elf32_Phdr *kernel_phdrs = NULL;
u_long start_mem, mem_size, rd_size, text_offset = 0, kernel_size;
+ int prefer_bootp = 1, kname_set = 0, n_knames;
#ifdef USE_BOOTP
- int prefer_bootp = 1, kname_set = 0;
+ int err;
#endif
+ char kname_list[5][64];
void *bi_ptr;
ramdisk_name = NULL;
kernel_name = "vmlinux";
/* print the startup message */
- puts("\fLinux/68k Atari Bootstrap version 2.0"
+ puts("\fLinux/68k Atari Bootstrap version 2.2"
#ifdef USE_BOOTP
" (with BOOTP)"
#endif
@@ -410,11 +432,7 @@
bi.machtype = MACH_ATARI;
/* check arguments */
-#ifdef USE_BOOTP
while ((ch = getopt(argc, argv, "bdtsk:r:")) != EOF)
-#else
- while ((ch = getopt(argc, argv, "dtsk:r:")) != EOF)
-#endif
switch (ch) {
case 'd':
debugflag = 1;
@@ -427,18 +445,14 @@
break;
case 'k':
kernel_name = optarg;
-#ifdef USE_BOOTP
kname_set = 1;
-#endif
break;
case 'r':
ramdisk_name = optarg;
break;
-#ifdef USE_BOOTP
case 'b':
prefer_bootp = 0;
break;
-#endif
case '?':
default:
usage();
@@ -744,38 +758,60 @@
boot_exit(-1);
#endif /* TEST */
+ i = 0;
#ifdef USE_BOOTP
+ if (!kname_set)
+ kname_list[i++][0] = '\0'; /* default kernel which BOOTP server says */
+#endif
+#ifdef ZKERNEL
+ strcpy( kname_list[i], kernel_name );
+ strcat( kname_list[i], ".gz" );
+ ++i;
+#endif
+ strcpy( kname_list[i++], kernel_name );
+#ifdef ZKERNEL
+ if (!kname_set)
+ strcpy( kname_list[i++], "vmlinuz" );
+#endif
+ n_knames = i;
+
kfd = -1;
+#ifdef USE_BOOTP
if (prefer_bootp) {
- /* First try to get a remote kernel, then use a local kernel (if
- * present) */
- if (get_remote_kernel( kname_set ? kernel_name : NULL ) < 0) {
- printf( "\nremote boot failed; trying local kernel\n" );
- if ((kfd = open (kernel_name, O_RDONLY)) == -1) {
- fprintf (stderr, "Unable to open kernel file %s\n",
- kernel_name);
- boot_exit (EXIT_FAILURE);
- }
+ for( i = 0; i < n_knames; ++i ) {
+ if ((err = get_remote_kernel( kname_list[i] )) >= 0)
+ goto kernel_open;
+ if (err < -1) /* fatal error; retries don't help... */
+ break;
}
+ printf( "\nremote boot failed; trying local kernel\n" );
}
- else {
- /* Try BOOTP if local kernel cannot be opened */
- if ((kfd = open (kernel_name, O_RDONLY)) == -1) {
- printf( "\nlocal kernel failed; trying remote boot\n" );
- if (get_remote_kernel( kname_set ? kernel_name : NULL ) < 0) {
- fprintf (stderr, "Unable to remote boot and "
- "to open kernel file %s\n", kernel_name);
- boot_exit (EXIT_FAILURE);
- }
- }
+#endif
+ for( i = 0; i < n_knames; ++i ) {
+ if ((kfd = open( kname_list[i], O_RDONLY )) != -1)
+ goto kernel_open;
}
-#else
- /* open kernel executable and read exec header */
- if ((kfd = open (kernel_name, O_RDONLY)) == -1) {
- fprintf (stderr, "Unable to open kernel file %s\n", kernel_name);
- boot_exit (EXIT_FAILURE);
+#ifdef USE_BOOTP
+ if (!prefer_bootp) {
+ printf( "\nlocal kernel failed; trying remote boot\n" );
+ for( i = 0; i < n_knames; ++i ) {
+ if ((err = get_remote_kernel( kname_list[i] )) >= 0)
+ goto kernel_open;
+ if (err < -1) /* fatal error; retries don't help... */
+ break;
+ }
}
#endif
+ fprintf( stderr, "Unable to open any kernel file\n(Tried " );
+ for( i = 0; i < n_knames; ++i ) {
+ fprintf( stderr, "%s%s", kname_list[i],
+ i < n_knames-2 ? ", " :
+ i == n_knames-2 ? ", and " :
+ ")\n" );
+ }
+ boot_exit( EXIT_FAILURE );
+
+ kernel_open:
if (kread (kfd, (void *)&kexec, sizeof(kexec)) != sizeof(kexec))
{
@@ -783,6 +819,19 @@
boot_exit (EXIT_FAILURE);
}
+#ifdef ZKERNEL
+ if (((unsigned char *)&kexec)[0] == 037 &&
+ (((unsigned char *)&kexec)[1] == 0213 ||
+ ((unsigned char *)&kexec)[1] == 0236)) {
+ /* That's a compressed kernel */
+ printf( "Kernel is compressed\n" );
+ if (load_zkernel( kfd )) {
+ printf( "Decompression error -- aborting\n" );
+ boot_exit( EXIT_FAILURE );
+ }
+ }
+#endif
+
switch (N_MAGIC(kexec)) {
case ZMAGIC:
text_offset = N_TXTOFF(kexec);
@@ -847,18 +896,6 @@
}
else
bi.ramdisk.size = 0;
-
- rd_size = bi.ramdisk.size;
- if (mem_size - rd_size < MB && bi.num_memory > 1)
- /* If running low on ST ram load ramdisk into alternate ram. */
- bi.ramdisk.addr = (u_long) bi.memory[1].addr + bi.memory[1].size - rd_size;
- else
- /* Else hopefully there is enough ST ram. */
- bi.ramdisk.addr = (u_long)start_mem + mem_size - rd_size;
-
- /* create the bootinfo structure */
- if (!create_bootinfo())
- boot_exit (EXIT_FAILURE);
/* calculate the total required amount of memory */
if (elf_kernel)
@@ -885,6 +922,19 @@
}
else
kernel_size = kexec.a_text + kexec.a_data + kexec.a_bss;
+
+ rd_size = bi.ramdisk.size;
+ if (rd_size + kernel_size > mem_size - MB/2 && bi.num_memory > 1)
+ /* If running low on ST ram load ramdisk into alternate ram. */
+ bi.ramdisk.addr = (u_long) bi.memory[1].addr + bi.memory[1].size - rd_size;
+ else
+ /* Else hopefully there is enough ST ram. */
+ bi.ramdisk.addr = (u_long)start_mem + mem_size - rd_size;
+
+ /* create the bootinfo structure */
+ if (!create_bootinfo())
+ boot_exit (EXIT_FAILURE);
+
memreq = kernel_size + bi_size;
#ifdef BOOTINFO_COMPAT_1_0
if (sizeof(compat_bootinfo) > bi_size)
@@ -997,7 +1047,7 @@
if (debugflag)
{
if (bi.ramdisk.size)
- printf ("RAM disk at %#lx, size is %ldK\n",
+ printf ("RAM disk at %#lx, size is %ld\n",
(u_long)(memptr + memreq - rd_size),
bi.ramdisk.size);
@@ -1192,7 +1242,7 @@
static int add_bi_record(u_short tag, u_short size, const void *data)
{
struct bi_record *record;
- u_int size2;
+ u_short size2;
size2 = (sizeof(struct bi_record)+size+3)&-4;
if (bi_size+size2+sizeof(bi_union.record.tag) > MAX_BI_SIZE) {
@@ -1238,7 +1288,7 @@
else if (bi.cputype & CPU_68060)
compat_bootinfo.cputype = COMPAT_CPU_68060;
else {
- Printf("CPU type 0x%08lx not supported by kernel\n", bi.cputype);
+ printf("CPU type 0x%08lx not supported by kernel\n", bi.cputype);
return(0);
}
if (bi.fputype & FPU_68881)
@@ -1250,12 +1300,12 @@
else if (bi.fputype & FPU_68060)
compat_bootinfo.cputype |= COMPAT_FPU_68060;
else {
- Printf("FPU type 0x%08lx not supported by kernel\n", bi.fputype);
+ printf("FPU type 0x%08lx not supported by kernel\n", bi.fputype);
return(0);
}
compat_bootinfo.num_memory = bi.num_memory;
if (compat_bootinfo.num_memory > COMPAT_NUM_MEMINFO) {
- Printf("Warning: using only %d blocks of memory\n",
+ printf("Warning: using only %d blocks of memory\n",
COMPAT_NUM_MEMINFO);
compat_bootinfo.num_memory = COMPAT_NUM_MEMINFO;
}
@@ -1278,3 +1328,275 @@
return(1);
}
#endif /* BOOTINFO_COMPAT_1_0 */
+
+
+#ifdef ZKERNEL
+
+#define ZFILE_CHUNK_BITS 16 /* chunk is 64 KB */
+#define ZFILE_CHUNK_SIZE (1 << ZFILE_CHUNK_BITS)
+#define ZFILE_CHUNK_MASK (ZFILE_CHUNK_SIZE-1)
+#define ZFILE_N_CHUNKS (2*1024*1024/ZFILE_CHUNK_SIZE)
+
+/* variables for storing the uncompressed data */
+static char *ZFile[ZFILE_N_CHUNKS];
+static int ZFileSize = 0;
+static int ZFpos = 0;
+static int Zwpos = 0;
+
+static int Zinfd = 0; /* fd of compressed file */
+
+/*
+ * gzip declarations
+ */
+
+#define OF(args) args
+
+#define memzero(s, n) memset ((s), 0, (n))
+
+typedef unsigned char uch;
+typedef unsigned short ush;
+typedef unsigned long ulg;
+
+#define INBUFSIZ 4096
+#define WSIZE 0x8000 /* window size--must be a power of two, and */
+ /* at least 32K for zip's deflate method */
+
+static uch *inbuf;
+static uch *window;
+
+static unsigned insize = 0; /* valid bytes in inbuf */
+static unsigned inptr = 0; /* index of next byte to be processed in inbuf */
+static unsigned outcnt = 0; /* bytes in output buffer */
+static int exit_code = 0;
+static long bytes_out = 0;
+
+#define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf())
+
+/* Diagnostic functions (stubbed out) */
+#define Assert(cond,msg)
+#define Trace(x)
+#define Tracev(x)
+#define Tracevv(x)
+#define Tracec(c,x)
+#define Tracecv(c,x)
+
+#define STATIC static
+
+static int fill_inbuf(void);
+static void flush_window(void);
+static void error(char *m);
+static void gzip_mark(void **);
+static void gzip_release(void **);
+
+#include "../../../../lib/inflate.c"
+
+static void gzip_mark( void **ptr )
+{
+}
+
+static void gzip_release( void **ptr )
+{
+}
+
+
+/*
+ * Fill the input buffer. This is called only when the buffer is empty
+ * and at least one byte is really needed.
+ */
+static int fill_inbuf( void )
+{
+ if (exit_code)
+ return -1;
+
+ insize = ll_read( Zinfd, inbuf, INBUFSIZ );
+ if (insize <= 0)
+ return -1;
+
+ 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.)
+ */
+static void flush_window( void )
+{
+ ulg c = crc; /* temporary variable */
+ unsigned n;
+ uch *in, ch;
+ int chunk = Zwpos >> ZFILE_CHUNK_BITS;
+
+ if (chunk >= ZFILE_N_CHUNKS) {
+ fprintf( stderr, "compressed image too large! Aborting.\n" );
+ boot_exit( EXIT_FAILURE );
+ }
+ if (!ZFile[chunk]) {
+ if (!(ZFile[chunk] = (char *)Malloc( ZFILE_CHUNK_SIZE ))) {
+ fprintf( stderr, "Out of memory for decompresing kernel image\n" );
+ boot_exit( EXIT_FAILURE );
+ }
+ }
+ memcpy( ZFile[chunk] + (Zwpos & ZFILE_CHUNK_MASK), window, outcnt );
+ Zwpos += outcnt;
+
+#define DISPLAY_BITS 13
+ if ((Zwpos & ((1 << DISPLAY_BITS)-1)) == 0) {
+ printf( "." );
+ fflush( stdout );
+ }
+
+ in = window;
+ for (n = 0; n < outcnt; n++) {
+ ch = *in++;
+ c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8);
+ }
+ crc = c;
+ bytes_out += (ulg)outcnt;
+ outcnt = 0;
+}
+
+static void error( char *x )
+{
+ fprintf( stderr, "\n%s", x);
+ exit_code = 1;
+}
+
+static int load_zkernel( int fd )
+{
+ int i, err;
+
+ for( i = 0; i < ZFILE_N_CHUNKS; ++i )
+ ZFile[i] = NULL;
+ Zinfd = fd;
+ ll_lseek( fd, 0, SEEK_SET );
+
+ if (!(inbuf = (uch *)Malloc( INBUFSIZ ))) {
+ fprintf( stderr, "Couldn't allocate gunzip buffer\n" );
+ boot_exit( EXIT_FAILURE );
+ }
+ if (!(window = (uch *)Malloc( WSIZE ))) {
+ fprintf( stderr, "Couldn't allocate gunzip window\n" );
+ boot_exit( EXIT_FAILURE );
+ }
+
+ printf( "Uncompressing kernel image " );
+ fflush( stdout );
+ makecrc();
+ if (!(err = gunzip()))
+ printf( "done\n" );
+ ZFileSize = Zwpos;
+ ll_close( Zinfd ); /* input file not needed anymore */
+
+ Mfree( inbuf );
+ Mfree( window );
+ return( err );
+}
+
+/* Note about the read/lseek wrapper and its memory management: It assumes
+ * that all seeks are only forward, and thus data already read or skipped can
+ * be freed. This is true for current organization of bootstrap and kernels.
+ * Little exception: The struct kexec at the start of the file. After reading
+ * it, there may be a seek back to the end of the file. But this currently
+ * doesn't hurt. Same considerations apply to the TFTP file buffers. (Roman)
+ */
+
+static int kread( int fd, void *buf, unsigned cnt )
+{
+ unsigned done = 0;
+
+ if (!ZFileSize)
+ return( ll_read( fd, buf, cnt ) );
+
+ if (ZFpos + cnt > ZFileSize)
+ cnt = ZFileSize - ZFpos;
+
+ while( cnt > 0 ) {
+ unsigned chunk = ZFpos >> ZFILE_CHUNK_BITS;
+ unsigned endchunk = (chunk+1) << ZFILE_CHUNK_BITS;
+ unsigned n = cnt;
+
+ if (ZFpos + n > endchunk)
+ n = endchunk - ZFpos;
+ memcpy( buf, ZFile[chunk] + (ZFpos & ZFILE_CHUNK_MASK), n );
+ cnt -= n;
+ buf += n;
+ done += n;
+ ZFpos += n;
+
+ if (ZFpos == endchunk) {
+ Mfree( ZFile[chunk] );
+ ZFile[chunk] = NULL;
+ }
+ }
+
+ return( done );
+}
+
+
+static int klseek( int fd, int where, int whence )
+{
+ unsigned oldpos, oldchunk, newchunk;
+
+ if (!ZFileSize)
+ return( ll_lseek( fd, where, whence ) );
+
+ oldpos = ZFpos;
+ switch( whence ) {
+ case SEEK_SET:
+ ZFpos = where;
+ break;
+ case SEEK_CUR:
+ ZFpos += where;
+ break;
+ case SEEK_END:
+ ZFpos = ZFileSize + where;
+ break;
+ default:
+ return( -1 );
+ }
+ if (ZFpos < 0) {
+ ZFpos = 0;
+ return( -1 );
+ }
+ else if (ZFpos > ZFileSize) {
+ ZFpos = ZFileSize;
+ return( -1 );
+ }
+
+ /* free memory of skipped-over data */
+ oldchunk = oldpos >> ZFILE_CHUNK_BITS;
+ newchunk = ZFpos >> ZFILE_CHUNK_BITS;
+ while( oldchunk < newchunk ) {
+ if (ZFile[oldchunk]) {
+ Mfree( ZFile[oldchunk] );
+ ZFile[oldchunk] = NULL;
+ }
+ ++oldchunk;
+ }
+
+ return( ZFpos );
+}
+
+
+static void free_zfile( void )
+{
+ int i;
+
+ for( i = 0; i < ZFILE_N_CHUNKS; ++i )
+ if (ZFile[i]) Mfree( ZFile[i] );
+}
+
+static int kclose( int fd )
+{
+ if (ZFileSize) {
+ free_zfile();
+ return( 0 );
+ }
+ else
+ return( ll_close( fd ) );
+}
+
+
+
+#endif /* ZKERNEL */
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov