blob: 9589969cec725d86b1817d0248efc244ec8b73ae [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002 * Misc. bootloader code (almost) all platforms can use
3 *
4 * Author: Johnnie Peters <jpeters@mvista.com>
5 * Editor: Tom Rini <trini@mvista.com>
6 *
7 * Derived from arch/ppc/boot/prep/misc.c
8 *
9 * 2000-2001 (c) MontaVista, Software, Inc. This file is licensed under
10 * the terms of the GNU General Public License version 2. This program
11 * is licensed "as is" without any warranty of any kind, whether express
12 * or implied.
13 */
14
15#include <stdarg.h> /* for va_ bits */
Linus Torvalds1da177e2005-04-16 15:20:36 -070016#include <linux/string.h>
17#include <linux/zlib.h>
18#include "nonstdio.h"
19
20/* If we're on a PReP, assume we have a keyboard controller
21 * Also note, if we're not PReP, we assume you are a serial
22 * console - Tom */
23#if defined(CONFIG_PPC_PREP) && defined(CONFIG_VGA_CONSOLE)
24extern void cursor(int x, int y);
25extern void scroll(void);
26extern char *vidmem;
27extern int lines, cols;
28extern int orig_x, orig_y;
29extern int keyb_present;
30extern int CRT_tstc(void);
31extern int CRT_getc(void);
32#else
33int cursor(int x, int y) {return 0;}
34void scroll(void) {}
35char vidmem[1];
36#define lines 0
37#define cols 0
38int orig_x = 0;
39int orig_y = 0;
40#define keyb_present 0
41int CRT_tstc(void) {return 0;}
42int CRT_getc(void) {return 0;}
43#endif
44
45extern char *avail_ram;
46extern char *end_avail;
47extern char _end[];
48
49void puts(const char *);
50void putc(const char c);
51void puthex(unsigned long val);
52void gunzip(void *, int, unsigned char *, int *);
53static int _cvt(unsigned long val, char *buf, long radix, char *digits);
54
55void _vprintk(void(*putc)(const char), const char *fmt0, va_list ap);
56unsigned char *ISA_io = NULL;
57
58#if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \
59 || defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \
Grant Likely8b016532007-04-28 05:50:03 +100060 || defined(CONFIG_SERIAL_MPSC_CONSOLE) \
61 || defined(CONFIG_SERIAL_UARTLITE_CONSOLE)
Linus Torvalds1da177e2005-04-16 15:20:36 -070062extern unsigned long com_port;
63
64extern int serial_tstc(unsigned long com_port);
65extern unsigned char serial_getc(unsigned long com_port);
66extern void serial_putc(unsigned long com_port, unsigned char c);
67#endif
68
69void pause(void)
70{
71 puts("pause\n");
72}
73
74void exit(void)
75{
76 puts("exit\n");
77 while(1);
78}
79
80int tstc(void)
81{
82#if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \
83 || defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \
Grant Likely8b016532007-04-28 05:50:03 +100084 || defined(CONFIG_SERIAL_MPSC_CONSOLE) \
85 || defined(CONFIG_SERIAL_UARTLITE_CONSOLE)
Linus Torvalds1da177e2005-04-16 15:20:36 -070086 if(keyb_present)
87 return (CRT_tstc() || serial_tstc(com_port));
88 else
89 return (serial_tstc(com_port));
90#else
91 return CRT_tstc();
92#endif
93}
94
95int getc(void)
96{
97 while (1) {
98#if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \
99 || defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \
Grant Likely8b016532007-04-28 05:50:03 +1000100 || defined(CONFIG_SERIAL_MPSC_CONSOLE) \
101 || defined(CONFIG_SERIAL_UARTLITE_CONSOLE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102 if (serial_tstc(com_port))
103 return (serial_getc(com_port));
104#endif /* serial console */
105 if (keyb_present)
106 if(CRT_tstc())
107 return (CRT_getc());
108 }
109}
110
111void
112putc(const char c)
113{
114 int x,y;
115
116#if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \
117 || defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \
Grant Likely8b016532007-04-28 05:50:03 +1000118 || defined(CONFIG_SERIAL_MPSC_CONSOLE) \
119 || defined(CONFIG_SERIAL_UARTLITE_CONSOLE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120 serial_putc(com_port, c);
121 if ( c == '\n' )
122 serial_putc(com_port, '\r');
123#endif /* serial console */
124
125 x = orig_x;
126 y = orig_y;
127
128 if ( c == '\n' ) {
129 x = 0;
130 if ( ++y >= lines ) {
131 scroll();
132 y--;
133 }
134 } else if (c == '\r') {
135 x = 0;
136 } else if (c == '\b') {
137 if (x > 0) {
138 x--;
139 }
140 } else {
141 vidmem [ ( x + cols * y ) * 2 ] = c;
142 if ( ++x >= cols ) {
143 x = 0;
144 if ( ++y >= lines ) {
145 scroll();
146 y--;
147 }
148 }
149 }
150
151 cursor(x, y);
152
153 orig_x = x;
154 orig_y = y;
155}
156
157void puts(const char *s)
158{
159 int x,y;
160 char c;
161
162 x = orig_x;
163 y = orig_y;
164
165 while ( ( c = *s++ ) != '\0' ) {
166#if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \
167 || defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \
Grant Likely8b016532007-04-28 05:50:03 +1000168 || defined(CONFIG_SERIAL_MPSC_CONSOLE) \
169 || defined(CONFIG_SERIAL_UARTLITE_CONSOLE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170 serial_putc(com_port, c);
171 if ( c == '\n' ) serial_putc(com_port, '\r');
172#endif /* serial console */
173
174 if ( c == '\n' ) {
175 x = 0;
176 if ( ++y >= lines ) {
177 scroll();
178 y--;
179 }
180 } else if (c == '\b') {
181 if (x > 0) {
182 x--;
183 }
184 } else {
185 vidmem [ ( x + cols * y ) * 2 ] = c;
186 if ( ++x >= cols ) {
187 x = 0;
188 if ( ++y >= lines ) {
189 scroll();
190 y--;
191 }
192 }
193 }
194 }
195
196 cursor(x, y);
197
198 orig_x = x;
199 orig_y = y;
200}
201
202void error(char *x)
203{
204 puts("\n\n");
205 puts(x);
206 puts("\n\n -- System halted");
207
208 while(1); /* Halt */
209}
210
211static void *zalloc(unsigned size)
212{
213 void *p = avail_ram;
214
215 size = (size + 7) & -8;
216 avail_ram += size;
217 if (avail_ram > end_avail) {
218 puts("oops... out of memory\n");
219 pause();
220 }
221 return p;
222}
223
224#define HEAD_CRC 2
225#define EXTRA_FIELD 4
226#define ORIG_NAME 8
227#define COMMENT 0x10
228#define RESERVED 0xe0
229
230void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp)
231{
232 z_stream s;
233 int r, i, flags;
234
235 /* skip header */
236 i = 10;
237 flags = src[3];
238 if (src[2] != Z_DEFLATED || (flags & RESERVED) != 0) {
239 puts("bad gzipped data\n");
240 exit();
241 }
242 if ((flags & EXTRA_FIELD) != 0)
243 i = 12 + src[10] + (src[11] << 8);
244 if ((flags & ORIG_NAME) != 0)
245 while (src[i++] != 0)
246 ;
247 if ((flags & COMMENT) != 0)
248 while (src[i++] != 0)
249 ;
250 if ((flags & HEAD_CRC) != 0)
251 i += 2;
252 if (i >= *lenp) {
253 puts("gunzip: ran out of data in header\n");
254 exit();
255 }
256
257 /* Initialize ourself. */
258 s.workspace = zalloc(zlib_inflate_workspacesize());
259 r = zlib_inflateInit2(&s, -MAX_WBITS);
260 if (r != Z_OK) {
261 puts("zlib_inflateInit2 returned "); puthex(r); puts("\n");
262 exit();
263 }
264 s.next_in = src + i;
265 s.avail_in = *lenp - i;
266 s.next_out = dst;
267 s.avail_out = dstlen;
268 r = zlib_inflate(&s, Z_FINISH);
269 if (r != Z_OK && r != Z_STREAM_END) {
270 puts("inflate returned "); puthex(r); puts("\n");
271 exit();
272 }
273 *lenp = s.next_out - (unsigned char *) dst;
274 zlib_inflateEnd(&s);
275}
276
277void
278puthex(unsigned long val)
279{
280
281 unsigned char buf[10];
282 int i;
283 for (i = 7; i >= 0; i--)
284 {
285 buf[i] = "0123456789ABCDEF"[val & 0x0F];
286 val >>= 4;
287 }
288 buf[8] = '\0';
289 puts(buf);
290}
291
292#define FALSE 0
293#define TRUE 1
294
295void
296_printk(char const *fmt, ...)
297{
298 va_list ap;
299
300 va_start(ap, fmt);
301 _vprintk(putc, fmt, ap);
302 va_end(ap);
303 return;
304}
305
306#define is_digit(c) ((c >= '0') && (c <= '9'))
307
308void
309_vprintk(void(*putc)(const char), const char *fmt0, va_list ap)
310{
311 char c, sign, *cp = 0;
312 int left_prec, right_prec, zero_fill, length = 0, pad, pad_on_right;
313 char buf[32];
314 long val;
315 while ((c = *fmt0++))
316 {
317 if (c == '%')
318 {
319 c = *fmt0++;
320 left_prec = right_prec = pad_on_right = 0;
321 if (c == '-')
322 {
323 c = *fmt0++;
324 pad_on_right++;
325 }
326 if (c == '0')
327 {
328 zero_fill = TRUE;
329 c = *fmt0++;
330 } else
331 {
332 zero_fill = FALSE;
333 }
334 while (is_digit(c))
335 {
336 left_prec = (left_prec * 10) + (c - '0');
337 c = *fmt0++;
338 }
339 if (c == '.')
340 {
341 c = *fmt0++;
342 zero_fill++;
343 while (is_digit(c))
344 {
345 right_prec = (right_prec * 10) + (c - '0');
346 c = *fmt0++;
347 }
348 } else
349 {
350 right_prec = left_prec;
351 }
352 sign = '\0';
353 switch (c)
354 {
355 case 'd':
356 case 'x':
357 case 'X':
358 val = va_arg(ap, long);
359 switch (c)
360 {
361 case 'd':
362 if (val < 0)
363 {
364 sign = '-';
365 val = -val;
366 }
367 length = _cvt(val, buf, 10, "0123456789");
368 break;
369 case 'x':
370 length = _cvt(val, buf, 16, "0123456789abcdef");
371 break;
372 case 'X':
373 length = _cvt(val, buf, 16, "0123456789ABCDEF");
374 break;
375 }
376 cp = buf;
377 break;
378 case 's':
379 cp = va_arg(ap, char *);
380 length = strlen(cp);
381 break;
382 case 'c':
383 c = va_arg(ap, long /*char*/);
384 (*putc)(c);
385 continue;
386 default:
387 (*putc)('?');
388 }
389 pad = left_prec - length;
390 if (sign != '\0')
391 {
392 pad--;
393 }
394 if (zero_fill)
395 {
396 c = '0';
397 if (sign != '\0')
398 {
399 (*putc)(sign);
400 sign = '\0';
401 }
402 } else
403 {
404 c = ' ';
405 }
406 if (!pad_on_right)
407 {
408 while (pad-- > 0)
409 {
410 (*putc)(c);
411 }
412 }
413 if (sign != '\0')
414 {
415 (*putc)(sign);
416 }
417 while (length-- > 0)
418 {
419 (*putc)(c = *cp++);
420 if (c == '\n')
421 {
422 (*putc)('\r');
423 }
424 }
425 if (pad_on_right)
426 {
427 while (pad-- > 0)
428 {
429 (*putc)(c);
430 }
431 }
432 } else
433 {
434 (*putc)(c);
435 if (c == '\n')
436 {
437 (*putc)('\r');
438 }
439 }
440 }
441}
442
443int
444_cvt(unsigned long val, char *buf, long radix, char *digits)
445{
446 char temp[80];
447 char *cp = temp;
448 int length = 0;
449 if (val == 0)
450 { /* Special case */
451 *cp++ = '0';
452 } else
453 while (val)
454 {
455 *cp++ = digits[val % radix];
456 val /= radix;
457 }
458 while (cp != temp)
459 {
460 *buf++ = *--cp;
461 length++;
462 }
463 *buf = '\0';
464 return (length);
465}
466
467void
468_dump_buf_with_offset(unsigned char *p, int s, unsigned char *base)
469{
470 int i, c;
471 if ((unsigned int)s > (unsigned int)p)
472 {
473 s = (unsigned int)s - (unsigned int)p;
474 }
475 while (s > 0)
476 {
477 if (base)
478 {
479 _printk("%06X: ", (int)p - (int)base);
480 } else
481 {
482 _printk("%06X: ", p);
483 }
484 for (i = 0; i < 16; i++)
485 {
486 if (i < s)
487 {
488 _printk("%02X", p[i] & 0xFF);
489 } else
490 {
491 _printk(" ");
492 }
493 if ((i % 2) == 1) _printk(" ");
494 if ((i % 8) == 7) _printk(" ");
495 }
496 _printk(" |");
497 for (i = 0; i < 16; i++)
498 {
499 if (i < s)
500 {
501 c = p[i] & 0xFF;
502 if ((c < 0x20) || (c >= 0x7F)) c = '.';
503 } else
504 {
505 c = ' ';
506 }
507 _printk("%c", c);
508 }
509 _printk("|\n");
510 s -= 16;
511 p += 16;
512 }
513}
514
515void
516_dump_buf(unsigned char *p, int s)
517{
518 _printk("\n");
519 _dump_buf_with_offset(p, s, 0);
520}
521
522/* Very simple inb/outb routines. We declare ISA_io to be 0 above, and
523 * then modify it on platforms which need to. We do it like this
524 * because on some platforms we give inb/outb an exact location, and
525 * on others it's an offset from a given location. -- Tom
526 */
527
528void ISA_init(unsigned long base)
529{
530 ISA_io = (unsigned char *)base;
531}
532
533void
534outb(int port, unsigned char val)
535{
536 /* Ensure I/O operations complete */
537 __asm__ volatile("eieio");
538 ISA_io[port] = val;
539}
540
541unsigned char
542inb(int port)
543{
544 /* Ensure I/O operations complete */
545 __asm__ volatile("eieio");
546 return (ISA_io[port]);
547}
548
549/*
550 * Local variables:
551 * c-indent-level: 8
552 * c-basic-offset: 8
553 * tab-width: 8
554 * End:
555 */