diff options
Diffstat (limited to 'arch/mn10300/boot/compressed/misc.c')
-rw-r--r-- | arch/mn10300/boot/compressed/misc.c | 429 |
1 files changed, 429 insertions, 0 deletions
diff --git a/arch/mn10300/boot/compressed/misc.c b/arch/mn10300/boot/compressed/misc.c new file mode 100644 index 000000000000..ded207efc97a --- /dev/null +++ b/arch/mn10300/boot/compressed/misc.c | |||
@@ -0,0 +1,429 @@ | |||
1 | /* MN10300 Miscellaneous helper routines for kernel decompressor | ||
2 | * | ||
3 | * Copyright (C) 2007 Matsushita Electric Industrial Co., Ltd. | ||
4 | * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. | ||
5 | * Modified by David Howells (dhowells@redhat.com) | ||
6 | * - Derived from arch/x86/boot/compressed/misc_32.c | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public Licence | ||
10 | * as published by the Free Software Foundation; either version | ||
11 | * 2 of the Licence, or (at your option) any later version. | ||
12 | */ | ||
13 | #include <linux/compiler.h> | ||
14 | #include <asm/serial-regs.h> | ||
15 | #include "misc.h" | ||
16 | |||
17 | #ifndef CONFIG_GDBSTUB_ON_TTYSx | ||
18 | /* display 'Uncompressing Linux... ' messages on ttyS0 or ttyS1 */ | ||
19 | #if 1 /* ttyS0 */ | ||
20 | #define CYG_DEV_BASE 0xA6FB0000 | ||
21 | #else /* ttyS1 */ | ||
22 | #define CYG_DEV_BASE 0xA6FC0000 | ||
23 | #endif | ||
24 | |||
25 | #define CYG_DEV_THR (*((volatile __u8*)(CYG_DEV_BASE + 0x00))) | ||
26 | #define CYG_DEV_MCR (*((volatile __u8*)(CYG_DEV_BASE + 0x10))) | ||
27 | #define SIO_MCR_DTR 0x01 | ||
28 | #define SIO_MCR_RTS 0x02 | ||
29 | #define CYG_DEV_LSR (*((volatile __u8*)(CYG_DEV_BASE + 0x14))) | ||
30 | #define SIO_LSR_THRE 0x20 /* transmitter holding register empty */ | ||
31 | #define SIO_LSR_TEMT 0x40 /* transmitter register empty */ | ||
32 | #define CYG_DEV_MSR (*((volatile __u8*)(CYG_DEV_BASE + 0x18))) | ||
33 | #define SIO_MSR_CTS 0x10 /* clear to send */ | ||
34 | #define SIO_MSR_DSR 0x20 /* data set ready */ | ||
35 | |||
36 | #define LSR_WAIT_FOR(STATE) \ | ||
37 | do { while (!(CYG_DEV_LSR & SIO_LSR_##STATE)) {} } while (0) | ||
38 | #define FLOWCTL_QUERY(LINE) \ | ||
39 | ({ CYG_DEV_MSR & SIO_MSR_##LINE; }) | ||
40 | #define FLOWCTL_WAIT_FOR(LINE) \ | ||
41 | do { while (!(CYG_DEV_MSR & SIO_MSR_##LINE)) {} } while (0) | ||
42 | #define FLOWCTL_CLEAR(LINE) \ | ||
43 | do { CYG_DEV_MCR &= ~SIO_MCR_##LINE; } while (0) | ||
44 | #define FLOWCTL_SET(LINE) \ | ||
45 | do { CYG_DEV_MCR |= SIO_MCR_##LINE; } while (0) | ||
46 | #endif | ||
47 | |||
48 | /* | ||
49 | * gzip declarations | ||
50 | */ | ||
51 | |||
52 | #define OF(args) args | ||
53 | #define STATIC static | ||
54 | |||
55 | #undef memset | ||
56 | #undef memcpy | ||
57 | |||
58 | static inline void *memset(const void *s, int c, size_t n) | ||
59 | { | ||
60 | int i; | ||
61 | char *ss = (char *) s; | ||
62 | |||
63 | for (i = 0; i < n; i++) | ||
64 | ss[i] = c; | ||
65 | return (void *)s; | ||
66 | } | ||
67 | |||
68 | #define memzero(s, n) memset((s), 0, (n)) | ||
69 | |||
70 | static inline void *memcpy(void *__dest, const void *__src, size_t __n) | ||
71 | { | ||
72 | int i; | ||
73 | const char *s = __src; | ||
74 | char *d = __dest; | ||
75 | |||
76 | for (i = 0; i < __n; i++) | ||
77 | d[i] = s[i]; | ||
78 | return __dest; | ||
79 | } | ||
80 | |||
81 | typedef unsigned char uch; | ||
82 | typedef unsigned short ush; | ||
83 | typedef unsigned long ulg; | ||
84 | |||
85 | #define WSIZE 0x8000 /* Window size must be at least 32k, and a power of | ||
86 | * two */ | ||
87 | |||
88 | static uch *inbuf; /* input buffer */ | ||
89 | static uch window[WSIZE]; /* sliding window buffer */ | ||
90 | |||
91 | static unsigned insize; /* valid bytes in inbuf */ | ||
92 | static unsigned inptr; /* index of next byte to be processed in inbuf */ | ||
93 | static unsigned outcnt; /* bytes in output buffer */ | ||
94 | |||
95 | /* gzip flag byte */ | ||
96 | #define ASCII_FLAG 0x01 /* bit 0 set: file probably ASCII text */ | ||
97 | #define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */ | ||
98 | #define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ | ||
99 | #define ORIG_NAME 0x08 /* bit 3 set: original file name present */ | ||
100 | #define COMMENT 0x10 /* bit 4 set: file comment present */ | ||
101 | #define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */ | ||
102 | #define RESERVED 0xC0 /* bit 6,7: reserved */ | ||
103 | |||
104 | /* Diagnostic functions */ | ||
105 | #ifdef DEBUG | ||
106 | # define Assert(cond, msg) { if (!(cond)) error(msg); } | ||
107 | # define Trace(x) fprintf x | ||
108 | # define Tracev(x) { if (verbose) fprintf x ; } | ||
109 | # define Tracevv(x) { if (verbose > 1) fprintf x ; } | ||
110 | # define Tracec(c, x) { if (verbose && (c)) fprintf x ; } | ||
111 | # define Tracecv(c, x) { if (verbose > 1 && (c)) fprintf x ; } | ||
112 | #else | ||
113 | # define Assert(cond, msg) | ||
114 | # define Trace(x) | ||
115 | # define Tracev(x) | ||
116 | # define Tracevv(x) | ||
117 | # define Tracec(c, x) | ||
118 | # define Tracecv(c, x) | ||
119 | #endif | ||
120 | |||
121 | static int fill_inbuf(void); | ||
122 | static void flush_window(void); | ||
123 | static void error(const char *) __attribute__((noreturn)); | ||
124 | static void kputs(const char *); | ||
125 | |||
126 | static inline unsigned char get_byte(void) | ||
127 | { | ||
128 | unsigned char ch = inptr < insize ? inbuf[inptr++] : fill_inbuf(); | ||
129 | |||
130 | #if 0 | ||
131 | char hex[3]; | ||
132 | hex[0] = ((ch & 0x0f) > 9) ? | ||
133 | ((ch & 0x0f) + 'A' - 0xa) : ((ch & 0x0f) + '0'); | ||
134 | hex[1] = ((ch >> 4) > 9) ? | ||
135 | ((ch >> 4) + 'A' - 0xa) : ((ch >> 4) + '0'); | ||
136 | hex[2] = 0; | ||
137 | kputs(hex); | ||
138 | #endif | ||
139 | return ch; | ||
140 | } | ||
141 | |||
142 | /* | ||
143 | * This is set up by the setup-routine at boot-time | ||
144 | */ | ||
145 | #define EXT_MEM_K (*(unsigned short *)0x90002) | ||
146 | #ifndef STANDARD_MEMORY_BIOS_CALL | ||
147 | #define ALT_MEM_K (*(unsigned long *) 0x901e0) | ||
148 | #endif | ||
149 | #define SCREEN_INFO (*(struct screen_info *)0x90000) | ||
150 | |||
151 | static long bytes_out; | ||
152 | static uch *output_data; | ||
153 | static unsigned long output_ptr; | ||
154 | |||
155 | |||
156 | static void *malloc(int size); | ||
157 | |||
158 | static inline void free(void *where) | ||
159 | { /* Don't care */ | ||
160 | } | ||
161 | |||
162 | static unsigned long free_mem_ptr = (unsigned long) &end; | ||
163 | static unsigned long free_mem_end_ptr = (unsigned long) &end + 0x90000; | ||
164 | |||
165 | static inline void gzip_mark(void **ptr) | ||
166 | { | ||
167 | kputs("."); | ||
168 | *ptr = (void *) free_mem_ptr; | ||
169 | } | ||
170 | |||
171 | static inline void gzip_release(void **ptr) | ||
172 | { | ||
173 | free_mem_ptr = (unsigned long) *ptr; | ||
174 | } | ||
175 | |||
176 | #define INPLACE_MOVE_ROUTINE 0x1000 | ||
177 | #define LOW_BUFFER_START 0x2000 | ||
178 | #define LOW_BUFFER_END 0x90000 | ||
179 | #define LOW_BUFFER_SIZE (LOW_BUFFER_END - LOW_BUFFER_START) | ||
180 | #define HEAP_SIZE 0x3000 | ||
181 | static int high_loaded; | ||
182 | static uch *high_buffer_start /* = (uch *)(((ulg)&end) + HEAP_SIZE)*/; | ||
183 | |||
184 | static char *vidmem = (char *)0xb8000; | ||
185 | static int lines, cols; | ||
186 | |||
187 | #include "../../../../lib/inflate.c" | ||
188 | |||
189 | static void *malloc(int size) | ||
190 | { | ||
191 | void *p; | ||
192 | |||
193 | if (size < 0) | ||
194 | error("Malloc error\n"); | ||
195 | if (!free_mem_ptr) | ||
196 | error("Memory error\n"); | ||
197 | |||
198 | free_mem_ptr = (free_mem_ptr + 3) & ~3; /* Align */ | ||
199 | |||
200 | p = (void *) free_mem_ptr; | ||
201 | free_mem_ptr += size; | ||
202 | |||
203 | if (free_mem_ptr >= free_mem_end_ptr) | ||
204 | error("\nOut of memory\n"); | ||
205 | |||
206 | return p; | ||
207 | } | ||
208 | |||
209 | static inline void scroll(void) | ||
210 | { | ||
211 | int i; | ||
212 | |||
213 | memcpy(vidmem, vidmem + cols * 2, (lines - 1) * cols * 2); | ||
214 | for (i = (lines - 1) * cols * 2; i < lines * cols * 2; i += 2) | ||
215 | vidmem[i] = ' '; | ||
216 | } | ||
217 | |||
218 | static inline void kputchar(unsigned char ch) | ||
219 | { | ||
220 | #ifdef CONFIG_MN10300_UNIT_ASB2305 | ||
221 | while (SC0STR & SC01STR_TBF) | ||
222 | continue; | ||
223 | |||
224 | if (ch == 0x0a) { | ||
225 | SC0TXB = 0x0d; | ||
226 | while (SC0STR & SC01STR_TBF) | ||
227 | continue; | ||
228 | } | ||
229 | |||
230 | SC0TXB = ch; | ||
231 | |||
232 | #else | ||
233 | while (SC1STR & SC01STR_TBF) | ||
234 | continue; | ||
235 | |||
236 | if (ch == 0x0a) { | ||
237 | SC1TXB = 0x0d; | ||
238 | while (SC1STR & SC01STR_TBF) | ||
239 | continue; | ||
240 | } | ||
241 | |||
242 | SC1TXB = ch; | ||
243 | |||
244 | #endif | ||
245 | } | ||
246 | |||
247 | static void kputs(const char *s) | ||
248 | { | ||
249 | #ifdef CONFIG_DEBUG_DECOMPRESS_KERNEL | ||
250 | #ifndef CONFIG_GDBSTUB_ON_TTYSx | ||
251 | char ch; | ||
252 | |||
253 | FLOWCTL_SET(DTR); | ||
254 | |||
255 | while (*s) { | ||
256 | LSR_WAIT_FOR(THRE); | ||
257 | |||
258 | ch = *s++; | ||
259 | if (ch == 0x0a) { | ||
260 | CYG_DEV_THR = 0x0d; | ||
261 | LSR_WAIT_FOR(THRE); | ||
262 | } | ||
263 | CYG_DEV_THR = ch; | ||
264 | } | ||
265 | |||
266 | FLOWCTL_CLEAR(DTR); | ||
267 | #else | ||
268 | |||
269 | for (; *s; s++) | ||
270 | kputchar(*s); | ||
271 | |||
272 | #endif | ||
273 | #endif /* CONFIG_DEBUG_DECOMPRESS_KERNEL */ | ||
274 | } | ||
275 | |||
276 | /* =========================================================================== | ||
277 | * Fill the input buffer. This is called only when the buffer is empty | ||
278 | * and at least one byte is really needed. | ||
279 | */ | ||
280 | static int fill_inbuf() | ||
281 | { | ||
282 | if (insize != 0) | ||
283 | error("ran out of input data\n"); | ||
284 | |||
285 | inbuf = input_data; | ||
286 | insize = input_len; | ||
287 | inptr = 1; | ||
288 | return inbuf[0]; | ||
289 | } | ||
290 | |||
291 | /* =========================================================================== | ||
292 | * Write the output window window[0..outcnt-1] and update crc and bytes_out. | ||
293 | * (Used for the decompressed data only.) | ||
294 | */ | ||
295 | static void flush_window_low(void) | ||
296 | { | ||
297 | ulg c = crc; /* temporary variable */ | ||
298 | unsigned n; | ||
299 | uch *in, *out, ch; | ||
300 | |||
301 | in = window; | ||
302 | out = &output_data[output_ptr]; | ||
303 | for (n = 0; n < outcnt; n++) { | ||
304 | ch = *out++ = *in++; | ||
305 | c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8); | ||
306 | } | ||
307 | crc = c; | ||
308 | bytes_out += (ulg)outcnt; | ||
309 | output_ptr += (ulg)outcnt; | ||
310 | outcnt = 0; | ||
311 | } | ||
312 | |||
313 | static void flush_window_high(void) | ||
314 | { | ||
315 | ulg c = crc; /* temporary variable */ | ||
316 | unsigned n; | ||
317 | uch *in, ch; | ||
318 | in = window; | ||
319 | for (n = 0; n < outcnt; n++) { | ||
320 | ch = *output_data++ = *in++; | ||
321 | if ((ulg) output_data == LOW_BUFFER_END) | ||
322 | output_data = high_buffer_start; | ||
323 | c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8); | ||
324 | } | ||
325 | crc = c; | ||
326 | bytes_out += (ulg)outcnt; | ||
327 | outcnt = 0; | ||
328 | } | ||
329 | |||
330 | static void flush_window(void) | ||
331 | { | ||
332 | if (high_loaded) | ||
333 | flush_window_high(); | ||
334 | else | ||
335 | flush_window_low(); | ||
336 | } | ||
337 | |||
338 | static void error(const char *x) | ||
339 | { | ||
340 | kputs("\n\n"); | ||
341 | kputs(x); | ||
342 | kputs("\n\n -- System halted"); | ||
343 | |||
344 | while (1) | ||
345 | /* Halt */; | ||
346 | } | ||
347 | |||
348 | #define STACK_SIZE (4096) | ||
349 | |||
350 | long user_stack[STACK_SIZE]; | ||
351 | |||
352 | struct { | ||
353 | long *a; | ||
354 | short b; | ||
355 | } stack_start = { &user_stack[STACK_SIZE], 0 }; | ||
356 | |||
357 | void setup_normal_output_buffer(void) | ||
358 | { | ||
359 | #ifdef STANDARD_MEMORY_BIOS_CALL | ||
360 | if (EXT_MEM_K < 1024) | ||
361 | error("Less than 2MB of memory.\n"); | ||
362 | #else | ||
363 | if ((ALT_MEM_K > EXT_MEM_K ? ALT_MEM_K : EXT_MEM_K) < 1024) | ||
364 | error("Less than 2MB of memory.\n"); | ||
365 | #endif | ||
366 | output_data = (char *) 0x100000; /* Points to 1M */ | ||
367 | } | ||
368 | |||
369 | struct moveparams { | ||
370 | uch *low_buffer_start; | ||
371 | int lcount; | ||
372 | uch *high_buffer_start; | ||
373 | int hcount; | ||
374 | }; | ||
375 | |||
376 | void setup_output_buffer_if_we_run_high(struct moveparams *mv) | ||
377 | { | ||
378 | high_buffer_start = (uch *)(((ulg) &end) + HEAP_SIZE); | ||
379 | #ifdef STANDARD_MEMORY_BIOS_CALL | ||
380 | if (EXT_MEM_K < (3 * 1024)) | ||
381 | error("Less than 4MB of memory.\n"); | ||
382 | #else | ||
383 | if ((ALT_MEM_K > EXT_MEM_K ? ALT_MEM_K : EXT_MEM_K) < (3 * 1024)) | ||
384 | error("Less than 4MB of memory.\n"); | ||
385 | #endif | ||
386 | mv->low_buffer_start = output_data = (char *) LOW_BUFFER_START; | ||
387 | high_loaded = 1; | ||
388 | free_mem_end_ptr = (long) high_buffer_start; | ||
389 | if (0x100000 + LOW_BUFFER_SIZE > (ulg) high_buffer_start) { | ||
390 | high_buffer_start = (uch *)(0x100000 + LOW_BUFFER_SIZE); | ||
391 | mv->hcount = 0; /* say: we need not to move high_buffer */ | ||
392 | } else { | ||
393 | mv->hcount = -1; | ||
394 | } | ||
395 | mv->high_buffer_start = high_buffer_start; | ||
396 | } | ||
397 | |||
398 | void close_output_buffer_if_we_run_high(struct moveparams *mv) | ||
399 | { | ||
400 | mv->lcount = bytes_out; | ||
401 | if (bytes_out > LOW_BUFFER_SIZE) { | ||
402 | mv->lcount = LOW_BUFFER_SIZE; | ||
403 | if (mv->hcount) | ||
404 | mv->hcount = bytes_out - LOW_BUFFER_SIZE; | ||
405 | } else { | ||
406 | mv->hcount = 0; | ||
407 | } | ||
408 | } | ||
409 | |||
410 | #undef DEBUGFLAG | ||
411 | #ifdef DEBUGFLAG | ||
412 | int debugflag; | ||
413 | #endif | ||
414 | |||
415 | int decompress_kernel(struct moveparams *mv) | ||
416 | { | ||
417 | #ifdef DEBUGFLAG | ||
418 | while (!debugflag) | ||
419 | barrier(); | ||
420 | #endif | ||
421 | |||
422 | output_data = (char *) CONFIG_KERNEL_TEXT_ADDRESS; | ||
423 | |||
424 | makecrc(); | ||
425 | kputs("Uncompressing Linux... "); | ||
426 | gunzip(); | ||
427 | kputs("Ok, booting the kernel.\n"); | ||
428 | return 0; | ||
429 | } | ||