1 /* $NetBSD: boot.c,v 1.4 2004/04/10 12:30:26 tsutsui Exp $ */ 2 3 /*- 4 * Copyright (c) 2003 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Jonathan Stone, Michael Hitch, Simon Burge and Wayne Knowles. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 /* 40 * Copyright (c) 1992, 1993 41 * The Regents of the University of California. All rights reserved. 42 * 43 * This code is derived from software contributed to Berkeley by 44 * Ralph Campbell. 45 * 46 * Redistribution and use in source and binary forms, with or without 47 * modification, are permitted provided that the following conditions 48 * are met: 49 * 1. Redistributions of source code must retain the above copyright 50 * notice, this list of conditions and the following disclaimer. 51 * 2. Redistributions in binary form must reproduce the above copyright 52 * notice, this list of conditions and the following disclaimer in the 53 * documentation and/or other materials provided with the distribution. 54 * 3. Neither the name of the University nor the names of its contributors 55 * may be used to endorse or promote products derived from this software 56 * without specific prior written permission. 57 * 58 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 59 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 60 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 61 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 62 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 63 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 64 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 65 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 66 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 67 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 68 * SUCH DAMAGE. 69 * 70 * @(#)boot.c 8.1 (Berkeley) 6/10/93 71 */ 72 73 #include <machine/cpu.h> 74 #include <machine/leds.h> 75 #include <machine/vmparam.h> 76 77 #include <lib/libsa/stand.h> 78 #include <lib/libsa/loadfile.h> 79 #include <lib/libkern/libkern.h> 80 81 #include <sys/param.h> 82 #include <sys/boot_flag.h> 83 #include <sys/exec.h> 84 #include <sys/exec_elf.h> 85 86 #include "boot.h" 87 #include "cons.h" 88 #include "common.h" 89 #include "bootinfo.h" 90 91 char *kernelnames[] = { 92 "netbsd", 93 "netbsd.gz", 94 "onetbsd", 95 "onetbsd.gz", 96 "netbsd.bak", 97 "netbsd.bak.gz", 98 "netbsd.old", 99 "netbsd.old.gz", 100 "netbsd.cobalt", 101 "netbsd.cobalt.gz", 102 "netbsd.elf", 103 "netbsd.elf.gz", 104 NULL 105 }; 106 107 extern u_long end; /* Boot loader code end address */ 108 void start(void); 109 110 static char *bootstring; 111 112 static int patch_bootstring (char *bootspec); 113 static int get_bsdbootname(char **, char **); 114 static int parse_bootname(char *, int, char **, char **); 115 static int prominit (unsigned int memsize); 116 static int print_banner (unsigned int memsize); 117 118 int cpu_reboot(void); 119 120 int main(unsigned int memsize); 121 122 /* 123 * Perform CPU reboot. 124 */ 125 int 126 cpu_reboot() 127 { 128 printf("rebooting...\n\n"); 129 130 *(volatile char *)MIPS_PHYS_TO_KSEG1(LED_ADDR) = LED_RESET; 131 printf("WARNING: reboot failed!\n"); 132 133 for (;;); 134 } 135 136 /* 137 * Substitute root value with NetBSD root partition name. 138 */ 139 int 140 patch_bootstring(bootspec) 141 char *bootspec; 142 { 143 char *sp = bootstring; 144 u_int8_t unit, part; 145 int dev, error; 146 char *file; 147 148 DPRINTF(("patch_bootstring: %s\n", bootspec)); 149 150 /* get boot parameters */ 151 if (devparse(bootspec, &dev, &unit, &part, (const char **)&file) != 0) 152 unit = part = 0; 153 154 DPRINTF(("patch_bootstring: %d, %d\n", unit, part)); 155 156 /* take out the 'root=xxx' parameter */ 157 if ( (sp = strstr(bootstring, "root=")) != NULL) { 158 const char *end; 159 160 end = strchr(sp, ' '); 161 162 /* strip off leading spaces */ 163 for (--sp; (sp > bootstring) && (*sp == ' '); --sp) 164 ; 165 166 if (end != NULL) 167 strcpy(++sp, end); 168 else 169 *++sp = '\0'; 170 } 171 172 DPRINTF(("patch_bootstring: [%s]\n", bootstring)); 173 174 #define DEVNAMESIZE (MAXDEVNAME + sizeof(" root=/dev/hd") + sizeof("0a")) 175 /* bsd notation -> linux notation (wd0a -> hda1) */ 176 if (strlen(bootstring) <= (511 - DEVNAMESIZE)) { 177 int len; 178 179 strcat(bootstring, " root=/dev/hd"); 180 181 len = strlen(bootstring); 182 bootstring[len++] = unit + 'a'; 183 bootstring[len++] = part + '1'; 184 bootstring[len++] = '\0'; 185 } 186 187 DPRINTF(("patch_bootstring: -> %s\n", bootstring)); 188 return (0); 189 } 190 191 /* 192 * Extract NetBSD boot specification 193 */ 194 static int 195 get_bsdbootname(dev, kname) 196 char **dev; 197 char **kname; 198 { 199 int len, error; 200 char *bootstr_dev, *bootstr_kname; 201 char *prompt_dev, *prompt_kname; 202 char *ptr, *spec; 203 char c, namebuf[PATH_MAX]; 204 205 bootstr_dev = prompt_dev = NULL; 206 bootstr_kname = prompt_kname = NULL; 207 208 /* first, get bootname from bootstrings */ 209 if ((spec = strstr(bootstring, "nbsd=")) != NULL) { 210 ptr = strchr(spec, ' '); 211 spec += 5; /* skip 'nbsd=' */ 212 len = (ptr == NULL) ? strlen(spec) : ptr - spec; 213 if (len > 0) { 214 if (parse_bootname(spec, len, 215 &bootstr_dev, &bootstr_kname)) 216 return 1; 217 } 218 } 219 220 DPRINTF(("bootstr_dev = %s, bootstr_kname = %s\n", 221 bootstr_dev ? bootstr_dev : "<NULL>", 222 bootstr_kname ? bootstr_kname : "<NULL>")); 223 224 spec = NULL; 225 len = 0; 226 227 memset(namebuf, 0, sizeof namebuf); 228 printf("Boot [%s:%s]: ", 229 bootstr_dev ? bootstr_dev : DEFBOOTDEV, 230 bootstr_kname ? bootstr_kname : DEFKERNELNAME); 231 232 if (tgets(namebuf) == -1) 233 printf("\n"); 234 235 ptr = namebuf; 236 while ((c = *ptr) != '\0') { 237 while (c == ' ') 238 c = *++ptr; 239 if (c == '\0') 240 break; 241 if (c == '-') { 242 while ((c = *++ptr) && c != ' ') 243 ; 244 #if notyet 245 BOOT_FLAG(c, boothowto); 246 #endif 247 } else { 248 spec = ptr; 249 while ((c = *++ptr) && c != ' ') 250 ; 251 if (c) 252 *ptr++ = '\0'; 253 len = strlen(spec); 254 } 255 } 256 257 if (len > 0) { 258 if (parse_bootname(spec, len, &prompt_dev, &prompt_kname)) 259 return 1; 260 } 261 262 DPRINTF(("prompt_dev = %s, prompt_kname = %s\n", 263 prompt_dev ? prompt_dev : "<NULL>", 264 prompt_kname ? prompt_kname : "<NULL>")); 265 266 if (prompt_dev) 267 *dev = prompt_dev; 268 else 269 *dev = bootstr_dev; 270 271 if (prompt_kname) 272 *kname = prompt_kname; 273 else 274 *kname = bootstr_kname; 275 276 DPRINTF(("dev = %s, kname = %s\n", 277 *dev ? *dev : "<NULL>", 278 *kname ? *kname : "<NULL>")); 279 280 return 0; 281 } 282 283 static int 284 parse_bootname(spec, len, dev, kname) 285 char *spec; 286 int len; 287 char **dev; 288 char **kname; 289 { 290 char *bootname, *ptr; 291 292 bootname = alloc(len + 1); 293 if (bootname == NULL) 294 return 1; 295 memcpy(bootname, spec, len); 296 bootname[len] = '\0'; 297 298 if ((ptr = memchr(bootname, ':', len)) != NULL) { 299 /* "wdXX:kernel" */ 300 *ptr = '\0'; 301 *dev = bootname; 302 if (*++ptr) 303 *kname = ptr; 304 } else 305 /* "kernel" */ 306 *kname = bootname; 307 return 0; 308 } 309 310 /* 311 * Get the bootstring from PROM. 312 */ 313 int 314 prominit(memsize) 315 unsigned int memsize; 316 { 317 bootstring = (char *)(memsize - 512); 318 bootstring[511] = '\0'; 319 } 320 321 /* 322 * Print boot message. 323 */ 324 int 325 print_banner(memsize) 326 unsigned int memsize; 327 { 328 printf("\n"); 329 printf(">> %s " NETBSD_VERS " Bootloader, Revision %s [@%p]\n", 330 bootprog_name, bootprog_rev, (void*)&start); 331 printf(">> (%s, %s)\n", bootprog_maker, bootprog_date); 332 printf(">> Memory:\t\t%u k\n", (memsize - MIPS_KSEG0_START) / 1024); 333 printf(">> PROM boot string:\t%s\n", bootstring); 334 } 335 336 /* 337 * Entry point. 338 * Parse PROM boot string, load the kernel and jump into it 339 */ 340 int 341 main(memsize) 342 unsigned int memsize; 343 { 344 char **namep, *dev, *kernel, *bi_addr; 345 char bootpath[PATH_MAX]; 346 int win; 347 u_long marks[MARK_MAX]; 348 void (*entry) __P((unsigned int, u_int, char*)); 349 350 struct btinfo_flags bi_flags; 351 struct btinfo_symtab bi_syms; 352 struct btinfo_bootpath bi_bpath; 353 354 int addr, speed; 355 356 /* Initialize boot info early */ 357 bi_flags.bi_flags = 0x0; 358 bi_addr = bi_init(); 359 360 prominit(memsize); 361 if (cninit(&addr, &speed) != NULL) 362 bi_flags.bi_flags |= BI_SERIAL_CONSOLE; 363 364 print_banner(memsize); 365 366 memset(marks, 0, sizeof marks); 367 get_bsdbootname(&dev, &kernel); 368 369 if (kernel != NULL) { 370 DPRINTF(("kernel: %s\n", kernel)); 371 kernelnames[0] = kernel; 372 kernelnames[1] = NULL; 373 } else { 374 DPRINTF(("kernel: NULL\n")); 375 } 376 377 win = 0; 378 DPRINTF(("Kernel names: %p\n", kernelnames)); 379 for (namep = kernelnames, win = 0; (*namep != NULL) && !win; namep++) { 380 kernel = *namep; 381 382 bootpath[0] = '\0'; 383 384 strcpy(bootpath, dev ? dev : DEFBOOTDEV); 385 strcat(bootpath, ":"); 386 strcat(bootpath, kernel); 387 388 printf("Loading: %s\n", bootpath); 389 patch_bootstring(bootpath); 390 win = (loadfile(bootpath, marks, LOAD_ALL) != -1); 391 } 392 393 if (win) { 394 strncpy(bi_bpath.bootpath, kernel, BTINFO_BOOTPATH_LEN); 395 bi_add(&bi_bpath, BTINFO_BOOTPATH, sizeof(bi_bpath)); 396 397 entry = (void *) marks[MARK_ENTRY]; 398 bi_syms.nsym = marks[MARK_NSYM]; 399 bi_syms.ssym = marks[MARK_SYM]; 400 bi_syms.esym = marks[MARK_END]; 401 bi_add(&bi_syms, BTINFO_SYMTAB, sizeof(bi_syms)); 402 403 bi_add(&bi_flags, BTINFO_FLAGS, sizeof(bi_flags)); 404 405 entry = (void *) marks[MARK_ENTRY]; 406 407 DPRINTF(("Bootinfo @ 0x%x\n", bi_addr)); 408 printf("Starting at 0x%x\n\n", (u_int)entry); 409 (*entry)(memsize, BOOTINFO_MAGIC, bi_addr); 410 } 411 412 (void)printf("Boot failed! Rebooting...\n"); 413 return (0); 414 } 415