Home | History | Annotate | Line # | Download | only in efiboot
boot.c revision 1.38
      1 /*	$NetBSD: boot.c,v 1.38 2021/10/06 10:13:19 jmcneill Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2016 Kimihiro Nonaka <nonaka (at) netbsd.org>
      5  * Copyright (c) 2018 Jared McNeill <jmcneill (at) 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 "efirng.h"
     34 #include "module.h"
     35 #include "bootmenu.h"
     36 
     37 #ifdef EFIBOOT_FDT
     38 #include "efifdt.h"
     39 #include "overlay.h"
     40 #endif
     41 
     42 #ifdef EFIBOOT_ACPI
     43 #include "efiacpi.h"
     44 #endif
     45 
     46 #include <sys/bootblock.h>
     47 #include <sys/boot_flag.h>
     48 #include <machine/limits.h>
     49 
     50 #include <loadfile.h>
     51 #include <bootcfg.h>
     52 
     53 extern const char bootprog_name[], bootprog_rev[], bootprog_kernrev[];
     54 
     55 extern char twiddle_toggle;
     56 
     57 static const char * const names[] = {
     58 	"netbsd", "netbsd.gz",
     59 	"onetbsd", "onetbsd.gz",
     60 	"netbsd.old", "netbsd.old.gz",
     61 };
     62 
     63 #define NUMNAMES	__arraycount(names)
     64 
     65 static const char *efi_memory_type[] = {
     66         [EfiReservedMemoryType]         = "Reserved Memory Type",
     67         [EfiLoaderCode]                 = "Loader Code",
     68         [EfiLoaderData]                 = "Loader Data",
     69         [EfiBootServicesCode]           = "Boot Services Code",
     70         [EfiBootServicesData]           = "Boot Services Data",
     71         [EfiRuntimeServicesCode]        = "Runtime Services Code",
     72         [EfiRuntimeServicesData]        = "Runtime Services Data",
     73         [EfiConventionalMemory]         = "Conventional Memory",
     74         [EfiUnusableMemory]             = "Unusable Memory",
     75         [EfiACPIReclaimMemory]          = "ACPI Reclaim Memory",
     76         [EfiACPIMemoryNVS]              = "ACPI Memory NVS",
     77         [EfiMemoryMappedIO]             = "MMIO",
     78         [EfiMemoryMappedIOPortSpace]    = "MMIO (Port Space)",
     79         [EfiPalCode]                    = "Pal Code",
     80         [EfiPersistentMemory]           = "Persistent Memory",
     81 };
     82 
     83 static char default_device[32];
     84 static int default_fstype = FS_UNUSED;
     85 static char initrd_path[255];
     86 static char dtb_path[255];
     87 static char netbsd_path[255];
     88 static char netbsd_args[255];
     89 static char rndseed_path[255];
     90 
     91 #define	DEFTIMEOUT	5
     92 #define DEFFILENAME	names[0]
     93 
     94 int	set_bootfile(const char *);
     95 int	set_bootargs(const char *);
     96 
     97 void	command_boot(char *);
     98 void	command_dev(char *);
     99 void	command_initrd(char *);
    100 void	command_rndseed(char *);
    101 #ifdef EFIBOOT_FDT
    102 void	command_dtb(char *);
    103 void	command_dtoverlay(char *);
    104 void	command_dtoverlays(char *);
    105 #endif
    106 void	command_modules(char *);
    107 void	command_load(char *);
    108 void	command_unload(char *);
    109 void	command_ls(char *);
    110 void	command_gop(char *);
    111 void	command_mem(char *);
    112 void	command_menu(char *);
    113 void	command_reset(char *);
    114 void	command_version(char *);
    115 void	command_quit(char *);
    116 
    117 const struct boot_command commands[] = {
    118 	{ "boot",	command_boot,		"boot [dev:][filename] [args]\n     (ex. \"hd0a:\\netbsd.old -s\"" },
    119 	{ "dev",	command_dev,		"dev" },
    120 #ifdef EFIBOOT_FDT
    121 	{ "dtb",	command_dtb,		"dtb [dev:][filename]" },
    122 	{ "dtoverlay",	command_dtoverlay,	"dtoverlay [dev:][filename]" },
    123 	{ "dtoverlays",	command_dtoverlays,	"dtoverlays [{on|off|reset}]" },
    124 #endif
    125 	{ "initrd",	command_initrd,		"initrd [dev:][filename]" },
    126 	{ "fs",		command_initrd,		NULL },
    127 	{ "rndseed",	command_rndseed,	"rndseed [dev:][filename]" },
    128 	{ "modules",	command_modules,	"modules [{on|off|reset}]" },
    129 	{ "load",	command_load,		"load <module_name>" },
    130 	{ "unload",	command_unload,		"unload <module_name>" },
    131 	{ "ls",		command_ls,		"ls [hdNn:/path]" },
    132 	{ "gop",	command_gop,		"gop [mode]" },
    133 	{ "mem",	command_mem,		"mem" },
    134 	{ "menu",	command_menu,		"menu" },
    135 	{ "reboot",	command_reset,		"reboot|reset" },
    136 	{ "reset",	command_reset,		NULL },
    137 	{ "version",	command_version,	"version" },
    138 	{ "ver",	command_version,	NULL },
    139 	{ "help",	command_help,		"help|?" },
    140 	{ "?",		command_help,		NULL },
    141 	{ "quit",	command_quit,		"quit" },
    142 	{ NULL,		NULL },
    143 };
    144 
    145 static int
    146 bootcfg_path(char *pathbuf, size_t pathbuflen)
    147 {
    148 
    149 	/*
    150 	 * Fallback to default_device
    151 	 * - for ISO9660 (efi_file_path() succeeds but does not work correctly)
    152 	 * - or whenever efi_file_path() fails (due to broken firmware)
    153 	 */
    154 	if (default_fstype == FS_ISO9660 || efi_bootdp == NULL ||
    155 	    efi_file_path(efi_bootdp, BOOTCFG_FILENAME, pathbuf, pathbuflen))
    156 		snprintf(pathbuf, pathbuflen, "%s:%s", default_device,
    157 		    BOOTCFG_FILENAME);
    158 
    159 	return 0;
    160 }
    161 
    162 void
    163 command_help(char *arg)
    164 {
    165 	int n;
    166 
    167 	printf("commands are:\n");
    168 	for (n = 0; commands[n].c_name; n++) {
    169 		if (commands[n].c_help)
    170 			printf("%s\n", commands[n].c_help);
    171 	}
    172 }
    173 
    174 void
    175 command_boot(char *arg)
    176 {
    177 	char *fname = arg;
    178 	const char *kernel = *fname ? fname : bootfile;
    179 	char *bootargs = gettrailer(arg);
    180 
    181 	if (!kernel || !*kernel)
    182 		kernel = DEFFILENAME;
    183 
    184 	if (!*bootargs)
    185 		bootargs = netbsd_args;
    186 
    187 	efi_block_set_readahead(true);
    188 	exec_netbsd(kernel, bootargs);
    189 	efi_block_set_readahead(false);
    190 }
    191 
    192 void
    193 command_dev(char *arg)
    194 {
    195 	if (arg && *arg) {
    196 		set_default_device(arg);
    197 	} else {
    198 		efi_block_show();
    199 		efi_net_show();
    200 	}
    201 
    202 	if (strlen(default_device) > 0) {
    203 		printf("\n");
    204 		printf("default: %s\n", default_device);
    205 	}
    206 }
    207 
    208 void
    209 command_initrd(char *arg)
    210 {
    211 	set_initrd_path(arg);
    212 }
    213 
    214 void
    215 command_rndseed(char *arg)
    216 {
    217 	set_rndseed_path(arg);
    218 }
    219 
    220 #ifdef EFIBOOT_FDT
    221 void
    222 command_dtb(char *arg)
    223 {
    224 	set_dtb_path(arg);
    225 }
    226 
    227 void
    228 command_dtoverlays(char *arg)
    229 {
    230 	if (arg && *arg) {
    231 		if (strcmp(arg, "on") == 0)
    232 			dtoverlay_enable(1);
    233 		else if (strcmp(arg, "off") == 0)
    234 			dtoverlay_enable(0);
    235 		else if (strcmp(arg, "reset") == 0)
    236 			dtoverlay_remove_all();
    237 		else {
    238 			command_help("");
    239 			return;
    240 		}
    241 	} else {
    242 		printf("Device Tree overlays are %sabled\n",
    243 		    dtoverlay_enabled ? "en" : "dis");
    244 	}
    245 }
    246 
    247 void
    248 command_dtoverlay(char *arg)
    249 {
    250 	if (!arg || !*arg) {
    251 		command_help("");
    252 		return;
    253 	}
    254 
    255 	dtoverlay_add(arg);
    256 }
    257 #endif
    258 
    259 void
    260 command_modules(char *arg)
    261 {
    262 	if (arg && *arg) {
    263 		if (strcmp(arg, "on") == 0)
    264 			module_enable(1);
    265 		else if (strcmp(arg, "off") == 0)
    266 			module_enable(0);
    267 		else if (strcmp(arg, "reset") == 0)
    268 			module_remove_all();
    269 		else {
    270 			command_help("");
    271 			return;
    272 		}
    273 	} else {
    274 		printf("modules are %sabled\n", module_enabled ? "en" : "dis");
    275 	}
    276 }
    277 
    278 void
    279 command_load(char *arg)
    280 {
    281 	if (!arg || !*arg) {
    282 		command_help("");
    283 		return;
    284 	}
    285 
    286 	module_add(arg);
    287 }
    288 
    289 void
    290 command_unload(char *arg)
    291 {
    292 	if (!arg || !*arg) {
    293 		command_help("");
    294 		return;
    295 	}
    296 
    297 	module_remove(arg);
    298 }
    299 
    300 void
    301 command_ls(char *arg)
    302 {
    303 	ls(arg);
    304 }
    305 
    306 void
    307 command_gop(char *arg)
    308 {
    309 	UINT32 mode;
    310 
    311 	if (!arg || !*arg) {
    312 		efi_gop_dump();
    313 		return;
    314 	}
    315 
    316 	mode = atoi(arg);
    317 	efi_gop_setmode(mode);
    318 }
    319 
    320 void
    321 command_mem(char *arg)
    322 {
    323 	EFI_MEMORY_DESCRIPTOR *md, *memmap;
    324 	UINTN nentries, mapkey, descsize;
    325 	UINT32 descver;
    326 	int n;
    327 
    328 	printf("Type                    Start             End               Attributes\n");
    329 	printf("----------------------  ----------------  ----------------  ----------------\n");
    330 	memmap = LibMemoryMap(&nentries, &mapkey, &descsize, &descver);
    331 	for (n = 0, md = memmap; n < nentries; n++, md = NextMemoryDescriptor(md, descsize)) {
    332 		const char *mem_type = "<unknown>";
    333 		if (md->Type < __arraycount(efi_memory_type))
    334 			mem_type = efi_memory_type[md->Type];
    335 
    336 		printf("%-22s  %016" PRIx64 "  %016" PRIx64 "  %016" PRIx64 "\n",
    337 		    mem_type, md->PhysicalStart, md->PhysicalStart + (md->NumberOfPages * EFI_PAGE_SIZE) - 1,
    338 		    md->Attribute);
    339 	}
    340 }
    341 
    342 void
    343 command_menu(char *arg)
    344 {
    345 	if (bootcfg_info.nummenu == 0) {
    346 		printf("No menu defined in boot.cfg\n");
    347 		return;
    348 	}
    349 
    350 	doboottypemenu();	/* Does not return */
    351 }
    352 
    353 void
    354 command_version(char *arg)
    355 {
    356 	char pathbuf[80];
    357 	char *ufirmware;
    358 	int rv;
    359 
    360 	printf("Version: %s (%s)\n", bootprog_rev, bootprog_kernrev);
    361 	printf("EFI: %d.%02d\n",
    362 	    ST->Hdr.Revision >> 16, ST->Hdr.Revision & 0xffff);
    363 	ufirmware = NULL;
    364 	rv = ucs2_to_utf8(ST->FirmwareVendor, &ufirmware);
    365 	if (rv == 0) {
    366 		printf("Firmware: %s (rev 0x%x)\n", ufirmware,
    367 		    ST->FirmwareRevision);
    368 		FreePool(ufirmware);
    369 	}
    370 	if (bootcfg_path(pathbuf, sizeof(pathbuf)) == 0) {
    371 		printf("Config path: %s\n", pathbuf);
    372 	}
    373 
    374 #ifdef EFIBOOT_FDT
    375 	efi_fdt_show();
    376 #endif
    377 #ifdef EFIBOOT_ACPI
    378 	efi_acpi_show();
    379 #endif
    380 	efi_rng_show();
    381 	efi_md_show();
    382 	efi_gop_show();
    383 }
    384 
    385 void
    386 command_quit(char *arg)
    387 {
    388 	efi_exit();
    389 }
    390 
    391 void
    392 command_reset(char *arg)
    393 {
    394 	efi_reboot();
    395 }
    396 
    397 int
    398 set_default_device(const char *arg)
    399 {
    400 	if (strlen(arg) + 1 > sizeof(default_device))
    401 		return ERANGE;
    402 	strcpy(default_device, arg);
    403 	return 0;
    404 }
    405 
    406 char *
    407 get_default_device(void)
    408 {
    409 	return default_device;
    410 }
    411 
    412 void
    413 set_default_fstype(int fstype)
    414 {
    415 	default_fstype = fstype;
    416 }
    417 
    418 int
    419 get_default_fstype(void)
    420 {
    421 	return default_fstype;
    422 }
    423 
    424 int
    425 set_initrd_path(const char *arg)
    426 {
    427 	if (strlen(arg) + 1 > sizeof(initrd_path))
    428 		return ERANGE;
    429 	strcpy(initrd_path, arg);
    430 	return 0;
    431 }
    432 
    433 char *
    434 get_initrd_path(void)
    435 {
    436 	return initrd_path;
    437 }
    438 
    439 int
    440 set_dtb_path(const char *arg)
    441 {
    442 	if (strlen(arg) + 1 > sizeof(dtb_path))
    443 		return ERANGE;
    444 	strcpy(dtb_path, arg);
    445 	return 0;
    446 }
    447 
    448 char *
    449 get_dtb_path(void)
    450 {
    451 	return dtb_path;
    452 }
    453 
    454 int
    455 set_rndseed_path(const char *arg)
    456 {
    457 	if (strlen(arg) + 1 > sizeof(rndseed_path))
    458 		return ERANGE;
    459 	strcpy(rndseed_path, arg);
    460 	return 0;
    461 }
    462 
    463 char *
    464 get_rndseed_path(void)
    465 {
    466 	return rndseed_path;
    467 }
    468 
    469 int
    470 set_bootfile(const char *arg)
    471 {
    472 	if (strlen(arg) + 1 > sizeof(netbsd_path))
    473 		return ERANGE;
    474 	strcpy(netbsd_path, arg);
    475 	return 0;
    476 }
    477 
    478 int
    479 set_bootargs(const char *arg)
    480 {
    481 	if (strlen(arg) + 1 > sizeof(netbsd_args))
    482 		return ERANGE;
    483 	strcpy(netbsd_args, arg);
    484 	return 0;
    485 }
    486 
    487 void
    488 boot(void)
    489 {
    490 	char pathbuf[80];
    491 	int currname, c;
    492 
    493 	if (bootcfg_path(pathbuf, sizeof(pathbuf)) == 0) {
    494 		twiddle_toggle = 1;
    495 		parsebootconf(pathbuf);
    496 	}
    497 
    498 	if (bootcfg_info.clear)
    499 		uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut);
    500 
    501 	print_bootcfg_banner(bootprog_name, bootprog_rev);
    502 
    503 	/* Display menu if configured */
    504 	if (bootcfg_info.nummenu > 0) {
    505 		doboottypemenu();	/* No return */
    506 	}
    507 
    508 	printf("Press return to boot now, any other key for boot prompt\n");
    509 
    510 	if (netbsd_path[0] != '\0')
    511 		currname = -1;
    512 	else
    513 		currname = 0;
    514 
    515 	for (; currname < (int)NUMNAMES; currname++) {
    516 		if (currname >= 0)
    517 			set_bootfile(names[currname]);
    518 		printf("booting %s%s%s - starting in ", netbsd_path,
    519 		    netbsd_args[0] != '\0' ? " " : "", netbsd_args);
    520 
    521 		c = awaitkey(DEFTIMEOUT, 1);
    522 		if (c != '\r' && c != '\n' && c != '\0')
    523 			bootprompt(); /* does not return */
    524 
    525 		efi_block_set_readahead(true);
    526 		exec_netbsd(netbsd_path, netbsd_args);
    527 		efi_block_set_readahead(false);
    528 	}
    529 
    530 	bootprompt();	/* does not return */
    531 }
    532