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