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