| /* | |
| * 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/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) \ | |
| || defined(CONFIG_SERIAL_UARTLITE_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) \ | |
| || defined(CONFIG_SERIAL_UARTLITE_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) \ | |
| || defined(CONFIG_SERIAL_UARTLITE_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) \ | |
| || defined(CONFIG_SERIAL_UARTLITE_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) \ | |
| || defined(CONFIG_SERIAL_UARTLITE_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: | |
| */ |