diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 15:20:36 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 15:20:36 -0700 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/ppc/boot/simple/misc.c |
Linux-2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'arch/ppc/boot/simple/misc.c')
-rw-r--r-- | arch/ppc/boot/simple/misc.c | 284 |
1 files changed, 284 insertions, 0 deletions
diff --git a/arch/ppc/boot/simple/misc.c b/arch/ppc/boot/simple/misc.c new file mode 100644 index 00000000000..ab0f9902cb6 --- /dev/null +++ b/arch/ppc/boot/simple/misc.c @@ -0,0 +1,284 @@ +/* + * arch/ppc/simple/misc.c + * + * Misc. bootloader code for many machines. This assumes you have are using + * a 6xx/7xx/74xx CPU in your machine. This assumes the chunk of memory + * below 8MB is free. Finally, it assumes you have a NS16550-style uart for + * your serial console. If a machine meets these requirements, it can quite + * likely use this code during boot. + * + * Author: Matt Porter <mporter@mvista.com> + * Derived from arch/ppc/boot/prep/misc.c + * + * 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 <linux/types.h> +#include <linux/config.h> +#include <linux/string.h> + +#include <asm/page.h> +#include <asm/mmu.h> +#include <asm/bootinfo.h> +#ifdef CONFIG_44x +#include <asm/ibm4xx.h> +#endif +#include <asm/reg.h> + +#include "nonstdio.h" + +/* Default cmdline */ +#ifdef CONFIG_CMDLINE +#define CMDLINE CONFIG_CMDLINE +#else +#define CMDLINE "" +#endif + +/* Keyboard (and VGA console)? */ +#ifdef CONFIG_VGA_CONSOLE +#define HAS_KEYB 1 +#else +#define HAS_KEYB 0 +#endif + +/* Will / Can the user give input? + * Val Henson has requested that Gemini doesn't wait for the + * user to edit the cmdline or not. + */ +#if (defined(CONFIG_SERIAL_8250_CONSOLE) \ + || defined(CONFIG_VGA_CONSOLE) \ + || defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \ + || defined(CONFIG_SERIAL_MPSC_CONSOLE)) \ + && !defined(CONFIG_GEMINI) +#define INTERACTIVE_CONSOLE 1 +#endif + +char *avail_ram; +char *end_avail; +char *zimage_start; +char cmd_preset[] = CMDLINE; +char cmd_buf[256]; +char *cmd_line = cmd_buf; +int keyb_present = HAS_KEYB; +int zimage_size; + +unsigned long com_port; +unsigned long initrd_size = 0; + +/* The linker tells us various locations in the image */ +extern char __image_begin, __image_end; +extern char __ramdisk_begin, __ramdisk_end; +extern char _end[]; +/* Original location */ +extern unsigned long start; + +extern int CRT_tstc(void); +extern unsigned long serial_init(int chan, void *ignored); +extern void serial_close(unsigned long com_port); +extern void gunzip(void *, int, unsigned char *, int *); +extern void serial_fixups(void); + +/* Allow get_mem_size to be hooked into. This is the default. */ +unsigned long __attribute__ ((weak)) +get_mem_size(void) +{ + return 0; +} + +struct bi_record * +decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum) +{ +#ifdef INTERACTIVE_CONSOLE + int timer = 0; + char ch; +#endif + char *cp; + struct bi_record *rec; + unsigned long initrd_loc = 0, TotalMemory = 0; + +#if defined(CONFIG_SERIAL_8250_CONSOLE) || defined(CONFIG_SERIAL_MPSC_CONSOLE) + com_port = serial_init(0, NULL); +#endif + +#if defined(CONFIG_44x) && defined(PPC44x_EMAC0_MR0) + /* Reset MAL */ + mtdcr(DCRN_MALCR(DCRN_MAL_BASE), MALCR_MMSR); + /* Wait for reset */ + while (mfdcr(DCRN_MALCR(DCRN_MAL_BASE)) & MALCR_MMSR) {}; + /* Reset EMAC */ + *(volatile unsigned long *)PPC44x_EMAC0_MR0 = 0x20000000; + __asm__ __volatile__("eieio"); +#endif + + /* + * Call get_mem_size(), which is memory controller dependent, + * and we must have the correct file linked in here. + */ + TotalMemory = get_mem_size(); + + /* assume the chunk below 8M is free */ + end_avail = (char *)0x00800000; + + /* + * Reveal where we were loaded at and where we + * were relocated to. + */ + puts("loaded at: "); puthex(load_addr); + puts(" "); puthex((unsigned long)(load_addr + (4*num_words))); + puts("\n"); + if ( (unsigned long)load_addr != (unsigned long)&start ) + { + puts("relocated to: "); puthex((unsigned long)&start); + puts(" "); + puthex((unsigned long)((unsigned long)&start + (4*num_words))); + puts("\n"); + } + + /* + * We link ourself to 0x00800000. When we run, we relocate + * ourselves there. So we just need __image_begin for the + * start. -- Tom + */ + zimage_start = (char *)(unsigned long)(&__image_begin); + zimage_size = (unsigned long)(&__image_end) - + (unsigned long)(&__image_begin); + + initrd_size = (unsigned long)(&__ramdisk_end) - + (unsigned long)(&__ramdisk_begin); + + /* + * The zImage and initrd will be between start and _end, so they've + * already been moved once. We're good to go now. -- Tom + */ + avail_ram = (char *)PAGE_ALIGN((unsigned long)_end); + puts("zimage at: "); puthex((unsigned long)zimage_start); + puts(" "); puthex((unsigned long)(zimage_size+zimage_start)); + puts("\n"); + + if ( initrd_size ) { + puts("initrd at: "); + puthex((unsigned long)(&__ramdisk_begin)); + puts(" "); puthex((unsigned long)(&__ramdisk_end));puts("\n"); + } + + avail_ram = (char *)0x00400000; + end_avail = (char *)0x00800000; + puts("avail ram: "); puthex((unsigned long)avail_ram); puts(" "); + puthex((unsigned long)end_avail); puts("\n"); + + if (keyb_present) + CRT_tstc(); /* Forces keyboard to be initialized */ +#ifdef CONFIG_GEMINI + /* + * If cmd_line is empty and cmd_preset is not, copy cmd_preset + * to cmd_line. This way we can override cmd_preset with the + * command line from Smon. + */ + + if ( (cmd_line[0] == '\0') && (cmd_preset[0] != '\0')) + memcpy (cmd_line, cmd_preset, sizeof(cmd_preset)); +#endif + + /* Display standard Linux/PPC boot prompt for kernel args */ + puts("\nLinux/PPC load: "); + cp = cmd_line; + memcpy (cmd_line, cmd_preset, sizeof(cmd_preset)); + while ( *cp ) putc(*cp++); + +#ifdef INTERACTIVE_CONSOLE + /* + * If they have a console, allow them to edit the command line. + * Otherwise, don't bother wasting the five seconds. + */ + while (timer++ < 5*1000) { + if (tstc()) { + while ((ch = getc()) != '\n' && ch != '\r') { + /* Test for backspace/delete */ + if (ch == '\b' || ch == '\177') { + if (cp != cmd_line) { + cp--; + puts("\b \b"); + } + /* Test for ^x/^u (and wipe the line) */ + } else if (ch == '\030' || ch == '\025') { + while (cp != cmd_line) { + cp--; + puts("\b \b"); + } + } else { + *cp++ = ch; + putc(ch); + } + } + break; /* Exit 'timer' loop */ + } + udelay(1000); /* 1 msec */ + } + *cp = 0; +#endif + puts("\n"); + + puts("Uncompressing Linux..."); + gunzip(0x0, 0x400000, zimage_start, &zimage_size); + puts("done.\n"); + + /* get the bi_rec address */ + rec = bootinfo_addr(zimage_size); + + /* We need to make sure that the initrd and bi_recs do not + * overlap. */ + if ( initrd_size ) { + unsigned long rec_loc = (unsigned long) rec; + initrd_loc = (unsigned long)(&__ramdisk_begin); + /* If the bi_recs are in the middle of the current + * initrd, move the initrd to the next MB + * boundary. */ + if ((rec_loc > initrd_loc) && + ((initrd_loc + initrd_size) > rec_loc)) { + initrd_loc = _ALIGN((unsigned long)(zimage_size) + + (2 << 20) - 1, (2 << 20)); + memmove((void *)initrd_loc, &__ramdisk_begin, + initrd_size); + puts("initrd moved: "); puthex(initrd_loc); + puts(" "); puthex(initrd_loc + initrd_size); + puts("\n"); + } + } + + bootinfo_init(rec); + if ( TotalMemory ) + bootinfo_append(BI_MEMSIZE, sizeof(int), (void*)&TotalMemory); + + bootinfo_append(BI_CMD_LINE, strlen(cmd_line)+1, (void*)cmd_line); + + /* add a bi_rec for the initrd if it exists */ + if (initrd_size) { + unsigned long initrd[2]; + + initrd[0] = initrd_loc; + initrd[1] = initrd_size; + + bootinfo_append(BI_INITRD, sizeof(initrd), &initrd); + } + puts("Now booting the kernel\n"); + serial_close(com_port); + + return rec; +} + +void __attribute__ ((weak)) +board_isa_init(void) +{ +} + +/* Allow decompress_kernel to be hooked into. This is the default. */ +void * __attribute__ ((weak)) +load_kernel(unsigned long load_addr, int num_words, unsigned long cksum, + void *ign1, void *ign2) +{ + board_isa_init(); + return decompress_kernel(load_addr, num_words, cksum); +} |