pre-2.3.4..
[davej-history.git] / arch / ppc / boot / misc.c
blob65b0e74a67dc0ea2e825f864969571cde6b6374d
1 /*
2 * misc.c
4 * $Id: misc.c,v 1.65 1999/05/17 19:11:13 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 char sanity[0x2000];
314 unsigned long
315 decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum,
316 RESIDUAL *residual, void *OFW_interface)
318 int timer;
319 extern unsigned long start;
320 char *cp, ch;
321 unsigned long i;
322 BATU *u;
323 BATL *l;
324 unsigned long TotalMemory;
325 unsigned long orig_MSR;
326 int dev_handle;
327 int mem_info[2];
328 int res, size;
329 unsigned char board_type;
330 unsigned char base_mod;
332 lines = 25;
333 cols = 80;
334 orig_x = 0;
335 orig_y = 24;
339 * IBM's have the MMU on, so we have to disable it or
340 * things get really unhappy in the kernel when
341 * trying to setup the BATs with the MMU on
342 * -- Cort
344 flush_instruction_cache();
345 _put_HID0(_get_HID0() & ~0x0000C000);
346 _put_MSR((orig_MSR = _get_MSR()) & ~0x0030);
348 #if defined(CONFIG_SERIAL_CONSOLE)
349 com_port = (struct NS16550 *)NS16550_init(0);
350 #endif /* CONFIG_SERIAL_CONSOLE */
351 vga_init(0xC0000000);
353 if (residual)
355 /* Is this Motorola PPCBug? */
356 if ((1 & residual->VitalProductData.FirmwareSupports) &&
357 (1 == residual->VitalProductData.FirmwareSupplier)) {
358 board_type = inb(0x800) & 0xF0;
360 /* If this is genesis 2 board then check for no
361 * keyboard controller and more than one processor.
363 if (board_type == 0xe0) {
364 base_mod = inb(0x803);
365 /* if a MVME2300/2400 or a Sitka then no keyboard */
366 if((base_mod == 0xFA) || (base_mod == 0xF9) ||
367 (base_mod == 0xE1)) {
368 keyb_present = 0; /* no keyboard */
372 memcpy(hold_residual,residual,sizeof(RESIDUAL));
373 } else {
374 /* Assume 32M in the absence of more info... */
375 TotalMemory = 0x02000000;
377 * This is a 'best guess' check. We want to make sure
378 * we don't try this on a PReP box without OF
379 * -- Cort
381 while (OFW_interface && ((unsigned long)OFW_interface < 0x10000000) )
383 /* The MMU needs to be on when we call OFW */
384 _put_MSR(orig_MSR);
385 of_init(OFW_interface);
387 /* get handle to memory description */
388 res = of_finddevice("/memory@0",
389 &dev_handle);
390 // puthex(res); puts("\n");
391 if (res) break;
393 /* get the info */
394 // puts("get info = ");
395 res = of_getprop(dev_handle,
396 "reg",
397 mem_info,
398 sizeof(mem_info),
399 &size);
400 // puthex(res); puts(", info = "); puthex(mem_info[0]);
401 // puts(" "); puthex(mem_info[1]); puts("\n");
402 if (res) break;
404 TotalMemory = mem_info[1];
405 break;
407 hold_residual->TotalMemory = TotalMemory;
408 residual = hold_residual;
409 /* Turn MMU back off */
410 _put_MSR(orig_MSR & ~0x0030);
413 /* assume the chunk below 8M is free */
414 end_avail = (char *)0x00800000;
416 /* tell the user where we were loaded at and where we
417 * were relocated to for debugging this process
419 puts("loaded at: "); puthex(load_addr);
420 puts(" "); puthex((unsigned long)(load_addr + (4*num_words))); puts("\n");
421 if ( (unsigned long)load_addr != (unsigned long)&start )
423 puts("relocated to: "); puthex((unsigned long)&start);
424 puts(" ");
425 puthex((unsigned long)((unsigned long)&start + (4*num_words)));
426 puts("\n");
429 if ( residual )
431 puts("board data at: "); puthex((unsigned long)residual);
432 puts(" ");
433 puthex((unsigned long)((unsigned long)residual + sizeof(RESIDUAL)));
434 puts("\n");
435 puts("relocated to: ");
436 puthex((unsigned long)hold_residual);
437 puts(" ");
438 puthex((unsigned long)((unsigned long)hold_residual + sizeof(RESIDUAL)));
439 puts("\n");
442 /* we have to subtract 0x10000 here to correct for objdump including the
443 size of the elf header which we strip -- Cort */
444 zimage_start = (char *)(load_addr - 0x10000 + ZIMAGE_OFFSET);
445 zimage_size = ZIMAGE_SIZE;
447 if ( INITRD_OFFSET )
448 initrd_start = load_addr - 0x10000 + INITRD_OFFSET;
449 else
450 initrd_start = 0;
451 initrd_end = INITRD_SIZE + initrd_start;
454 * Find a place to stick the zimage and initrd and
455 * relocate them if we have to. -- Cort
457 avail_ram = (char *)PAGE_ALIGN((unsigned long)_end);
458 puts("zimage at: "); puthex((unsigned long)zimage_start);
459 puts(" "); puthex((unsigned long)(zimage_size+zimage_start)); puts("\n");
460 if ( (unsigned long)zimage_start <= 0x00800000 )
462 memcpy( (void *)avail_ram, (void *)zimage_start, zimage_size );
463 zimage_start = (char *)avail_ram;
464 puts("relocated to: "); puthex((unsigned long)zimage_start);
465 puts(" ");
466 puthex((unsigned long)zimage_size+(unsigned long)zimage_start);
467 puts("\n");
470 /* relocate initrd */
471 if ( initrd_start )
473 puts("initrd at: "); puthex(initrd_start);
474 puts(" "); puthex(initrd_end); puts("\n");
475 #ifdef OMIT
476 avail_ram = (char *)PAGE_ALIGN(
477 (unsigned long)zimage_size+(unsigned long)zimage_start);
478 memcpy ((void *)avail_ram, (void *)initrd_start, INITRD_SIZE );
479 initrd_start = (unsigned long)avail_ram;
480 initrd_end = initrd_start + INITRD_SIZE;
481 puts("relocated to: "); puthex(initrd_start);
482 puts(" "); puthex(initrd_end); puts("\n");
483 #endif
486 avail_ram = (char *)0x00400000;
487 end_avail = (char *)0x00800000;
488 puts("avail ram: "); puthex((unsigned long)avail_ram); puts(" ");
489 puthex((unsigned long)end_avail); puts("\n");
491 if (keyb_present)
492 CRT_tstc(); /* Forces keyboard to be initialized */
494 puts("\nLinux/PPC load: ");
495 timer = 0;
496 cp = cmd_line;
497 memcpy (cmd_line, cmd_preset, sizeof(cmd_preset));
498 while ( *cp ) putc(*cp++);
499 while (timer++ < 5*1000) {
500 if (tstc()) {
501 while ((ch = getc()) != '\n' && ch != '\r') {
502 if (ch == '\b') {
503 if (cp != cmd_line) {
504 cp--;
505 puts("\b \b");
507 } else {
508 *cp++ = ch;
509 putc(ch);
512 break; /* Exit 'timer' loop */
514 udelay(1000); /* 1 msec */
516 *cp = 0;
517 puts("\n");
519 /* mappings on early boot can only handle 16M */
520 if ( (int)(cmd_line[0]) > (16<<20))
521 puts("cmd_line located > 16M\n");
522 if ( (int)hold_residual > (16<<20))
523 puts("hold_residual located > 16M\n");
524 if ( initrd_start > (16<<20))
525 puts("initrd_start located > 16M\n");
527 puts("Uncompressing Linux...");
529 gunzip(0, 0x400000, zimage_start, &zimage_size);
530 puts("done.\n");
531 puts("Now booting the kernel\n");
532 return (unsigned long)hold_residual;
535 void puthex(unsigned long val)
537 unsigned char buf[10];
538 int i;
539 for (i = 7; i >= 0; i--)
541 buf[i] = "0123456789ABCDEF"[val & 0x0F];
542 val >>= 4;
544 buf[8] = '\0';
545 puts(buf);
549 * PCI/ISA I/O support
552 volatile unsigned char *ISA_io = (unsigned char *)0x80000000;
553 volatile unsigned char *ISA_mem = (unsigned char *)0xC0000000;
555 void
556 outb(int port, char val)
558 /* Ensure I/O operations complete */
559 __asm__ volatile("eieio");
560 ISA_io[port] = val;
563 unsigned char
564 inb(int port)
566 /* Ensure I/O operations complete */
567 __asm__ volatile("eieio");
568 return (ISA_io[port]);
571 unsigned long
572 local_to_PCI(unsigned long addr)
574 return ((addr & 0x7FFFFFFF) | 0x80000000);
577 void
578 _bcopy(char *src, char *dst, int len)
580 while (len--) *dst++ = *src++;
584 #define FALSE 0
585 #define TRUE 1
586 #include <stdarg.h>
589 strlen(char *s)
591 int len = 0;
592 while (*s++) len++;
593 return len;
596 _printk(char const *fmt, ...)
598 int ret;
599 va_list ap;
601 va_start(ap, fmt);
602 ret = _vprintk(putc, fmt, ap);
603 va_end(ap);
604 return (ret);
607 #define is_digit(c) ((c >= '0') && (c <= '9'))
610 _vprintk(putc, fmt0, ap)
611 int (*putc)();
612 const char *fmt0;
613 va_list ap;
615 char c, sign, *cp;
616 int left_prec, right_prec, zero_fill, length, pad, pad_on_right;
617 char buf[32];
618 long val;
619 while (c = *fmt0++)
621 if (c == '%')
623 c = *fmt0++;
624 left_prec = right_prec = pad_on_right = 0;
625 if (c == '-')
627 c = *fmt0++;
628 pad_on_right++;
630 if (c == '0')
632 zero_fill = TRUE;
633 c = *fmt0++;
634 } else
636 zero_fill = FALSE;
638 while (is_digit(c))
640 left_prec = (left_prec * 10) + (c - '0');
641 c = *fmt0++;
643 if (c == '.')
645 c = *fmt0++;
646 zero_fill++;
647 while (is_digit(c))
649 right_prec = (right_prec * 10) + (c - '0');
650 c = *fmt0++;
652 } else
654 right_prec = left_prec;
656 sign = '\0';
657 switch (c)
659 case 'd':
660 case 'x':
661 case 'X':
662 val = va_arg(ap, long);
663 switch (c)
665 case 'd':
666 if (val < 0)
668 sign = '-';
669 val = -val;
671 length = _cvt(val, buf, 10, "0123456789");
672 break;
673 case 'x':
674 length = _cvt(val, buf, 16, "0123456789abcdef");
675 break;
676 case 'X':
677 length = _cvt(val, buf, 16, "0123456789ABCDEF");
678 break;
680 cp = buf;
681 break;
682 case 's':
683 cp = va_arg(ap, char *);
684 length = strlen(cp);
685 break;
686 case 'c':
687 c = va_arg(ap, long /*char*/);
688 (*putc)(c);
689 continue;
690 default:
691 (*putc)('?');
693 pad = left_prec - length;
694 if (sign != '\0')
696 pad--;
698 if (zero_fill)
700 c = '0';
701 if (sign != '\0')
703 (*putc)(sign);
704 sign = '\0';
706 } else
708 c = ' ';
710 if (!pad_on_right)
712 while (pad-- > 0)
714 (*putc)(c);
717 if (sign != '\0')
719 (*putc)(sign);
721 while (length-- > 0)
723 (*putc)(c = *cp++);
724 if (c == '\n')
726 (*putc)('\r');
729 if (pad_on_right)
731 while (pad-- > 0)
733 (*putc)(c);
736 } else
738 (*putc)(c);
739 if (c == '\n')
741 (*putc)('\r');
747 int _cvt(unsigned long val, char *buf, long radix, char *digits)
749 char temp[80];
750 char *cp = temp;
751 int length = 0;
752 if (val == 0)
753 { /* Special case */
754 *cp++ = '0';
755 } else
756 while (val)
758 *cp++ = digits[val % radix];
759 val /= radix;
761 while (cp != temp)
763 *buf++ = *--cp;
764 length++;
766 *buf = '\0';
767 return (length);
770 _dump_buf_with_offset(unsigned char *p, int s, unsigned char *base)
772 int i, c;
773 if ((unsigned int)s > (unsigned int)p)
775 s = (unsigned int)s - (unsigned int)p;
777 while (s > 0)
779 if (base)
781 _printk("%06X: ", (int)p - (int)base);
782 } else
784 _printk("%06X: ", p);
786 for (i = 0; i < 16; i++)
788 if (i < s)
790 _printk("%02X", p[i] & 0xFF);
791 } else
793 _printk(" ");
795 if ((i % 2) == 1) _printk(" ");
796 if ((i % 8) == 7) _printk(" ");
798 _printk(" |");
799 for (i = 0; i < 16; i++)
801 if (i < s)
803 c = p[i] & 0xFF;
804 if ((c < 0x20) || (c >= 0x7F)) c = '.';
805 } else
807 c = ' ';
809 _printk("%c", c);
811 _printk("|\n");
812 s -= 16;
813 p += 16;
817 _dump_buf(unsigned char *p, int s)
819 _printk("\n");
820 _dump_buf_with_offset(p, s, 0);