1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
|
/*
* arch/ppc/common/misc-simple.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
*
* Copyright 2001 MontaVista Software Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <linux/types.h>
#include <linux/elf.h>
#include <linux/config.h>
#include <asm/page.h>
#include <asm/processor.h>
#include <asm/mmu.h>
#include "nonstdio.h"
#include "zlib.h"
unsigned long com_port;
char *avail_ram;
char *end_avail;
extern char _end[];
#ifdef CONFIG_CMDLINE
#define CMDLINE CONFIG_CMDLINE
#else
#define CMDLINE ""
#endif
char cmd_preset[] = CMDLINE;
char cmd_buf[256];
char *cmd_line = cmd_buf;
unsigned long initrd_start = 0, initrd_end = 0;
char *zimage_start;
int zimage_size;
extern void gunzip(void *, int, unsigned char *, int *);
extern unsigned long serial_init(int chan);
void
decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum)
{
int timer = 0;
extern unsigned long start;
char *cp, ch;
com_port = serial_init(0);
/* 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 have to subtract 0x10000 here to correct for objdump including
the size of the elf header which we strip -- Cort */
zimage_start = (char *)(load_addr - 0x10000 + ZIMAGE_OFFSET);
zimage_size = ZIMAGE_SIZE;
if ( INITRD_OFFSET )
initrd_start = load_addr - 0x10000 + INITRD_OFFSET;
else
initrd_start = 0;
initrd_end = INITRD_SIZE + initrd_start;
/*
* Find a place to stick the zimage and initrd and
* relocate them if we have to. -- Cort
*/
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 ( (unsigned long)zimage_start <= 0x00800000 )
{
memcpy( (void *)avail_ram, (void *)zimage_start, zimage_size );
zimage_start = (char *)avail_ram;
puts("relocated to: "); puthex((unsigned long)zimage_start);
puts(" ");
puthex((unsigned long)zimage_size+(unsigned long)zimage_start);
puts("\n");
/* relocate initrd */
if ( initrd_start )
{
puts("initrd at: "); puthex(initrd_start);
puts(" "); puthex(initrd_end); puts("\n");
avail_ram = (char *)PAGE_ALIGN(
(unsigned long)zimage_size+(unsigned long)zimage_start);
memcpy ((void *)avail_ram, (void *)initrd_start, INITRD_SIZE );
initrd_start = (unsigned long)avail_ram;
initrd_end = initrd_start + INITRD_SIZE;
puts("relocated to: "); puthex(initrd_start);
puts(" "); puthex(initrd_end); puts("\n");
}
} else if ( initrd_start ) {
puts("initrd at: "); puthex(initrd_start);
puts(" "); puthex(initrd_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");
/* 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++);
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;
puts("\n");
/* mappings on early boot can only handle 16M */
if ( (int)(cmd_line[0]) > (16<<20))
puts("cmd_line located > 16M\n");
if ( initrd_start > (16<<20))
puts("initrd_start located > 16M\n");
puts("Uncompressing Linux...");
gunzip(0, 0x400000, zimage_start, &zimage_size);
puts("done.\n");
puts("Now booting the kernel\n");
}
|