4 * $Id: misc.c,v 1.67 1999/08/10 22:53:57 cort Exp $
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>
18 #include <asm/processor.h>
20 #if defined(CONFIG_SERIAL_CONSOLE)
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.
37 #define CMDLINE CONFIG_CMDLINE
41 char cmd_preset
[] = CMDLINE
;
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;
52 char *vidmem
= (char *)0xC00B8000;
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
,
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);
77 static void clear_screen()
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;
92 memcpy ( vidmem
, vidmem
+ cols
* 2, ( lines
- 1 ) * cols
* 2 );
93 for ( i
= ( lines
- 1 ) * cols
* 2; i
< lines
* cols
* 2; i
+= 2 )
99 #if defined(CONFIG_SERIAL_CONSOLE)
101 return (CRT_tstc() || NS16550_tstc(com_port
));
103 NS16550_tstc(com_port
);
105 return (CRT_tstc() );
106 #endif /* CONFIG_SERIAL_CONSOLE */
112 #if defined(CONFIG_SERIAL_CONSOLE)
113 if (NS16550_tstc(com_port
)) return (NS16550_getc(com_port
));
114 #endif /* CONFIG_SERIAL_CONSOLE */
116 if (CRT_tstc()) return (CRT_getc());
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 */
135 if ( ++y
>= lines
) {
139 } else if (c
== '\r') {
141 } else if (c
== '\b') {
146 vidmem
[ ( x
+ cols
* y
) * 2 ] = c
;
149 if ( ++y
>= lines
) {
162 void puts(const char *s
)
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 */
178 if ( ++y
>= lines
) {
182 } else if (c
== '\b') {
187 vidmem
[ ( x
+ cols
* y
) * 2 ] = c
;
190 if ( ++y
>= lines
) {
204 void * memcpy(void * __dest
, __const
void * __src
,
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
,
217 char *d
= (char *)__dest
, *s
= (char *)__src
;
219 for (i
=0;i
<__n
;i
++, d
++, s
++)
233 puts("\n\n -- System halted");
238 void *zalloc(void *x
, unsigned items
, unsigned size
)
243 size
= (size
+ 7) & -8;
245 if (avail_ram
> end_avail
) {
246 puts("oops... out of memory\n");
252 void zfree(void *x
, void *addr
, unsigned nb
)
257 #define EXTRA_FIELD 4
260 #define RESERVED 0xe0
265 void gunzip(void *dst
, int dstlen
, unsigned char *src
, int *lenp
)
273 if (src
[2] != DEFLATED
|| (flags
& RESERVED
) != 0) {
274 puts("bad gzipped data\n");
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)
288 puts("gunzip: ran out of data in header\n");
294 r
= inflateInit2(&s
, -MAX_WBITS
);
296 puts("inflateInit2 returned %d\n");
300 s
.avail_in
= *lenp
- i
;
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");
308 *lenp
= s
.next_out
- (unsigned char *) dst
;
313 decompress_kernel(unsigned long load_addr
, int num_words
, unsigned long cksum
,
314 RESIDUAL
*residual
, void *OFW_interface
)
317 extern unsigned long start
;
322 unsigned long TotalMemory
;
323 unsigned long orig_MSR
;
327 unsigned char board_type
;
328 unsigned char base_mod
;
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
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);
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
));
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
378 while (OFW_interface
&& ((unsigned long)OFW_interface
< 0x10000000) )
380 /* The MMU needs to be on when we call OFW */
382 of_init(OFW_interface
);
384 /* get handle to memory description */
385 res
= of_finddevice("/memory@0",
387 // puthex(res); puts("\n");
391 // puts("get info = ");
392 res
= of_getprop(dev_handle
,
397 // puthex(res); puts(", info = "); puthex(mem_info[0]);
398 // puts(" "); puthex(mem_info[1]); puts("\n");
401 TotalMemory
= mem_info
[1];
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
);
422 puthex((unsigned long)((unsigned long)&start
+ (4*num_words
)));
428 puts("board data at: "); puthex((unsigned long)residual
);
430 puthex((unsigned long)((unsigned long)residual
+ sizeof(RESIDUAL
)));
432 puts("relocated to: ");
433 puthex((unsigned long)hold_residual
);
435 puthex((unsigned long)((unsigned long)hold_residual
+ sizeof(RESIDUAL
)));
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
;
445 initrd_start
= load_addr
- 0x10000 + INITRD_OFFSET
;
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
);
463 puthex((unsigned long)zimage_size
+(unsigned long)zimage_start
);
467 /* relocate initrd */
470 puts("initrd at: "); puthex(initrd_start
);
471 puts(" "); puthex(initrd_end
); puts("\n");
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");
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");
489 CRT_tstc(); /* Forces keyboard to be initialized */
491 puts("\nLinux/PPC load: ");
494 memcpy (cmd_line
, cmd_preset
, sizeof(cmd_preset
));
495 while ( *cp
) putc(*cp
++);
496 while (timer
++ < 5*1000) {
498 while ((ch
= getc()) != '\n' && ch
!= '\r') {
500 if (cp
!= cmd_line
) {
509 break; /* Exit 'timer' loop */
511 udelay(1000); /* 1 msec */
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
);
527 puts("Now booting the kernel\n");
528 return (unsigned long)hold_residual
;
531 void puthex(unsigned long val
)
533 unsigned char buf
[10];
535 for (i
= 7; i
>= 0; i
--)
537 buf
[i
] = "0123456789ABCDEF"[val
& 0x0F];
545 * PCI/ISA I/O support
548 volatile unsigned char *ISA_io
= (unsigned char *)0x80000000;
549 volatile unsigned char *ISA_mem
= (unsigned char *)0xC0000000;
552 outb(int port
, char val
)
554 /* Ensure I/O operations complete */
555 __asm__
volatile("eieio");
562 /* Ensure I/O operations complete */
563 __asm__
volatile("eieio");
564 return (ISA_io
[port
]);
568 local_to_PCI(unsigned long addr
)
570 return ((addr
& 0x7FFFFFFF) | 0x80000000);
574 _bcopy(char *src
, char *dst
, int len
)
576 while (len
--) *dst
++ = *src
++;
592 _printk(char const *fmt
, ...)
598 ret
= _vprintk(putc
, fmt
, ap
);
603 #define is_digit(c) ((c >= '0') && (c <= '9'))
606 _vprintk(putc
, fmt0
, ap
)
612 int left_prec
, right_prec
, zero_fill
, length
, pad
, pad_on_right
;
620 left_prec
= right_prec
= pad_on_right
= 0;
636 left_prec
= (left_prec
* 10) + (c
- '0');
645 right_prec
= (right_prec
* 10) + (c
- '0');
650 right_prec
= left_prec
;
658 val
= va_arg(ap
, long);
667 length
= _cvt(val
, buf
, 10, "0123456789");
670 length
= _cvt(val
, buf
, 16, "0123456789abcdef");
673 length
= _cvt(val
, buf
, 16, "0123456789ABCDEF");
679 cp
= va_arg(ap
, char *);
683 c
= va_arg(ap
, long /*char*/);
689 pad
= left_prec
- length
;
743 int _cvt(unsigned long val
, char *buf
, long radix
, char *digits
)
754 *cp
++ = digits
[val
% radix
];
766 _dump_buf_with_offset(unsigned char *p
, int s
, unsigned char *base
)
769 if ((unsigned int)s
> (unsigned int)p
)
771 s
= (unsigned int)s
- (unsigned int)p
;
777 _printk("%06X: ", (int)p
- (int)base
);
780 _printk("%06X: ", p
);
782 for (i
= 0; i
< 16; i
++)
786 _printk("%02X", p
[i
] & 0xFF);
791 if ((i
% 2) == 1) _printk(" ");
792 if ((i
% 8) == 7) _printk(" ");
795 for (i
= 0; i
< 16; i
++)
800 if ((c
< 0x20) || (c
>= 0x7F)) c
= '.';
813 _dump_buf(unsigned char *p
, int s
)
816 _dump_buf_with_offset(p
, s
, 0);