554 lines
		
	
	
	
		
			9.7 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			554 lines
		
	
	
	
		
			9.7 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
|   | /*
 | ||
|  |  * arch/ppc/boot/common/misc-common.c | ||
|  |  * | ||
|  |  * Misc. bootloader code (almost) all platforms can use | ||
|  |  * | ||
|  |  * Author: Johnnie Peters <jpeters@mvista.com> | ||
|  |  * Editor: Tom Rini <trini@mvista.com> | ||
|  |  * | ||
|  |  * Derived from arch/ppc/boot/prep/misc.c | ||
|  |  * | ||
|  |  * 2000-2001 (c) MontaVista, Software, Inc.  This file is licensed under | ||
|  |  * the terms of the GNU General Public License version 2.  This program | ||
|  |  * is licensed "as is" without any warranty of any kind, whether express | ||
|  |  * or implied. | ||
|  |  */ | ||
|  | 
 | ||
|  | #include <stdarg.h>	/* for va_ bits */
 | ||
|  | #include <linux/config.h>
 | ||
|  | #include <linux/string.h>
 | ||
|  | #include <linux/zlib.h>
 | ||
|  | #include "nonstdio.h"
 | ||
|  | 
 | ||
|  | /* If we're on a PReP, assume we have a keyboard controller
 | ||
|  |  * Also note, if we're not PReP, we assume you are a serial | ||
|  |  * console - Tom */ | ||
|  | #if defined(CONFIG_PPC_PREP) && defined(CONFIG_VGA_CONSOLE)
 | ||
|  | extern void cursor(int x, int y); | ||
|  | extern void scroll(void); | ||
|  | extern char *vidmem; | ||
|  | extern int lines, cols; | ||
|  | extern int orig_x, orig_y; | ||
|  | extern int keyb_present; | ||
|  | extern int CRT_tstc(void); | ||
|  | extern int CRT_getc(void); | ||
|  | #else
 | ||
|  | int cursor(int x, int y) {return 0;} | ||
|  | void scroll(void) {} | ||
|  | char vidmem[1]; | ||
|  | #define lines 0
 | ||
|  | #define cols 0
 | ||
|  | int orig_x = 0; | ||
|  | int orig_y = 0; | ||
|  | #define keyb_present 0
 | ||
|  | int CRT_tstc(void) {return 0;} | ||
|  | int CRT_getc(void) {return 0;} | ||
|  | #endif
 | ||
|  | 
 | ||
|  | extern char *avail_ram; | ||
|  | extern char *end_avail; | ||
|  | extern char _end[]; | ||
|  | 
 | ||
|  | void puts(const char *); | ||
|  | void putc(const char c); | ||
|  | void puthex(unsigned long val); | ||
|  | void gunzip(void *, int, unsigned char *, int *); | ||
|  | static int _cvt(unsigned long val, char *buf, long radix, char *digits); | ||
|  | 
 | ||
|  | void _vprintk(void(*putc)(const char), const char *fmt0, va_list ap); | ||
|  | unsigned char *ISA_io = NULL; | ||
|  | 
 | ||
|  | #if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \
 | ||
|  | 	|| defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \ | ||
|  | 	|| defined(CONFIG_SERIAL_MPSC_CONSOLE) | ||
|  | extern unsigned long com_port; | ||
|  | 
 | ||
|  | extern int serial_tstc(unsigned long com_port); | ||
|  | extern unsigned char serial_getc(unsigned long com_port); | ||
|  | extern void serial_putc(unsigned long com_port, unsigned char c); | ||
|  | #endif
 | ||
|  | 
 | ||
|  | void pause(void) | ||
|  | { | ||
|  | 	puts("pause\n"); | ||
|  | } | ||
|  | 
 | ||
|  | void exit(void) | ||
|  | { | ||
|  | 	puts("exit\n"); | ||
|  | 	while(1); | ||
|  | } | ||
|  | 
 | ||
|  | int tstc(void) | ||
|  | { | ||
|  | #if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \
 | ||
|  | 	|| defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \ | ||
|  | 	|| defined(CONFIG_SERIAL_MPSC_CONSOLE) | ||
|  | 	if(keyb_present) | ||
|  | 		return (CRT_tstc() || serial_tstc(com_port)); | ||
|  | 	else | ||
|  | 		return (serial_tstc(com_port)); | ||
|  | #else
 | ||
|  | 	return CRT_tstc(); | ||
|  | #endif
 | ||
|  | } | ||
|  | 
 | ||
|  | int getc(void) | ||
|  | { | ||
|  | 	while (1) { | ||
|  | #if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \
 | ||
|  | 	|| defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \ | ||
|  | 	|| defined(CONFIG_SERIAL_MPSC_CONSOLE) | ||
|  | 		if (serial_tstc(com_port)) | ||
|  | 			return (serial_getc(com_port)); | ||
|  | #endif /* serial console */
 | ||
|  | 		if (keyb_present) | ||
|  | 			if(CRT_tstc()) | ||
|  | 				return (CRT_getc()); | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | void | ||
|  | putc(const char c) | ||
|  | { | ||
|  | 	int x,y; | ||
|  | 
 | ||
|  | #if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \
 | ||
|  | 	|| defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \ | ||
|  | 	|| defined(CONFIG_SERIAL_MPSC_CONSOLE) | ||
|  | 	serial_putc(com_port, c); | ||
|  | 	if ( c == '\n' ) | ||
|  | 		serial_putc(com_port, '\r'); | ||
|  | #endif /* serial console */
 | ||
|  | 
 | ||
|  | 	x = orig_x; | ||
|  | 	y = orig_y; | ||
|  | 
 | ||
|  | 	if ( c == '\n' ) { | ||
|  | 		x = 0; | ||
|  | 		if ( ++y >= lines ) { | ||
|  | 			scroll(); | ||
|  | 			y--; | ||
|  | 		} | ||
|  | 	} else if (c == '\r') { | ||
|  | 		x = 0; | ||
|  | 	} else if (c == '\b') { | ||
|  | 		if (x > 0) { | ||
|  | 			x--; | ||
|  | 		} | ||
|  | 	} else { | ||
|  | 		vidmem [ ( x + cols * y ) * 2 ] = c; | ||
|  | 		if ( ++x >= cols ) { | ||
|  | 			x = 0; | ||
|  | 			if ( ++y >= lines ) { | ||
|  | 				scroll(); | ||
|  | 				y--; | ||
|  | 			} | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	cursor(x, y); | ||
|  | 
 | ||
|  | 	orig_x = x; | ||
|  | 	orig_y = y; | ||
|  | } | ||
|  | 
 | ||
|  | void puts(const char *s) | ||
|  | { | ||
|  | 	int x,y; | ||
|  | 	char c; | ||
|  | 
 | ||
|  | 	x = orig_x; | ||
|  | 	y = orig_y; | ||
|  | 
 | ||
|  | 	while ( ( c = *s++ ) != '\0' ) { | ||
|  | #if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \
 | ||
|  | 	|| defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \ | ||
|  | 	|| defined(CONFIG_SERIAL_MPSC_CONSOLE) | ||
|  | 	        serial_putc(com_port, c); | ||
|  | 	        if ( c == '\n' ) serial_putc(com_port, '\r'); | ||
|  | #endif /* serial console */
 | ||
|  | 
 | ||
|  | 		if ( c == '\n' ) { | ||
|  | 			x = 0; | ||
|  | 			if ( ++y >= lines ) { | ||
|  | 				scroll(); | ||
|  | 				y--; | ||
|  | 			} | ||
|  | 		} else if (c == '\b') { | ||
|  | 		  if (x > 0) { | ||
|  | 		    x--; | ||
|  | 		  } | ||
|  | 		} else { | ||
|  | 			vidmem [ ( x + cols * y ) * 2 ] = c; | ||
|  | 			if ( ++x >= cols ) { | ||
|  | 				x = 0; | ||
|  | 				if ( ++y >= lines ) { | ||
|  | 					scroll(); | ||
|  | 					y--; | ||
|  | 				} | ||
|  | 			} | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	cursor(x, y); | ||
|  | 
 | ||
|  | 	orig_x = x; | ||
|  | 	orig_y = y; | ||
|  | } | ||
|  | 
 | ||
|  | void error(char *x) | ||
|  | { | ||
|  | 	puts("\n\n"); | ||
|  | 	puts(x); | ||
|  | 	puts("\n\n -- System halted"); | ||
|  | 
 | ||
|  | 	while(1);	/* Halt */ | ||
|  | } | ||
|  | 
 | ||
|  | static void *zalloc(unsigned size) | ||
|  | { | ||
|  | 	void *p = avail_ram; | ||
|  | 
 | ||
|  | 	size = (size + 7) & -8; | ||
|  | 	avail_ram += size; | ||
|  | 	if (avail_ram > end_avail) { | ||
|  | 		puts("oops... out of memory\n"); | ||
|  | 		pause(); | ||
|  | 	} | ||
|  | 	return p; | ||
|  | } | ||
|  | 
 | ||
|  | #define HEAD_CRC	2
 | ||
|  | #define EXTRA_FIELD	4
 | ||
|  | #define ORIG_NAME	8
 | ||
|  | #define COMMENT		0x10
 | ||
|  | #define RESERVED	0xe0
 | ||
|  | 
 | ||
|  | void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp) | ||
|  | { | ||
|  | 	z_stream s; | ||
|  | 	int r, i, flags; | ||
|  | 
 | ||
|  | 	/* skip header */ | ||
|  | 	i = 10; | ||
|  | 	flags = src[3]; | ||
|  | 	if (src[2] != Z_DEFLATED || (flags & RESERVED) != 0) { | ||
|  | 		puts("bad gzipped data\n"); | ||
|  | 		exit(); | ||
|  | 	} | ||
|  | 	if ((flags & EXTRA_FIELD) != 0) | ||
|  | 		i = 12 + src[10] + (src[11] << 8); | ||
|  | 	if ((flags & ORIG_NAME) != 0) | ||
|  | 		while (src[i++] != 0) | ||
|  | 			; | ||
|  | 	if ((flags & COMMENT) != 0) | ||
|  | 		while (src[i++] != 0) | ||
|  | 			; | ||
|  | 	if ((flags & HEAD_CRC) != 0) | ||
|  | 		i += 2; | ||
|  | 	if (i >= *lenp) { | ||
|  | 		puts("gunzip: ran out of data in header\n"); | ||
|  | 		exit(); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	/* Initialize ourself. */ | ||
|  | 	s.workspace = zalloc(zlib_inflate_workspacesize()); | ||
|  | 	r = zlib_inflateInit2(&s, -MAX_WBITS); | ||
|  | 	if (r != Z_OK) { | ||
|  | 		puts("zlib_inflateInit2 returned "); puthex(r); puts("\n"); | ||
|  | 		exit(); | ||
|  | 	} | ||
|  | 	s.next_in = src + i; | ||
|  | 	s.avail_in = *lenp - i; | ||
|  | 	s.next_out = dst; | ||
|  | 	s.avail_out = dstlen; | ||
|  | 	r = zlib_inflate(&s, Z_FINISH); | ||
|  | 	if (r != Z_OK && r != Z_STREAM_END) { | ||
|  | 		puts("inflate returned "); puthex(r); puts("\n"); | ||
|  | 		exit(); | ||
|  | 	} | ||
|  | 	*lenp = s.next_out - (unsigned char *) dst; | ||
|  | 	zlib_inflateEnd(&s); | ||
|  | } | ||
|  | 
 | ||
|  | void | ||
|  | puthex(unsigned long val) | ||
|  | { | ||
|  | 
 | ||
|  | 	unsigned char buf[10]; | ||
|  | 	int i; | ||
|  | 	for (i = 7;  i >= 0;  i--) | ||
|  | 	{ | ||
|  | 		buf[i] = "0123456789ABCDEF"[val & 0x0F]; | ||
|  | 		val >>= 4; | ||
|  | 	} | ||
|  | 	buf[8] = '\0'; | ||
|  | 	puts(buf); | ||
|  | } | ||
|  | 
 | ||
|  | #define FALSE 0
 | ||
|  | #define TRUE  1
 | ||
|  | 
 | ||
|  | void | ||
|  | _printk(char const *fmt, ...) | ||
|  | { | ||
|  | 	va_list ap; | ||
|  | 
 | ||
|  | 	va_start(ap, fmt); | ||
|  | 	_vprintk(putc, fmt, ap); | ||
|  | 	va_end(ap); | ||
|  | 	return; | ||
|  | } | ||
|  | 
 | ||
|  | #define is_digit(c) ((c >= '0') && (c <= '9'))
 | ||
|  | 
 | ||
|  | void | ||
|  | _vprintk(void(*putc)(const char), const char *fmt0, va_list ap) | ||
|  | { | ||
|  | 	char c, sign, *cp = 0; | ||
|  | 	int left_prec, right_prec, zero_fill, length = 0, pad, pad_on_right; | ||
|  | 	char buf[32]; | ||
|  | 	long val; | ||
|  | 	while ((c = *fmt0++)) | ||
|  | 	{ | ||
|  | 		if (c == '%') | ||
|  | 		{ | ||
|  | 			c = *fmt0++; | ||
|  | 			left_prec = right_prec = pad_on_right = 0; | ||
|  | 			if (c == '-') | ||
|  | 			{ | ||
|  | 				c = *fmt0++; | ||
|  | 				pad_on_right++; | ||
|  | 			} | ||
|  | 			if (c == '0') | ||
|  | 			{ | ||
|  | 				zero_fill = TRUE; | ||
|  | 				c = *fmt0++; | ||
|  | 			} else | ||
|  | 			{ | ||
|  | 				zero_fill = FALSE; | ||
|  | 			} | ||
|  | 			while (is_digit(c)) | ||
|  | 			{ | ||
|  | 				left_prec = (left_prec * 10) + (c - '0'); | ||
|  | 				c = *fmt0++; | ||
|  | 			} | ||
|  | 			if (c == '.') | ||
|  | 			{ | ||
|  | 				c = *fmt0++; | ||
|  | 				zero_fill++; | ||
|  | 				while (is_digit(c)) | ||
|  | 				{ | ||
|  | 					right_prec = (right_prec * 10) + (c - '0'); | ||
|  | 					c = *fmt0++; | ||
|  | 				} | ||
|  | 			} else | ||
|  | 			{ | ||
|  | 				right_prec = left_prec; | ||
|  | 			} | ||
|  | 			sign = '\0'; | ||
|  | 			switch (c) | ||
|  | 			{ | ||
|  | 			case 'd': | ||
|  | 			case 'x': | ||
|  | 			case 'X': | ||
|  | 				val = va_arg(ap, long); | ||
|  | 				switch (c) | ||
|  | 				{ | ||
|  | 				case 'd': | ||
|  | 					if (val < 0) | ||
|  | 					{ | ||
|  | 						sign = '-'; | ||
|  | 						val = -val; | ||
|  | 					} | ||
|  | 					length = _cvt(val, buf, 10, "0123456789"); | ||
|  | 					break; | ||
|  | 				case 'x': | ||
|  | 					length = _cvt(val, buf, 16, "0123456789abcdef"); | ||
|  | 					break; | ||
|  | 				case 'X': | ||
|  | 					length = _cvt(val, buf, 16, "0123456789ABCDEF"); | ||
|  | 					break; | ||
|  | 				} | ||
|  | 				cp = buf; | ||
|  | 				break; | ||
|  | 			case 's': | ||
|  | 				cp = va_arg(ap, char *); | ||
|  | 				length = strlen(cp); | ||
|  | 				break; | ||
|  | 			case 'c': | ||
|  | 				c = va_arg(ap, long /*char*/); | ||
|  | 				(*putc)(c); | ||
|  | 				continue; | ||
|  | 			default: | ||
|  | 				(*putc)('?'); | ||
|  | 			} | ||
|  | 			pad = left_prec - length; | ||
|  | 			if (sign != '\0') | ||
|  | 			{ | ||
|  | 				pad--; | ||
|  | 			} | ||
|  | 			if (zero_fill) | ||
|  | 			{ | ||
|  | 				c = '0'; | ||
|  | 				if (sign != '\0') | ||
|  | 				{ | ||
|  | 					(*putc)(sign); | ||
|  | 					sign = '\0'; | ||
|  | 				} | ||
|  | 			} else | ||
|  | 			{ | ||
|  | 				c = ' '; | ||
|  | 			} | ||
|  | 			if (!pad_on_right) | ||
|  | 			{ | ||
|  | 				while (pad-- > 0) | ||
|  | 				{ | ||
|  | 					(*putc)(c); | ||
|  | 				} | ||
|  | 			} | ||
|  | 			if (sign != '\0') | ||
|  | 			{ | ||
|  | 				(*putc)(sign); | ||
|  | 			} | ||
|  | 			while (length-- > 0) | ||
|  | 			{ | ||
|  | 				(*putc)(c = *cp++); | ||
|  | 				if (c == '\n') | ||
|  | 				{ | ||
|  | 					(*putc)('\r'); | ||
|  | 				} | ||
|  | 			} | ||
|  | 			if (pad_on_right) | ||
|  | 			{ | ||
|  | 				while (pad-- > 0) | ||
|  | 				{ | ||
|  | 					(*putc)(c); | ||
|  | 				} | ||
|  | 			} | ||
|  | 		} else | ||
|  | 		{ | ||
|  | 			(*putc)(c); | ||
|  | 			if (c == '\n') | ||
|  | 			{ | ||
|  | 				(*putc)('\r'); | ||
|  | 			} | ||
|  | 		} | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | int | ||
|  | _cvt(unsigned long val, char *buf, long radix, char *digits) | ||
|  | { | ||
|  | 	char temp[80]; | ||
|  | 	char *cp = temp; | ||
|  | 	int length = 0; | ||
|  | 	if (val == 0) | ||
|  | 	{ /* Special case */ | ||
|  | 		*cp++ = '0'; | ||
|  | 	} else | ||
|  | 		while (val) | ||
|  | 		{ | ||
|  | 			*cp++ = digits[val % radix]; | ||
|  | 			val /= radix; | ||
|  | 		} | ||
|  | 	while (cp != temp) | ||
|  | 	{ | ||
|  | 		*buf++ = *--cp; | ||
|  | 		length++; | ||
|  | 	} | ||
|  | 	*buf = '\0'; | ||
|  | 	return (length); | ||
|  | } | ||
|  | 
 | ||
|  | void | ||
|  | _dump_buf_with_offset(unsigned char *p, int s, unsigned char *base) | ||
|  | { | ||
|  | 	int i, c; | ||
|  | 	if ((unsigned int)s > (unsigned int)p) | ||
|  | 	{ | ||
|  | 		s = (unsigned int)s - (unsigned int)p; | ||
|  | 	} | ||
|  | 	while (s > 0) | ||
|  | 	{ | ||
|  | 		if (base) | ||
|  | 		{ | ||
|  | 			_printk("%06X: ", (int)p - (int)base); | ||
|  | 		} else | ||
|  | 		{ | ||
|  | 			_printk("%06X: ", p); | ||
|  | 		} | ||
|  | 		for (i = 0;  i < 16;  i++) | ||
|  | 		{ | ||
|  | 			if (i < s) | ||
|  | 			{ | ||
|  | 				_printk("%02X", p[i] & 0xFF); | ||
|  | 			} else | ||
|  | 			{ | ||
|  | 				_printk("  "); | ||
|  | 			} | ||
|  | 			if ((i % 2) == 1) _printk(" "); | ||
|  | 			if ((i % 8) == 7) _printk(" "); | ||
|  | 		} | ||
|  | 		_printk(" |"); | ||
|  | 		for (i = 0;  i < 16;  i++) | ||
|  | 		{ | ||
|  | 			if (i < s) | ||
|  | 			{ | ||
|  | 				c = p[i] & 0xFF; | ||
|  | 				if ((c < 0x20) || (c >= 0x7F)) c = '.'; | ||
|  | 			} else | ||
|  | 			{ | ||
|  | 				c = ' '; | ||
|  | 			} | ||
|  | 			_printk("%c", c); | ||
|  | 		} | ||
|  | 		_printk("|\n"); | ||
|  | 		s -= 16; | ||
|  | 		p += 16; | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | void | ||
|  | _dump_buf(unsigned char *p, int s) | ||
|  | { | ||
|  | 	_printk("\n"); | ||
|  | 	_dump_buf_with_offset(p, s, 0); | ||
|  | } | ||
|  | 
 | ||
|  | /* Very simple inb/outb routines.  We declare ISA_io to be 0 above, and
 | ||
|  |  * then modify it on platforms which need to.  We do it like this | ||
|  |  * because on some platforms we give inb/outb an exact location, and | ||
|  |  * on others it's an offset from a given location. -- Tom | ||
|  |  */ | ||
|  | 
 | ||
|  | void ISA_init(unsigned long base) | ||
|  | { | ||
|  | 	ISA_io = (unsigned char *)base; | ||
|  | } | ||
|  | 
 | ||
|  | void | ||
|  | outb(int port, unsigned char val) | ||
|  | { | ||
|  | 	/* Ensure I/O operations complete */ | ||
|  | 	__asm__ volatile("eieio"); | ||
|  | 	ISA_io[port] = val; | ||
|  | } | ||
|  | 
 | ||
|  | unsigned char | ||
|  | inb(int port) | ||
|  | { | ||
|  | 	/* Ensure I/O operations complete */ | ||
|  | 	__asm__ volatile("eieio"); | ||
|  | 	return (ISA_io[port]); | ||
|  | } | ||
|  | 
 | ||
|  | /*
 | ||
|  |  * Local variables: | ||
|  |  *  c-indent-level: 8 | ||
|  |  *  c-basic-offset: 8 | ||
|  |  *  tab-width: 8 | ||
|  |  * End: | ||
|  |  */ |