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