blob: 32fae92d72f41d5a1f02c2cb6fd2ce92dcc40884 [file] [log] [blame]
/* Self decompression and image decompression routines
Copyright (C) 1993 Hannu Savolainen
1996,1998 Jakub Jelinek
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
USA. */
#include <silo.h>
#include <setjmp.h>
#ifndef NULL
#define NULL (void *)0
#endif
/*
* gzip declarations
*/
#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 *);
#define gzip_mark mark
static inline void gzip_release (void **p)
{
release (*p);
}
static long bytes_out;
static uch *output_data, *output_limit;
static unsigned char (*get_input_fun) (void);
static void (*unget_input_fun) (void);
jmp_buf gunzip_env;
#define get_byte() (*get_input_fun)()
#define unget_byte() (*unget_input_fun)()
#include "../common/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 ("uncompressed 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;
bytes_out += (ulg) outcnt;
outcnt = 0;
}
int decompress (char *outptr, char *outptrlim, unsigned char (*get_input) (void), void (*unget_input) (void))
{
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;
get_input_fun = get_input;
unget_input_fun = unget_input;
bytes_out = 0;
crc = 0xffffffffL;
if (first) {
makecrc ();
first = 0;
}
gunzip ();
gzip_release (&save_ptr);
return bytes_out;
}
static unsigned char *gzminp;
static unsigned char get_input(void)
{
return *gzminp++;
}
static void unget_input(void)
{
gzminp--;
}
extern char main_text_start, main_text_end, main_data_start, main_data_end, main_rodata_start, main_rodata_end, __bss_start;
/* This has to be in data section, so that it does not get cleared. See crt0.S for details. */
unsigned char *gzminpi = (unsigned char *)0xdeadbeef;
extern int bootmain(void);
unsigned my_main(struct linux_romvec *promvec, void *cifh, void *cifs)
{
prom_init(promvec, cifh, cifs);
#ifdef TFTP
prom_puts ("SILO", 4);
#else
prom_puts ("O", 1);
#endif
printf(" Version %s\n", VERSION);
if (!cifh) {
unsigned short *pt = (unsigned short *)gzminpi;
while (*pt) pt++;
pt++;
while (*pt) pt++;
pt++;
gzminpi = (unsigned char *)pt;
}
gzminp = gzminpi;
if (decompress ((char *)0x200000, (char *)&_start, get_input, unget_input) == -1) {
printf ("\nInternal error\n");
prom_halt();
}
memcpy (&main_text_start, (char *)0x200000, &main_text_end - &main_text_start);
memcpy (&main_rodata_start, (char *)0x200000 + (&main_text_end - &main_text_start), &main_rodata_end - &main_rodata_start);
memcpy (&main_data_start, (char *)0x200000 + (&main_text_end - &main_text_start) + (&main_rodata_end - &main_rodata_start), &main_data_end - &main_data_start);
if (cifh) {
unsigned char *cp = (unsigned char *)LARGE_RELOC;
unsigned short *pt = (unsigned short *)((char *)0x200000 + (&main_text_end - &main_text_start) +
(&main_rodata_end - &main_rodata_start) + (&main_data_end - &main_data_start));
while (*pt) {
cp += *pt;
pt++;
*cp += 4;
}
pt++;
cp = (unsigned char *)LARGE_RELOC;
while (*pt) {
cp += *pt;
pt++;
*cp += 16;
}
}
return bootmain();
}