1 1.33 pgoyette /* $NetBSD: boot.c,v 1.33 2025/07/31 02:59:13 pgoyette Exp $ */ 2 1.1 nonaka 3 1.1 nonaka /*- 4 1.1 nonaka * Copyright (c) 2016 Kimihiro Nonaka <nonaka (at) netbsd.org> 5 1.1 nonaka * All rights reserved. 6 1.1 nonaka * 7 1.1 nonaka * Redistribution and use in source and binary forms, with or without 8 1.1 nonaka * modification, are permitted provided that the following conditions 9 1.1 nonaka * are met: 10 1.1 nonaka * 1. Redistributions of source code must retain the above copyright 11 1.1 nonaka * notice, this list of conditions and the following disclaimer. 12 1.1 nonaka * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 nonaka * notice, this list of conditions and the following disclaimer in the 14 1.1 nonaka * documentation and/or other materials provided with the distribution. 15 1.1 nonaka * 16 1.1 nonaka * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 17 1.1 nonaka * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 1.1 nonaka * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 1.1 nonaka * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 20 1.1 nonaka * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 1.1 nonaka * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 1.1 nonaka * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 1.1 nonaka * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 1.1 nonaka * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 1.1 nonaka * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 1.1 nonaka * SUCH DAMAGE. 27 1.1 nonaka */ 28 1.1 nonaka 29 1.1 nonaka #include "efiboot.h" 30 1.1 nonaka 31 1.1 nonaka #include <sys/bootblock.h> 32 1.1 nonaka #include <sys/boot_flag.h> 33 1.5 nonaka #include <machine/limits.h> 34 1.1 nonaka 35 1.4 nonaka #include "bootcfg.h" 36 1.4 nonaka #include "bootmod.h" 37 1.4 nonaka #include "bootmenu.h" 38 1.14 manu #include "biosdisk.h" 39 1.1 nonaka #include "devopen.h" 40 1.1 nonaka 41 1.18 mlelstv #ifdef _STANDALONE 42 1.18 mlelstv #include <bootinfo.h> 43 1.18 mlelstv #endif 44 1.18 mlelstv 45 1.1 nonaka int errno; 46 1.1 nonaka int boot_biosdev; 47 1.1 nonaka daddr_t boot_biossector; 48 1.1 nonaka 49 1.1 nonaka extern const char bootprog_name[], bootprog_rev[], bootprog_kernrev[]; 50 1.1 nonaka 51 1.1 nonaka extern struct x86_boot_params boot_params; 52 1.1 nonaka extern char twiddle_toggle; 53 1.1 nonaka 54 1.1 nonaka static const char * const names[][2] = { 55 1.33 pgoyette { "netbsd", "netbsd.gz" }, 56 1.33 pgoyette { "onetbsd", "onetbsd.gz" }, 57 1.33 pgoyette { "netbsd.old", "netbsd.old.gz" }, 58 1.24 pgoyette { "netbsd/kernel", "netbsd/kernel.gz" }, 59 1.24 pgoyette { "onetbsd/kernel", "onetbsd/kernel.gz" }, 60 1.24 pgoyette { "netbsd.old/kernel", "netbsd.old/kernel.gz" }, 61 1.1 nonaka }; 62 1.1 nonaka 63 1.1 nonaka #define NUMNAMES __arraycount(names) 64 1.1 nonaka #define DEFFILENAME names[0][0] 65 1.1 nonaka 66 1.9 nonaka #ifndef EFIBOOTCFG_FILENAME 67 1.9 nonaka #define EFIBOOTCFG_FILENAME "esp:/EFI/NetBSD/boot.cfg" 68 1.9 nonaka #endif 69 1.1 nonaka 70 1.1 nonaka void command_help(char *); 71 1.1 nonaka void command_quit(char *); 72 1.1 nonaka void command_boot(char *); 73 1.11 maxv void command_pkboot(char *); 74 1.1 nonaka void command_consdev(char *); 75 1.18 mlelstv void command_root(char *); 76 1.1 nonaka void command_dev(char *); 77 1.1 nonaka void command_devpath(char *); 78 1.1 nonaka void command_efivar(char *); 79 1.1 nonaka void command_gop(char *); 80 1.1 nonaka #if LIBSA_ENABLE_LS_OP 81 1.1 nonaka void command_ls(char *); 82 1.1 nonaka #endif 83 1.1 nonaka void command_memmap(char *); 84 1.1 nonaka #ifndef SMALL 85 1.1 nonaka void command_menu(char *); 86 1.1 nonaka #endif 87 1.1 nonaka void command_modules(char *); 88 1.1 nonaka void command_multiboot(char *); 89 1.22 manu void command_reloc(char *); 90 1.1 nonaka void command_text(char *); 91 1.1 nonaka void command_version(char *); 92 1.1 nonaka 93 1.1 nonaka const struct bootblk_command commands[] = { 94 1.1 nonaka { "help", command_help }, 95 1.1 nonaka { "?", command_help }, 96 1.1 nonaka { "quit", command_quit }, 97 1.1 nonaka { "boot", command_boot }, 98 1.11 maxv { "pkboot", command_pkboot }, 99 1.1 nonaka { "consdev", command_consdev }, 100 1.18 mlelstv { "root", command_root }, 101 1.1 nonaka { "dev", command_dev }, 102 1.1 nonaka { "devpath", command_devpath }, 103 1.1 nonaka { "efivar", command_efivar }, 104 1.1 nonaka { "fs", fs_add }, 105 1.1 nonaka { "gop", command_gop }, 106 1.1 nonaka { "load", module_add }, 107 1.1 nonaka #if LIBSA_ENABLE_LS_OP 108 1.1 nonaka { "ls", command_ls }, 109 1.1 nonaka #endif 110 1.1 nonaka { "memmap", command_memmap }, 111 1.1 nonaka #ifndef SMALL 112 1.1 nonaka { "menu", command_menu }, 113 1.1 nonaka #endif 114 1.1 nonaka { "modules", command_modules }, 115 1.1 nonaka { "multiboot", command_multiboot }, 116 1.22 manu { "reloc", command_reloc }, 117 1.1 nonaka { "rndseed", rnd_add }, 118 1.1 nonaka { "splash", splash_add }, 119 1.1 nonaka { "text", command_text }, 120 1.1 nonaka { "userconf", userconf_add }, 121 1.1 nonaka { "version", command_version }, 122 1.1 nonaka { NULL, NULL }, 123 1.1 nonaka }; 124 1.1 nonaka 125 1.17 nonaka static char *default_fsname; 126 1.1 nonaka static char *default_devname; 127 1.1 nonaka static int default_unit, default_partition; 128 1.1 nonaka static const char *default_filename; 129 1.14 manu static const char *default_part_name; 130 1.1 nonaka 131 1.1 nonaka static char *sprint_bootsel(const char *); 132 1.1 nonaka static void bootit(const char *, int); 133 1.27 pgoyette static void bootit2(char *, size_t, int); 134 1.1 nonaka 135 1.1 nonaka int 136 1.1 nonaka parsebootfile(const char *fname, char **fsname, char **devname, int *unit, 137 1.1 nonaka int *partition, const char **file) 138 1.1 nonaka { 139 1.1 nonaka const char *col; 140 1.14 manu static char savedevname[MAXDEVNAME+1]; 141 1.17 nonaka #if defined(SUPPORT_NFS) || defined(SUPPORT_TFTP) 142 1.17 nonaka const struct netboot_fstab *nf; 143 1.17 nonaka #endif 144 1.1 nonaka 145 1.17 nonaka *fsname = default_fsname; 146 1.14 manu if (default_part_name == NULL) { 147 1.14 manu *devname = default_devname; 148 1.14 manu } else { 149 1.15 manu snprintf(savedevname, sizeof(savedevname), 150 1.15 manu "NAME=%s", default_part_name); 151 1.14 manu *devname = savedevname; 152 1.14 manu } 153 1.1 nonaka *unit = default_unit; 154 1.1 nonaka *partition = default_partition; 155 1.1 nonaka *file = default_filename; 156 1.1 nonaka 157 1.1 nonaka if (fname == NULL) 158 1.1 nonaka return 0; 159 1.1 nonaka 160 1.1 nonaka if ((col = strchr(fname, ':')) != NULL) { /* device given */ 161 1.1 nonaka int devlen; 162 1.1 nonaka int u = 0, p = 0; 163 1.1 nonaka int i = 0; 164 1.1 nonaka 165 1.1 nonaka devlen = col - fname; 166 1.1 nonaka if (devlen > MAXDEVNAME) 167 1.1 nonaka return EINVAL; 168 1.1 nonaka 169 1.14 manu if (strstr(fname, "NAME=") == fname) { 170 1.14 manu strlcpy(savedevname, fname, devlen + 1); 171 1.17 nonaka *fsname = "ufs"; 172 1.14 manu *devname = savedevname; 173 1.14 manu *unit = -1; 174 1.14 manu *partition = -1; 175 1.14 manu fname = col + 1; 176 1.14 manu goto out; 177 1.14 manu } 178 1.14 manu 179 1.1 nonaka #define isvalidname(c) ((c) >= 'a' && (c) <= 'z') 180 1.1 nonaka if (!isvalidname(fname[i])) 181 1.1 nonaka return EINVAL; 182 1.1 nonaka do { 183 1.1 nonaka savedevname[i] = fname[i]; 184 1.1 nonaka i++; 185 1.1 nonaka } while (isvalidname(fname[i])); 186 1.1 nonaka savedevname[i] = '\0'; 187 1.1 nonaka 188 1.1 nonaka #define isnum(c) ((c) >= '0' && (c) <= '9') 189 1.1 nonaka if (i < devlen) { 190 1.1 nonaka if (!isnum(fname[i])) 191 1.1 nonaka return EUNIT; 192 1.1 nonaka do { 193 1.1 nonaka u *= 10; 194 1.1 nonaka u += fname[i++] - '0'; 195 1.1 nonaka } while (isnum(fname[i])); 196 1.1 nonaka } 197 1.1 nonaka 198 1.1 nonaka #define isvalidpart(c) ((c) >= 'a' && (c) <= 'z') 199 1.1 nonaka if (i < devlen) { 200 1.1 nonaka if (!isvalidpart(fname[i])) 201 1.1 nonaka return EPART; 202 1.1 nonaka p = fname[i++] - 'a'; 203 1.1 nonaka } 204 1.1 nonaka 205 1.1 nonaka if (i != devlen) 206 1.1 nonaka return ENXIO; 207 1.1 nonaka 208 1.17 nonaka #if defined(SUPPORT_NFS) || defined(SUPPORT_TFTP) 209 1.17 nonaka nf = netboot_fstab_find(savedevname); 210 1.17 nonaka if (nf != NULL) 211 1.17 nonaka *fsname = (char *)nf->name; 212 1.17 nonaka else 213 1.17 nonaka #endif 214 1.17 nonaka *fsname = "ufs"; 215 1.1 nonaka *devname = savedevname; 216 1.1 nonaka *unit = u; 217 1.1 nonaka *partition = p; 218 1.1 nonaka fname = col + 1; 219 1.1 nonaka } 220 1.1 nonaka 221 1.14 manu out: 222 1.1 nonaka if (*fname) 223 1.1 nonaka *file = fname; 224 1.1 nonaka 225 1.1 nonaka return 0; 226 1.1 nonaka } 227 1.1 nonaka 228 1.1 nonaka static char * 229 1.10 nonaka snprint_bootdev(char *buf, size_t bufsize, const char *devname, int unit, 230 1.10 nonaka int partition) 231 1.10 nonaka { 232 1.10 nonaka static const char *no_partition_devs[] = { "esp", "net", "nfs", "tftp" }; 233 1.10 nonaka int i; 234 1.10 nonaka 235 1.10 nonaka for (i = 0; i < __arraycount(no_partition_devs); i++) 236 1.10 nonaka if (strcmp(devname, no_partition_devs[i]) == 0) 237 1.10 nonaka break; 238 1.14 manu if (strstr(devname, "NAME=") == devname) 239 1.14 manu strlcpy(buf, devname, bufsize); 240 1.14 manu else 241 1.14 manu snprintf(buf, bufsize, "%s%d%c", devname, unit, 242 1.14 manu i < __arraycount(no_partition_devs) ? '\0' : 'a' + partition); 243 1.10 nonaka return buf; 244 1.10 nonaka } 245 1.10 nonaka 246 1.10 nonaka static char * 247 1.1 nonaka sprint_bootsel(const char *filename) 248 1.1 nonaka { 249 1.1 nonaka char *fsname, *devname; 250 1.1 nonaka int unit, partition; 251 1.1 nonaka const char *file; 252 1.1 nonaka static char buf[80]; 253 1.1 nonaka 254 1.1 nonaka if (parsebootfile(filename, &fsname, &devname, &unit, 255 1.1 nonaka &partition, &file) == 0) { 256 1.10 nonaka snprintf(buf, sizeof(buf), "%s:%s", snprint_bootdev(buf, 257 1.10 nonaka sizeof(buf), devname, unit, partition), file); 258 1.1 nonaka return buf; 259 1.1 nonaka } 260 1.1 nonaka return "(invalid)"; 261 1.1 nonaka } 262 1.1 nonaka 263 1.1 nonaka void 264 1.1 nonaka clearit(void) 265 1.1 nonaka { 266 1.1 nonaka 267 1.1 nonaka if (bootcfg_info.clear) 268 1.1 nonaka clear_pc_screen(); 269 1.1 nonaka } 270 1.1 nonaka 271 1.1 nonaka static void 272 1.1 nonaka bootit(const char *filename, int howto) 273 1.1 nonaka { 274 1.1 nonaka 275 1.1 nonaka if (howto & AB_VERBOSE) 276 1.1 nonaka printf("booting %s (howto 0x%x)\n", sprint_bootsel(filename), 277 1.1 nonaka howto); 278 1.1 nonaka 279 1.12 nonaka if (exec_netbsd(filename, efi_loadaddr, howto, 0, efi_cleanup) < 0) 280 1.1 nonaka printf("boot: %s: %s\n", sprint_bootsel(filename), 281 1.1 nonaka strerror(errno)); 282 1.1 nonaka else 283 1.1 nonaka printf("boot returned\n"); 284 1.1 nonaka } 285 1.1 nonaka 286 1.1 nonaka void 287 1.1 nonaka boot(void) 288 1.1 nonaka { 289 1.1 nonaka int currname; 290 1.1 nonaka int c; 291 1.17 nonaka #if defined(SUPPORT_NFS) || defined(SUPPORT_TFTP) 292 1.17 nonaka const struct netboot_fstab *nf; 293 1.17 nonaka #endif 294 1.1 nonaka 295 1.1 nonaka boot_modules_enabled = !(boot_params.bp_flags & X86_BP_FLAGS_NOMODULES); 296 1.1 nonaka 297 1.1 nonaka /* try to set default device to what BIOS tells us */ 298 1.1 nonaka bios2dev(boot_biosdev, boot_biossector, &default_devname, &default_unit, 299 1.14 manu &default_partition, &default_part_name); 300 1.1 nonaka 301 1.1 nonaka /* if the user types "boot" without filename */ 302 1.1 nonaka default_filename = DEFFILENAME; 303 1.1 nonaka 304 1.17 nonaka #if defined(SUPPORT_NFS) || defined(SUPPORT_TFTP) 305 1.17 nonaka nf = netboot_fstab_find(default_devname); 306 1.17 nonaka if (nf != NULL) 307 1.17 nonaka default_fsname = (char *)nf->name; 308 1.17 nonaka else 309 1.17 nonaka #endif 310 1.17 nonaka default_fsname = "ufs"; 311 1.17 nonaka 312 1.1 nonaka if (!(boot_params.bp_flags & X86_BP_FLAGS_NOBOOTCONF)) { 313 1.9 nonaka #ifdef EFIBOOTCFG_FILENAME 314 1.10 nonaka int rv = EINVAL; 315 1.10 nonaka if (efi_bootdp_type != BOOT_DEVICE_TYPE_NET) 316 1.10 nonaka rv = parsebootconf(EFIBOOTCFG_FILENAME); 317 1.9 nonaka if (rv) 318 1.9 nonaka #endif 319 1.1 nonaka parsebootconf(BOOTCFG_FILENAME); 320 1.1 nonaka } else { 321 1.1 nonaka bootcfg_info.timeout = boot_params.bp_timeout; 322 1.1 nonaka } 323 1.1 nonaka 324 1.1 nonaka /* 325 1.1 nonaka * If console set in boot.cfg, switch to it. 326 1.1 nonaka * This will print the banner, so we don't need to explicitly do it 327 1.1 nonaka */ 328 1.20 nia if (bootcfg_info.consdev) { 329 1.1 nonaka command_consdev(bootcfg_info.consdev); 330 1.20 nia } else { 331 1.20 nia clearit(); 332 1.20 nia print_bootcfg_banner(bootprog_name, bootprog_rev); 333 1.20 nia } 334 1.1 nonaka 335 1.1 nonaka /* Display the menu, if applicable */ 336 1.1 nonaka twiddle_toggle = 0; 337 1.1 nonaka if (bootcfg_info.nummenu > 0) { 338 1.1 nonaka /* Does not return */ 339 1.1 nonaka doboottypemenu(); 340 1.1 nonaka } 341 1.1 nonaka 342 1.1 nonaka printf("Press return to boot now, any other key for boot menu\n"); 343 1.1 nonaka for (currname = 0; currname < NUMNAMES; currname++) { 344 1.1 nonaka printf("booting %s - starting in ", 345 1.1 nonaka sprint_bootsel(names[currname][0])); 346 1.1 nonaka 347 1.1 nonaka c = awaitkey((bootcfg_info.timeout < 0) ? 0 348 1.1 nonaka : bootcfg_info.timeout, 1); 349 1.1 nonaka if ((c != '\r') && (c != '\n') && (c != '\0')) { 350 1.1 nonaka if ((boot_params.bp_flags & X86_BP_FLAGS_PASSWORD) == 0) { 351 1.1 nonaka /* do NOT ask for password */ 352 1.1 nonaka bootmenu(); /* does not return */ 353 1.1 nonaka } else { 354 1.1 nonaka /* DO ask for password */ 355 1.1 nonaka if (check_password((char *)boot_params.bp_password)) { 356 1.1 nonaka /* password ok */ 357 1.1 nonaka printf("type \"?\" or \"help\" for help.\n"); 358 1.1 nonaka bootmenu(); /* does not return */ 359 1.1 nonaka } else { 360 1.1 nonaka /* bad password */ 361 1.1 nonaka printf("Wrong password.\n"); 362 1.1 nonaka currname = 0; 363 1.1 nonaka continue; 364 1.1 nonaka } 365 1.1 nonaka } 366 1.1 nonaka } 367 1.1 nonaka 368 1.1 nonaka /* 369 1.1 nonaka * try pairs of names[] entries, foo and foo.gz 370 1.1 nonaka */ 371 1.1 nonaka /* don't print "booting..." again */ 372 1.1 nonaka bootit(names[currname][0], 0); 373 1.1 nonaka /* since it failed, try compressed bootfile. */ 374 1.1 nonaka bootit(names[currname][1], AB_VERBOSE); 375 1.1 nonaka } 376 1.1 nonaka 377 1.1 nonaka bootmenu(); /* does not return */ 378 1.1 nonaka } 379 1.1 nonaka 380 1.1 nonaka /* ARGSUSED */ 381 1.1 nonaka void 382 1.1 nonaka command_help(char *arg) 383 1.1 nonaka { 384 1.1 nonaka 385 1.1 nonaka printf("commands are:\n" 386 1.14 manu "boot [dev:][filename] [-12acdqsvxz]\n" 387 1.14 manu #ifndef NO_RAIDFRAME 388 1.14 manu " dev syntax is (hd|fd|cd|raid)[N[x]]\n" 389 1.14 manu #else 390 1.14 manu " dev syntax is (hd|fd|cd)[N[x]]\n" 391 1.14 manu #endif 392 1.14 manu #ifndef NO_GPT 393 1.14 manu " or NAME=gpt_label\n" 394 1.14 manu #endif 395 1.11 maxv " (ex. \"hd0a:netbsd.old -s\")\n" 396 1.14 manu "pkboot [dev:][filename] [-12acdqsvxz]\n" 397 1.14 manu "dev [dev:]\n" 398 1.5 nonaka "consdev {pc|com[0123][,{speed}]|com,{ioport}[,{speed}]}\n" 399 1.18 mlelstv "root {spec}\n" 400 1.18 mlelstv " spec can be disk, e.g. wd0, sd0\n" 401 1.18 mlelstv " or string like wedge:name\n" 402 1.1 nonaka "devpath\n" 403 1.1 nonaka "efivar\n" 404 1.1 nonaka "gop [{modenum|list}]\n" 405 1.1 nonaka "load {path_to_module}\n" 406 1.1 nonaka #if LIBSA_ENABLE_LS_OP 407 1.14 manu "ls [dev:][path]\n" 408 1.1 nonaka #endif 409 1.13 nonaka "memmap [{sorted|unsorted|compact}]\n" 410 1.1 nonaka #ifndef SMALL 411 1.1 nonaka "menu (reenters boot menu, if defined in boot.cfg)\n" 412 1.1 nonaka #endif 413 1.1 nonaka "modules {on|off|enabled|disabled}\n" 414 1.14 manu "multiboot [dev:][filename] [<args>]\n" 415 1.22 manu "reloc {address|none|default}\n" 416 1.1 nonaka "rndseed {path_to_rndseed_file}\n" 417 1.1 nonaka "splash {path_to_image_file}\n" 418 1.1 nonaka "text [{modenum|list}]\n" 419 1.1 nonaka "userconf {command}\n" 420 1.1 nonaka "version\n" 421 1.1 nonaka "help|?\n" 422 1.1 nonaka "quit\n"); 423 1.1 nonaka } 424 1.1 nonaka 425 1.1 nonaka #if LIBSA_ENABLE_LS_OP 426 1.1 nonaka void 427 1.1 nonaka command_ls(char *arg) 428 1.1 nonaka { 429 1.1 nonaka const char *save = default_filename; 430 1.1 nonaka 431 1.1 nonaka default_filename = "/"; 432 1.1 nonaka ls(arg); 433 1.1 nonaka default_filename = save; 434 1.1 nonaka } 435 1.1 nonaka #endif 436 1.1 nonaka 437 1.1 nonaka /* ARGSUSED */ 438 1.1 nonaka void 439 1.1 nonaka command_quit(char *arg) 440 1.1 nonaka { 441 1.1 nonaka 442 1.1 nonaka printf("Exiting...\n"); 443 1.1 nonaka delay(1 * 1000 * 1000); 444 1.1 nonaka reboot(); 445 1.1 nonaka /* Note: we shouldn't get to this point! */ 446 1.1 nonaka panic("Could not reboot!"); 447 1.1 nonaka } 448 1.1 nonaka 449 1.27 pgoyette static void 450 1.27 pgoyette bootit2(char *path, size_t plen, int howto) 451 1.27 pgoyette { 452 1.27 pgoyette bootit(path, howto); 453 1.27 pgoyette snprintf(path, plen, "%s.gz", path); 454 1.27 pgoyette bootit(path, howto | AB_VERBOSE); 455 1.27 pgoyette } 456 1.27 pgoyette 457 1.1 nonaka void 458 1.1 nonaka command_boot(char *arg) 459 1.1 nonaka { 460 1.1 nonaka char *filename; 461 1.29 pgoyette char path[512]; 462 1.1 nonaka int howto; 463 1.1 nonaka 464 1.1 nonaka if (!parseboot(arg, &filename, &howto)) 465 1.1 nonaka return; 466 1.1 nonaka 467 1.32 pgoyette if (filename != NULL && filename[0] != '\0') { 468 1.29 pgoyette /* try old locations first to appease atf test beds */ 469 1.29 pgoyette snprintf(path, sizeof(path) - 4, "%s", filename); 470 1.29 pgoyette bootit2(path, sizeof(path), howto); 471 1.28 pgoyette 472 1.32 pgoyette /* 473 1.32 pgoyette * now treat given filename as a directory unless there 474 1.32 pgoyette * is already an embedded path-name separator '/' present 475 1.32 pgoyette */ 476 1.32 pgoyette if (strchr(filename + 1, '/') == NULL) { 477 1.32 pgoyette snprintf(path, sizeof(path) - 4, "%s/kernel", 478 1.32 pgoyette filename); 479 1.27 pgoyette bootit2(path, sizeof(path), howto); 480 1.27 pgoyette } 481 1.1 nonaka } else { 482 1.1 nonaka int i; 483 1.1 nonaka 484 1.1 nonaka for (i = 0; i < NUMNAMES; i++) { 485 1.1 nonaka bootit(names[i][0], howto); 486 1.1 nonaka bootit(names[i][1], howto); 487 1.1 nonaka } 488 1.1 nonaka } 489 1.1 nonaka } 490 1.1 nonaka 491 1.1 nonaka void 492 1.11 maxv command_pkboot(char *arg) 493 1.11 maxv { 494 1.11 maxv extern int has_prekern; 495 1.11 maxv has_prekern = 1; 496 1.11 maxv command_boot(arg); 497 1.11 maxv has_prekern = 0; 498 1.11 maxv } 499 1.11 maxv 500 1.11 maxv void 501 1.1 nonaka command_dev(char *arg) 502 1.1 nonaka { 503 1.1 nonaka static char savedevname[MAXDEVNAME + 1]; 504 1.10 nonaka char buf[80]; 505 1.17 nonaka char *devname; 506 1.1 nonaka const char *file; /* dummy */ 507 1.1 nonaka 508 1.1 nonaka if (*arg == '\0') { 509 1.6 nonaka efi_disk_show(); 510 1.10 nonaka efi_net_show(); 511 1.23 riastrad 512 1.14 manu if (default_part_name != NULL) 513 1.14 manu printf("default NAME=%s\n", default_part_name); 514 1.14 manu else 515 1.14 manu printf("default %s\n", 516 1.14 manu snprint_bootdev(buf, sizeof(buf), 517 1.14 manu default_devname, default_unit, 518 1.14 manu default_partition)); 519 1.1 nonaka return; 520 1.1 nonaka } 521 1.1 nonaka 522 1.1 nonaka if (strchr(arg, ':') == NULL || 523 1.17 nonaka parsebootfile(arg, &default_fsname, &devname, &default_unit, 524 1.1 nonaka &default_partition, &file)) { 525 1.1 nonaka command_help(NULL); 526 1.1 nonaka return; 527 1.1 nonaka } 528 1.1 nonaka 529 1.1 nonaka /* put to own static storage */ 530 1.1 nonaka strncpy(savedevname, devname, MAXDEVNAME + 1); 531 1.1 nonaka default_devname = savedevname; 532 1.14 manu 533 1.14 manu /* +5 to skip leading NAME= */ 534 1.14 manu if (strstr(devname, "NAME=") == devname) 535 1.14 manu default_part_name = default_devname + 5; 536 1.1 nonaka } 537 1.1 nonaka 538 1.5 nonaka static const struct cons_devs { 539 1.5 nonaka const char *name; 540 1.5 nonaka u_int tag; 541 1.5 nonaka int ioport; 542 1.5 nonaka } cons_devs[] = { 543 1.5 nonaka { "pc", CONSDEV_PC, 0 }, 544 1.5 nonaka { "com0", CONSDEV_COM0, 0 }, 545 1.5 nonaka { "com1", CONSDEV_COM1, 0 }, 546 1.5 nonaka { "com2", CONSDEV_COM2, 0 }, 547 1.5 nonaka { "com3", CONSDEV_COM3, 0 }, 548 1.5 nonaka { "com0kbd", CONSDEV_COM0KBD, 0 }, 549 1.5 nonaka { "com1kbd", CONSDEV_COM1KBD, 0 }, 550 1.5 nonaka { "com2kbd", CONSDEV_COM2KBD, 0 }, 551 1.5 nonaka { "com3kbd", CONSDEV_COM3KBD, 0 }, 552 1.5 nonaka { "com", CONSDEV_COM0, -1 }, 553 1.5 nonaka { "auto", CONSDEV_AUTO, 0 }, 554 1.5 nonaka { NULL, 0 } 555 1.5 nonaka }; 556 1.5 nonaka 557 1.1 nonaka void 558 1.1 nonaka command_consdev(char *arg) 559 1.1 nonaka { 560 1.5 nonaka const struct cons_devs *cdp; 561 1.5 nonaka char *sep, *sep2 = NULL; 562 1.5 nonaka int ioport, speed = 0; 563 1.5 nonaka 564 1.8 nonaka if (*arg == '\0') { 565 1.8 nonaka efi_cons_show(); 566 1.8 nonaka return; 567 1.8 nonaka } 568 1.8 nonaka 569 1.5 nonaka sep = strchr(arg, ','); 570 1.5 nonaka if (sep != NULL) { 571 1.5 nonaka *sep++ = '\0'; 572 1.5 nonaka sep2 = strchr(sep, ','); 573 1.8 nonaka if (sep2 != NULL) 574 1.5 nonaka *sep2++ = '\0'; 575 1.5 nonaka } 576 1.5 nonaka 577 1.5 nonaka for (cdp = cons_devs; cdp->name; cdp++) { 578 1.5 nonaka if (strcmp(arg, cdp->name) == 0) { 579 1.5 nonaka ioport = cdp->ioport; 580 1.5 nonaka if (cdp->tag == CONSDEV_PC || cdp->tag == CONSDEV_AUTO) { 581 1.5 nonaka if (sep != NULL || sep2 != NULL) 582 1.5 nonaka goto error; 583 1.5 nonaka } else { 584 1.5 nonaka /* com? */ 585 1.5 nonaka if (ioport == -1) { 586 1.5 nonaka if (sep != NULL) { 587 1.5 nonaka u_long t = strtoul(sep, NULL, 0); 588 1.5 nonaka if (t > INT_MAX) 589 1.5 nonaka goto error; 590 1.5 nonaka ioport = (int)t; 591 1.5 nonaka } 592 1.5 nonaka if (sep2 != NULL) { 593 1.5 nonaka speed = atoi(sep2); 594 1.5 nonaka if (speed < 0) 595 1.5 nonaka goto error; 596 1.5 nonaka } 597 1.5 nonaka } else { 598 1.5 nonaka if (sep != NULL) { 599 1.5 nonaka speed = atoi(sep); 600 1.5 nonaka if (speed < 0) 601 1.5 nonaka goto error; 602 1.5 nonaka } 603 1.5 nonaka if (sep2 != NULL) 604 1.5 nonaka goto error; 605 1.5 nonaka } 606 1.5 nonaka } 607 1.16 manu efi_consinit(cdp->tag, ioport, speed); 608 1.20 nia clearit(); 609 1.20 nia print_bootcfg_banner(bootprog_name, bootprog_rev); 610 1.5 nonaka return; 611 1.5 nonaka } 612 1.5 nonaka } 613 1.5 nonaka error: 614 1.5 nonaka printf("invalid console device.\n"); 615 1.1 nonaka } 616 1.1 nonaka 617 1.18 mlelstv void 618 1.18 mlelstv command_root(char *arg) 619 1.18 mlelstv { 620 1.18 mlelstv struct btinfo_rootdevice *biv = &bi_root; 621 1.18 mlelstv 622 1.18 mlelstv strncpy(biv->devname, arg, sizeof(biv->devname)); 623 1.18 mlelstv if (biv->devname[sizeof(biv->devname)-1] != '\0') { 624 1.18 mlelstv biv->devname[sizeof(biv->devname)-1] = '\0'; 625 1.18 mlelstv printf("truncated to %s\n",biv->devname); 626 1.18 mlelstv } 627 1.18 mlelstv } 628 1.18 mlelstv 629 1.18 mlelstv 630 1.1 nonaka #ifndef SMALL 631 1.1 nonaka /* ARGSUSED */ 632 1.1 nonaka void 633 1.1 nonaka command_menu(char *arg) 634 1.1 nonaka { 635 1.1 nonaka 636 1.1 nonaka if (bootcfg_info.nummenu > 0) { 637 1.1 nonaka /* Does not return */ 638 1.1 nonaka doboottypemenu(); 639 1.1 nonaka } else 640 1.1 nonaka printf("No menu defined in boot.cfg\n"); 641 1.1 nonaka } 642 1.1 nonaka #endif /* !SMALL */ 643 1.1 nonaka 644 1.1 nonaka void 645 1.1 nonaka command_modules(char *arg) 646 1.1 nonaka { 647 1.1 nonaka 648 1.1 nonaka if (strcmp(arg, "enabled") == 0 || 649 1.1 nonaka strcmp(arg, "on") == 0) 650 1.1 nonaka boot_modules_enabled = true; 651 1.1 nonaka else if (strcmp(arg, "disabled") == 0 || 652 1.1 nonaka strcmp(arg, "off") == 0) 653 1.1 nonaka boot_modules_enabled = false; 654 1.1 nonaka else 655 1.1 nonaka printf("invalid flag, must be 'enabled' or 'disabled'.\n"); 656 1.1 nonaka } 657 1.1 nonaka 658 1.1 nonaka void 659 1.1 nonaka command_multiboot(char *arg) 660 1.1 nonaka { 661 1.1 nonaka char *filename; 662 1.1 nonaka 663 1.1 nonaka filename = arg; 664 1.1 nonaka if (exec_multiboot(filename, gettrailer(arg)) < 0) 665 1.1 nonaka printf("multiboot: %s: %s\n", sprint_bootsel(filename), 666 1.1 nonaka strerror(errno)); 667 1.1 nonaka else 668 1.1 nonaka printf("boot returned\n"); 669 1.1 nonaka } 670 1.1 nonaka 671 1.1 nonaka void 672 1.22 manu command_reloc(char *arg) 673 1.22 manu { 674 1.22 manu char *ep; 675 1.23 riastrad 676 1.22 manu if (*arg == '\0') { 677 1.22 manu switch (efi_reloc_type) { 678 1.22 manu case RELOC_NONE: 679 1.22 manu printf("reloc: none\n"); 680 1.22 manu break; 681 1.22 manu case RELOC_ADDR: 682 1.22 manu printf("reloc: %p\n", (void *)efi_kernel_reloc); 683 1.22 manu break; 684 1.22 manu case RELOC_DEFAULT: 685 1.22 manu default: 686 1.22 manu printf("reloc: default\n"); 687 1.22 manu break; 688 1.22 manu } 689 1.22 manu goto out; 690 1.22 manu } 691 1.22 manu 692 1.22 manu if (strcmp(arg, "default") == 0) { 693 1.22 manu efi_reloc_type = RELOC_DEFAULT; 694 1.22 manu goto out; 695 1.22 manu } 696 1.22 manu 697 1.22 manu if (strcmp(arg, "none") == 0) { 698 1.22 manu efi_reloc_type = RELOC_NONE; 699 1.22 manu goto out; 700 1.22 manu } 701 1.22 manu 702 1.22 manu errno = 0; 703 1.22 manu efi_kernel_reloc = strtoul(arg, &ep, 0); 704 1.22 manu if (ep == arg || *ep != '\0' || errno) 705 1.22 manu printf("could not parse address \"%s\"\n", arg); 706 1.22 manu else 707 1.22 manu efi_reloc_type = RELOC_ADDR; 708 1.22 manu out: 709 1.22 manu return; 710 1.22 manu 711 1.22 manu } 712 1.22 manu 713 1.22 manu void 714 1.1 nonaka command_version(char *arg) 715 1.1 nonaka { 716 1.6 nonaka CHAR16 *path; 717 1.8 nonaka char *upath, *ufirmware; 718 1.8 nonaka int rv; 719 1.1 nonaka 720 1.1 nonaka if (strcmp(arg, "full") == 0) { 721 1.1 nonaka printf("ImageBase: 0x%" PRIxPTR "\n", 722 1.1 nonaka (uintptr_t)efi_li->ImageBase); 723 1.1 nonaka printf("Stack: 0x%" PRIxPTR "\n", efi_main_sp); 724 1.1 nonaka printf("EFI version: %d.%02d\n", 725 1.1 nonaka ST->Hdr.Revision >> 16, ST->Hdr.Revision & 0xffff); 726 1.8 nonaka ufirmware = NULL; 727 1.8 nonaka rv = ucs2_to_utf8(ST->FirmwareVendor, &ufirmware); 728 1.8 nonaka if (rv == 0) { 729 1.8 nonaka printf("EFI Firmware: %s (rev %d.%02d)\n", ufirmware, 730 1.8 nonaka ST->FirmwareRevision >> 16, 731 1.8 nonaka ST->FirmwareRevision & 0xffff); 732 1.8 nonaka FreePool(ufirmware); 733 1.8 nonaka } 734 1.6 nonaka path = DevicePathToStr(efi_bootdp); 735 1.8 nonaka upath = NULL; 736 1.8 nonaka rv = ucs2_to_utf8(path, &upath); 737 1.6 nonaka FreePool(path); 738 1.8 nonaka if (rv == 0) { 739 1.8 nonaka printf("Boot DevicePath: %d:%d:%s\n", 740 1.8 nonaka DevicePathType(efi_bootdp), 741 1.8 nonaka DevicePathSubType(efi_bootdp), upath); 742 1.8 nonaka FreePool(upath); 743 1.8 nonaka } 744 1.1 nonaka } 745 1.1 nonaka 746 1.1 nonaka printf("\n" 747 1.1 nonaka ">> %s, Revision %s (from NetBSD %s)\n" 748 1.1 nonaka ">> Memory: %d/%d k\n", 749 1.1 nonaka bootprog_name, bootprog_rev, bootprog_kernrev, 750 1.1 nonaka getbasemem(), getextmem()); 751 1.1 nonaka } 752 1.1 nonaka 753 1.1 nonaka void 754 1.1 nonaka command_memmap(char *arg) 755 1.1 nonaka { 756 1.1 nonaka bool sorted = true; 757 1.13 nonaka bool compact = false; 758 1.1 nonaka 759 1.1 nonaka if (*arg == '\0' || strcmp(arg, "sorted") == 0) 760 1.1 nonaka /* Already sorted is true. */; 761 1.1 nonaka else if (strcmp(arg, "unsorted") == 0) 762 1.1 nonaka sorted = false; 763 1.13 nonaka else if (strcmp(arg, "compact") == 0) 764 1.13 nonaka compact = true; 765 1.1 nonaka else { 766 1.1 nonaka printf("invalid flag, " 767 1.13 nonaka "must be 'sorted', 'unsorted' or 'compact'.\n"); 768 1.1 nonaka return; 769 1.1 nonaka } 770 1.1 nonaka 771 1.13 nonaka efi_memory_show_map(sorted, compact); 772 1.1 nonaka } 773 1.1 nonaka 774 1.1 nonaka void 775 1.1 nonaka command_devpath(char *arg) 776 1.1 nonaka { 777 1.1 nonaka EFI_STATUS status; 778 1.1 nonaka UINTN i, nhandles; 779 1.1 nonaka EFI_HANDLE *handles; 780 1.1 nonaka EFI_DEVICE_PATH *dp0, *dp; 781 1.1 nonaka CHAR16 *path; 782 1.8 nonaka char *upath; 783 1.1 nonaka UINTN cols, rows, row = 0; 784 1.8 nonaka int rv; 785 1.1 nonaka 786 1.1 nonaka status = uefi_call_wrapper(ST->ConOut->QueryMode, 4, ST->ConOut, 787 1.1 nonaka ST->ConOut->Mode->Mode, &cols, &rows); 788 1.1 nonaka if (EFI_ERROR(status) || rows <= 2) 789 1.1 nonaka rows = 0; 790 1.1 nonaka else 791 1.1 nonaka rows -= 2; 792 1.1 nonaka 793 1.1 nonaka /* 794 1.1 nonaka * all devices. 795 1.1 nonaka */ 796 1.1 nonaka status = LibLocateHandle(ByProtocol, &DevicePathProtocol, NULL, 797 1.1 nonaka &nhandles, &handles); 798 1.1 nonaka if (EFI_ERROR(status)) 799 1.1 nonaka return; 800 1.1 nonaka 801 1.1 nonaka for (i = 0; i < nhandles; i++) { 802 1.1 nonaka status = uefi_call_wrapper(BS->HandleProtocol, 3, handles[i], 803 1.1 nonaka &DevicePathProtocol, (void **)&dp0); 804 1.1 nonaka if (EFI_ERROR(status)) 805 1.1 nonaka break; 806 1.1 nonaka 807 1.8 nonaka printf("DevicePathType %d\n", DevicePathType(dp0)); 808 1.7 nonaka if (++row >= rows) { 809 1.7 nonaka row = 0; 810 1.8 nonaka printf("Press Any Key to continue :"); 811 1.7 nonaka (void) awaitkey(-1, 0); 812 1.8 nonaka printf("\n"); 813 1.7 nonaka } 814 1.1 nonaka for (dp = dp0; 815 1.1 nonaka !IsDevicePathEnd(dp); 816 1.1 nonaka dp = NextDevicePathNode(dp)) { 817 1.8 nonaka 818 1.1 nonaka path = DevicePathToStr(dp); 819 1.8 nonaka upath = NULL; 820 1.8 nonaka rv = ucs2_to_utf8(path, &upath); 821 1.1 nonaka FreePool(path); 822 1.8 nonaka if (rv) { 823 1.8 nonaka printf("convert failed\n"); 824 1.8 nonaka break; 825 1.8 nonaka } 826 1.8 nonaka 827 1.8 nonaka printf("%d:%d:%s\n", DevicePathType(dp), 828 1.8 nonaka DevicePathSubType(dp), upath); 829 1.8 nonaka FreePool(upath); 830 1.1 nonaka 831 1.2 roy if (++row >= rows) { 832 1.1 nonaka row = 0; 833 1.8 nonaka printf("Press Any Key to continue :"); 834 1.1 nonaka (void) awaitkey(-1, 0); 835 1.8 nonaka printf("\n"); 836 1.1 nonaka } 837 1.1 nonaka } 838 1.1 nonaka } 839 1.1 nonaka } 840 1.1 nonaka 841 1.8 nonaka 842 1.1 nonaka void 843 1.1 nonaka command_efivar(char *arg) 844 1.1 nonaka { 845 1.8 nonaka static const char header[] = 846 1.8 nonaka "GUID Variable Name Value\n" 847 1.8 nonaka "==================================== ==================== ========\n"; 848 1.1 nonaka EFI_STATUS status; 849 1.3 nonaka UINTN sz = 64, osz; 850 1.8 nonaka CHAR16 *name = NULL, *tmp, *val, guid[128]; 851 1.8 nonaka char *uname, *uval, *uguid; 852 1.1 nonaka EFI_GUID vendor; 853 1.1 nonaka UINTN cols, rows, row = 0; 854 1.8 nonaka int rv; 855 1.1 nonaka 856 1.1 nonaka status = uefi_call_wrapper(ST->ConOut->QueryMode, 4, ST->ConOut, 857 1.1 nonaka ST->ConOut->Mode->Mode, &cols, &rows); 858 1.1 nonaka if (EFI_ERROR(status) || rows <= 2) 859 1.1 nonaka rows = 0; 860 1.1 nonaka else 861 1.1 nonaka rows -= 2; 862 1.1 nonaka 863 1.1 nonaka name = AllocatePool(sz); 864 1.1 nonaka if (name == NULL) { 865 1.8 nonaka printf("memory allocation failed: %" PRIuMAX" bytes\n", 866 1.8 nonaka (uintmax_t)sz); 867 1.1 nonaka return; 868 1.1 nonaka } 869 1.1 nonaka 870 1.3 nonaka SetMem(name, sz, 0); 871 1.1 nonaka vendor = NullGuid; 872 1.1 nonaka 873 1.8 nonaka printf("%s", header); 874 1.1 nonaka for (;;) { 875 1.3 nonaka osz = sz; 876 1.1 nonaka status = uefi_call_wrapper(RT->GetNextVariableName, 3, 877 1.1 nonaka &sz, name, &vendor); 878 1.1 nonaka if (EFI_ERROR(status)) { 879 1.1 nonaka if (status == EFI_NOT_FOUND) 880 1.1 nonaka break; 881 1.1 nonaka if (status != EFI_BUFFER_TOO_SMALL) { 882 1.8 nonaka printf("GetNextVariableName failed: %" PRIxMAX "\n", 883 1.8 nonaka (uintmax_t)status); 884 1.1 nonaka break; 885 1.1 nonaka } 886 1.1 nonaka 887 1.1 nonaka tmp = AllocatePool(sz); 888 1.1 nonaka if (tmp == NULL) { 889 1.8 nonaka printf("memory allocation failed: %" PRIuMAX 890 1.8 nonaka "bytes\n", (uintmax_t)sz); 891 1.1 nonaka break; 892 1.1 nonaka } 893 1.3 nonaka SetMem(tmp, sz, 0); 894 1.3 nonaka CopyMem(tmp, name, osz); 895 1.1 nonaka FreePool(name); 896 1.1 nonaka name = tmp; 897 1.3 nonaka continue; 898 1.1 nonaka } 899 1.1 nonaka 900 1.1 nonaka val = LibGetVariable(name, &vendor); 901 1.8 nonaka if (val != NULL) { 902 1.8 nonaka uval = NULL; 903 1.8 nonaka rv = ucs2_to_utf8(val, &uval); 904 1.8 nonaka FreePool(val); 905 1.8 nonaka if (rv) { 906 1.8 nonaka printf("value convert failed\n"); 907 1.8 nonaka break; 908 1.8 nonaka } 909 1.8 nonaka } else 910 1.8 nonaka uval = NULL; 911 1.8 nonaka uname = NULL; 912 1.8 nonaka rv = ucs2_to_utf8(name, &uname); 913 1.8 nonaka if (rv) { 914 1.8 nonaka printf("name convert failed\n"); 915 1.8 nonaka FreePool(uval); 916 1.8 nonaka break; 917 1.8 nonaka } 918 1.8 nonaka GuidToString(guid, &vendor); 919 1.8 nonaka uguid = NULL; 920 1.8 nonaka rv = ucs2_to_utf8(guid, &uguid); 921 1.8 nonaka if (rv) { 922 1.8 nonaka printf("GUID convert failed\n"); 923 1.8 nonaka FreePool(uval); 924 1.8 nonaka FreePool(uname); 925 1.8 nonaka break; 926 1.8 nonaka } 927 1.8 nonaka printf("%-35s %-20s %s\n", uguid, uname, uval ? uval : "(null)"); 928 1.8 nonaka FreePool(uguid); 929 1.8 nonaka FreePool(uname); 930 1.8 nonaka if (uval != NULL) 931 1.8 nonaka FreePool(uval); 932 1.1 nonaka 933 1.2 roy if (++row >= rows) { 934 1.1 nonaka row = 0; 935 1.8 nonaka printf("Press Any Key to continue :"); 936 1.1 nonaka (void) awaitkey(-1, 0); 937 1.8 nonaka printf("\n"); 938 1.1 nonaka } 939 1.1 nonaka } 940 1.1 nonaka 941 1.1 nonaka FreePool(name); 942 1.1 nonaka } 943