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