| /* TILO: The TFTP Image LOader |
| |
| Copyright (C) 1996 Jakub Jelinek |
| 1998 Jan Vondrak |
| |
| 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 |
| |
| #ifndef LARGETILO |
| #define MOVED_BASE 0x3c0000 |
| #else |
| #define MOVED_BASE 0x4c0000 |
| #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 |
| 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 = (unsigned char *)outptr; |
| output_limit = (unsigned char *)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); |
| #ifdef TILO_DEBUG |
| printf("Returning from decompress()\n"); |
| #endif |
| return bytes_out; |
| } |
| |
| static unsigned char *gzminp; |
| static unsigned char get_input(void) |
| { |
| return *gzminp++; |
| } |
| |
| static void unget_input(void) |
| { |
| gzminp--; |
| } |
| |
| extern char start, main_text_start, main_text_end, main_data_start, main_data_end, main_rodata_start, main_rodata_end, __bss_start; |
| |
| struct ImageInfo |
| { |
| unsigned packed_start; |
| unsigned packed_len; |
| unsigned unpacked_len; /* this is meaningful for the kernel images only */ |
| unsigned root_start; /* this is meaningful for the kernel images only */ |
| }; |
| |
| extern struct ImageInfo image_table[4]; /* Sun4 kernel, Sun4c/d/m kernel, Sun4u kernel, root image */ |
| |
| #define SUN4_KERNEL 0 |
| #define SUN4C_KERNEL 1 |
| #define SUN4U_KERNEL 2 |
| #define ROOT_IMAGE 3 |
| |
| #define HDRS_TAG (('H'<<24) | ('d'<<16) | ('r'<<8) | 'S') |
| |
| char *my_main (struct linux_romvec *promvec, void *cifh, void *cifs) |
| { |
| char *orig_code,*moved_code,*moved_ramdisk,*moved_kernel,*kernel_base; |
| unsigned *p,*q = NULL; |
| int kernel_number; |
| |
| prom_init(promvec, cifh, cifs); |
| |
| printf ("TILO\n"); |
| |
| if (cifh) |
| { |
| kernel_number = SUN4U_KERNEL; /* Sun4u */ |
| printf("Selecting sun4u kernel...\n"); |
| } |
| else if ((long)promvec == 0x4000) |
| { |
| kernel_number = SUN4_KERNEL; /* Sun4 */ |
| printf("Selecting sun4 kernel...\n"); |
| } |
| else |
| { |
| kernel_number = SUN4C_KERNEL; /* Sun4c/d/m */ |
| printf("Selecting sun4cdm kernel...\n"); |
| } |
| |
| if (image_table[kernel_number].packed_len == 0) |
| { |
| printf ("ERROR: No kernel for this architecture in this TILO image\n"); |
| prom_halt (); |
| } |
| |
| orig_code = (char*) 0x4000; |
| moved_code = (char*) MOVED_BASE; |
| moved_ramdisk = (char*)((long)(moved_code - image_table[ROOT_IMAGE].packed_len) & ~0xfff); |
| moved_kernel = (char*)((long)(moved_ramdisk - image_table[kernel_number].packed_len) & ~0xfff); |
| #ifdef TILO_DEBUG |
| printf("Locations: moved_code=%x moved_ramdisk=%x moved_kernel=%x\n", |
| moved_code, moved_ramdisk, moved_kernel); |
| #endif |
| memmove (moved_ramdisk, orig_code + image_table[ROOT_IMAGE].packed_start, image_table[ROOT_IMAGE].packed_len); |
| memmove (moved_kernel, orig_code + image_table[kernel_number].packed_start, image_table[kernel_number].packed_len); |
| |
| gzminp = (unsigned char *)moved_kernel; /* decompress kernel */ |
| kernel_base = (char*) 0x4000; |
| |
| if (decompress (kernel_base, kernel_base + ((image_table[kernel_number].unpacked_len |
| + 0xfff) & ~0xfff), get_input, unget_input) == -1) |
| { |
| printf ("\nKernel decompression error\n"); |
| prom_halt(); |
| } |
| |
| switch (kernel_number) |
| { |
| case SUN4U_KERNEL: |
| /* find HdrS in Sun4u kernel */ |
| q = (unsigned*)kernel_base + 2; |
| break; |
| |
| case SUN4C_KERNEL: |
| /* find HdrS in Sun4c/m/d kernel */ |
| p = (unsigned*)kernel_base; |
| p += *p & 0xffff; /* extract jump offset */ |
| q = p - 16; /* from the branch instruction */ |
| |
| while (q < p && *q != HDRS_TAG) |
| q++; |
| break; |
| |
| default: |
| /* find HdrS in Sun4 kernel */ |
| printf ("Sun4 kernel not supported yet\n"); |
| prom_halt (); |
| break; |
| |
| } |
| |
| if (*q != HDRS_TAG) |
| { |
| printf ("Can't find HdrS tag in kernel\n"); |
| prom_halt (); |
| } |
| |
| /* reset root flags */ |
| q[2] &= 0xffff0000; |
| /* Set root device and flags. Basically read-write. 0x0100 is ramdisk */ |
| q[3] = 0x01000000; |
| q[4] = image_table[kernel_number].root_start; |
| q[5] = image_table[ROOT_IMAGE].packed_len; |
| |
| /* move root image */ |
| memmove ((void*)(image_table[kernel_number].root_start & 0x3fffff), |
| moved_ramdisk, image_table[ROOT_IMAGE].packed_len); |
| #ifdef TILO_DEBUG |
| printf("Returning from my_main() with address %x\n", kernel_base); |
| #endif |
| return kernel_base; /* return address to jump into kernel */ |
| } |