1 /* $NetBSD: boot.c,v 1.20 2011/01/22 19:19:16 joerg 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 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * Copyright (c) 1992, 1993 34 * The Regents of the University of California. All rights reserved. 35 * 36 * This code is derived from software contributed to Berkeley by 37 * Ralph Campbell. 38 * 39 * Redistribution and use in source and binary forms, with or without 40 * modification, are permitted provided that the following conditions 41 * are met: 42 * 1. Redistributions of source code must retain the above copyright 43 * notice, this list of conditions and the following disclaimer. 44 * 2. Redistributions in binary form must reproduce the above copyright 45 * notice, this list of conditions and the following disclaimer in the 46 * documentation and/or other materials provided with the distribution. 47 * 3. Neither the name of the University nor the names of its contributors 48 * may be used to endorse or promote products derived from this software 49 * without specific prior written permission. 50 * 51 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 52 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 53 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 54 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 55 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 56 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 57 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 58 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 59 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 60 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 61 * SUCH DAMAGE. 62 * 63 * @(#)boot.c 8.1 (Berkeley) 6/10/93 64 */ 65 66 #include <lib/libsa/stand.h> 67 #include <lib/libsa/loadfile.h> 68 #include <lib/libsa/dev_net.h> 69 #include <lib/libkern/libkern.h> 70 71 #include <sys/param.h> 72 #include <sys/boot_flag.h> 73 #include <sys/exec.h> 74 #include <sys/exec_elf.h> 75 76 #include <machine/cpu.h> 77 78 #include <cobalt/dev/gtreg.h> 79 80 #include "boot.h" 81 #include "cons.h" 82 #include "common.h" 83 #include "bootinfo.h" 84 85 char *kernelnames[] = { 86 "netbsd", 87 "netbsd.gz", 88 "onetbsd", 89 "onetbsd.gz", 90 "netbsd.bak", 91 "netbsd.bak.gz", 92 "netbsd.old", 93 "netbsd.old.gz", 94 "netbsd.cobalt", 95 "netbsd.cobalt.gz", 96 "netbsd.elf", 97 "netbsd.elf.gz", 98 NULL 99 }; 100 101 u_int cobalt_id; 102 static const char * const cobalt_model[] = 103 { 104 [0] = "Unknown Cobalt", 105 [COBALT_ID_QUBE2700] = "Cobalt Qube 2700", 106 [COBALT_ID_RAQ] = "Cobalt RaQ", 107 [COBALT_ID_QUBE2] = "Cobalt Qube 2", 108 [COBALT_ID_RAQ2] = "Cobalt RaQ 2" 109 }; 110 #define COBALT_MODELS __arraycount(cobalt_model) 111 112 extern u_long end; /* Boot loader code end address */ 113 void start(void); 114 115 static char *bootstring; 116 117 static int patch_bootstring(char *bootspec); 118 static int get_bsdbootname(char **, char **, int *); 119 static int parse_bootname(char *, int, char **, char **); 120 static void prominit(unsigned int memsize); 121 static void print_banner(unsigned int memsize); 122 static u_int read_board_id(void); 123 124 void cpu_reboot(void); 125 126 int main(unsigned int memsize); 127 128 /* 129 * Perform CPU reboot. 130 */ 131 void 132 cpu_reboot(void) 133 { 134 135 printf("rebooting...\n\n"); 136 137 *(volatile uint8_t *)MIPS_PHYS_TO_KSEG1(LED_ADDR) = LED_RESET; 138 printf("WARNING: reboot failed!\n"); 139 140 for (;;) 141 ; 142 } 143 144 /* 145 * Substitute root value with NetBSD root partition name. 146 */ 147 int 148 patch_bootstring(char *bootspec) 149 { 150 char *sp = bootstring; 151 uint8_t unit, part; 152 int dev; 153 char *file; 154 155 DPRINTF(("patch_bootstring: %s\n", bootspec)); 156 157 /* get boot parameters */ 158 if (devparse(bootspec, &dev, &unit, &part, (const char **)&file) != 0) 159 unit = part = 0; 160 161 DPRINTF(("patch_bootstring: unit = %d, part = %d\n", unit, part)); 162 163 /* take out the 'root=xxx' parameter */ 164 if ((sp = strstr(bootstring, "root=")) != NULL) { 165 const char *end; 166 167 end = strchr(sp, ' '); 168 169 /* strip off leading spaces */ 170 for (--sp; (sp > bootstring) && (*sp == ' '); --sp) 171 ; 172 173 if (end != NULL) 174 strcpy(++sp, end); 175 else 176 *++sp = '\0'; 177 } 178 179 DPRINTF(("patch_bootstring: [%s]\n", bootstring)); 180 181 #define DEVNAMESIZE (MAXDEVNAME + sizeof(" root=/dev/hd") + sizeof("0a")) 182 if (strcmp(devsw[dev].dv_name, "wd") == 0 && 183 strlen(bootstring) <= (511 - DEVNAMESIZE)) { 184 int len; 185 186 /* omit "nfsroot=" arg on wd boot */ 187 if ((sp = strstr(bootstring, "nfsroot=")) != NULL) { 188 const char *end; 189 190 end = strchr(sp, ' '); 191 192 /* strip off leading spaces */ 193 for (--sp; (sp > bootstring) && (*sp == ' '); --sp) 194 ; 195 196 if (end != NULL) 197 strcpy(++sp, end); 198 else 199 *++sp = '\0'; 200 } 201 202 /* bsd notation -> linux notation (wd0a -> hda1) */ 203 strcat(bootstring, " root=/dev/hd"); 204 205 len = strlen(bootstring); 206 bootstring[len++] = unit + 'a'; 207 bootstring[len++] = part + '1'; 208 bootstring[len++] = '\0'; 209 } 210 211 DPRINTF(("patch_bootstring: -> %s\n", bootstring)); 212 return 0; 213 } 214 215 /* 216 * Extract NetBSD boot specification 217 */ 218 static int 219 get_bsdbootname(char **dev, char **kname, int *howtop) 220 { 221 int len; 222 int bootunit, bootpart; 223 char *bootstr_dev, *bootstr_kname; 224 char *prompt_dev, *prompt_kname; 225 char *ptr, *spec; 226 char c, namebuf[PATH_MAX]; 227 static char bootdev[] = "wd0a"; 228 static char nfsbootdev[] = "nfs"; 229 230 bootstr_dev = prompt_dev = NULL; 231 bootstr_kname = prompt_kname = NULL; 232 233 /* first, get root device specified by the firmware */ 234 spec = bootstring; 235 236 /* assume the last one is valid */ 237 while ((spec = strstr(spec, "root=")) != NULL) { 238 spec += 5; /* skip 'root=' */ 239 ptr = strchr(spec, ' '); 240 len = (ptr == NULL) ? strlen(spec) : ptr - spec; 241 /* decode unit and part from "/dev/hd[ab][1-4]" strings */ 242 if (len == 9 && memcmp("/dev/hd", spec, 7) == 0) { 243 bootunit = spec[7] - 'a'; 244 bootpart = spec[8] - '1'; 245 if (bootunit >= 0 && bootunit < 2 && 246 bootpart >= 0 && bootpart < 4) { 247 bootdev[sizeof(bootdev) - 3] = '0' + bootunit; 248 #if 0 /* bootpart is fdisk partition of Linux root */ 249 bootdev[sizeof(bootdev) - 2] = 'a' + bootpart; 250 #endif 251 bootstr_dev = bootdev; 252 } 253 } 254 spec += len; 255 } 256 257 /* second, get bootname from bootstrings */ 258 if ((spec = strstr(bootstring, "nbsd=")) != NULL) { 259 ptr = strchr(spec, ' '); 260 spec += 5; /* skip 'nbsd=' */ 261 len = (ptr == NULL) ? strlen(spec) : ptr - spec; 262 if (len > 0) { 263 if (parse_bootname(spec, len, 264 &bootstr_dev, &bootstr_kname)) 265 return 1; 266 } 267 } 268 269 /* third, check if netboot */ 270 if (strstr(bootstring, "nfsroot=") != NULL) { 271 bootstr_dev = nfsbootdev; 272 } 273 274 DPRINTF(("bootstr_dev = %s, bootstr_kname = %s\n", 275 bootstr_dev ? bootstr_dev : "<NULL>", 276 bootstr_kname ? bootstr_kname : "<NULL>")); 277 278 spec = NULL; 279 len = 0; 280 281 memset(namebuf, 0, sizeof namebuf); 282 printf("Boot [%s:%s]: ", 283 bootstr_dev ? bootstr_dev : DEFBOOTDEV, 284 bootstr_kname ? bootstr_kname : DEFKERNELNAME); 285 286 if (tgets(namebuf) == -1) 287 printf("\n"); 288 289 ptr = namebuf; 290 while ((c = *ptr) != '\0') { 291 while (c == ' ') 292 c = *++ptr; 293 if (c == '\0') 294 break; 295 if (c == '-') { 296 while ((c = *++ptr) && c != ' ') 297 BOOT_FLAG(c, *howtop); 298 } else { 299 spec = ptr; 300 while ((c = *++ptr) && c != ' ') 301 ; 302 if (c) 303 *ptr++ = '\0'; 304 len = strlen(spec); 305 } 306 } 307 308 if (len > 0) { 309 if (parse_bootname(spec, len, &prompt_dev, &prompt_kname)) 310 return 1; 311 } 312 313 DPRINTF(("prompt_dev = %s, prompt_kname = %s\n", 314 prompt_dev ? prompt_dev : "<NULL>", 315 prompt_kname ? prompt_kname : "<NULL>")); 316 317 if (prompt_dev) 318 *dev = prompt_dev; 319 else 320 *dev = bootstr_dev; 321 322 if (prompt_kname) 323 *kname = prompt_kname; 324 else 325 *kname = bootstr_kname; 326 327 DPRINTF(("dev = %s, kname = %s\n", 328 *dev ? *dev : "<NULL>", 329 *kname ? *kname : "<NULL>")); 330 331 return 0; 332 } 333 334 static int 335 parse_bootname(char *spec, int len, char **dev, char **kname) 336 { 337 char *bootname, *ptr; 338 339 bootname = alloc(len + 1); 340 if (bootname == NULL) 341 return 1; 342 memcpy(bootname, spec, len); 343 bootname[len] = '\0'; 344 345 if ((ptr = memchr(bootname, ':', len)) != NULL) { 346 /* "wdXX:kernel" */ 347 *ptr = '\0'; 348 *dev = bootname; 349 if (*++ptr) 350 *kname = ptr; 351 } else 352 /* "kernel" */ 353 *kname = bootname; 354 return 0; 355 } 356 357 /* 358 * Get the bootstring from PROM. 359 */ 360 void 361 prominit(unsigned int memsize) 362 { 363 364 bootstring = (char *)(memsize - 512); 365 bootstring[511] = '\0'; 366 } 367 368 /* 369 * Print boot message. 370 */ 371 void 372 print_banner(unsigned int memsize) 373 { 374 375 lcd_banner(); 376 377 printf("\n"); 378 printf(">> %s " NETBSD_VERS " Bootloader, Revision %s [@%p]\n", 379 bootprog_name, bootprog_rev, (void*)&start); 380 printf(">> Model:\t\t%s\n", cobalt_model[cobalt_id]); 381 printf(">> Memory:\t\t%lu k\n", (memsize - MIPS_KSEG0_START) / 1024); 382 printf(">> PROM boot string:\t%s\n", bootstring); 383 } 384 385 u_int 386 read_board_id(void) 387 { 388 uint32_t tag, reg; 389 390 #define PCIB_PCI_BUS 0 391 #define PCIB_PCI_DEV 9 392 #define PCIB_PCI_FUNC 0 393 #define PCIB_BOARD_ID_REG 0x94 394 #define COBALT_BOARD_ID(reg) ((reg & 0x000000f0) >> 4) 395 396 tag = (PCIB_PCI_BUS << 16) | (PCIB_PCI_DEV << 11) | 397 (PCIB_PCI_FUNC << 8); 398 reg = pcicfgread(tag, PCIB_BOARD_ID_REG); 399 400 return COBALT_BOARD_ID(reg); 401 } 402 403 /* 404 * Entry point. 405 * Parse PROM boot string, load the kernel and jump into it 406 */ 407 int 408 main(unsigned int memsize) 409 { 410 char **namep, *dev, *kernel, *bi_addr; 411 char bootpath[PATH_MAX]; 412 int win; 413 u_long marks[MARK_MAX]; 414 void (*entry)(unsigned int, u_int, char *); 415 416 struct btinfo_flags bi_flags; 417 struct btinfo_symtab bi_syms; 418 struct btinfo_bootpath bi_bpath; 419 struct btinfo_howto bi_howto; 420 int addr, speed, howto; 421 422 try_bootp = 1; 423 424 /* Initialize boot info early */ 425 dev = NULL; 426 kernel = NULL; 427 howto = 0x0; 428 bi_flags.bi_flags = 0x0; 429 bi_addr = bi_init(); 430 431 lcd_init(); 432 cobalt_id = read_board_id(); 433 prominit(memsize); 434 if (cninit(&addr, &speed) != NULL) 435 bi_flags.bi_flags |= BI_SERIAL_CONSOLE; 436 437 print_banner(memsize); 438 439 memset(marks, 0, sizeof marks); 440 get_bsdbootname(&dev, &kernel, &howto); 441 442 if (kernel != NULL) { 443 DPRINTF(("kernel: %s\n", kernel)); 444 kernelnames[0] = kernel; 445 kernelnames[1] = NULL; 446 } else { 447 DPRINTF(("kernel: NULL\n")); 448 } 449 450 win = 0; 451 DPRINTF(("Kernel names: %p\n", kernelnames)); 452 for (namep = kernelnames, win = 0; (*namep != NULL) && !win; namep++) { 453 kernel = *namep; 454 455 bootpath[0] = '\0'; 456 457 strcpy(bootpath, dev ? dev : DEFBOOTDEV); 458 strcat(bootpath, ":"); 459 strcat(bootpath, kernel); 460 461 lcd_loadfile(bootpath); 462 printf("Loading: %s", bootpath); 463 if (howto) 464 printf(" (howto 0x%x)", howto); 465 printf("\n"); 466 patch_bootstring(bootpath); 467 win = (loadfile(bootpath, marks, LOAD_ALL) != -1); 468 } 469 470 if (win) { 471 strncpy(bi_bpath.bootpath, kernel, BTINFO_BOOTPATH_LEN); 472 bi_add(&bi_bpath, BTINFO_BOOTPATH, sizeof(bi_bpath)); 473 474 entry = (void *)marks[MARK_ENTRY]; 475 bi_syms.nsym = marks[MARK_NSYM]; 476 bi_syms.ssym = marks[MARK_SYM]; 477 bi_syms.esym = marks[MARK_END]; 478 bi_add(&bi_syms, BTINFO_SYMTAB, sizeof(bi_syms)); 479 480 bi_add(&bi_flags, BTINFO_FLAGS, sizeof(bi_flags)); 481 482 bi_howto.bi_howto = howto; 483 bi_add(&bi_howto, BTINFO_HOWTO, sizeof(bi_howto)); 484 485 entry = (void *)marks[MARK_ENTRY]; 486 487 DPRINTF(("Bootinfo @ 0x%lx\n", (u_long)bi_addr)); 488 printf("Starting at 0x%lx\n\n", (u_long)entry); 489 (*entry)(memsize, BOOTINFO_MAGIC, bi_addr); 490 } 491 492 delay(20000); 493 lcd_failed(); 494 (void)printf("Boot failed! Rebooting...\n"); 495 return 0; 496 } 497