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 176
|
/*
* 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;
/* These values must be variables. If not, the compiler optimizer
* will remove some code, causing the size of the code to vary
* when these values are zero. This is bad because we first
* compile with these zero to determine the size and offsets
* in an image, than compile again with these set to the proper
* discovered value.
*/
unsigned int initrd_offset, initrd_size;
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;
initrd_offset = INITRD_OFFSET;
initrd_size = INITRD_SIZE;
if ( initrd_offset )
initrd_start = load_addr - 0x10000 + initrd_offset;
else
initrd_start = 0;
initrd_end = initrd_size + initrd_start;
/* Relocate the zImage */
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");
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");
if ( initrd_start ) {
puts("initrd at: "); puthex(initrd_start);
puts(" "); puthex(initrd_end); puts("\n");
/* relocate initrd */
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");
}
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 ( (u32)(cmd_line) > (16<<20))
puts("cmd_line located > 16M\n");
puts("Uncompressing Linux...");
gunzip(0, 0x400000, zimage_start, &zimage_size);
puts("done.\n");
puts("Now booting the kernel\n");
}
|