at v2.6.21 7.4 kB view raw
1/* 2 * Misc. bootloader code for many machines. This assumes you have are using 3 * a 6xx/7xx/74xx CPU in your machine. This assumes the chunk of memory 4 * below 8MB is free. Finally, it assumes you have a NS16550-style uart for 5 * your serial console. If a machine meets these requirements, it can quite 6 * likely use this code during boot. 7 * 8 * Author: Matt Porter <mporter@mvista.com> 9 * Derived from arch/ppc/boot/prep/misc.c 10 * 11 * 2001 (c) MontaVista, Software, Inc. This file is licensed under 12 * the terms of the GNU General Public License version 2. This program 13 * is licensed "as is" without any warranty of any kind, whether express 14 * or implied. 15 */ 16 17#include <linux/types.h> 18#include <linux/string.h> 19 20#include <asm/page.h> 21#include <asm/mmu.h> 22#include <asm/bootinfo.h> 23#ifdef CONFIG_4xx 24#include <asm/ibm4xx.h> 25#endif 26#include <asm/reg.h> 27 28#include "nonstdio.h" 29 30/* Default cmdline */ 31#ifdef CONFIG_CMDLINE 32#define CMDLINE CONFIG_CMDLINE 33#else 34#define CMDLINE "" 35#endif 36 37/* Keyboard (and VGA console)? */ 38#ifdef CONFIG_VGA_CONSOLE 39#define HAS_KEYB 1 40#else 41#define HAS_KEYB 0 42#endif 43 44/* Will / Can the user give input? 45 */ 46#if (defined(CONFIG_SERIAL_8250_CONSOLE) \ 47 || defined(CONFIG_VGA_CONSOLE) \ 48 || defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \ 49 || defined(CONFIG_SERIAL_MPSC_CONSOLE)) 50#define INTERACTIVE_CONSOLE 1 51#endif 52 53char *avail_ram; 54char *end_avail; 55char *zimage_start; 56char cmd_preset[] = CMDLINE; 57char cmd_buf[256]; 58char *cmd_line = cmd_buf; 59int keyb_present = HAS_KEYB; 60int zimage_size; 61 62unsigned long com_port; 63unsigned long initrd_size = 0; 64 65/* The linker tells us various locations in the image */ 66extern char __image_begin, __image_end; 67extern char __ramdisk_begin, __ramdisk_end; 68extern char _end[]; 69/* Original location */ 70extern unsigned long start; 71 72extern int CRT_tstc(void); 73extern unsigned long serial_init(int chan, void *ignored); 74extern void serial_close(unsigned long com_port); 75extern void gunzip(void *, int, unsigned char *, int *); 76extern void serial_fixups(void); 77 78/* Allow get_mem_size to be hooked into. This is the default. */ 79unsigned long __attribute__ ((weak)) 80get_mem_size(void) 81{ 82 return 0; 83} 84 85#if defined(CONFIG_40x) 86#define PPC4xx_EMAC0_MR0 EMAC0_BASE 87#endif 88 89#if defined(CONFIG_44x) && defined(PPC44x_EMAC0_MR0) 90#define PPC4xx_EMAC0_MR0 PPC44x_EMAC0_MR0 91#endif 92 93struct bi_record * 94decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum) 95{ 96#ifdef INTERACTIVE_CONSOLE 97 int timer = 0; 98 char ch; 99#endif 100 char *cp; 101 struct bi_record *rec; 102 unsigned long initrd_loc = 0, TotalMemory = 0; 103 104#if defined(CONFIG_SERIAL_8250_CONSOLE) || defined(CONFIG_SERIAL_MPSC_CONSOLE) 105 com_port = serial_init(0, NULL); 106#endif 107 108#if defined(PPC4xx_EMAC0_MR0) 109 /* Reset MAL */ 110 mtdcr(DCRN_MALCR(DCRN_MAL_BASE), MALCR_MMSR); 111 /* Wait for reset */ 112 while (mfdcr(DCRN_MALCR(DCRN_MAL_BASE)) & MALCR_MMSR) {}; 113 /* Reset EMAC */ 114 *(volatile unsigned long *)PPC4xx_EMAC0_MR0 = 0x20000000; 115 __asm__ __volatile__("eieio"); 116#endif 117 118 /* 119 * Call get_mem_size(), which is memory controller dependent, 120 * and we must have the correct file linked in here. 121 */ 122 TotalMemory = get_mem_size(); 123 124 /* assume the chunk below 8M is free */ 125 end_avail = (char *)0x00800000; 126 127 /* 128 * Reveal where we were loaded at and where we 129 * were relocated to. 130 */ 131 puts("loaded at: "); puthex(load_addr); 132 puts(" "); puthex((unsigned long)(load_addr + (4*num_words))); 133 puts("\n"); 134 if ( (unsigned long)load_addr != (unsigned long)&start ) 135 { 136 puts("relocated to: "); puthex((unsigned long)&start); 137 puts(" "); 138 puthex((unsigned long)((unsigned long)&start + (4*num_words))); 139 puts("\n"); 140 } 141 142 /* 143 * We link ourself to 0x00800000. When we run, we relocate 144 * ourselves there. So we just need __image_begin for the 145 * start. -- Tom 146 */ 147 zimage_start = (char *)(unsigned long)(&__image_begin); 148 zimage_size = (unsigned long)(&__image_end) - 149 (unsigned long)(&__image_begin); 150 151 initrd_size = (unsigned long)(&__ramdisk_end) - 152 (unsigned long)(&__ramdisk_begin); 153 154 /* 155 * The zImage and initrd will be between start and _end, so they've 156 * already been moved once. We're good to go now. -- Tom 157 */ 158 avail_ram = (char *)PAGE_ALIGN((unsigned long)_end); 159 puts("zimage at: "); puthex((unsigned long)zimage_start); 160 puts(" "); puthex((unsigned long)(zimage_size+zimage_start)); 161 puts("\n"); 162 163 if ( initrd_size ) { 164 puts("initrd at: "); 165 puthex((unsigned long)(&__ramdisk_begin)); 166 puts(" "); puthex((unsigned long)(&__ramdisk_end));puts("\n"); 167 } 168 169#ifndef CONFIG_40x /* don't overwrite the 40x image located at 0x00400000! */ 170 avail_ram = (char *)0x00400000; 171#endif 172 end_avail = (char *)0x00800000; 173 puts("avail ram: "); puthex((unsigned long)avail_ram); puts(" "); 174 puthex((unsigned long)end_avail); puts("\n"); 175 176 if (keyb_present) 177 CRT_tstc(); /* Forces keyboard to be initialized */ 178 179 /* Display standard Linux/PPC boot prompt for kernel args */ 180 puts("\nLinux/PPC load: "); 181 cp = cmd_line; 182 memcpy (cmd_line, cmd_preset, sizeof(cmd_preset)); 183 while ( *cp ) putc(*cp++); 184 185#ifdef INTERACTIVE_CONSOLE 186 /* 187 * If they have a console, allow them to edit the command line. 188 * Otherwise, don't bother wasting the five seconds. 189 */ 190 while (timer++ < 5*1000) { 191 if (tstc()) { 192 while ((ch = getc()) != '\n' && ch != '\r') { 193 /* Test for backspace/delete */ 194 if (ch == '\b' || ch == '\177') { 195 if (cp != cmd_line) { 196 cp--; 197 puts("\b \b"); 198 } 199 /* Test for ^x/^u (and wipe the line) */ 200 } else if (ch == '\030' || ch == '\025') { 201 while (cp != cmd_line) { 202 cp--; 203 puts("\b \b"); 204 } 205 } else { 206 *cp++ = ch; 207 putc(ch); 208 } 209 } 210 break; /* Exit 'timer' loop */ 211 } 212 udelay(1000); /* 1 msec */ 213 } 214 *cp = 0; 215#endif 216 puts("\n"); 217 218 puts("Uncompressing Linux..."); 219 gunzip(NULL, 0x400000, zimage_start, &zimage_size); 220 puts("done.\n"); 221 222 /* get the bi_rec address */ 223 rec = bootinfo_addr(zimage_size); 224 225 /* We need to make sure that the initrd and bi_recs do not 226 * overlap. */ 227 if ( initrd_size ) { 228 unsigned long rec_loc = (unsigned long) rec; 229 initrd_loc = (unsigned long)(&__ramdisk_begin); 230 /* If the bi_recs are in the middle of the current 231 * initrd, move the initrd to the next MB 232 * boundary. */ 233 if ((rec_loc > initrd_loc) && 234 ((initrd_loc + initrd_size) > rec_loc)) { 235 initrd_loc = _ALIGN((unsigned long)(zimage_size) 236 + (2 << 20) - 1, (2 << 20)); 237 memmove((void *)initrd_loc, &__ramdisk_begin, 238 initrd_size); 239 puts("initrd moved: "); puthex(initrd_loc); 240 puts(" "); puthex(initrd_loc + initrd_size); 241 puts("\n"); 242 } 243 } 244 245 bootinfo_init(rec); 246 if ( TotalMemory ) 247 bootinfo_append(BI_MEMSIZE, sizeof(int), (void*)&TotalMemory); 248 249 bootinfo_append(BI_CMD_LINE, strlen(cmd_line)+1, (void*)cmd_line); 250 251 /* add a bi_rec for the initrd if it exists */ 252 if (initrd_size) { 253 unsigned long initrd[2]; 254 255 initrd[0] = initrd_loc; 256 initrd[1] = initrd_size; 257 258 bootinfo_append(BI_INITRD, sizeof(initrd), &initrd); 259 } 260 puts("Now booting the kernel\n"); 261 serial_close(com_port); 262 263 return rec; 264} 265 266void __attribute__ ((weak)) 267board_isa_init(void) 268{ 269} 270 271/* Allow decompress_kernel to be hooked into. This is the default. */ 272void * __attribute__ ((weak)) 273load_kernel(unsigned long load_addr, int num_words, unsigned long cksum, 274 void *ign1, void *ign2) 275{ 276 board_isa_init(); 277 return decompress_kernel(load_addr, num_words, cksum); 278}