Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6
[sfrench/cifs-2.6.git] / arch / arm / boot / compressed / misc.c
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
19 unsigned int __machine_arch_type;
20
21 #define _LINUX_STRING_H_
22
23 #include <linux/compiler.h>     /* for inline */
24 #include <linux/types.h>        /* for size_t */
25 #include <linux/stddef.h>       /* for NULL */
26 #include <asm/string.h>
27 #include <linux/linkage.h>
28
29 #include <asm/unaligned.h>
30
31 #ifdef STANDALONE_DEBUG
32 #define putstr printf
33 #else
34
35 static void putstr(const char *ptr);
36
37 #include <mach/uncompress.h>
38
39 #ifdef CONFIG_DEBUG_ICEDCC
40
41 #ifdef CONFIG_CPU_V6
42
43 static void icedcc_putc(int ch)
44 {
45         int status, i = 0x4000000;
46
47         do {
48                 if (--i < 0)
49                         return;
50
51                 asm volatile ("mrc p14, 0, %0, c0, c1, 0" : "=r" (status));
52         } while (status & (1 << 29));
53
54         asm("mcr p14, 0, %0, c0, c5, 0" : : "r" (ch));
55 }
56
57 #elif defined(CONFIG_CPU_V7)
58
59 static void icedcc_putc(int ch)
60 {
61         asm(
62         "wait:  mrc     p14, 0, pc, c0, c1, 0                   \n\
63                 bcs     wait                                    \n\
64                 mcr     p14, 0, %0, c0, c5, 0                   "
65         : : "r" (ch));
66 }
67
68 #elif defined(CONFIG_CPU_XSCALE)
69
70 static void icedcc_putc(int ch)
71 {
72         int status, i = 0x4000000;
73
74         do {
75                 if (--i < 0)
76                         return;
77
78                 asm volatile ("mrc p14, 0, %0, c14, c0, 0" : "=r" (status));
79         } while (status & (1 << 28));
80
81         asm("mcr p14, 0, %0, c8, c0, 0" : : "r" (ch));
82 }
83
84 #else
85
86 static void icedcc_putc(int ch)
87 {
88         int status, i = 0x4000000;
89
90         do {
91                 if (--i < 0)
92                         return;
93
94                 asm volatile ("mrc p14, 0, %0, c0, c0, 0" : "=r" (status));
95         } while (status & 2);
96
97         asm("mcr p14, 0, %0, c1, c0, 0" : : "r" (ch));
98 }
99
100 #endif
101
102 #define putc(ch)        icedcc_putc(ch)
103 #endif
104
105 static void putstr(const char *ptr)
106 {
107         char c;
108
109         while ((c = *ptr++) != '\0') {
110                 if (c == '\n')
111                         putc('\r');
112                 putc(c);
113         }
114
115         flush();
116 }
117
118 #endif
119
120 #define __ptr_t void *
121
122 #define memzero(s,n) __memzero(s,n)
123
124 /*
125  * Optimised C version of memzero for the ARM.
126  */
127 void __memzero (__ptr_t s, size_t n)
128 {
129         union { void *vp; unsigned long *ulp; unsigned char *ucp; } u;
130         int i;
131
132         u.vp = s;
133
134         for (i = n >> 5; i > 0; i--) {
135                 *u.ulp++ = 0;
136                 *u.ulp++ = 0;
137                 *u.ulp++ = 0;
138                 *u.ulp++ = 0;
139                 *u.ulp++ = 0;
140                 *u.ulp++ = 0;
141                 *u.ulp++ = 0;
142                 *u.ulp++ = 0;
143         }
144
145         if (n & 1 << 4) {
146                 *u.ulp++ = 0;
147                 *u.ulp++ = 0;
148                 *u.ulp++ = 0;
149                 *u.ulp++ = 0;
150         }
151
152         if (n & 1 << 3) {
153                 *u.ulp++ = 0;
154                 *u.ulp++ = 0;
155         }
156
157         if (n & 1 << 2)
158                 *u.ulp++ = 0;
159
160         if (n & 1 << 1) {
161                 *u.ucp++ = 0;
162                 *u.ucp++ = 0;
163         }
164
165         if (n & 1)
166                 *u.ucp++ = 0;
167 }
168
169 static inline __ptr_t memcpy(__ptr_t __dest, __const __ptr_t __src,
170                             size_t __n)
171 {
172         int i = 0;
173         unsigned char *d = (unsigned char *)__dest, *s = (unsigned char *)__src;
174
175         for (i = __n >> 3; i > 0; i--) {
176                 *d++ = *s++;
177                 *d++ = *s++;
178                 *d++ = *s++;
179                 *d++ = *s++;
180                 *d++ = *s++;
181                 *d++ = *s++;
182                 *d++ = *s++;
183                 *d++ = *s++;
184         }
185
186         if (__n & 1 << 2) {
187                 *d++ = *s++;
188                 *d++ = *s++;
189                 *d++ = *s++;
190                 *d++ = *s++;
191         }
192
193         if (__n & 1 << 1) {
194                 *d++ = *s++;
195                 *d++ = *s++;
196         }
197
198         if (__n & 1)
199                 *d++ = *s++;
200
201         return __dest;
202 }
203
204 /*
205  * gzip delarations
206  */
207 #define STATIC static
208
209 /* Diagnostic functions */
210 #ifdef DEBUG
211 #  define Assert(cond,msg) {if(!(cond)) error(msg);}
212 #  define Trace(x) fprintf x
213 #  define Tracev(x) {if (verbose) fprintf x ;}
214 #  define Tracevv(x) {if (verbose>1) fprintf x ;}
215 #  define Tracec(c,x) {if (verbose && (c)) fprintf x ;}
216 #  define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;}
217 #else
218 #  define Assert(cond,msg)
219 #  define Trace(x)
220 #  define Tracev(x)
221 #  define Tracevv(x)
222 #  define Tracec(c,x)
223 #  define Tracecv(c,x)
224 #endif
225
226 static void error(char *m);
227
228 extern char input_data[];
229 extern char input_data_end[];
230
231 static unsigned char *output_data;
232 static unsigned long output_ptr;
233
234 static void error(char *m);
235
236 static void putstr(const char *);
237
238 static unsigned long free_mem_ptr;
239 static unsigned long free_mem_end_ptr;
240
241 #ifdef STANDALONE_DEBUG
242 #define NO_INFLATE_MALLOC
243 #endif
244
245 #define ARCH_HAS_DECOMP_WDOG
246
247 #ifdef CONFIG_KERNEL_GZIP
248 #include "../../../../lib/decompress_inflate.c"
249 #endif
250
251 #ifdef CONFIG_KERNEL_LZO
252 #include "../../../../lib/decompress_unlzo.c"
253 #endif
254
255 #ifndef arch_error
256 #define arch_error(x)
257 #endif
258
259 static void error(char *x)
260 {
261         arch_error(x);
262
263         putstr("\n\n");
264         putstr(x);
265         putstr("\n\n -- System halted");
266
267         while(1);       /* Halt */
268 }
269
270 asmlinkage void __div0(void)
271 {
272         error("Attempting division by 0!");
273 }
274
275 #ifndef STANDALONE_DEBUG
276
277 unsigned long
278 decompress_kernel(unsigned long output_start, unsigned long free_mem_ptr_p,
279                 unsigned long free_mem_ptr_end_p,
280                 int arch_id)
281 {
282         unsigned char *tmp;
283
284         output_data             = (unsigned char *)output_start;
285         free_mem_ptr            = free_mem_ptr_p;
286         free_mem_end_ptr        = free_mem_ptr_end_p;
287         __machine_arch_type     = arch_id;
288
289         arch_decomp_setup();
290
291         tmp = (unsigned char *) (((unsigned long)input_data_end) - 4);
292         output_ptr = get_unaligned_le32(tmp);
293
294         putstr("Uncompressing Linux...");
295         decompress(input_data, input_data_end - input_data,
296                         NULL, NULL, output_data, NULL, error);
297         putstr(" done, booting the kernel.\n");
298         return output_ptr;
299 }
300 #else
301
302 char output_buffer[1500*1024];
303
304 int main()
305 {
306         output_data = output_buffer;
307
308         putstr("Uncompressing Linux...");
309         decompress(input_data, input_data_end - input_data,
310                         NULL, NULL, output_data, NULL, error);
311         putstr("done.\n");
312         return 0;
313 }
314 #endif