1 /* $NetBSD: boot.c,v 1.10 2007/10/30 15:07:07 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 76 #include <lib/libsa/stand.h> 77 #include <lib/libsa/loadfile.h> 78 #include <lib/libsa/dev_net.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 **, int *); 114 static int parse_bootname(char *, int, char **, char **); 115 static void prominit(unsigned int memsize); 116 static void print_banner(unsigned int memsize); 117 118 void cpu_reboot(void); 119 120 int main(unsigned int memsize); 121 122 /* 123 * Perform CPU reboot. 124 */ 125 void 126 cpu_reboot(void) 127 { 128 129 printf("rebooting...\n\n"); 130 131 *(volatile uint8_t *)MIPS_PHYS_TO_KSEG1(LED_ADDR) = LED_RESET; 132 printf("WARNING: reboot failed!\n"); 133 134 for (;;) 135 ; 136 } 137 138 /* 139 * Substitute root value with NetBSD root partition name. 140 */ 141 int 142 patch_bootstring(char *bootspec) 143 { 144 char *sp = bootstring; 145 uint8_t unit, part; 146 int dev; 147 char *file; 148 149 DPRINTF(("patch_bootstring: %s\n", bootspec)); 150 151 /* get boot parameters */ 152 if (devparse(bootspec, &dev, &unit, &part, (const char **)&file) != 0) 153 unit = part = 0; 154 155 DPRINTF(("patch_bootstring: unit = %d, part = %d\n", unit, part)); 156 157 /* take out the 'root=xxx' parameter */ 158 if ((sp = strstr(bootstring, "root=")) != NULL) { 159 const char *end; 160 161 end = strchr(sp, ' '); 162 163 /* strip off leading spaces */ 164 for (--sp; (sp > bootstring) && (*sp == ' '); --sp) 165 ; 166 167 if (end != NULL) 168 strcpy(++sp, end); 169 else 170 *++sp = '\0'; 171 } 172 173 DPRINTF(("patch_bootstring: [%s]\n", bootstring)); 174 175 #define DEVNAMESIZE (MAXDEVNAME + sizeof(" root=/dev/hd") + sizeof("0a")) 176 if (strcmp(devsw[dev].dv_name, "wd") == 0 && 177 strlen(bootstring) <= (511 - DEVNAMESIZE)) { 178 int len; 179 180 /* omit "nfsroot=" arg on wd boot */ 181 if ((sp = strstr(bootstring, "nfsroot=")) != NULL) { 182 const char *end; 183 184 end = strchr(sp, ' '); 185 186 /* strip off leading spaces */ 187 for (--sp; (sp > bootstring) && (*sp == ' '); --sp) 188 ; 189 190 if (end != NULL) 191 strcpy(++sp, end); 192 else 193 *++sp = '\0'; 194 } 195 196 /* bsd notation -> linux notation (wd0a -> hda1) */ 197 strcat(bootstring, " root=/dev/hd"); 198 199 len = strlen(bootstring); 200 bootstring[len++] = unit + 'a'; 201 bootstring[len++] = part + '1'; 202 bootstring[len++] = '\0'; 203 } 204 205 DPRINTF(("patch_bootstring: -> %s\n", bootstring)); 206 return 0; 207 } 208 209 /* 210 * Extract NetBSD boot specification 211 */ 212 static int 213 get_bsdbootname(char **dev, char **kname, int *howtop) 214 { 215 int len; 216 int bootunit, bootpart; 217 char *bootstr_dev, *bootstr_kname; 218 char *prompt_dev, *prompt_kname; 219 char *ptr, *spec; 220 char c, namebuf[PATH_MAX]; 221 static char bootdev[] = "wd0a"; 222 static char nfsbootdev[] = "nfs"; 223 224 bootstr_dev = prompt_dev = NULL; 225 bootstr_kname = prompt_kname = NULL; 226 227 /* first, get root device specified by the firmware */ 228 spec = bootstring; 229 230 /* assume the last one is valid */ 231 while ((spec = strstr(spec, "root=")) != NULL) { 232 spec += 5; /* skip 'root=' */ 233 ptr = strchr(spec, ' '); 234 len = (ptr == NULL) ? strlen(spec) : ptr - spec; 235 /* decode unit and part from "/dev/hd[ab][1-4]" strings */ 236 if (len == 9 && memcmp("/dev/hd", spec, 7) == 0) { 237 bootunit = spec[7] - 'a'; 238 bootpart = spec[8] - '1'; 239 if (bootunit >= 0 && bootunit < 2 && 240 bootpart >= 0 && bootpart < 4) { 241 bootdev[sizeof(bootdev) - 3] = '0' + bootunit; 242 #if 0 /* bootpart is fdisk partition of Linux root */ 243 bootdev[sizeof(bootdev) - 2] = 'a' + bootpart; 244 #endif 245 bootstr_dev = bootdev; 246 } 247 } 248 spec += len; 249 } 250 251 /* second, get bootname from bootstrings */ 252 if ((spec = strstr(bootstring, "nbsd=")) != NULL) { 253 ptr = strchr(spec, ' '); 254 spec += 5; /* skip 'nbsd=' */ 255 len = (ptr == NULL) ? strlen(spec) : ptr - spec; 256 if (len > 0) { 257 if (parse_bootname(spec, len, 258 &bootstr_dev, &bootstr_kname)) 259 return 1; 260 } 261 } 262 263 /* third, check if netboot */ 264 if (strstr(bootstring, "nfsroot=") != NULL) { 265 bootstr_dev = nfsbootdev; 266 } 267 268 DPRINTF(("bootstr_dev = %s, bootstr_kname = %s\n", 269 bootstr_dev ? bootstr_dev : "<NULL>", 270 bootstr_kname ? bootstr_kname : "<NULL>")); 271 272 spec = NULL; 273 len = 0; 274 275 memset(namebuf, 0, sizeof namebuf); 276 printf("Boot [%s:%s]: ", 277 bootstr_dev ? bootstr_dev : DEFBOOTDEV, 278 bootstr_kname ? bootstr_kname : DEFKERNELNAME); 279 280 if (tgets(namebuf) == -1) 281 printf("\n"); 282 283 ptr = namebuf; 284 while ((c = *ptr) != '\0') { 285 while (c == ' ') 286 c = *++ptr; 287 if (c == '\0') 288 break; 289 if (c == '-') { 290 while ((c = *++ptr) && c != ' ') 291 BOOT_FLAG(c, *howtop); 292 } else { 293 spec = ptr; 294 while ((c = *++ptr) && c != ' ') 295 ; 296 if (c) 297 *ptr++ = '\0'; 298 len = strlen(spec); 299 } 300 } 301 302 if (len > 0) { 303 if (parse_bootname(spec, len, &prompt_dev, &prompt_kname)) 304 return 1; 305 } 306 307 DPRINTF(("prompt_dev = %s, prompt_kname = %s\n", 308 prompt_dev ? prompt_dev : "<NULL>", 309 prompt_kname ? prompt_kname : "<NULL>")); 310 311 if (prompt_dev) 312 *dev = prompt_dev; 313 else 314 *dev = bootstr_dev; 315 316 if (prompt_kname) 317 *kname = prompt_kname; 318 else 319 *kname = bootstr_kname; 320 321 DPRINTF(("dev = %s, kname = %s\n", 322 *dev ? *dev : "<NULL>", 323 *kname ? *kname : "<NULL>")); 324 325 return 0; 326 } 327 328 static int 329 parse_bootname(char *spec, int len, char **dev, char **kname) 330 { 331 char *bootname, *ptr; 332 333 bootname = alloc(len + 1); 334 if (bootname == NULL) 335 return 1; 336 memcpy(bootname, spec, len); 337 bootname[len] = '\0'; 338 339 if ((ptr = memchr(bootname, ':', len)) != NULL) { 340 /* "wdXX:kernel" */ 341 *ptr = '\0'; 342 *dev = bootname; 343 if (*++ptr) 344 *kname = ptr; 345 } else 346 /* "kernel" */ 347 *kname = bootname; 348 return 0; 349 } 350 351 /* 352 * Get the bootstring from PROM. 353 */ 354 void 355 prominit(unsigned int memsize) 356 { 357 358 bootstring = (char *)(memsize - 512); 359 bootstring[511] = '\0'; 360 } 361 362 /* 363 * Print boot message. 364 */ 365 void 366 print_banner(unsigned int memsize) 367 { 368 369 printf("\n"); 370 printf(">> %s " NETBSD_VERS " Bootloader, Revision %s [@%p]\n", 371 bootprog_name, bootprog_rev, (void*)&start); 372 printf(">> (%s, %s)\n", bootprog_maker, bootprog_date); 373 printf(">> Memory:\t\t%u k\n", (memsize - MIPS_KSEG0_START) / 1024); 374 printf(">> PROM boot string:\t%s\n", bootstring); 375 } 376 377 /* 378 * Entry point. 379 * Parse PROM boot string, load the kernel and jump into it 380 */ 381 int 382 main(unsigned int memsize) 383 { 384 char **namep, *dev, *kernel, *bi_addr; 385 char bootpath[PATH_MAX]; 386 int win; 387 u_long marks[MARK_MAX]; 388 void (*entry)(unsigned int, u_int, char *); 389 390 struct btinfo_flags bi_flags; 391 struct btinfo_symtab bi_syms; 392 struct btinfo_bootpath bi_bpath; 393 struct btinfo_howto bi_howto; 394 int addr, speed, howto; 395 396 try_bootp = 1; 397 398 /* Initialize boot info early */ 399 howto = 0x0; 400 bi_flags.bi_flags = 0x0; 401 bi_addr = bi_init(); 402 403 prominit(memsize); 404 if (cninit(&addr, &speed) != NULL) 405 bi_flags.bi_flags |= BI_SERIAL_CONSOLE; 406 407 print_banner(memsize); 408 409 memset(marks, 0, sizeof marks); 410 get_bsdbootname(&dev, &kernel, &howto); 411 412 if (kernel != NULL) { 413 DPRINTF(("kernel: %s\n", kernel)); 414 kernelnames[0] = kernel; 415 kernelnames[1] = NULL; 416 } else { 417 DPRINTF(("kernel: NULL\n")); 418 } 419 420 win = 0; 421 DPRINTF(("Kernel names: %p\n", kernelnames)); 422 for (namep = kernelnames, win = 0; (*namep != NULL) && !win; namep++) { 423 kernel = *namep; 424 425 bootpath[0] = '\0'; 426 427 strcpy(bootpath, dev ? dev : DEFBOOTDEV); 428 strcat(bootpath, ":"); 429 strcat(bootpath, kernel); 430 431 printf("Loading: %s", bootpath); 432 if (howto) 433 printf(" (howto 0x%x)", howto); 434 printf("\n"); 435 patch_bootstring(bootpath); 436 win = (loadfile(bootpath, marks, LOAD_ALL) != -1); 437 } 438 439 if (win) { 440 strncpy(bi_bpath.bootpath, kernel, BTINFO_BOOTPATH_LEN); 441 bi_add(&bi_bpath, BTINFO_BOOTPATH, sizeof(bi_bpath)); 442 443 entry = (void *)marks[MARK_ENTRY]; 444 bi_syms.nsym = marks[MARK_NSYM]; 445 bi_syms.ssym = marks[MARK_SYM]; 446 bi_syms.esym = marks[MARK_END]; 447 bi_add(&bi_syms, BTINFO_SYMTAB, sizeof(bi_syms)); 448 449 bi_add(&bi_flags, BTINFO_FLAGS, sizeof(bi_flags)); 450 451 bi_howto.bi_howto = howto; 452 bi_add(&bi_howto, BTINFO_HOWTO, sizeof(bi_howto)); 453 454 entry = (void *)marks[MARK_ENTRY]; 455 456 DPRINTF(("Bootinfo @ 0x%x\n", bi_addr)); 457 printf("Starting at 0x%x\n\n", (u_int)entry); 458 (*entry)(memsize, BOOTINFO_MAGIC, bi_addr); 459 } 460 461 (void)printf("Boot failed! Rebooting...\n"); 462 return 0; 463 } 464