1 /* $NetBSD: boot.c,v 1.27 2020/06/28 11:39:50 jmcneill Exp $ */ 2 3 /*- 4 * Copyright (c) 2016 Kimihiro Nonaka <nonaka@netbsd.org> 5 * Copyright (c) 2018 Jared McNeill <jmcneill@invisible.ca> 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30 #include "efiboot.h" 31 #include "efiblock.h" 32 #include "efifile.h" 33 #include "efifdt.h" 34 #include "efiacpi.h" 35 #include "efirng.h" 36 #include "module.h" 37 #include "overlay.h" 38 #include "bootmenu.h" 39 40 #include <sys/bootblock.h> 41 #include <sys/boot_flag.h> 42 #include <machine/limits.h> 43 44 #include <loadfile.h> 45 #include <bootcfg.h> 46 47 extern const char bootprog_name[], bootprog_rev[], bootprog_kernrev[]; 48 49 extern char twiddle_toggle; 50 51 static const char * const names[] = { 52 "netbsd", "netbsd.gz", 53 "onetbsd", "onetbsd.gz", 54 "netbsd.old", "netbsd.old.gz", 55 }; 56 57 #define NUMNAMES __arraycount(names) 58 59 static const char *efi_memory_type[] = { 60 [EfiReservedMemoryType] = "Reserved Memory Type", 61 [EfiLoaderCode] = "Loader Code", 62 [EfiLoaderData] = "Loader Data", 63 [EfiBootServicesCode] = "Boot Services Code", 64 [EfiBootServicesData] = "Boot Services Data", 65 [EfiRuntimeServicesCode] = "Runtime Services Code", 66 [EfiRuntimeServicesData] = "Runtime Services Data", 67 [EfiConventionalMemory] = "Conventional Memory", 68 [EfiUnusableMemory] = "Unusable Memory", 69 [EfiACPIReclaimMemory] = "ACPI Reclaim Memory", 70 [EfiACPIMemoryNVS] = "ACPI Memory NVS", 71 [EfiMemoryMappedIO] = "MMIO", 72 [EfiMemoryMappedIOPortSpace] = "MMIO (Port Space)", 73 [EfiPalCode] = "Pal Code", 74 [EfiPersistentMemory] = "Persistent Memory", 75 }; 76 77 static char default_device[32]; 78 static char initrd_path[255]; 79 static char dtb_path[255]; 80 static char netbsd_path[255]; 81 static char netbsd_args[255]; 82 static char rndseed_path[255]; 83 84 #define DEFTIMEOUT 5 85 #define DEFFILENAME names[0] 86 87 int set_bootfile(const char *); 88 int set_bootargs(const char *); 89 90 void command_boot(char *); 91 void command_dev(char *); 92 void command_dtb(char *); 93 void command_initrd(char *); 94 void command_rndseed(char *); 95 void command_dtoverlay(char *); 96 void command_dtoverlays(char *); 97 void command_modules(char *); 98 void command_load(char *); 99 void command_unload(char *); 100 void command_ls(char *); 101 void command_mem(char *); 102 void command_menu(char *); 103 void command_reset(char *); 104 void command_version(char *); 105 void command_quit(char *); 106 107 const struct boot_command commands[] = { 108 { "boot", command_boot, "boot [dev:][filename] [args]\n (ex. \"hd0a:\\netbsd.old -s\"" }, 109 { "dev", command_dev, "dev" }, 110 { "dtb", command_dtb, "dtb [dev:][filename]" }, 111 { "initrd", command_initrd, "initrd [dev:][filename]" }, 112 { "rndseed", command_rndseed, "rndseed [dev:][filename]" }, 113 { "dtoverlay", command_dtoverlay, "dtoverlay [dev:][filename]" }, 114 { "dtoverlays", command_dtoverlays, "dtoverlays [{on|off|reset}]" }, 115 { "modules", command_modules, "modules [{on|off|reset}]" }, 116 { "load", command_load, "load <module_name>" }, 117 { "unload", command_unload, "unload <module_name>" }, 118 { "ls", command_ls, "ls [hdNn:/path]" }, 119 { "mem", command_mem, "mem" }, 120 { "menu", command_menu, "menu" }, 121 { "reboot", command_reset, "reboot|reset" }, 122 { "reset", command_reset, NULL }, 123 { "version", command_version, "version" }, 124 { "ver", command_version, NULL }, 125 { "help", command_help, "help|?" }, 126 { "?", command_help, NULL }, 127 { "quit", command_quit, "quit" }, 128 { NULL, NULL }, 129 }; 130 131 void 132 command_help(char *arg) 133 { 134 int n; 135 136 printf("commands are:\n"); 137 for (n = 0; commands[n].c_name; n++) { 138 if (commands[n].c_help) 139 printf("%s\n", commands[n].c_help); 140 } 141 } 142 143 void 144 command_boot(char *arg) 145 { 146 char *fname = arg; 147 const char *kernel = *fname ? fname : bootfile; 148 char *bootargs = gettrailer(arg); 149 150 if (!kernel || !*kernel) 151 kernel = DEFFILENAME; 152 153 if (!*bootargs) 154 bootargs = netbsd_args; 155 156 exec_netbsd(kernel, bootargs); 157 } 158 159 void 160 command_dev(char *arg) 161 { 162 if (arg && *arg) { 163 set_default_device(arg); 164 } else { 165 efi_block_show(); 166 efi_net_show(); 167 } 168 169 if (strlen(default_device) > 0) { 170 printf("\n"); 171 printf("default: %s\n", default_device); 172 } 173 } 174 175 void 176 command_dtb(char *arg) 177 { 178 set_dtb_path(arg); 179 } 180 181 void 182 command_initrd(char *arg) 183 { 184 set_initrd_path(arg); 185 } 186 187 void 188 command_rndseed(char *arg) 189 { 190 set_rndseed_path(arg); 191 } 192 193 void 194 command_dtoverlays(char *arg) 195 { 196 if (arg && *arg) { 197 if (strcmp(arg, "on") == 0) 198 dtoverlay_enable(1); 199 else if (strcmp(arg, "off") == 0) 200 dtoverlay_enable(0); 201 else if (strcmp(arg, "reset") == 0) 202 dtoverlay_remove_all(); 203 else { 204 command_help(""); 205 return; 206 } 207 } else { 208 printf("Device Tree overlays are %sabled\n", 209 dtoverlay_enabled ? "en" : "dis"); 210 } 211 } 212 213 void 214 command_dtoverlay(char *arg) 215 { 216 if (!arg || !*arg) { 217 command_help(""); 218 return; 219 } 220 221 dtoverlay_add(arg); 222 } 223 224 void 225 command_modules(char *arg) 226 { 227 if (arg && *arg) { 228 if (strcmp(arg, "on") == 0) 229 module_enable(1); 230 else if (strcmp(arg, "off") == 0) 231 module_enable(0); 232 else if (strcmp(arg, "reset") == 0) 233 module_remove_all(); 234 else { 235 command_help(""); 236 return; 237 } 238 } else { 239 printf("modules are %sabled\n", module_enabled ? "en" : "dis"); 240 } 241 } 242 243 void 244 command_load(char *arg) 245 { 246 if (!arg || !*arg) { 247 command_help(""); 248 return; 249 } 250 251 module_add(arg); 252 } 253 254 void 255 command_unload(char *arg) 256 { 257 if (!arg || !*arg) { 258 command_help(""); 259 return; 260 } 261 262 module_remove(arg); 263 } 264 265 void 266 command_ls(char *arg) 267 { 268 ls(arg); 269 } 270 271 void 272 command_mem(char *arg) 273 { 274 EFI_MEMORY_DESCRIPTOR *md, *memmap; 275 UINTN nentries, mapkey, descsize; 276 UINT32 descver; 277 int n; 278 279 printf("Type Start End Attributes\n"); 280 printf("---------------------- ---------------- ---------------- ----------------\n"); 281 memmap = LibMemoryMap(&nentries, &mapkey, &descsize, &descver); 282 for (n = 0, md = memmap; n < nentries; n++, md = NextMemoryDescriptor(md, descsize)) { 283 const char *mem_type = "<unknown>"; 284 if (md->Type < __arraycount(efi_memory_type)) 285 mem_type = efi_memory_type[md->Type]; 286 287 printf("%-22s %016" PRIx64 " %016" PRIx64 " %016" PRIx64 "\n", 288 mem_type, md->PhysicalStart, md->PhysicalStart + (md->NumberOfPages * EFI_PAGE_SIZE) - 1, 289 md->Attribute); 290 } 291 } 292 293 void 294 command_menu(char *arg) 295 { 296 if (bootcfg_info.nummenu == 0) { 297 printf("No menu defined in boot.cfg\n"); 298 return; 299 } 300 301 doboottypemenu(); /* Does not return */ 302 } 303 304 void 305 command_version(char *arg) 306 { 307 char pathbuf[80]; 308 char *ufirmware; 309 int rv; 310 311 printf("Version: %s (%s)\n", bootprog_rev, bootprog_kernrev); 312 printf("EFI: %d.%02d\n", 313 ST->Hdr.Revision >> 16, ST->Hdr.Revision & 0xffff); 314 ufirmware = NULL; 315 rv = ucs2_to_utf8(ST->FirmwareVendor, &ufirmware); 316 if (rv == 0) { 317 printf("Firmware: %s (rev 0x%x)\n", ufirmware, 318 ST->FirmwareRevision); 319 FreePool(ufirmware); 320 } 321 if (efi_bootdp != NULL && 322 efi_file_path(efi_bootdp, BOOTCFG_FILENAME, pathbuf, sizeof(pathbuf)) == 0) { 323 printf("Config path: %s\n", pathbuf); 324 } 325 326 efi_fdt_show(); 327 efi_acpi_show(); 328 efi_rng_show(); 329 } 330 331 void 332 command_quit(char *arg) 333 { 334 efi_exit(); 335 } 336 337 void 338 command_reset(char *arg) 339 { 340 efi_reboot(); 341 } 342 343 int 344 set_default_device(const char *arg) 345 { 346 if (strlen(arg) + 1 > sizeof(default_device)) 347 return ERANGE; 348 strcpy(default_device, arg); 349 return 0; 350 } 351 352 char * 353 get_default_device(void) 354 { 355 return default_device; 356 } 357 358 int 359 set_initrd_path(const char *arg) 360 { 361 if (strlen(arg) + 1 > sizeof(initrd_path)) 362 return ERANGE; 363 strcpy(initrd_path, arg); 364 return 0; 365 } 366 367 char * 368 get_initrd_path(void) 369 { 370 return initrd_path; 371 } 372 373 int 374 set_dtb_path(const char *arg) 375 { 376 if (strlen(arg) + 1 > sizeof(dtb_path)) 377 return ERANGE; 378 strcpy(dtb_path, arg); 379 return 0; 380 } 381 382 char * 383 get_dtb_path(void) 384 { 385 return dtb_path; 386 } 387 388 int 389 set_rndseed_path(const char *arg) 390 { 391 if (strlen(arg) + 1 > sizeof(rndseed_path)) 392 return ERANGE; 393 strcpy(rndseed_path, arg); 394 return 0; 395 } 396 397 char * 398 get_rndseed_path(void) 399 { 400 return rndseed_path; 401 } 402 403 int 404 set_bootfile(const char *arg) 405 { 406 if (strlen(arg) + 1 > sizeof(netbsd_path)) 407 return ERANGE; 408 strcpy(netbsd_path, arg); 409 return 0; 410 } 411 412 int 413 set_bootargs(const char *arg) 414 { 415 if (strlen(arg) + 1 > sizeof(netbsd_args)) 416 return ERANGE; 417 strcpy(netbsd_args, arg); 418 return 0; 419 } 420 421 void 422 print_banner(void) 423 { 424 printf("\n\n" 425 ">> %s, Revision %s\n", 426 bootprog_name, bootprog_rev); 427 } 428 429 void 430 boot(void) 431 { 432 char pathbuf[80]; 433 int currname, c; 434 435 if (efi_bootdp != NULL && efi_file_path(efi_bootdp, BOOTCFG_FILENAME, pathbuf, sizeof(pathbuf)) == 0) { 436 twiddle_toggle = 1; 437 parsebootconf(pathbuf); 438 } 439 440 if (bootcfg_info.clear) 441 uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut); 442 443 print_banner(); 444 445 /* Display menu if configured */ 446 if (bootcfg_info.nummenu > 0) { 447 doboottypemenu(); /* No return */ 448 } 449 450 printf("Press return to boot now, any other key for boot prompt\n"); 451 452 if (netbsd_path[0] != '\0') 453 currname = -1; 454 else 455 currname = 0; 456 457 for (; currname < (int)NUMNAMES; currname++) { 458 if (currname >= 0) 459 set_bootfile(names[currname]); 460 printf("booting %s%s%s - starting in ", netbsd_path, 461 netbsd_args[0] != '\0' ? " " : "", netbsd_args); 462 463 c = awaitkey(DEFTIMEOUT, 1); 464 if (c != '\r' && c != '\n' && c != '\0') 465 bootprompt(); /* does not return */ 466 467 exec_netbsd(netbsd_path, netbsd_args); 468 } 469 470 bootprompt(); /* does not return */ 471 } 472