blob: 65ce8fff29db1583890fe54f438f6f03385e11a9 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * misc.c
3 *
4 * This is a collection of several routines from gzip-1.0.3
5 * adapted for Linux.
6 *
7 * malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994
8 *
9 * Modified for ARM Linux by Russell King
10 *
11 * Nicolas Pitre <nico@visuaide.com> 1999/04/14 :
12 * For this code to run directly from Flash, all constant variables must
13 * be marked with 'const' and all other variables initialized at run-time
14 * only. This way all non constant variables will end up in the bss segment,
15 * which should point to addresses in RAM and cleared to 0 on start.
16 * This allows for a much quicker boot time.
17 */
18
19unsigned int __machine_arch_type;
20
21#include <linux/string.h>
22
Linus Torvalds1da177e2005-04-16 15:20:36 -070023#ifdef STANDALONE_DEBUG
24#define putstr printf
Russell Kinga0815682006-03-28 10:24:33 +010025#else
26
27static void putstr(const char *ptr);
28
29#include <linux/compiler.h>
Russell Kinga09e64f2008-08-05 16:14:15 +010030#include <mach/uncompress.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070031
32#ifdef CONFIG_DEBUG_ICEDCC
Tony Lindgren7d95ded2006-09-20 13:03:34 +010033
34#ifdef CONFIG_CPU_V6
35
36static void icedcc_putc(int ch)
37{
38 int status, i = 0x4000000;
39
40 do {
41 if (--i < 0)
42 return;
43
44 asm volatile ("mrc p14, 0, %0, c0, c1, 0" : "=r" (status));
45 } while (status & (1 << 29));
46
47 asm("mcr p14, 0, %0, c0, c5, 0" : : "r" (ch));
48}
49
50#else
51
Russell Kingde4533a2006-03-28 10:34:05 +010052static void icedcc_putc(int ch)
53{
54 int status, i = 0x4000000;
55
56 do {
57 if (--i < 0)
58 return;
59
Uwe Zeisbergerb2556da2006-05-02 20:40:56 +010060 asm volatile ("mrc p14, 0, %0, c0, c0, 0" : "=r" (status));
Russell Kingde4533a2006-03-28 10:34:05 +010061 } while (status & 2);
62
Uwe Zeisbergerb2556da2006-05-02 20:40:56 +010063 asm("mcr p14, 0, %0, c1, c0, 0" : : "r" (ch));
Russell Kingde4533a2006-03-28 10:34:05 +010064}
65
Tony Lindgren7d95ded2006-09-20 13:03:34 +010066#endif
67
Russell Kinga0815682006-03-28 10:24:33 +010068#define putc(ch) icedcc_putc(ch)
69#define flush() do { } while (0)
70#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070071
Russell Kinga0815682006-03-28 10:24:33 +010072static void putstr(const char *ptr)
Linus Torvalds1da177e2005-04-16 15:20:36 -070073{
Russell Kinga0815682006-03-28 10:24:33 +010074 char c;
75
76 while ((c = *ptr++) != '\0') {
77 if (c == '\n')
78 putc('\r');
79 putc(c);
Linus Torvalds1da177e2005-04-16 15:20:36 -070080 }
Russell Kinga0815682006-03-28 10:24:33 +010081
82 flush();
Linus Torvalds1da177e2005-04-16 15:20:36 -070083}
84
85#endif
86
87#define __ptr_t void *
88
89/*
90 * Optimised C version of memzero for the ARM.
91 */
92void __memzero (__ptr_t s, size_t n)
93{
94 union { void *vp; unsigned long *ulp; unsigned char *ucp; } u;
95 int i;
96
97 u.vp = s;
98
99 for (i = n >> 5; i > 0; i--) {
100 *u.ulp++ = 0;
101 *u.ulp++ = 0;
102 *u.ulp++ = 0;
103 *u.ulp++ = 0;
104 *u.ulp++ = 0;
105 *u.ulp++ = 0;
106 *u.ulp++ = 0;
107 *u.ulp++ = 0;
108 }
109
110 if (n & 1 << 4) {
111 *u.ulp++ = 0;
112 *u.ulp++ = 0;
113 *u.ulp++ = 0;
114 *u.ulp++ = 0;
115 }
116
117 if (n & 1 << 3) {
118 *u.ulp++ = 0;
119 *u.ulp++ = 0;
120 }
121
122 if (n & 1 << 2)
123 *u.ulp++ = 0;
124
125 if (n & 1 << 1) {
126 *u.ucp++ = 0;
127 *u.ucp++ = 0;
128 }
129
130 if (n & 1)
131 *u.ucp++ = 0;
132}
133
134static inline __ptr_t memcpy(__ptr_t __dest, __const __ptr_t __src,
135 size_t __n)
136{
137 int i = 0;
138 unsigned char *d = (unsigned char *)__dest, *s = (unsigned char *)__src;
139
140 for (i = __n >> 3; i > 0; i--) {
141 *d++ = *s++;
142 *d++ = *s++;
143 *d++ = *s++;
144 *d++ = *s++;
145 *d++ = *s++;
146 *d++ = *s++;
147 *d++ = *s++;
148 *d++ = *s++;
149 }
150
151 if (__n & 1 << 2) {
152 *d++ = *s++;
153 *d++ = *s++;
154 *d++ = *s++;
155 *d++ = *s++;
156 }
157
158 if (__n & 1 << 1) {
159 *d++ = *s++;
160 *d++ = *s++;
161 }
162
163 if (__n & 1)
164 *d++ = *s++;
165
166 return __dest;
167}
168
169/*
170 * gzip delarations
171 */
172#define OF(args) args
173#define STATIC static
174
175typedef unsigned char uch;
176typedef unsigned short ush;
177typedef unsigned long ulg;
178
179#define WSIZE 0x8000 /* Window size must be at least 32k, */
180 /* and a power of two */
181
182static uch *inbuf; /* input buffer */
183static uch window[WSIZE]; /* Sliding window buffer */
184
185static unsigned insize; /* valid bytes in inbuf */
186static unsigned inptr; /* index of next byte to be processed in inbuf */
187static unsigned outcnt; /* bytes in output buffer */
188
189/* gzip flag byte */
190#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */
191#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
192#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
193#define ORIG_NAME 0x08 /* bit 3 set: original file name present */
194#define COMMENT 0x10 /* bit 4 set: file comment present */
195#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */
196#define RESERVED 0xC0 /* bit 6,7: reserved */
197
198#define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf())
199
200/* Diagnostic functions */
201#ifdef DEBUG
202# define Assert(cond,msg) {if(!(cond)) error(msg);}
203# define Trace(x) fprintf x
204# define Tracev(x) {if (verbose) fprintf x ;}
205# define Tracevv(x) {if (verbose>1) fprintf x ;}
206# define Tracec(c,x) {if (verbose && (c)) fprintf x ;}
207# define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;}
208#else
209# define Assert(cond,msg)
210# define Trace(x)
211# define Tracev(x)
212# define Tracevv(x)
213# define Tracec(c,x)
214# define Tracecv(c,x)
215#endif
216
217static int fill_inbuf(void);
218static void flush_window(void);
219static void error(char *m);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220
221extern char input_data[];
222extern char input_data_end[];
223
224static uch *output_data;
225static ulg output_ptr;
226static ulg bytes_out;
227
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228static void error(char *m);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229
230static void putstr(const char *);
231
232extern int end;
233static ulg free_mem_ptr;
Thomas Petazzoni2d6ffcc2008-07-25 01:45:44 -0700234static ulg free_mem_end_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235
Thomas Petazzoni2d6ffcc2008-07-25 01:45:44 -0700236#ifdef STANDALONE_DEBUG
237#define NO_INFLATE_MALLOC
238#endif
239
240#define ARCH_HAS_DECOMP_WDOG
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241
242#include "../../../../lib/inflate.c"
243
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244/* ===========================================================================
245 * Fill the input buffer. This is called only when the buffer is empty
246 * and at least one byte is really needed.
247 */
248int fill_inbuf(void)
249{
250 if (insize != 0)
251 error("ran out of input data");
252
253 inbuf = input_data;
254 insize = &input_data_end[0] - &input_data[0];
255
256 inptr = 1;
257 return inbuf[0];
258}
259
260/* ===========================================================================
261 * Write the output window window[0..outcnt-1] and update crc and bytes_out.
262 * (Used for the decompressed data only.)
263 */
264void flush_window(void)
265{
266 ulg c = crc;
267 unsigned n;
268 uch *in, *out, ch;
269
270 in = window;
271 out = &output_data[output_ptr];
272 for (n = 0; n < outcnt; n++) {
273 ch = *out++ = *in++;
274 c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8);
275 }
276 crc = c;
277 bytes_out += (ulg)outcnt;
278 output_ptr += (ulg)outcnt;
279 outcnt = 0;
280 putstr(".");
281}
282
Ben Dooksf8c905d2005-11-08 22:43:05 +0000283#ifndef arch_error
284#define arch_error(x)
285#endif
286
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287static void error(char *x)
288{
Ben Dooksf8c905d2005-11-08 22:43:05 +0000289 arch_error(x);
290
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291 putstr("\n\n");
292 putstr(x);
293 putstr("\n\n -- System halted");
294
295 while(1); /* Halt */
296}
297
298#ifndef STANDALONE_DEBUG
299
300ulg
301decompress_kernel(ulg output_start, ulg free_mem_ptr_p, ulg free_mem_ptr_end_p,
302 int arch_id)
303{
304 output_data = (uch *)output_start; /* Points to kernel start */
305 free_mem_ptr = free_mem_ptr_p;
Thomas Petazzoni2d6ffcc2008-07-25 01:45:44 -0700306 free_mem_end_ptr = free_mem_ptr_end_p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307 __machine_arch_type = arch_id;
308
309 arch_decomp_setup();
310
311 makecrc();
312 putstr("Uncompressing Linux...");
313 gunzip();
314 putstr(" done, booting the kernel.\n");
315 return output_ptr;
316}
317#else
318
319char output_buffer[1500*1024];
320
321int main()
322{
323 output_data = output_buffer;
324
325 makecrc();
326 putstr("Uncompressing Linux...");
327 gunzip();
328 putstr("done.\n");
329 return 0;
330}
331#endif
332