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) 43extern void cursor(int x, int y); 44extern void scroll(void); 45extern char *vidmem; 46extern int lines, cols; 47extern int orig_x, orig_y; 48extern int keyb_present; 49extern int CRT_tstc(void); 50extern int CRT_getc(void); 51#else 52int cursor(int x, int y) {return 0;} 53void scroll(void) {} 54char vidmem[1]; 55#define lines 0 56#define cols 0 57int orig_x = 0; 58int orig_y = 0; 59#define keyb_present 0 60int CRT_tstc(void) {return 0;} 61int CRT_getc(void) {return 0;} 62#endif 63 64extern char *avail_ram; 65extern char *end_avail; 66extern char _end[]; 67 68void puts(const char *); 69void putc(const char c); 70void puthex(unsigned long val); 71void _bcopy(char *src, char *dst, int len); 72void gunzip(void *, int, unsigned char *, int *); 73static int _cvt(unsigned long val, char *buf, long radix, char *digits); 74 75void _vprintk(void(*putc)(const char), const char *fmt0, va_list ap); 76unsigned char *ISA_io = NULL; 77 78#if defined(CONFIG_SERIAL_CONSOLE) 79extern unsigned long com_port; 80 81extern int serial_tstc(unsigned long com_port); 82extern unsigned char serial_getc(unsigned long com_port); 83extern void serial_putc(unsigned long com_port, unsigned char c); 84#endif 85 86void pause(void) 87{ 88 puts("pause\n"); 89} 90 91void exit(void) 92{ 93 puts("exit\n"); 94 while(1); 95} 96 97int 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 109int 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 122void 123putc(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 165void 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 207void error(char *x) 208{ 209 puts("\n\n"); 210 puts(x); 211 puts("\n\n -- System halted"); 212 213 while(1); /* Halt */ 214} 215 216void *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 230void 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 242void 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 289void 290puthex(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 307void 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 320void 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 455int 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 479void 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 527void 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 540void 541outb(int port, unsigned char val) 542{ 543 /* Ensure I/O operations complete */ 544 __asm__ volatile("eieio"); 545 ISA_io[port] = val; 546} 547 548unsigned char 549inb(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