Import 2.3.16
[davej-history.git] / arch / ppc / boot / misc.c
blobaee4075429c2cad61012b366ce3e28c9cb4e674e
1 /*
2 * misc.c
4 * $Id: misc.c,v 1.67 1999/08/10 22:53:57 cort Exp $
5 *
6 * Adapted for PowerPC by Gary Thomas
8 * Rewritten by Cort Dougan (cort@cs.nmt.edu)
9 * One day to be replaced by a single bootloader for chrp/prep/pmac. -- Cort
12 #include <linux/types.h>
13 #include "../coffboot/zlib.h"
14 #include "asm/residual.h"
15 #include <linux/elf.h>
16 #include <linux/config.h>
17 #include <asm/page.h>
18 #include <asm/processor.h>
19 #include <asm/mmu.h>
20 #if defined(CONFIG_SERIAL_CONSOLE)
21 #include "ns16550.h"
22 struct NS16550 *com_port;
23 #endif /* CONFIG_SERIAL_CONSOLE */
26 * Please send me load/board info and such data for hardware not
27 * listed here so I can keep track since things are getting tricky
28 * with the different load addrs with different firmware. This will
29 * help to avoid breaking the load/boot process.
30 * -- Cort
32 char *avail_ram;
33 char *end_avail;
34 extern char _end[];
36 #ifdef CONFIG_CMDLINE
37 #define CMDLINE CONFIG_CMDLINE
38 #else
39 #define CMDLINE "";
40 #endif
41 char cmd_preset[] = CMDLINE;
42 char cmd_buf[256];
43 char *cmd_line = cmd_buf;
45 int keyb_present = 1; /* keyboard controller is present by default */
46 RESIDUAL hold_resid_buf;
47 RESIDUAL *hold_residual = &hold_resid_buf;
48 unsigned long initrd_start = 0, initrd_end = 0;
49 char *zimage_start;
50 int zimage_size;
52 char *vidmem = (char *)0xC00B8000;
53 int lines, cols;
54 int orig_x, orig_y;
56 void puts(const char *);
57 void putc(const char c);
58 void puthex(unsigned long val);
59 void _bcopy(char *src, char *dst, int len);
60 void * memcpy(void * __dest, __const void * __src,
61 int __n);
62 void gunzip(void *, int, unsigned char *, int *);
63 static int _cvt(unsigned long val, char *buf, long radix, char *digits);
64 unsigned char inb(int);
66 void pause()
68 puts("pause\n");
71 void exit()
73 puts("exit\n");
74 while(1);
77 static void clear_screen()
79 int i, j;
80 for (i = 0; i < lines; i++) {
81 for (j = 0; j < cols; j++) {
82 vidmem[((i*cols)+j)*2] = ' ';
83 vidmem[((i*cols)+j)*2+1] = 0x07;
88 static void scroll()
90 int i;
92 memcpy ( vidmem, vidmem + cols * 2, ( lines - 1 ) * cols * 2 );
93 for ( i = ( lines - 1 ) * cols * 2; i < lines * cols * 2; i += 2 )
94 vidmem[i] = ' ';
97 tstc(void)
99 #if defined(CONFIG_SERIAL_CONSOLE)
100 if (keyb_present)
101 return (CRT_tstc() || NS16550_tstc(com_port));
102 else
103 NS16550_tstc(com_port);
104 #else
105 return (CRT_tstc() );
106 #endif /* CONFIG_SERIAL_CONSOLE */
109 getc(void)
111 while (1) {
112 #if defined(CONFIG_SERIAL_CONSOLE)
113 if (NS16550_tstc(com_port)) return (NS16550_getc(com_port));
114 #endif /* CONFIG_SERIAL_CONSOLE */
115 if (keyb_present)
116 if (CRT_tstc()) return (CRT_getc());
120 void
121 putc(const char c)
123 int x,y;
125 #if defined(CONFIG_SERIAL_CONSOLE)
126 NS16550_putc(com_port, c);
127 if ( c == '\n' ) NS16550_putc(com_port, '\r');
128 #endif /* CONFIG_SERIAL_CONSOLE */
130 x = orig_x;
131 y = orig_y;
133 if ( c == '\n' ) {
134 x = 0;
135 if ( ++y >= lines ) {
136 scroll();
137 y--;
139 } else if (c == '\r') {
140 x = 0;
141 } else if (c == '\b') {
142 if (x > 0) {
143 x--;
145 } else {
146 vidmem [ ( x + cols * y ) * 2 ] = c;
147 if ( ++x >= cols ) {
148 x = 0;
149 if ( ++y >= lines ) {
150 scroll();
151 y--;
156 cursor(x, y);
158 orig_x = x;
159 orig_y = y;
162 void puts(const char *s)
164 int x,y;
165 char c;
167 x = orig_x;
168 y = orig_y;
170 while ( ( c = *s++ ) != '\0' ) {
171 #if defined(CONFIG_SERIAL_CONSOLE)
172 NS16550_putc(com_port, c);
173 if ( c == '\n' ) NS16550_putc(com_port, '\r');
174 #endif /* CONFIG_SERIAL_CONSOLE */
176 if ( c == '\n' ) {
177 x = 0;
178 if ( ++y >= lines ) {
179 scroll();
180 y--;
182 } else if (c == '\b') {
183 if (x > 0) {
184 x--;
186 } else {
187 vidmem [ ( x + cols * y ) * 2 ] = c;
188 if ( ++x >= cols ) {
189 x = 0;
190 if ( ++y >= lines ) {
191 scroll();
192 y--;
198 cursor(x, y);
200 orig_x = x;
201 orig_y = y;
204 void * memcpy(void * __dest, __const void * __src,
205 int __n)
207 int i;
208 char *d = (char *)__dest, *s = (char *)__src;
210 for (i=0;i<__n;i++) d[i] = s[i];
213 int memcmp(__const void * __dest, __const void * __src,
214 int __n)
216 int i;
217 char *d = (char *)__dest, *s = (char *)__src;
219 for (i=0;i<__n;i++, d++, s++)
221 if (*d != *s)
223 return (*s - *d);
226 return (0);
229 void error(char *x)
231 puts("\n\n");
232 puts(x);
233 puts("\n\n -- System halted");
235 while(1); /* Halt */
238 void *zalloc(void *x, unsigned items, unsigned size)
240 void *p = avail_ram;
242 size *= items;
243 size = (size + 7) & -8;
244 avail_ram += size;
245 if (avail_ram > end_avail) {
246 puts("oops... out of memory\n");
247 pause();
249 return p;
252 void zfree(void *x, void *addr, unsigned nb)
256 #define HEAD_CRC 2
257 #define EXTRA_FIELD 4
258 #define ORIG_NAME 8
259 #define COMMENT 0x10
260 #define RESERVED 0xe0
262 #define DEFLATED 8
265 void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp)
267 z_stream s;
268 int r, i, flags;
270 /* skip header */
271 i = 10;
272 flags = src[3];
273 if (src[2] != DEFLATED || (flags & RESERVED) != 0) {
274 puts("bad gzipped data\n");
275 exit();
277 if ((flags & EXTRA_FIELD) != 0)
278 i = 12 + src[10] + (src[11] << 8);
279 if ((flags & ORIG_NAME) != 0)
280 while (src[i++] != 0)
282 if ((flags & COMMENT) != 0)
283 while (src[i++] != 0)
285 if ((flags & HEAD_CRC) != 0)
286 i += 2;
287 if (i >= *lenp) {
288 puts("gunzip: ran out of data in header\n");
289 exit();
292 s.zalloc = zalloc;
293 s.zfree = zfree;
294 r = inflateInit2(&s, -MAX_WBITS);
295 if (r != Z_OK) {
296 puts("inflateInit2 returned %d\n");
297 exit();
299 s.next_in = src + i;
300 s.avail_in = *lenp - i;
301 s.next_out = dst;
302 s.avail_out = dstlen;
303 r = inflate(&s, Z_FINISH);
304 if (r != Z_OK && r != Z_STREAM_END) {
305 puts("inflate returned %d\n");
306 exit();
308 *lenp = s.next_out - (unsigned char *) dst;
309 inflateEnd(&s);
312 unsigned long
313 decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum,
314 RESIDUAL *residual, void *OFW_interface)
316 int timer;
317 extern unsigned long start;
318 char *cp, ch;
319 unsigned long i;
320 BATU *u;
321 BATL *l;
322 unsigned long TotalMemory;
323 unsigned long orig_MSR;
324 int dev_handle;
325 int mem_info[2];
326 int res, size;
327 unsigned char board_type;
328 unsigned char base_mod;
330 lines = 25;
331 cols = 80;
332 orig_x = 0;
333 orig_y = 24;
336 * IBM's have the MMU on, so we have to disable it or
337 * things get really unhappy in the kernel when
338 * trying to setup the BATs with the MMU on
339 * -- Cort
341 flush_instruction_cache();
342 _put_HID0(_get_HID0() & ~0x0000C000);
343 _put_MSR((orig_MSR = _get_MSR()) & ~0x0030);
345 #if defined(CONFIG_SERIAL_CONSOLE)
346 com_port = (struct NS16550 *)NS16550_init(0);
347 #endif /* CONFIG_SERIAL_CONSOLE */
348 vga_init(0xC0000000);
350 if (residual)
352 /* Is this Motorola PPCBug? */
353 if ((1 & residual->VitalProductData.FirmwareSupports) &&
354 (1 == residual->VitalProductData.FirmwareSupplier)) {
355 board_type = inb(0x800) & 0xF0;
357 /* If this is genesis 2 board then check for no
358 * keyboard controller and more than one processor.
360 if (board_type == 0xe0) {
361 base_mod = inb(0x803);
362 /* if a MVME2300/2400 or a Sitka then no keyboard */
363 if((base_mod == 0xFA) || (base_mod == 0xF9) ||
364 (base_mod == 0xE1)) {
365 keyb_present = 0; /* no keyboard */
369 memcpy(hold_residual,residual,sizeof(RESIDUAL));
370 } else {
371 /* Assume 32M in the absence of more info... */
372 TotalMemory = 0x02000000;
374 * This is a 'best guess' check. We want to make sure
375 * we don't try this on a PReP box without OF
376 * -- Cort
378 while (OFW_interface && ((unsigned long)OFW_interface < 0x10000000) )
380 /* The MMU needs to be on when we call OFW */
381 _put_MSR(orig_MSR);
382 of_init(OFW_interface);
384 /* get handle to memory description */
385 res = of_finddevice("/memory@0",
386 &dev_handle);
387 // puthex(res); puts("\n");
388 if (res) break;
390 /* get the info */
391 // puts("get info = ");
392 res = of_getprop(dev_handle,
393 "reg",
394 mem_info,
395 sizeof(mem_info),
396 &size);
397 // puthex(res); puts(", info = "); puthex(mem_info[0]);
398 // puts(" "); puthex(mem_info[1]); puts("\n");
399 if (res) break;
401 TotalMemory = mem_info[1];
402 break;
404 hold_residual->TotalMemory = TotalMemory;
405 residual = hold_residual;
406 /* Turn MMU back off */
407 _put_MSR(orig_MSR & ~0x0030);
410 /* assume the chunk below 8M is free */
411 end_avail = (char *)0x00800000;
413 /* tell the user where we were loaded at and where we
414 * were relocated to for debugging this process
416 puts("loaded at: "); puthex(load_addr);
417 puts(" "); puthex((unsigned long)(load_addr + (4*num_words))); puts("\n");
418 if ( (unsigned long)load_addr != (unsigned long)&start )
420 puts("relocated to: "); puthex((unsigned long)&start);
421 puts(" ");
422 puthex((unsigned long)((unsigned long)&start + (4*num_words)));
423 puts("\n");
426 if ( residual )
428 puts("board data at: "); puthex((unsigned long)residual);
429 puts(" ");
430 puthex((unsigned long)((unsigned long)residual + sizeof(RESIDUAL)));
431 puts("\n");
432 puts("relocated to: ");
433 puthex((unsigned long)hold_residual);
434 puts(" ");
435 puthex((unsigned long)((unsigned long)hold_residual + sizeof(RESIDUAL)));
436 puts("\n");
439 /* we have to subtract 0x10000 here to correct for objdump including the
440 size of the elf header which we strip -- Cort */
441 zimage_start = (char *)(load_addr - 0x10000 + ZIMAGE_OFFSET);
442 zimage_size = ZIMAGE_SIZE;
444 if ( INITRD_OFFSET )
445 initrd_start = load_addr - 0x10000 + INITRD_OFFSET;
446 else
447 initrd_start = 0;
448 initrd_end = INITRD_SIZE + initrd_start;
451 * Find a place to stick the zimage and initrd and
452 * relocate them if we have to. -- Cort
454 avail_ram = (char *)PAGE_ALIGN((unsigned long)_end);
455 puts("zimage at: "); puthex((unsigned long)zimage_start);
456 puts(" "); puthex((unsigned long)(zimage_size+zimage_start)); puts("\n");
457 if ( (unsigned long)zimage_start <= 0x00800000 )
459 memcpy( (void *)avail_ram, (void *)zimage_start, zimage_size );
460 zimage_start = (char *)avail_ram;
461 puts("relocated to: "); puthex((unsigned long)zimage_start);
462 puts(" ");
463 puthex((unsigned long)zimage_size+(unsigned long)zimage_start);
464 puts("\n");
467 /* relocate initrd */
468 if ( initrd_start )
470 puts("initrd at: "); puthex(initrd_start);
471 puts(" "); puthex(initrd_end); puts("\n");
472 #ifdef OMIT
473 avail_ram = (char *)PAGE_ALIGN(
474 (unsigned long)zimage_size+(unsigned long)zimage_start);
475 memcpy ((void *)avail_ram, (void *)initrd_start, INITRD_SIZE );
476 initrd_start = (unsigned long)avail_ram;
477 initrd_end = initrd_start + INITRD_SIZE;
478 puts("relocated to: "); puthex(initrd_start);
479 puts(" "); puthex(initrd_end); puts("\n");
480 #endif
483 avail_ram = (char *)0x00400000;
484 end_avail = (char *)0x00800000;
485 puts("avail ram: "); puthex((unsigned long)avail_ram); puts(" ");
486 puthex((unsigned long)end_avail); puts("\n");
488 if (keyb_present)
489 CRT_tstc(); /* Forces keyboard to be initialized */
491 puts("\nLinux/PPC load: ");
492 timer = 0;
493 cp = cmd_line;
494 memcpy (cmd_line, cmd_preset, sizeof(cmd_preset));
495 while ( *cp ) putc(*cp++);
496 while (timer++ < 5*1000) {
497 if (tstc()) {
498 while ((ch = getc()) != '\n' && ch != '\r') {
499 if (ch == '\b') {
500 if (cp != cmd_line) {
501 cp--;
502 puts("\b \b");
504 } else {
505 *cp++ = ch;
506 putc(ch);
509 break; /* Exit 'timer' loop */
511 udelay(1000); /* 1 msec */
513 *cp = 0;
514 puts("\n");
516 /* mappings on early boot can only handle 16M */
517 if ( (int)(cmd_line[0]) > (16<<20))
518 puts("cmd_line located > 16M\n");
519 if ( (int)hold_residual > (16<<20))
520 puts("hold_residual located > 16M\n");
521 if ( initrd_start > (16<<20))
522 puts("initrd_start located > 16M\n");
524 puts("Uncompressing Linux...");
525 gunzip(0, 0x400000, zimage_start, &zimage_size);
526 puts("done.\n");
527 puts("Now booting the kernel\n");
528 return (unsigned long)hold_residual;
531 void puthex(unsigned long val)
533 unsigned char buf[10];
534 int i;
535 for (i = 7; i >= 0; i--)
537 buf[i] = "0123456789ABCDEF"[val & 0x0F];
538 val >>= 4;
540 buf[8] = '\0';
541 puts(buf);
545 * PCI/ISA I/O support
548 volatile unsigned char *ISA_io = (unsigned char *)0x80000000;
549 volatile unsigned char *ISA_mem = (unsigned char *)0xC0000000;
551 void
552 outb(int port, char val)
554 /* Ensure I/O operations complete */
555 __asm__ volatile("eieio");
556 ISA_io[port] = val;
559 unsigned char
560 inb(int port)
562 /* Ensure I/O operations complete */
563 __asm__ volatile("eieio");
564 return (ISA_io[port]);
567 unsigned long
568 local_to_PCI(unsigned long addr)
570 return ((addr & 0x7FFFFFFF) | 0x80000000);
573 void
574 _bcopy(char *src, char *dst, int len)
576 while (len--) *dst++ = *src++;
580 #define FALSE 0
581 #define TRUE 1
582 #include <stdarg.h>
585 strlen(char *s)
587 int len = 0;
588 while (*s++) len++;
589 return len;
592 _printk(char const *fmt, ...)
594 int ret;
595 va_list ap;
597 va_start(ap, fmt);
598 ret = _vprintk(putc, fmt, ap);
599 va_end(ap);
600 return (ret);
603 #define is_digit(c) ((c >= '0') && (c <= '9'))
606 _vprintk(putc, fmt0, ap)
607 int (*putc)();
608 const char *fmt0;
609 va_list ap;
611 char c, sign, *cp;
612 int left_prec, right_prec, zero_fill, length, pad, pad_on_right;
613 char buf[32];
614 long val;
615 while (c = *fmt0++)
617 if (c == '%')
619 c = *fmt0++;
620 left_prec = right_prec = pad_on_right = 0;
621 if (c == '-')
623 c = *fmt0++;
624 pad_on_right++;
626 if (c == '0')
628 zero_fill = TRUE;
629 c = *fmt0++;
630 } else
632 zero_fill = FALSE;
634 while (is_digit(c))
636 left_prec = (left_prec * 10) + (c - '0');
637 c = *fmt0++;
639 if (c == '.')
641 c = *fmt0++;
642 zero_fill++;
643 while (is_digit(c))
645 right_prec = (right_prec * 10) + (c - '0');
646 c = *fmt0++;
648 } else
650 right_prec = left_prec;
652 sign = '\0';
653 switch (c)
655 case 'd':
656 case 'x':
657 case 'X':
658 val = va_arg(ap, long);
659 switch (c)
661 case 'd':
662 if (val < 0)
664 sign = '-';
665 val = -val;
667 length = _cvt(val, buf, 10, "0123456789");
668 break;
669 case 'x':
670 length = _cvt(val, buf, 16, "0123456789abcdef");
671 break;
672 case 'X':
673 length = _cvt(val, buf, 16, "0123456789ABCDEF");
674 break;
676 cp = buf;
677 break;
678 case 's':
679 cp = va_arg(ap, char *);
680 length = strlen(cp);
681 break;
682 case 'c':
683 c = va_arg(ap, long /*char*/);
684 (*putc)(c);
685 continue;
686 default:
687 (*putc)('?');
689 pad = left_prec - length;
690 if (sign != '\0')
692 pad--;
694 if (zero_fill)
696 c = '0';
697 if (sign != '\0')
699 (*putc)(sign);
700 sign = '\0';
702 } else
704 c = ' ';
706 if (!pad_on_right)
708 while (pad-- > 0)
710 (*putc)(c);
713 if (sign != '\0')
715 (*putc)(sign);
717 while (length-- > 0)
719 (*putc)(c = *cp++);
720 if (c == '\n')
722 (*putc)('\r');
725 if (pad_on_right)
727 while (pad-- > 0)
729 (*putc)(c);
732 } else
734 (*putc)(c);
735 if (c == '\n')
737 (*putc)('\r');
743 int _cvt(unsigned long val, char *buf, long radix, char *digits)
745 char temp[80];
746 char *cp = temp;
747 int length = 0;
748 if (val == 0)
749 { /* Special case */
750 *cp++ = '0';
751 } else
752 while (val)
754 *cp++ = digits[val % radix];
755 val /= radix;
757 while (cp != temp)
759 *buf++ = *--cp;
760 length++;
762 *buf = '\0';
763 return (length);
766 _dump_buf_with_offset(unsigned char *p, int s, unsigned char *base)
768 int i, c;
769 if ((unsigned int)s > (unsigned int)p)
771 s = (unsigned int)s - (unsigned int)p;
773 while (s > 0)
775 if (base)
777 _printk("%06X: ", (int)p - (int)base);
778 } else
780 _printk("%06X: ", p);
782 for (i = 0; i < 16; i++)
784 if (i < s)
786 _printk("%02X", p[i] & 0xFF);
787 } else
789 _printk(" ");
791 if ((i % 2) == 1) _printk(" ");
792 if ((i % 8) == 7) _printk(" ");
794 _printk(" |");
795 for (i = 0; i < 16; i++)
797 if (i < s)
799 c = p[i] & 0xFF;
800 if ((c < 0x20) || (c >= 0x7F)) c = '.';
801 } else
803 c = ' ';
805 _printk("%c", c);
807 _printk("|\n");
808 s -= 16;
809 p += 16;
813 _dump_buf(unsigned char *p, int s)
815 _printk("\n");
816 _dump_buf_with_offset(p, s, 0);