VServer 1.9.2 (patch-2.6.8.1-vs1.9.2.diff)
[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 "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 void *zalloc(void *x, unsigned items, unsigned size)
206 {
207         void *p = avail_ram;
208
209         size *= items;
210         size = (size + 7) & -8;
211         avail_ram += size;
212         if (avail_ram > end_avail) {
213                 puts("oops... out of memory\n");
214                 pause();
215         }
216         return p;
217 }
218
219 void zfree(void *x, void *addr, unsigned nb)
220 {
221 }
222
223 #define HEAD_CRC        2
224 #define EXTRA_FIELD     4
225 #define ORIG_NAME       8
226 #define COMMENT         0x10
227 #define RESERVED        0xe0
228
229 #define DEFLATED        8
230
231 void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp)
232 {
233         z_stream s;
234         int r, i, flags;
235
236         /* skip header */
237         i = 10;
238         flags = src[3];
239         if (src[2] != DEFLATED || (flags & RESERVED) != 0) {
240                 puts("bad gzipped data\n");
241                 exit();
242         }
243         if ((flags & EXTRA_FIELD) != 0)
244                 i = 12 + src[10] + (src[11] << 8);
245         if ((flags & ORIG_NAME) != 0)
246                 while (src[i++] != 0)
247                         ;
248         if ((flags & COMMENT) != 0)
249                 while (src[i++] != 0)
250                         ;
251         if ((flags & HEAD_CRC) != 0)
252                 i += 2;
253         if (i >= *lenp) {
254                 puts("gunzip: ran out of data in header\n");
255                 exit();
256         }
257
258         s.zalloc = zalloc;
259         s.zfree = zfree;
260         r = inflateInit2(&s, -MAX_WBITS);
261         if (r != Z_OK) {
262                 puts("inflateInit2 returned "); puthex(r); puts("\n");
263                 exit();
264         }
265         s.next_in = src + i;
266         s.avail_in = *lenp - i;
267         s.next_out = dst;
268         s.avail_out = dstlen;
269         r = inflate(&s, Z_FINISH);
270         if (r != Z_OK && r != Z_STREAM_END) {
271                 puts("inflate returned "); puthex(r); puts("\n");
272                 exit();
273         }
274         *lenp = s.next_out - (unsigned char *) dst;
275         inflateEnd(&s);
276 }
277
278 void
279 puthex(unsigned long val)
280 {
281
282         unsigned char buf[10];
283         int i;
284         for (i = 7;  i >= 0;  i--)
285         {
286                 buf[i] = "0123456789ABCDEF"[val & 0x0F];
287                 val >>= 4;
288         }
289         buf[8] = '\0';
290         puts(buf);
291 }
292
293 #define FALSE 0
294 #define TRUE  1
295
296 void
297 _printk(char const *fmt, ...)
298 {
299         va_list ap;
300
301         va_start(ap, fmt);
302         _vprintk(putc, fmt, ap);
303         va_end(ap);
304         return;
305 }
306
307 #define is_digit(c) ((c >= '0') && (c <= '9'))
308
309 void
310 _vprintk(void(*putc)(const char), const char *fmt0, va_list ap)
311 {
312         char c, sign, *cp = 0;
313         int left_prec, right_prec, zero_fill, length = 0, pad, pad_on_right;
314         char buf[32];
315         long val;
316         while ((c = *fmt0++))
317         {
318                 if (c == '%')
319                 {
320                         c = *fmt0++;
321                         left_prec = right_prec = pad_on_right = 0;
322                         if (c == '-')
323                         {
324                                 c = *fmt0++;
325                                 pad_on_right++;
326                         }
327                         if (c == '0')
328                         {
329                                 zero_fill = TRUE;
330                                 c = *fmt0++;
331                         } else
332                         {
333                                 zero_fill = FALSE;
334                         }
335                         while (is_digit(c))
336                         {
337                                 left_prec = (left_prec * 10) + (c - '0');
338                                 c = *fmt0++;
339                         }
340                         if (c == '.')
341                         {
342                                 c = *fmt0++;
343                                 zero_fill++;
344                                 while (is_digit(c))
345                                 {
346                                         right_prec = (right_prec * 10) + (c - '0');
347                                         c = *fmt0++;
348                                 }
349                         } else
350                         {
351                                 right_prec = left_prec;
352                         }
353                         sign = '\0';
354                         switch (c)
355                         {
356                         case 'd':
357                         case 'x':
358                         case 'X':
359                                 val = va_arg(ap, long);
360                                 switch (c)
361                                 {
362                                 case 'd':
363                                         if (val < 0)
364                                         {
365                                                 sign = '-';
366                                                 val = -val;
367                                         }
368                                         length = _cvt(val, buf, 10, "0123456789");
369                                         break;
370                                 case 'x':
371                                         length = _cvt(val, buf, 16, "0123456789abcdef");
372                                         break;
373                                 case 'X':
374                                         length = _cvt(val, buf, 16, "0123456789ABCDEF");
375                                         break;
376                                 }
377                                 cp = buf;
378                                 break;
379                         case 's':
380                                 cp = va_arg(ap, char *);
381                                 length = strlen(cp);
382                                 break;
383                         case 'c':
384                                 c = va_arg(ap, long /*char*/);
385                                 (*putc)(c);
386                                 continue;
387                         default:
388                                 (*putc)('?');
389                         }
390                         pad = left_prec - length;
391                         if (sign != '\0')
392                         {
393                                 pad--;
394                         }
395                         if (zero_fill)
396                         {
397                                 c = '0';
398                                 if (sign != '\0')
399                                 {
400                                         (*putc)(sign);
401                                         sign = '\0';
402                                 }
403                         } else
404                         {
405                                 c = ' ';
406                         }
407                         if (!pad_on_right)
408                         {
409                                 while (pad-- > 0)
410                                 {
411                                         (*putc)(c);
412                                 }
413                         }
414                         if (sign != '\0')
415                         {
416                                 (*putc)(sign);
417                         }
418                         while (length-- > 0)
419                         {
420                                 (*putc)(c = *cp++);
421                                 if (c == '\n')
422                                 {
423                                         (*putc)('\r');
424                                 }
425                         }
426                         if (pad_on_right)
427                         {
428                                 while (pad-- > 0)
429                                 {
430                                         (*putc)(c);
431                                 }
432                         }
433                 } else
434                 {
435                         (*putc)(c);
436                         if (c == '\n')
437                         {
438                                 (*putc)('\r');
439                         }
440                 }
441         }
442 }
443
444 int
445 _cvt(unsigned long val, char *buf, long radix, char *digits)
446 {
447         char temp[80];
448         char *cp = temp;
449         int length = 0;
450         if (val == 0)
451         { /* Special case */
452                 *cp++ = '0';
453         } else
454                 while (val)
455                 {
456                         *cp++ = digits[val % radix];
457                         val /= radix;
458                 }
459         while (cp != temp)
460         {
461                 *buf++ = *--cp;
462                 length++;
463         }
464         *buf = '\0';
465         return (length);
466 }
467
468 void
469 _dump_buf_with_offset(unsigned char *p, int s, unsigned char *base)
470 {
471         int i, c;
472         if ((unsigned int)s > (unsigned int)p)
473         {
474                 s = (unsigned int)s - (unsigned int)p;
475         }
476         while (s > 0)
477         {
478                 if (base)
479                 {
480                         _printk("%06X: ", (int)p - (int)base);
481                 } else
482                 {
483                         _printk("%06X: ", p);
484                 }
485                 for (i = 0;  i < 16;  i++)
486                 {
487                         if (i < s)
488                         {
489                                 _printk("%02X", p[i] & 0xFF);
490                         } else
491                         {
492                                 _printk("  ");
493                         }
494                         if ((i % 2) == 1) _printk(" ");
495                         if ((i % 8) == 7) _printk(" ");
496                 }
497                 _printk(" |");
498                 for (i = 0;  i < 16;  i++)
499                 {
500                         if (i < s)
501                         {
502                                 c = p[i] & 0xFF;
503                                 if ((c < 0x20) || (c >= 0x7F)) c = '.';
504                         } else
505                         {
506                                 c = ' ';
507                         }
508                         _printk("%c", c);
509                 }
510                 _printk("|\n");
511                 s -= 16;
512                 p += 16;
513         }
514 }
515
516 void
517 _dump_buf(unsigned char *p, int s)
518 {
519         _printk("\n");
520         _dump_buf_with_offset(p, s, 0);
521 }
522
523 /* Very simple inb/outb routines.  We declare ISA_io to be 0 above, and
524  * then modify it on platforms which need to.  We do it like this
525  * because on some platforms we give inb/outb an exact location, and
526  * on others it's an offset from a given location. -- Tom
527  */
528
529 void
530 outb(int port, unsigned char val)
531 {
532         /* Ensure I/O operations complete */
533         __asm__ volatile("eieio");
534         ISA_io[port] = val;
535 }
536
537 unsigned char
538 inb(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  */