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