1/*
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
23#ifdef STANDALONE_DEBUG
24#define putstr printf
25#else
26
27static void putstr(const char *ptr);
28
29#include <linux/compiler.h>
30#include <asm/arch/uncompress.h>
31
32#ifdef CONFIG_DEBUG_ICEDCC
33
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
52static void icedcc_putc(int ch)
53{
54	int status, i = 0x4000000;
55
56	do {
57		if (--i < 0)
58			return;
59
60		asm volatile ("mrc p14, 0, %0, c0, c0, 0" : "=r" (status));
61	} while (status & 2);
62
63	asm("mcr p14, 0, %0, c1, c0, 0" : : "r" (ch));
64}
65
66#endif
67
68#define putc(ch)	icedcc_putc(ch)
69#define flush()	do { } while (0)
70#endif
71
72static void putstr(const char *ptr)
73{
74	char c;
75
76	while ((c = *ptr++) != '\0') {
77		if (c == '\n')
78			putc('\r');
79		putc(c);
80	}
81
82	flush();
83}
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);
220static void gzip_mark(void **);
221static void gzip_release(void **);
222
223extern char input_data[];
224extern char input_data_end[];
225
226static uch *output_data;
227static ulg output_ptr;
228static ulg bytes_out;
229
230static void *malloc(int size);
231static void free(void *where);
232static void error(char *m);
233static void gzip_mark(void **);
234static void gzip_release(void **);
235
236static void putstr(const char *);
237
238extern int end;
239static ulg free_mem_ptr;
240static ulg free_mem_ptr_end;
241
242#define HEAP_SIZE 0x3000
243
244#include "../../../../lib/inflate.c"
245
246#ifndef STANDALONE_DEBUG
247static void *malloc(int size)
248{
249	void *p;
250
251	if (size <0) error("Malloc error");
252	if (free_mem_ptr <= 0) error("Memory error");
253
254	free_mem_ptr = (free_mem_ptr + 3) & ~3;	/* Align */
255
256	p = (void *)free_mem_ptr;
257	free_mem_ptr += size;
258
259	if (free_mem_ptr >= free_mem_ptr_end)
260		error("Out of memory");
261	return p;
262}
263
264static void free(void *where)
265{ /* gzip_mark & gzip_release do the free */
266}
267
268static void gzip_mark(void **ptr)
269{
270	arch_decomp_wdog();
271	*ptr = (void *) free_mem_ptr;
272}
273
274static void gzip_release(void **ptr)
275{
276	arch_decomp_wdog();
277	free_mem_ptr = (long) *ptr;
278}
279#else
280static void gzip_mark(void **ptr)
281{
282}
283
284static void gzip_release(void **ptr)
285{
286}
287#endif
288
289/* ===========================================================================
290 * Fill the input buffer. This is called only when the buffer is empty
291 * and at least one byte is really needed.
292 */
293int fill_inbuf(void)
294{
295	if (insize != 0)
296		error("ran out of input data");
297
298	inbuf = input_data;
299	insize = &input_data_end[0] - &input_data[0];
300
301	inptr = 1;
302	return inbuf[0];
303}
304
305/* ===========================================================================
306 * Write the output window window[0..outcnt-1] and update crc and bytes_out.
307 * (Used for the decompressed data only.)
308 */
309void flush_window(void)
310{
311	ulg c = crc;
312	unsigned n;
313	uch *in, *out, ch;
314
315	in = window;
316	out = &output_data[output_ptr];
317	for (n = 0; n < outcnt; n++) {
318		ch = *out++ = *in++;
319		c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8);
320	}
321	crc = c;
322	bytes_out += (ulg)outcnt;
323	output_ptr += (ulg)outcnt;
324	outcnt = 0;
325	putstr(".");
326}
327
328#ifndef arch_error
329#define arch_error(x)
330#endif
331
332static void error(char *x)
333{
334	arch_error(x);
335
336	putstr("\n\n");
337	putstr(x);
338	putstr("\n\n -- System halted");
339
340	while(1);	/* Halt */
341}
342
343#ifndef STANDALONE_DEBUG
344
345ulg
346decompress_kernel(ulg output_start, ulg free_mem_ptr_p, ulg free_mem_ptr_end_p,
347		  int arch_id)
348{
349	output_data		= (uch *)output_start;	/* Points to kernel start */
350	free_mem_ptr		= free_mem_ptr_p;
351	free_mem_ptr_end	= free_mem_ptr_end_p;
352	__machine_arch_type	= arch_id;
353
354	arch_decomp_setup();
355
356	makecrc();
357	putstr("Uncompressing Linux...");
358	gunzip();
359	putstr(" done, booting the kernel.\n");
360	return output_ptr;
361}
362#else
363
364char output_buffer[1500*1024];
365
366int main()
367{
368	output_data = output_buffer;
369
370	makecrc();
371	putstr("Uncompressing Linux...");
372	gunzip();
373	putstr("done.\n");
374	return 0;
375}
376#endif
377
378