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