| /* 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(); |
| } |