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