1 /* $NetBSD: boot.c,v 1.5 2005/11/25 13:37:58 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/libkern/libkern.h> 79 80 #include <sys/param.h> 81 #include <sys/boot_flag.h> 82 #include <sys/exec.h> 83 #include <sys/exec_elf.h> 84 85 #include "boot.h" 86 #include "cons.h" 87 #include "common.h" 88 #include "bootinfo.h" 89 90 char *kernelnames[] = { 91 "netbsd", 92 "netbsd.gz", 93 "onetbsd", 94 "onetbsd.gz", 95 "netbsd.bak", 96 "netbsd.bak.gz", 97 "netbsd.old", 98 "netbsd.old.gz", 99 "netbsd.cobalt", 100 "netbsd.cobalt.gz", 101 "netbsd.elf", 102 "netbsd.elf.gz", 103 NULL 104 }; 105 106 extern u_long end; /* Boot loader code end address */ 107 void start(void); 108 109 static char *bootstring; 110 111 static int patch_bootstring (char *bootspec); 112 static int get_bsdbootname(char **, char **); 113 static int parse_bootname(char *, int, char **, char **); 114 static int prominit (unsigned int memsize); 115 static int print_banner (unsigned int memsize); 116 117 int cpu_reboot(void); 118 119 int main(unsigned int memsize); 120 121 /* 122 * Perform CPU reboot. 123 */ 124 int 125 cpu_reboot() 126 { 127 printf("rebooting...\n\n"); 128 129 *(volatile char *)MIPS_PHYS_TO_KSEG1(LED_ADDR) = LED_RESET; 130 printf("WARNING: reboot failed!\n"); 131 132 for (;;); 133 } 134 135 /* 136 * Substitute root value with NetBSD root partition name. 137 */ 138 int 139 patch_bootstring(bootspec) 140 char *bootspec; 141 { 142 char *sp = bootstring; 143 u_int8_t unit, part; 144 int dev, error; 145 char *file; 146 147 DPRINTF(("patch_bootstring: %s\n", bootspec)); 148 149 /* get boot parameters */ 150 if (devparse(bootspec, &dev, &unit, &part, (const char **)&file) != 0) 151 unit = part = 0; 152 153 DPRINTF(("patch_bootstring: %d, %d\n", unit, part)); 154 155 /* take out the 'root=xxx' parameter */ 156 if ( (sp = strstr(bootstring, "root=")) != NULL) { 157 const char *end; 158 159 end = strchr(sp, ' '); 160 161 /* strip off leading spaces */ 162 for (--sp; (sp > bootstring) && (*sp == ' '); --sp) 163 ; 164 165 if (end != NULL) 166 strcpy(++sp, end); 167 else 168 *++sp = '\0'; 169 } 170 171 DPRINTF(("patch_bootstring: [%s]\n", bootstring)); 172 173 #define DEVNAMESIZE (MAXDEVNAME + sizeof(" root=/dev/hd") + sizeof("0a")) 174 /* bsd notation -> linux notation (wd0a -> hda1) */ 175 if (strlen(bootstring) <= (511 - DEVNAMESIZE)) { 176 int len; 177 178 strcat(bootstring, " root=/dev/hd"); 179 180 len = strlen(bootstring); 181 bootstring[len++] = unit + 'a'; 182 bootstring[len++] = part + '1'; 183 bootstring[len++] = '\0'; 184 } 185 186 DPRINTF(("patch_bootstring: -> %s\n", bootstring)); 187 return (0); 188 } 189 190 /* 191 * Extract NetBSD boot specification 192 */ 193 static int 194 get_bsdbootname(dev, kname) 195 char **dev; 196 char **kname; 197 { 198 int len, error; 199 char *bootstr_dev, *bootstr_kname; 200 char *prompt_dev, *prompt_kname; 201 char *ptr, *spec; 202 char c, namebuf[PATH_MAX]; 203 204 bootstr_dev = prompt_dev = NULL; 205 bootstr_kname = prompt_kname = NULL; 206 207 /* first, get bootname from bootstrings */ 208 if ((spec = strstr(bootstring, "nbsd=")) != NULL) { 209 ptr = strchr(spec, ' '); 210 spec += 5; /* skip 'nbsd=' */ 211 len = (ptr == NULL) ? strlen(spec) : ptr - spec; 212 if (len > 0) { 213 if (parse_bootname(spec, len, 214 &bootstr_dev, &bootstr_kname)) 215 return 1; 216 } 217 } 218 219 DPRINTF(("bootstr_dev = %s, bootstr_kname = %s\n", 220 bootstr_dev ? bootstr_dev : "<NULL>", 221 bootstr_kname ? bootstr_kname : "<NULL>")); 222 223 spec = NULL; 224 len = 0; 225 226 memset(namebuf, 0, sizeof namebuf); 227 printf("Boot [%s:%s]: ", 228 bootstr_dev ? bootstr_dev : DEFBOOTDEV, 229 bootstr_kname ? bootstr_kname : DEFKERNELNAME); 230 231 if (tgets(namebuf) == -1) 232 printf("\n"); 233 234 ptr = namebuf; 235 while ((c = *ptr) != '\0') { 236 while (c == ' ') 237 c = *++ptr; 238 if (c == '\0') 239 break; 240 if (c == '-') { 241 while ((c = *++ptr) && c != ' ') 242 ; 243 #if notyet 244 BOOT_FLAG(c, boothowto); 245 #endif 246 } else { 247 spec = ptr; 248 while ((c = *++ptr) && c != ' ') 249 ; 250 if (c) 251 *ptr++ = '\0'; 252 len = strlen(spec); 253 } 254 } 255 256 if (len > 0) { 257 if (parse_bootname(spec, len, &prompt_dev, &prompt_kname)) 258 return 1; 259 } 260 261 DPRINTF(("prompt_dev = %s, prompt_kname = %s\n", 262 prompt_dev ? prompt_dev : "<NULL>", 263 prompt_kname ? prompt_kname : "<NULL>")); 264 265 if (prompt_dev) 266 *dev = prompt_dev; 267 else 268 *dev = bootstr_dev; 269 270 if (prompt_kname) 271 *kname = prompt_kname; 272 else 273 *kname = bootstr_kname; 274 275 DPRINTF(("dev = %s, kname = %s\n", 276 *dev ? *dev : "<NULL>", 277 *kname ? *kname : "<NULL>")); 278 279 return 0; 280 } 281 282 static int 283 parse_bootname(spec, len, dev, kname) 284 char *spec; 285 int len; 286 char **dev; 287 char **kname; 288 { 289 char *bootname, *ptr; 290 291 bootname = alloc(len + 1); 292 if (bootname == NULL) 293 return 1; 294 memcpy(bootname, spec, len); 295 bootname[len] = '\0'; 296 297 if ((ptr = memchr(bootname, ':', len)) != NULL) { 298 /* "wdXX:kernel" */ 299 *ptr = '\0'; 300 *dev = bootname; 301 if (*++ptr) 302 *kname = ptr; 303 } else 304 /* "kernel" */ 305 *kname = bootname; 306 return 0; 307 } 308 309 /* 310 * Get the bootstring from PROM. 311 */ 312 int 313 prominit(memsize) 314 unsigned int memsize; 315 { 316 bootstring = (char *)(memsize - 512); 317 bootstring[511] = '\0'; 318 } 319 320 /* 321 * Print boot message. 322 */ 323 int 324 print_banner(memsize) 325 unsigned int memsize; 326 { 327 printf("\n"); 328 printf(">> %s " NETBSD_VERS " Bootloader, Revision %s [@%p]\n", 329 bootprog_name, bootprog_rev, (void*)&start); 330 printf(">> (%s, %s)\n", bootprog_maker, bootprog_date); 331 printf(">> Memory:\t\t%u k\n", (memsize - MIPS_KSEG0_START) / 1024); 332 printf(">> PROM boot string:\t%s\n", bootstring); 333 } 334 335 /* 336 * Entry point. 337 * Parse PROM boot string, load the kernel and jump into it 338 */ 339 int 340 main(memsize) 341 unsigned int memsize; 342 { 343 char **namep, *dev, *kernel, *bi_addr; 344 char bootpath[PATH_MAX]; 345 int win; 346 u_long marks[MARK_MAX]; 347 void (*entry) __P((unsigned int, u_int, char*)); 348 349 struct btinfo_flags bi_flags; 350 struct btinfo_symtab bi_syms; 351 struct btinfo_bootpath bi_bpath; 352 353 int addr, speed; 354 355 /* Initialize boot info early */ 356 bi_flags.bi_flags = 0x0; 357 bi_addr = bi_init(); 358 359 prominit(memsize); 360 if (cninit(&addr, &speed) != NULL) 361 bi_flags.bi_flags |= BI_SERIAL_CONSOLE; 362 363 print_banner(memsize); 364 365 memset(marks, 0, sizeof marks); 366 get_bsdbootname(&dev, &kernel); 367 368 if (kernel != NULL) { 369 DPRINTF(("kernel: %s\n", kernel)); 370 kernelnames[0] = kernel; 371 kernelnames[1] = NULL; 372 } else { 373 DPRINTF(("kernel: NULL\n")); 374 } 375 376 win = 0; 377 DPRINTF(("Kernel names: %p\n", kernelnames)); 378 for (namep = kernelnames, win = 0; (*namep != NULL) && !win; namep++) { 379 kernel = *namep; 380 381 bootpath[0] = '\0'; 382 383 strcpy(bootpath, dev ? dev : DEFBOOTDEV); 384 strcat(bootpath, ":"); 385 strcat(bootpath, kernel); 386 387 printf("Loading: %s\n", bootpath); 388 patch_bootstring(bootpath); 389 win = (loadfile(bootpath, marks, LOAD_ALL) != -1); 390 } 391 392 if (win) { 393 strncpy(bi_bpath.bootpath, kernel, BTINFO_BOOTPATH_LEN); 394 bi_add(&bi_bpath, BTINFO_BOOTPATH, sizeof(bi_bpath)); 395 396 entry = (void *) marks[MARK_ENTRY]; 397 bi_syms.nsym = marks[MARK_NSYM]; 398 bi_syms.ssym = marks[MARK_SYM]; 399 bi_syms.esym = marks[MARK_END]; 400 bi_add(&bi_syms, BTINFO_SYMTAB, sizeof(bi_syms)); 401 402 bi_add(&bi_flags, BTINFO_FLAGS, sizeof(bi_flags)); 403 404 entry = (void *) marks[MARK_ENTRY]; 405 406 DPRINTF(("Bootinfo @ 0x%x\n", bi_addr)); 407 printf("Starting at 0x%x\n\n", (u_int)entry); 408 (*entry)(memsize, BOOTINFO_MAGIC, bi_addr); 409 } 410 411 (void)printf("Boot failed! Rebooting...\n"); 412 return (0); 413 } 414