Home | History | Annotate | Line # | Download | only in efiboot
boot.c revision 1.24
      1 /*	$NetBSD: boot.c,v 1.24 2020/06/26 03:23:04 thorpej 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 "efifdt.h"
     33 #include "efiacpi.h"
     34 #include "efienv.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_printenv(char *);
    104 void	command_setenv(char *);
    105 void	command_clearenv(char *);
    106 void	command_resetenv(char *);
    107 void	command_reset(char *);
    108 void	command_version(char *);
    109 void	command_quit(char *);
    110 
    111 const struct boot_command commands[] = {
    112 	{ "boot",	command_boot,		"boot [dev:][filename] [args]\n     (ex. \"hd0a:\\netbsd.old -s\"" },
    113 	{ "dev",	command_dev,		"dev" },
    114 	{ "dtb",	command_dtb,		"dtb [dev:][filename]" },
    115 	{ "initrd",	command_initrd,		"initrd [dev:][filename]" },
    116 	{ "rndseed",	command_rndseed,	"rndseed [dev:][filename]" },
    117 	{ "dtoverlay",	command_dtoverlay,	"dtoverlay [dev:][filename]" },
    118 	{ "dtoverlays",	command_dtoverlays,	"dtoverlays [{on|off|reset}]" },
    119 	{ "modules",	command_modules,	"modules [{on|off|reset}]" },
    120 	{ "load",	command_load,		"load <module_name>" },
    121 	{ "unload",	command_unload,		"unload <module_name>" },
    122 	{ "ls",		command_ls,		"ls [hdNn:/path]" },
    123 	{ "mem",	command_mem,		"mem" },
    124 	{ "menu",	command_menu,		"menu" },
    125 	{ "printenv",	command_printenv,	"printenv [key]" },
    126 	{ "setenv",	command_setenv,		"setenv <key> <value>" },
    127 	{ "clearenv",	command_clearenv,	"clearenv <key>" },
    128 	{ "resetenv",	command_resetenv,	"resetenv" },
    129 	{ "reboot",	command_reset,		"reboot|reset" },
    130 	{ "reset",	command_reset,		NULL },
    131 	{ "version",	command_version,	"version" },
    132 	{ "ver",	command_version,	NULL },
    133 	{ "help",	command_help,		"help|?" },
    134 	{ "?",		command_help,		NULL },
    135 	{ "quit",	command_quit,		"quit" },
    136 	{ NULL,		NULL },
    137 };
    138 
    139 void
    140 command_help(char *arg)
    141 {
    142 	int n;
    143 
    144 	printf("commands are:\n");
    145 	for (n = 0; commands[n].c_name; n++) {
    146 		if (commands[n].c_help)
    147 			printf("%s\n", commands[n].c_help);
    148 	}
    149 }
    150 
    151 void
    152 command_boot(char *arg)
    153 {
    154 	char *fname = arg;
    155 	const char *kernel = *fname ? fname : bootfile;
    156 	char *bootargs = gettrailer(arg);
    157 
    158 	if (!kernel || !*kernel)
    159 		kernel = DEFFILENAME;
    160 
    161 	if (!*bootargs)
    162 		bootargs = netbsd_args;
    163 
    164 	exec_netbsd(kernel, bootargs);
    165 }
    166 
    167 void
    168 command_dev(char *arg)
    169 {
    170 	if (arg && *arg) {
    171 		set_default_device(arg);
    172 	} else {
    173 		efi_block_show();
    174 		efi_net_show();
    175 	}
    176 
    177 	if (strlen(default_device) > 0) {
    178 		printf("\n");
    179 		printf("default: %s\n", default_device);
    180 	}
    181 }
    182 
    183 void
    184 command_dtb(char *arg)
    185 {
    186 	set_dtb_path(arg);
    187 }
    188 
    189 void
    190 command_initrd(char *arg)
    191 {
    192 	set_initrd_path(arg);
    193 }
    194 
    195 void
    196 command_rndseed(char *arg)
    197 {
    198 	set_rndseed_path(arg);
    199 }
    200 
    201 void
    202 command_dtoverlays(char *arg)
    203 {
    204 	if (arg && *arg) {
    205 		if (strcmp(arg, "on") == 0)
    206 			dtoverlay_enable(1);
    207 		else if (strcmp(arg, "off") == 0)
    208 			dtoverlay_enable(0);
    209 		else if (strcmp(arg, "reset") == 0)
    210 			dtoverlay_remove_all();
    211 		else {
    212 			command_help("");
    213 			return;
    214 		}
    215 	} else {
    216 		printf("Device Tree overlays are %sabled\n",
    217 		    dtoverlay_enabled ? "en" : "dis");
    218 	}
    219 }
    220 
    221 void
    222 command_dtoverlay(char *arg)
    223 {
    224 	if (!arg || !*arg) {
    225 		command_help("");
    226 		return;
    227 	}
    228 
    229 	dtoverlay_add(arg);
    230 }
    231 
    232 void
    233 command_modules(char *arg)
    234 {
    235 	if (arg && *arg) {
    236 		if (strcmp(arg, "on") == 0)
    237 			module_enable(1);
    238 		else if (strcmp(arg, "off") == 0)
    239 			module_enable(0);
    240 		else if (strcmp(arg, "reset") == 0)
    241 			module_remove_all();
    242 		else {
    243 			command_help("");
    244 			return;
    245 		}
    246 	} else {
    247 		printf("modules are %sabled\n", module_enabled ? "en" : "dis");
    248 	}
    249 }
    250 
    251 void
    252 command_load(char *arg)
    253 {
    254 	if (!arg || !*arg) {
    255 		command_help("");
    256 		return;
    257 	}
    258 
    259 	module_add(arg);
    260 }
    261 
    262 void
    263 command_unload(char *arg)
    264 {
    265 	if (!arg || !*arg) {
    266 		command_help("");
    267 		return;
    268 	}
    269 
    270 	module_remove(arg);
    271 }
    272 
    273 void
    274 command_ls(char *arg)
    275 {
    276 	ls(arg);
    277 }
    278 
    279 void
    280 command_mem(char *arg)
    281 {
    282 	EFI_MEMORY_DESCRIPTOR *md, *memmap;
    283 	UINTN nentries, mapkey, descsize;
    284 	UINT32 descver;
    285 	int n;
    286 
    287 	printf("Type                    Start             End               Attributes\n");
    288 	printf("----------------------  ----------------  ----------------  ----------------\n");
    289 	memmap = LibMemoryMap(&nentries, &mapkey, &descsize, &descver);
    290 	for (n = 0, md = memmap; n < nentries; n++, md = NextMemoryDescriptor(md, descsize)) {
    291 		const char *mem_type = "<unknown>";
    292 		if (md->Type < __arraycount(efi_memory_type))
    293 			mem_type = efi_memory_type[md->Type];
    294 
    295 		printf("%-22s  %016" PRIx64 "  %016" PRIx64 "  %016" PRIx64 "\n",
    296 		    mem_type, md->PhysicalStart, md->PhysicalStart + (md->NumberOfPages * EFI_PAGE_SIZE) - 1,
    297 		    md->Attribute);
    298 	}
    299 }
    300 
    301 void
    302 command_menu(char *arg)
    303 {
    304 	if (bootcfg_info.nummenu == 0) {
    305 		printf("No menu defined in boot.cfg\n");
    306 		return;
    307 	}
    308 
    309 	doboottypemenu();	/* Does not return */
    310 }
    311 
    312 void
    313 command_printenv(char *arg)
    314 {
    315 	char *val;
    316 
    317 	if (arg && *arg) {
    318 		val = efi_env_get(arg);
    319 		if (val) {
    320 			printf("\"%s\" = \"%s\"\n", arg, val);
    321 			FreePool(val);
    322 		}
    323 	} else {
    324 		efi_env_print();
    325 	}
    326 }
    327 
    328 void
    329 command_setenv(char *arg)
    330 {
    331 	char *spc;
    332 
    333 	spc = strchr(arg, ' ');
    334 	if (spc == NULL || spc[1] == '\0') {
    335 		command_help("");
    336 		return;
    337 	}
    338 
    339 	*spc = '\0';
    340 	efi_env_set(arg, spc + 1);
    341 }
    342 
    343 void
    344 command_clearenv(char *arg)
    345 {
    346 	if (*arg == '\0') {
    347 		command_help("");
    348 		return;
    349 	}
    350 	efi_env_clear(arg);
    351 }
    352 
    353 void
    354 command_resetenv(char *arg)
    355 {
    356 	efi_env_reset();
    357 }
    358 
    359 void
    360 command_version(char *arg)
    361 {
    362 	char *ufirmware;
    363 	int rv;
    364 
    365 	printf("Version: %s (%s)\n", bootprog_rev, bootprog_kernrev);
    366 	printf("EFI: %d.%02d\n",
    367 	    ST->Hdr.Revision >> 16, ST->Hdr.Revision & 0xffff);
    368 	ufirmware = NULL;
    369 	rv = ucs2_to_utf8(ST->FirmwareVendor, &ufirmware);
    370 	if (rv == 0) {
    371 		printf("Firmware: %s (rev 0x%x)\n", ufirmware,
    372 		    ST->FirmwareRevision);
    373 		FreePool(ufirmware);
    374 	}
    375 
    376 	efi_fdt_show();
    377 	efi_acpi_show();
    378 	efi_rng_show();
    379 }
    380 
    381 void
    382 command_quit(char *arg)
    383 {
    384 	efi_exit();
    385 }
    386 
    387 void
    388 command_reset(char *arg)
    389 {
    390 	efi_reboot();
    391 }
    392 
    393 int
    394 set_default_device(const char *arg)
    395 {
    396 	if (strlen(arg) + 1 > sizeof(default_device))
    397 		return ERANGE;
    398 	strcpy(default_device, arg);
    399 	return 0;
    400 }
    401 
    402 char *
    403 get_default_device(void)
    404 {
    405 	return default_device;
    406 }
    407 
    408 int
    409 set_initrd_path(const char *arg)
    410 {
    411 	if (strlen(arg) + 1 > sizeof(initrd_path))
    412 		return ERANGE;
    413 	strcpy(initrd_path, arg);
    414 	return 0;
    415 }
    416 
    417 char *
    418 get_initrd_path(void)
    419 {
    420 	return initrd_path;
    421 }
    422 
    423 int
    424 set_dtb_path(const char *arg)
    425 {
    426 	if (strlen(arg) + 1 > sizeof(dtb_path))
    427 		return ERANGE;
    428 	strcpy(dtb_path, arg);
    429 	return 0;
    430 }
    431 
    432 char *
    433 get_dtb_path(void)
    434 {
    435 	return dtb_path;
    436 }
    437 
    438 int
    439 set_rndseed_path(const char *arg)
    440 {
    441 	if (strlen(arg) + 1 > sizeof(rndseed_path))
    442 		return ERANGE;
    443 	strcpy(rndseed_path, arg);
    444 	return 0;
    445 }
    446 
    447 char *
    448 get_rndseed_path(void)
    449 {
    450 	return rndseed_path;
    451 }
    452 
    453 int
    454 set_bootfile(const char *arg)
    455 {
    456 	if (strlen(arg) + 1 > sizeof(netbsd_path))
    457 		return ERANGE;
    458 	strcpy(netbsd_path, arg);
    459 	return 0;
    460 }
    461 
    462 int
    463 set_bootargs(const char *arg)
    464 {
    465 	if (strlen(arg) + 1 > sizeof(netbsd_args))
    466 		return ERANGE;
    467 	strcpy(netbsd_args, arg);
    468 	return 0;
    469 }
    470 
    471 void
    472 print_banner(void)
    473 {
    474 	printf("\n\n"
    475 	    ">> %s, Revision %s\n",
    476 	    bootprog_name, bootprog_rev);
    477 }
    478 
    479 static void
    480 read_env(void)
    481 {
    482 	char *s;
    483 
    484 	s = efi_env_get("fdtfile");
    485 	if (s) {
    486 #ifdef EFIBOOT_DEBUG
    487 		printf(">> Setting DTB path to '%s' from environment\n", s);
    488 #endif
    489 		set_dtb_path(s);
    490 		FreePool(s);
    491 	}
    492 
    493 	s = efi_env_get("initrd");
    494 	if (s) {
    495 #ifdef EFIBOOT_DEBUG
    496 		printf(">> Setting initrd path to '%s' from environment\n", s);
    497 #endif
    498 		set_initrd_path(s);
    499 		FreePool(s);
    500 	}
    501 
    502 	s = efi_env_get("bootfile");
    503 	if (s) {
    504 #ifdef EFIBOOT_DEBUG
    505 		printf(">> Setting bootfile path to '%s' from environment\n", s);
    506 #endif
    507 		set_bootfile(s);
    508 		FreePool(s);
    509 	}
    510 
    511 	s = efi_env_get("rootdev");
    512 	if (s) {
    513 #ifdef EFIBOOT_DEBUG
    514 		printf(">> Setting default device to '%s' from environment\n", s);
    515 #endif
    516 		set_default_device(s);
    517 		FreePool(s);
    518 	}
    519 
    520 	s = efi_env_get("bootargs");
    521 	if (s) {
    522 #ifdef EFIBOOT_DEBUG
    523 		printf(">> Setting default boot args to '%s' from environment\n", s);
    524 #endif
    525 		set_bootargs(s);
    526 		FreePool(s);
    527 	}
    528 
    529 	s = efi_env_get("rndseed");
    530 	if (s) {
    531 #ifdef EFIBOOT_DEBUG
    532 		printf(">> Setting rndseed path to '%s' from environment\n", s);
    533 #endif
    534 		set_rndseed_path(s);
    535 		FreePool(s);
    536 	}
    537 }
    538 
    539 void
    540 boot(void)
    541 {
    542 	int currname, c;
    543 
    544 	read_env();
    545 
    546 	parsebootconf(BOOTCFG_FILENAME);
    547 
    548 	if (bootcfg_info.clear)
    549 		uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut);
    550 
    551 	print_banner();
    552 
    553 	/* Display menu if configured */
    554 	twiddle_toggle = 1;
    555 	if (bootcfg_info.nummenu > 0) {
    556 		doboottypemenu();	/* No return */
    557 	}
    558 
    559 	printf("Press return to boot now, any other key for boot prompt\n");
    560 
    561 	if (netbsd_path[0] != '\0')
    562 		currname = -1;
    563 	else
    564 		currname = 0;
    565 
    566 	for (; currname < (int)NUMNAMES; currname++) {
    567 		if (currname >= 0)
    568 			set_bootfile(names[currname]);
    569 		printf("booting %s%s%s - starting in ", netbsd_path,
    570 		    netbsd_args[0] != '\0' ? " " : "", netbsd_args);
    571 
    572 		c = awaitkey(DEFTIMEOUT, 1);
    573 		if (c != '\r' && c != '\n' && c != '\0')
    574 			bootprompt(); /* does not return */
    575 
    576 		exec_netbsd(netbsd_path, netbsd_args);
    577 	}
    578 
    579 	bootprompt();	/* does not return */
    580 }
    581