1 /* $NetBSD: boot.c,v 1.32 2025/01/13 17:33:10 tsutsui Exp $ */ 2 3 /*- 4 * Copyright (c) 1997 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Jason R. Thorpe. 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) 1995, 1996 Wolfgang Solfrank. 34 * Copyright (C) 1995, 1996 TooLs GmbH. 35 * All rights reserved. 36 * 37 * ELF support derived from NetBSD/alpha's boot loader, written 38 * by Christopher G. Demetriou. 39 * 40 * Redistribution and use in source and binary forms, with or without 41 * modification, are permitted provided that the following conditions 42 * are met: 43 * 1. Redistributions of source code must retain the above copyright 44 * notice, this list of conditions and the following disclaimer. 45 * 2. Redistributions in binary form must reproduce the above copyright 46 * notice, this list of conditions and the following disclaimer in the 47 * documentation and/or other materials provided with the distribution. 48 * 3. All advertising materials mentioning features or use of this software 49 * must display the following acknowledgement: 50 * This product includes software developed by TooLs GmbH. 51 * 4. The name of TooLs GmbH may not be used to endorse or promote products 52 * derived from this software without specific prior written permission. 53 * 54 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 55 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 56 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 57 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 58 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 59 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 60 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 61 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 62 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 63 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 64 */ 65 66 /* 67 * First try for the boot code 68 * 69 * Input syntax is: 70 * [promdev[{:|,}partition]]/[filename] [flags] 71 */ 72 73 #include "boot.h" 74 75 #include <sys/param.h> 76 #include <sys/boot_flag.h> 77 #include <sys/disklabel.h> 78 79 #include <lib/libsa/stand.h> 80 #include <lib/libsa/loadfile.h> 81 #include <lib/libkern/libkern.h> 82 83 #include "ofdev.h" 84 #include "openfirm.h" 85 86 extern void __syncicache(void *, size_t); /* in libkern */ 87 88 89 #ifdef DEBUG 90 # define DPRINTF printf 91 #else 92 # define DPRINTF while (0) printf 93 #endif 94 95 char bootdev[MAXBOOTPATHLEN]; 96 extern char bootfile[MAXBOOTPATHLEN]; 97 int boothowto; 98 bool floppyboot; 99 int ofw_version = 0; 100 101 static const char *kernels[] = { "/netbsd", "/netbsd.gz", "/netbsd.macppc", NULL }; 102 103 static void 104 prom2boot(char *dev) 105 { 106 char *cp; 107 108 DPRINTF("%s: bootpath from OF: \"%s\"\n", __func__, dev); 109 cp = dev + strlen(dev) - 1; 110 for (; *cp; cp--) { 111 if (*cp == ':') { 112 if (ofw_version < 3) { 113 /* sd@0:0 -> sd@0 */ 114 *cp = 0; 115 break; 116 } else { 117 /* 118 * OpenBIOS v1.1 on qemu-system-ppc emulates 119 * Open Firmware 3.x but it also recognizes 120 * pmBootEntry info in the Apple Partition Map 121 * like old Open Firmware 1.x/2.x machines. 122 * In such case, the OpenBIOS passes 123 * "/[boot device]/disk@0:,%BOOT" 124 * for bootpath strings, but it looks 125 * the OpenBIOS doesn't recognize 126 * partition info in "disk@0:0" format. 127 * So just remove file arg strings without 128 * adding partition info in such case. 129 */ 130 if (cp[1] == ',') { 131 /* just drop extra ",[bootfile]" */ 132 cp[1] = '\0'; 133 } else { 134 /* disk@0:5,boot -> disk@0:0 */ 135 strcpy(cp, ":0"); 136 } 137 break; 138 } 139 } 140 } 141 DPRINTF("%s: bootpath patched: \"%s\"\n", __func__, dev); 142 } 143 144 static void 145 parseargs(char *str, int *howtop) 146 { 147 char *cp; 148 149 /* Allow user to drop back to the PROM. */ 150 if (strcmp(str, "exit") == 0) 151 OF_exit(); 152 153 *howtop = 0; 154 155 cp = str; 156 if (*cp == '-') 157 goto found; 158 for (cp = str; *cp; cp++) 159 if (*cp == ' ') 160 goto found; 161 return; 162 163 found: 164 *cp++ = 0; 165 while (*cp) 166 BOOT_FLAG(*cp++, *howtop); 167 } 168 169 static bool 170 is_floppyboot(const char *path, const char *defaultdev) 171 { 172 char dev[MAXBOOTPATHLEN]; 173 char nam[16]; 174 int handle, rv; 175 176 if (parsefilepath(path, dev, NULL, NULL)) { 177 if (dev[0] == '\0' && defaultdev != NULL) 178 strlcpy(dev, defaultdev, sizeof(dev)); 179 180 /* check properties */ 181 handle = OF_finddevice(dev); 182 if (handle != -1) { 183 rv = OF_getprop(handle, "name", nam, sizeof(nam)); 184 if (rv >= 0 && 185 (strcmp(nam, "swim3") == 0 || 186 strcmp(nam, "floppy") == 0)) 187 return true; 188 } 189 190 /* also check devalias */ 191 if (strcmp(dev, "fd") == 0) 192 return true; 193 } 194 195 return false; 196 } 197 198 static void 199 chain(boot_entry_t entry, char *args, void *ssym, void *esym) 200 { 201 extern char end[]; 202 int l; 203 204 #if !defined(HEAP_VARIABLE) 205 freeall(); 206 #endif 207 208 /* 209 * Stash pointer to end of symbol table after the argument 210 * strings. 211 */ 212 l = strlen(args) + 1; 213 memcpy(args + l, &ssym, sizeof(ssym)); 214 l += sizeof(ssym); 215 memcpy(args + l, &esym, sizeof(esym)); 216 l += sizeof(esym); 217 l += sizeof(int); /* XXX */ 218 219 OF_chain((void *) RELOC, end - (char *) RELOC, entry, args, l); 220 panic("chain"); 221 } 222 223 __dead void 224 _rtt(void) 225 { 226 227 OF_exit(); 228 } 229 230 void 231 main(void) 232 { 233 extern char bootprog_name[], bootprog_rev[]; 234 char bootline[512]; /* Should check size? */ 235 char prop[32]; 236 char *cp; 237 u_long marks[MARK_MAX]; 238 u_int32_t entry; 239 void *ssym, *esym; 240 241 printf("\n"); 242 printf(">> %s, Revision %s\n", bootprog_name, bootprog_rev); 243 244 /* 245 * Figure out what version of Open Firmware... 246 */ 247 if (ofw_openprom != -1) { 248 memset(prop, 0, sizeof prop); 249 OF_getprop(ofw_openprom, "model", prop, sizeof prop); 250 for (cp = prop; *cp; cp++) 251 if (*cp >= '0' && *cp <= '9') { 252 ofw_version = *cp - '0'; 253 break; 254 } 255 printf(">> Open Firmware version %d.x\n", ofw_version); 256 } 257 printf(">> Open Firmware running in %s-mode.\n", 258 ofw_real_mode ? "real" : "virtual"); 259 260 /* 261 * Get the boot arguments from Openfirmware 262 */ 263 if (OF_getprop(ofw_chosen, "bootpath", bootdev, sizeof bootdev) < 0 || 264 OF_getprop(ofw_chosen, "bootargs", bootline, sizeof bootline) < 0) { 265 printf("Invalid Openfirmware environment\n"); 266 OF_exit(); 267 } 268 269 /* 270 * Some versions of Openfirmware sets bootpath to "". 271 * We use boot-device instead if it occurs. 272 */ 273 if (bootdev[0] == 0) { 274 printf("Cannot use bootpath\n"); 275 if (ofw_options == -1 || 276 OF_getprop(ofw_options, "boot-device", bootdev, 277 sizeof bootdev) < 0) { 278 printf("Invalid Openfirmware environment\n"); 279 OF_exit(); 280 } 281 printf("Using boot-device instead\n"); 282 } 283 284 prom2boot(bootdev); 285 parseargs(bootline, &boothowto); 286 DPRINTF("bootline=%s\n", bootline); 287 288 for (;;) { 289 int i, loadflag; 290 291 if (boothowto & RB_ASKNAME) { 292 printf("Boot: "); 293 kgets(bootline, sizeof(bootline)); 294 parseargs(bootline, &boothowto); 295 } 296 297 if (bootline[0]) { 298 kernels[0] = bootline; 299 kernels[1] = NULL; 300 } 301 302 for (i = 0; kernels[i]; i++) { 303 floppyboot = is_floppyboot(kernels[i], bootdev); 304 305 DPRINTF("Trying %s%s\n", kernels[i], 306 floppyboot ? " (floppyboot)" : ""); 307 308 loadflag = LOAD_KERNEL; 309 if (floppyboot) 310 loadflag &= ~LOAD_BACKWARDS; 311 312 marks[MARK_START] = 0; 313 if (loadfile(kernels[i], marks, loadflag) >= 0) 314 goto loaded; 315 } 316 boothowto |= RB_ASKNAME; 317 } 318 loaded: 319 320 #ifdef __notyet__ 321 OF_setprop(ofw_chosen, "bootpath", opened_name, 322 strlen(opened_name) + 1); 323 cp = bootline; 324 #else 325 strcpy(bootline, opened_name); 326 cp = bootline + strlen(bootline); 327 *cp++ = ' '; 328 #endif 329 *cp = '-'; 330 if (boothowto & RB_ASKNAME) 331 *++cp = 'a'; 332 if (boothowto & RB_USERCONF) 333 *++cp = 'c'; 334 if (boothowto & RB_SINGLE) 335 *++cp = 's'; 336 if (boothowto & RB_KDB) 337 *++cp = 'd'; 338 if (*cp == '-') 339 #ifdef __notyet__ 340 *cp = 0; 341 #else 342 *--cp = 0; 343 #endif 344 else 345 *++cp = 0; 346 #ifdef __notyet__ 347 OF_setprop(ofw_chosen, "bootargs", bootline, strlen(bootline) + 1); 348 #endif 349 350 entry = marks[MARK_ENTRY]; 351 ssym = (void *)marks[MARK_SYM]; 352 esym = (void *)marks[MARK_END]; 353 354 printf(" start=0x%x\n", entry); 355 __syncicache((void *)(uintptr_t)entry, (size_t)ssym - entry); 356 chain((boot_entry_t)(uintptr_t)entry, bootline, ssym, esym); 357 358 OF_exit(); 359 } 360 361 #ifdef HAVE_CHANGEDISK_HOOK 362 void 363 changedisk_hook(struct open_file *of) 364 { 365 struct of_dev *op = of->f_devdata; 366 int c; 367 368 OF_call_method("eject", op->handle, 0, 0, NULL); 369 370 c = getchar(); 371 if (c == 'q') { 372 printf("quit\n"); 373 OF_exit(); 374 } 375 376 OF_call_method("close", op->handle, 0, 0, NULL); 377 OF_call_method("open", op->handle, 0, 0, NULL); 378 } 379 #endif 380