blob: e4d97527e42af96c918195e8839b313580881f60 [file] [log] [blame]
/*
* 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) Helge Deller <deller@gmx.de>
*/
#ifdef __hpux
# define _LINUX_TYPES_H
#endif
#include "common.h"
#include "load.h"
#include <stdio.h>
#ifndef NULL
#define NULL (void *)0
#endif
/*
* gzip declarations
*/
#ifdef IPL_LOADER
# include "bootloader.h"
#else
# include <setjmp.h>
# include <string.h>
# include <stdlib.h>
# define pa_memcpy memcpy
# define mark gzip_mark
# define release gzip_release
#endif
# define gzip_mark(ptr) do { *ptr = 0UL; } while (0)
# define gzip_release(x) do { } while (0)
static void pa_free(void *ptr) { }
#define pa_malloc malloc
#define OF(args) args
#define STATIC static
#define memzero(s, n) memset ((s), 0, (n))
typedef unsigned char uch;
typedef unsigned short ush;
typedef unsigned long ulg;
#define WSIZE 0x8000 /* Window size must be at least 32k, */
/* and a power of two */
static uch window[WSIZE]; /* Sliding window buffer */
static unsigned outcnt = 0; /* bytes in output buffer */
/* 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 */
#define Assert(cond,msg)
#define Trace(x)
#define Tracev(x)
#define Tracevv(x)
#define Tracec(c,x)
#define Tracecv(c,x)
static void flush_window (void);
static void error (char *);
static long bytes_out;
static uch *output_data, *output_limit;
/* gzbuffer is the buffer in which we keep the uncompressed gzip data */
#define GZBUFFER_SIZE (4096*2)
static unsigned char gzbuffer[GZBUFFER_SIZE];
static int orig_fd; /* file descriptor for seekread */
static int blocknr;
static int gzminp;
static unsigned char get_byte(void)
{
if (gzminp == GZBUFFER_SIZE) {
blocknr++;
STRUCTREAD(orig_fd, gzbuffer, blocknr * GZBUFFER_SIZE);
gzminp = 0;
}
return gzbuffer[gzminp++];
}
static void unget_byte(void)
{
if (gzminp == 0) {
blocknr--;
STRUCTREAD(orig_fd, gzbuffer, blocknr * GZBUFFER_SIZE);
gzminp = GZBUFFER_SIZE;
}
gzminp--;
}
static jmp_buf gunzip_env;
#include "../lib/inflate.c"
static void error (char *m)
{
printf ("\nDecompression error: %s\n", m);
longjmp (gunzip_env, 1);
}
static void flush_window ()
{
ulg c = crc;
unsigned n;
uch *in, ch;
in = window;
if (output_data + outcnt > output_limit)
error ("\nuncompressed image too long - wouldn't fit into destination");
for (n = 0; n < outcnt; n++) {
ch = *output_data++ = *in++;
c = crc_32_tab[((int) c ^ ch) & 0xff] ^ (c >> 8);
}
crc = c;
/* show progress indicator */
printf(".");
bytes_out += (ulg) outcnt;
outcnt = 0;
}
static long decompress(char *outptr, char *outptrlim)
{
void *save_ptr;
static int first = 1;
gzip_mark (&save_ptr);
if (setjmp (gunzip_env)) {
gzip_release (&save_ptr);
return -1;
}
output_data = (uch *)outptr;
output_limit = (uch *)outptrlim;
bytes_out = 0;
outcnt = 0;
crc = 0xffffffffL;
if (first) {
makecrc ();
first = 0;
}
gunzip ();
gzip_release (&save_ptr);
return bytes_out;
}
#define GZIP_MAGIC0 0x1f
#define GZIP_MAGIC1 0x8b
#define GZIP_MAGIC2 0x08 /* DEFLATED */
int prepare_GZIP_loadable(int fd, struct loadable *loadable, int *wide)
{
unsigned char flags;
long bytes_len;
char *orig_filename = "unknown";
char *outptr, *outptrlim;
int i;
void *release_all_mallocs, *keep_unzipped;
blocknr = 0;
gzminp = 0;
orig_fd = fd;
STRUCTREAD(orig_fd, gzbuffer, 0);
if (gzbuffer[0] != GZIP_MAGIC0 ||
gzbuffer[1] != GZIP_MAGIC1 ||
gzbuffer[2] != GZIP_MAGIC2)
{
return PREPARE_CONTINUE;
}
flags = gzbuffer[3]; /* general flags */
if (flags & ORIG_NAME)
orig_filename = (char *) &gzbuffer[10];
mark(&release_all_mallocs);
#define MAX_GZ_LEN (100*1024*1024)
outptr = (char *) pa_malloc(MAX_GZ_LEN);
mark(&keep_unzipped);
outptrlim = outptr + MAX_GZ_LEN;
if (0)
printf("uncompressing %s to 0x%p", orig_filename, outptr);
else
printf("uncompressing Linux kernel");
bytes_len = decompress(outptr, outptrlim);
if (bytes_len > MAX_GZ_LEN)
printf("\nERROR: Internal buffer MAX_GZ_LEN too small!");
if (bytes_len < 0) {
release(release_all_mallocs);
return PREPARE_CONTINUE;
}
release(keep_unzipped);
loadable->uncompressed_size = bytes_len;
loadable->uncompressed_data = outptr;
if (0)
printf("\nGZIP compressed file size = %lu\n", bytes_len);
else
printf("\n");
/* try to detect real 32 or 64bit kernel now */
i = prepare_ELF32_loadable(fd, loadable, wide);
if (i != PREPARE_OK)
i = prepare_ELF64_loadable(fd, loadable, wide);
if (i != PREPARE_OK)
release(release_all_mallocs);
return i;
}