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