1 /* $NetBSD: boot.c,v 1.13 2006/07/13 20:03:34 uwe Exp $ */ 2 3 /* 4 * Copyright (c) 1997, 1999 Eduardo E. Horvath. All rights reserved. 5 * Copyright (c) 1997 Jason R. Thorpe. All rights reserved. 6 * Copyright (C) 1995, 1996 Wolfgang Solfrank. 7 * Copyright (C) 1995, 1996 TooLs GmbH. 8 * All rights reserved. 9 * 10 * ELF support derived from NetBSD/alpha's boot loader, written 11 * by Christopher G. Demetriou. 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 3. All advertising materials mentioning features or use of this software 22 * must display the following acknowledgement: 23 * This product includes software developed by TooLs GmbH. 24 * 4. The name of TooLs GmbH may not be used to endorse or promote products 25 * derived from this software without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 28 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 29 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 30 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 31 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 32 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 33 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 34 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 35 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 36 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 /* 40 * First try for the boot code 41 * 42 * Input syntax is: 43 * [promdev[{:|,}partition]]/[filename] [flags] 44 */ 45 46 #include <lib/libsa/stand.h> 47 #include <lib/libsa/loadfile.h> 48 #include <lib/libkern/libkern.h> 49 50 #include <sys/param.h> 51 #include <sys/reboot.h> 52 #include <sys/disklabel.h> 53 #include <sys/boot_flag.h> 54 55 #include <machine/cpu.h> 56 #include <machine/promlib.h> 57 #include <machine/bootinfo.h> 58 59 #include "boot.h" 60 #include "ofdev.h" 61 #include "openfirm.h" 62 63 64 #define COMPAT_BOOT(marks) (marks[MARK_START] == marks[MARK_ENTRY]) 65 66 67 typedef void (*entry_t)(long o0, long bootargs, long bootsize, long o3, 68 long ofw); 69 70 /* 71 * Boot device is derived from ROM provided information, or if there is none, 72 * this list is used in sequence, to find a kernel. 73 */ 74 const char *kernelnames[] = { 75 "netbsd", 76 "netbsd.gz", 77 "netbsd.old", 78 "netbsd.old.gz", 79 "onetbsd", 80 "onetbsd.gz", 81 "vmunix ", 82 #ifdef notyet 83 "netbsd.pl ", 84 "netbsd.pl.gz ", 85 "netbsd.el ", 86 "netbsd.el.gz ", 87 #endif 88 NULL 89 }; 90 91 char bootdev[PROM_MAX_PATH]; 92 93 int debug = 0; 94 int compatmode = 0; 95 96 #if 0 97 static void 98 prom2boot(char *dev) 99 { 100 char *cp, *lp = 0; 101 int handle; 102 char devtype[16]; 103 104 for (cp = dev; *cp; cp++) 105 if (*cp == ':') 106 lp = cp; 107 if (!lp) 108 lp = cp; 109 *lp = 0; 110 } 111 #endif 112 113 static int 114 bootoptions(const char *ap, char *kernel, char *options) 115 { 116 int v = 0; 117 const char *cp; 118 119 *kernel = '\0'; 120 *options = '\0'; 121 122 if (ap == NULL) { 123 return (0); 124 } 125 126 while (*ap == ' ') { 127 ap++; 128 } 129 130 cp = ap; 131 if (*ap != '-') { 132 while (*ap != '\0' && *ap != ' ') { 133 ap++; 134 } 135 136 memcpy(kernel, cp, (ap - cp)); 137 kernel[ap - cp] = '\0'; 138 139 while (*ap != '\0' && *ap == ' ') { 140 ap++; 141 } 142 } 143 144 strcpy(options, ap); 145 while (*ap != '\0' && *ap != ' ' && *ap != '\t' && *ap != '\n') { 146 BOOT_FLAG(*ap, v); 147 switch(*ap++) { 148 case 'D': 149 debug = 2; 150 break; 151 case 'C': 152 compatmode = 1; 153 break; 154 default: 155 break; 156 } 157 } 158 159 if (((v & RB_KDB) != 0) && (debug == 0)) { 160 debug = 1; 161 } 162 163 DPRINTF(("bootoptions: kernel='%s', options='%s'\n", kernel, options)); 164 return (v); 165 } 166 167 /* 168 * The older (those relying on ofwboot v1.8 and earlier) kernels can't handle 169 * ksyms information unless it resides in a dedicated memory allocated from 170 * PROM and aligned on NBPG boundary. This is because the kernels calculate 171 * their ends on their own, they use address of 'end[]' reference which follows 172 * text segment. Ok, allocate some memory from PROM and copy symbol information 173 * over there. 174 */ 175 static void 176 ksyms_copyout(void **ssym, void **esym) 177 { 178 void *addr; 179 int kssize = (int)(long)(*esym - *ssym + 1); 180 181 DPRINTF(("ksyms_copyout(): ssym = %p, esym = %p, kssize = %d\n", 182 *ssym, *esym, kssize)); 183 184 if ( (addr = OF_claim(0, kssize, NBPG)) == (void *)-1) { 185 panic("ksyms_copyout(): no space for symbol table"); 186 } 187 188 memcpy(addr, *ssym, kssize); 189 *ssym = addr; 190 *esym = addr + kssize - 1; 191 192 DPRINTF(("ksyms_copyout(): ssym = %p, esym = %p\n", *ssym, *esym)); 193 } 194 195 /* 196 * Prepare boot information and jump directly to the kernel. 197 */ 198 static void 199 jump_to_kernel(u_long *marks, char *kernel, char *args, void *ofw) 200 { 201 extern char end[]; 202 int l, machine_tag; 203 long newargs[4]; 204 void *ssym, *esym; 205 vaddr_t bootinfo; 206 struct btinfo_symtab bi_sym; 207 struct btinfo_kernend bi_kend; 208 char *cp; 209 char bootline[PROM_MAX_PATH * 2]; 210 211 /* Compose kernel boot line. */ 212 strncpy(bootline, kernel, sizeof(bootline)); 213 cp = bootline + strlen(bootline); 214 if (*args) { 215 *cp++ = ' '; 216 strncpy(bootline, args, sizeof(bootline) - (cp - bootline)); 217 } 218 *cp = 0; args = bootline; 219 220 /* Record symbol information in the bootinfo. */ 221 bootinfo = bi_init(marks[MARK_END]); 222 bi_sym.nsym = marks[MARK_NSYM]; 223 bi_sym.ssym = marks[MARK_SYM]; 224 bi_sym.esym = marks[MARK_END]; 225 bi_add(&bi_sym, BTINFO_SYMTAB, sizeof(bi_sym)); 226 bi_kend.addr= bootinfo + BOOTINFO_SIZE; 227 bi_add(&bi_kend, BTINFO_KERNEND, sizeof(bi_kend)); 228 sparc64_bi_add(); 229 230 ssym = (void*)(long)marks[MARK_SYM]; 231 esym = (void*)(long)marks[MARK_END]; 232 233 DPRINTF(("jump_to_kernel(): ssym = %p, esym = %p\n", ssym, esym)); 234 235 /* Adjust ksyms pointers, if needed. */ 236 if (COMPAT_BOOT(marks) || compatmode) { 237 ksyms_copyout(&ssym, &esym); 238 } 239 240 freeall(); 241 /* 242 * When we come in args consists of a pointer to the boot 243 * string. We need to fix it so it takes into account 244 * other params such as romp. 245 */ 246 247 /* 248 * Stash pointer to end of symbol table after the argument 249 * strings. 250 */ 251 l = strlen(args) + 1; 252 bcopy(&esym, args + l, sizeof(esym)); 253 l += sizeof(esym); 254 255 /* 256 * Tell the kernel we're an OpenFirmware system. 257 */ 258 machine_tag = SPARC_MACHINE_OPENFIRMWARE; 259 bcopy(&machine_tag, args + l, sizeof(machine_tag)); 260 l += sizeof(machine_tag); 261 262 /* 263 * Since we don't need the boot string (we can get it from /chosen) 264 * we won't pass it in. Just pass in esym and magic # 265 */ 266 newargs[0] = SPARC_MACHINE_OPENFIRMWARE; 267 newargs[1] = (long)esym; 268 newargs[2] = (long)ssym; 269 newargs[3] = (long)(void*)bootinfo; 270 args = (char *)newargs; 271 l = sizeof(newargs); 272 273 /* if -D is set then pause in the PROM. */ 274 if (debug > 1) callrom(); 275 276 /* 277 * Jump directly to the kernel. Solaris kernel and Sun PROM 278 * flash updates expect ROMP vector in %o0, so we do. Format 279 * of other parameters and their order reflect OF_chain() 280 * symantics since this is what older NetBSD kernels rely on. 281 * (see sparc64/include/bootinfo.h for specification). 282 */ 283 DPRINTF(("jump_to_kernel(%lx, %lx, %lx, %lx, %lx) @ %p\n", (long)ofw, 284 (long)args, (long)l, (long)ofw, (long)ofw, 285 (void*)marks[MARK_ENTRY])); 286 (*(entry_t)marks[MARK_ENTRY])((long)ofw, (long)args, (long)l, (long)ofw, 287 (long)ofw); 288 printf("Returned from kernel entry point!\n"); 289 } 290 291 static void 292 start_kernel(char *kernel, char *bootline, void *ofw) 293 { 294 int fd; 295 u_long marks[MARK_MAX]; 296 297 /* 298 * First, load headers using default allocator and check whether kernel 299 * entry address matches kernel text load address. If yes, this is the 300 * old kernel designed for ofwboot v1.8 and therefore it must be mapped 301 * by PROM. Otherwise, map the kernel with 4MB permanent pages. 302 */ 303 loadfile_set_allocator(LOADFILE_NOP_ALLOCATOR); 304 if ( (fd = loadfile(kernel, marks, LOAD_HDR|COUNT_TEXT)) != -1) { 305 if (COMPAT_BOOT(marks) || compatmode) { 306 (void)printf("[c] "); 307 loadfile_set_allocator(LOADFILE_OFW_ALLOCATOR); 308 } else { 309 loadfile_set_allocator(LOADFILE_MMU_ALLOCATOR); 310 } 311 (void)printf("Loading %s: ", kernel); 312 313 if (fdloadfile(fd, marks, LOAD_ALL) != -1) { 314 jump_to_kernel(marks, kernel, bootline, ofw); 315 } 316 } 317 (void)printf("Failed to load '%s'.\n", kernel); 318 } 319 320 void 321 main(void *ofw) 322 { 323 int boothowto, i = 0; 324 325 char kernel[PROM_MAX_PATH]; 326 char bootline[PROM_MAX_PATH]; 327 328 /* Initialize OpenFirmware */ 329 romp = ofw; 330 prom_init(); 331 332 printf("\r>> %s, Revision %s\n", bootprog_name, bootprog_rev); 333 printf(">> (%s, %s)\n", bootprog_maker, bootprog_date); 334 335 /* Figure boot arguments */ 336 boothowto = bootoptions(prom_getbootargs(), kernel, bootline); 337 strncpy(bootdev, prom_getbootpath(), sizeof(bootdev) - 1); 338 strncpy(bootline, prom_getbootargs(), sizeof(bootline) - 1); 339 340 for (;; *kernel = '\0') { 341 if (boothowto & RB_ASKNAME) { 342 char *cp, cmdline[PROM_MAX_PATH]; 343 344 printf("Boot: "); 345 gets(cmdline); 346 347 boothowto = bootoptions(cmdline, kernel, bootline); 348 boothowto |= RB_ASKNAME; 349 350 if (!strcmp(kernel,"exit") || !strcmp(kernel,"halt")) { 351 prom_halt(); 352 } 353 } 354 355 if (*kernel == '\0') { 356 if (kernelnames[i] == NULL) { 357 boothowto |= RB_ASKNAME; 358 continue; 359 } 360 strncpy(kernel, kernelnames[i++], PROM_MAX_PATH); 361 } else if (i == 0) { 362 /* 363 * Kernel name was passed via command line -- ask user 364 * again if requested image fails to boot. 365 */ 366 boothowto |= RB_ASKNAME; 367 } 368 369 start_kernel(kernel, bootline, ofw); 370 371 /* 372 * Try next name from kernel name list if not in askname mode, 373 * enter askname on reaching list's end. 374 */ 375 if ((boothowto & RB_ASKNAME) == 0 && (kernelnames[i] != NULL)) { 376 printf(": trying %s...\n", kernelnames[i]); 377 } else { 378 printf("\n"); 379 boothowto |= RB_ASKNAME; 380 } 381 } 382 383 (void)printf("Boot failed! Exiting to the Firmware.\n"); 384 prom_halt(); 385 } 386