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