Home | History | Annotate | Line # | Download | only in efiboot
boot.c revision 1.19.2.1
      1 /*	$NetBSD: boot.c,v 1.19.2.1 2020/01/25 22:38:52 ad 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 
     36 #include <sys/bootblock.h>
     37 #include <sys/boot_flag.h>
     38 #include <machine/limits.h>
     39 
     40 #include <loadfile.h>
     41 
     42 extern const char bootprog_name[], bootprog_rev[], bootprog_kernrev[];
     43 
     44 extern char twiddle_toggle;
     45 
     46 static const char * const names[] = {
     47 	"netbsd", "netbsd.gz",
     48 	"onetbsd", "onetbsd.gz",
     49 	"netbsd.old", "netbsd.old.gz",
     50 };
     51 
     52 #define NUMNAMES	__arraycount(names)
     53 
     54 static const char *efi_memory_type[] = {
     55         [EfiReservedMemoryType]         = "Reserved Memory Type",
     56         [EfiLoaderCode]                 = "Loader Code",
     57         [EfiLoaderData]                 = "Loader Data",
     58         [EfiBootServicesCode]           = "Boot Services Code",
     59         [EfiBootServicesData]           = "Boot Services Data",
     60         [EfiRuntimeServicesCode]        = "Runtime Services Code",
     61         [EfiRuntimeServicesData]        = "Runtime Services Data",
     62         [EfiConventionalMemory]         = "Conventional Memory",
     63         [EfiUnusableMemory]             = "Unusable Memory",
     64         [EfiACPIReclaimMemory]          = "ACPI Reclaim Memory",
     65         [EfiACPIMemoryNVS]              = "ACPI Memory NVS",
     66         [EfiMemoryMappedIO]             = "MMIO",
     67         [EfiMemoryMappedIOPortSpace]    = "MMIO (Port Space)",
     68         [EfiPalCode]                    = "Pal Code",
     69         [EfiPersistentMemory]           = "Persistent Memory",
     70 };
     71 
     72 static char default_device[32];
     73 static char initrd_path[255];
     74 static char dtb_path[255];
     75 static char efibootplist_path[255];
     76 static char netbsd_path[255];
     77 static char netbsd_args[255];
     78 static char rndseed_path[255];
     79 
     80 #define	DEFTIMEOUT	5
     81 #define DEFFILENAME	names[0]
     82 
     83 int	set_bootfile(const char *);
     84 int	set_bootargs(const char *);
     85 
     86 void	command_boot(char *);
     87 void	command_dev(char *);
     88 void	command_dtb(char *);
     89 void	command_plist(char *);
     90 void	command_initrd(char *);
     91 void	command_rndseed(char *);
     92 void	command_ls(char *);
     93 void	command_mem(char *);
     94 void	command_printenv(char *);
     95 void	command_setenv(char *);
     96 void	command_clearenv(char *);
     97 void	command_resetenv(char *);
     98 void	command_reset(char *);
     99 void	command_version(char *);
    100 void	command_quit(char *);
    101 
    102 const struct boot_command commands[] = {
    103 	{ "boot",	command_boot,		"boot [dev:][filename] [args]\n     (ex. \"hd0a:\\netbsd.old -s\"" },
    104 	{ "dev",	command_dev,		"dev" },
    105 	{ "dtb",	command_dtb,		"dtb [dev:][filename]" },
    106 	{ "plist",	command_plist,		"plist [dev:][filename]" },
    107 	{ "initrd",	command_initrd,		"initrd [dev:][filename]" },
    108 	{ "rndseed",	command_rndseed,	"rndseed [dev:][filename]" },
    109 	{ "ls",		command_ls,		"ls [hdNn:/path]" },
    110 	{ "mem",	command_mem,		"mem" },
    111 	{ "printenv",	command_printenv,	"printenv [key]" },
    112 	{ "setenv",	command_setenv,		"setenv <key> <value>" },
    113 	{ "clearenv",	command_clearenv,	"clearenv <key>" },
    114 	{ "resetenv",	command_resetenv,	"resetenv" },
    115 	{ "reboot",	command_reset,		"reboot|reset" },
    116 	{ "reset",	command_reset,		NULL },
    117 	{ "version",	command_version,	"version" },
    118 	{ "ver",	command_version,	NULL },
    119 	{ "help",	command_help,		"help|?" },
    120 	{ "?",		command_help,		NULL },
    121 	{ "quit",	command_quit,		"quit" },
    122 	{ NULL,		NULL },
    123 };
    124 
    125 void
    126 command_help(char *arg)
    127 {
    128 	int n;
    129 
    130 	printf("commands are:\n");
    131 	for (n = 0; commands[n].c_name; n++) {
    132 		if (commands[n].c_help)
    133 			printf("%s\n", commands[n].c_help);
    134 	}
    135 }
    136 
    137 void
    138 command_boot(char *arg)
    139 {
    140 	char *fname = arg;
    141 	const char *kernel = *fname ? fname : bootfile;
    142 	char *bootargs = gettrailer(arg);
    143 
    144 	if (!kernel || !*kernel)
    145 		kernel = DEFFILENAME;
    146 
    147 	if (!*bootargs)
    148 		bootargs = netbsd_args;
    149 
    150 	exec_netbsd(kernel, bootargs);
    151 }
    152 
    153 void
    154 command_dev(char *arg)
    155 {
    156 	if (arg && *arg) {
    157 		set_default_device(arg);
    158 	} else {
    159 		efi_block_show();
    160 		efi_net_show();
    161 	}
    162 
    163 	if (strlen(default_device) > 0) {
    164 		printf("\n");
    165 		printf("default: %s\n", default_device);
    166 	}
    167 }
    168 
    169 void
    170 command_dtb(char *arg)
    171 {
    172 	set_dtb_path(arg);
    173 }
    174 
    175 void
    176 command_plist(char *arg)
    177 {
    178 	if (set_efibootplist_path(arg) == 0)
    179 		load_efibootplist(false);
    180 }
    181 
    182 void
    183 command_initrd(char *arg)
    184 {
    185 	set_initrd_path(arg);
    186 }
    187 
    188 void
    189 command_rndseed(char *arg)
    190 {
    191 	set_rndseed_path(arg);
    192 }
    193 
    194 void
    195 command_ls(char *arg)
    196 {
    197 	ls(arg);
    198 }
    199 
    200 void
    201 command_mem(char *arg)
    202 {
    203 	EFI_MEMORY_DESCRIPTOR *md, *memmap;
    204 	UINTN nentries, mapkey, descsize;
    205 	UINT32 descver;
    206 	int n;
    207 
    208 	printf("Type                    Start             End               Attributes\n");
    209 	printf("----------------------  ----------------  ----------------  ----------------\n");
    210 	memmap = LibMemoryMap(&nentries, &mapkey, &descsize, &descver);
    211 	for (n = 0, md = memmap; n < nentries; n++, md = NextMemoryDescriptor(md, descsize)) {
    212 		const char *mem_type = "<unknown>";
    213 		if (md->Type < __arraycount(efi_memory_type))
    214 			mem_type = efi_memory_type[md->Type];
    215 
    216 		printf("%-22s  %016" PRIx64 "  %016" PRIx64 "  %016" PRIx64 "\n",
    217 		    mem_type, md->PhysicalStart, md->PhysicalStart + (md->NumberOfPages * EFI_PAGE_SIZE) - 1,
    218 		    md->Attribute);
    219 	}
    220 }
    221 
    222 void
    223 command_printenv(char *arg)
    224 {
    225 	char *val;
    226 
    227 	if (arg && *arg) {
    228 		val = efi_env_get(arg);
    229 		if (val) {
    230 			printf("\"%s\" = \"%s\"\n", arg, val);
    231 			FreePool(val);
    232 		}
    233 	} else {
    234 		efi_env_print();
    235 	}
    236 }
    237 
    238 void
    239 command_setenv(char *arg)
    240 {
    241 	char *spc;
    242 
    243 	spc = strchr(arg, ' ');
    244 	if (spc == NULL || spc[1] == '\0') {
    245 		command_help("");
    246 		return;
    247 	}
    248 
    249 	*spc = '\0';
    250 	efi_env_set(arg, spc + 1);
    251 }
    252 
    253 void
    254 command_clearenv(char *arg)
    255 {
    256 	if (*arg == '\0') {
    257 		command_help("");
    258 		return;
    259 	}
    260 	efi_env_clear(arg);
    261 }
    262 
    263 void
    264 command_resetenv(char *arg)
    265 {
    266 	efi_env_reset();
    267 }
    268 
    269 void
    270 command_version(char *arg)
    271 {
    272 	char *ufirmware;
    273 	int rv;
    274 
    275 	printf("Version: %s (%s)\n", bootprog_rev, bootprog_kernrev);
    276 	printf("EFI: %d.%02d\n",
    277 	    ST->Hdr.Revision >> 16, ST->Hdr.Revision & 0xffff);
    278 	ufirmware = NULL;
    279 	rv = ucs2_to_utf8(ST->FirmwareVendor, &ufirmware);
    280 	if (rv == 0) {
    281 		printf("Firmware: %s (rev 0x%x)\n", ufirmware,
    282 		    ST->FirmwareRevision);
    283 		FreePool(ufirmware);
    284 	}
    285 
    286 	efi_fdt_show();
    287 	efi_acpi_show();
    288 }
    289 
    290 void
    291 command_quit(char *arg)
    292 {
    293 	efi_exit();
    294 }
    295 
    296 void
    297 command_reset(char *arg)
    298 {
    299 	efi_reboot();
    300 }
    301 
    302 int
    303 set_default_device(const char *arg)
    304 {
    305 	if (strlen(arg) + 1 > sizeof(default_device))
    306 		return ERANGE;
    307 	strcpy(default_device, arg);
    308 	return 0;
    309 }
    310 
    311 char *
    312 get_default_device(void)
    313 {
    314 	return default_device;
    315 }
    316 
    317 int
    318 set_initrd_path(const char *arg)
    319 {
    320 	if (strlen(arg) + 1 > sizeof(initrd_path))
    321 		return ERANGE;
    322 	strcpy(initrd_path, arg);
    323 	return 0;
    324 }
    325 
    326 char *
    327 get_initrd_path(void)
    328 {
    329 	return initrd_path;
    330 }
    331 
    332 int
    333 set_dtb_path(const char *arg)
    334 {
    335 	if (strlen(arg) + 1 > sizeof(dtb_path))
    336 		return ERANGE;
    337 	strcpy(dtb_path, arg);
    338 	return 0;
    339 }
    340 
    341 char *
    342 get_dtb_path(void)
    343 {
    344 	return dtb_path;
    345 }
    346 
    347 int
    348 set_efibootplist_path(const char *arg)
    349 {
    350 	if (strlen(arg) + 1 > sizeof(efibootplist_path))
    351 		return ERANGE;
    352 	strcpy(efibootplist_path, arg);
    353 	return 0;
    354 }
    355 
    356 char *get_efibootplist_path(void)
    357 {
    358 	return efibootplist_path;
    359 }
    360 
    361 int
    362 set_rndseed_path(const char *arg)
    363 {
    364 	if (strlen(arg) + 1 > sizeof(rndseed_path))
    365 		return ERANGE;
    366 	strcpy(rndseed_path, arg);
    367 	return 0;
    368 }
    369 
    370 char *
    371 get_rndseed_path(void)
    372 {
    373 	return rndseed_path;
    374 }
    375 
    376 int
    377 set_bootfile(const char *arg)
    378 {
    379 	if (strlen(arg) + 1 > sizeof(netbsd_path))
    380 		return ERANGE;
    381 	strcpy(netbsd_path, arg);
    382 	return 0;
    383 }
    384 
    385 int
    386 set_bootargs(const char *arg)
    387 {
    388 	if (strlen(arg) + 1 > sizeof(netbsd_args))
    389 		return ERANGE;
    390 	strcpy(netbsd_args, arg);
    391 	return 0;
    392 }
    393 
    394 void
    395 print_banner(void)
    396 {
    397 	printf("\n\n"
    398 	    ">> %s, Revision %s\n",
    399 	    bootprog_name, bootprog_rev);
    400 }
    401 
    402 static void
    403 read_env(void)
    404 {
    405 	char *s;
    406 
    407 	s = efi_env_get("efibootplist");
    408 	if (s) {
    409 #ifdef EFIBOOT_DEBUG
    410 		printf(">> Setting efiboot.plist path to '%s' from environment\n", s);
    411 #endif
    412 		set_efibootplist_path(s);
    413 		FreePool(s);
    414 	}
    415 
    416 	/*
    417 	 * Read the efiboot.plist now as it may contain additional
    418 	 * environment variables.
    419 	 */
    420 	load_efibootplist(true);
    421 
    422 	s = efi_env_get("fdtfile");
    423 	if (s) {
    424 #ifdef EFIBOOT_DEBUG
    425 		printf(">> Setting DTB path to '%s' from environment\n", s);
    426 #endif
    427 		set_dtb_path(s);
    428 		FreePool(s);
    429 	}
    430 
    431 	s = efi_env_get("initrd");
    432 	if (s) {
    433 #ifdef EFIBOOT_DEBUG
    434 		printf(">> Setting initrd path to '%s' from environment\n", s);
    435 #endif
    436 		set_initrd_path(s);
    437 		FreePool(s);
    438 	}
    439 
    440 	s = efi_env_get("bootfile");
    441 	if (s) {
    442 #ifdef EFIBOOT_DEBUG
    443 		printf(">> Setting bootfile path to '%s' from environment\n", s);
    444 #endif
    445 		set_bootfile(s);
    446 		FreePool(s);
    447 	}
    448 
    449 	s = efi_env_get("rootdev");
    450 	if (s) {
    451 #ifdef EFIBOOT_DEBUG
    452 		printf(">> Setting default device to '%s' from environment\n", s);
    453 #endif
    454 		set_default_device(s);
    455 		FreePool(s);
    456 	}
    457 
    458 	s = efi_env_get("bootargs");
    459 	if (s) {
    460 #ifdef EFIBOOT_DEBUG
    461 		printf(">> Setting default boot args to '%s' from environment\n", s);
    462 #endif
    463 		set_bootargs(s);
    464 		FreePool(s);
    465 	}
    466 
    467 	s = efi_env_get("rndseed");
    468 	if (s) {
    469 #ifdef EFIBOOT_DEBUG
    470 		printf(">> Setting rndseed path to '%s' from environment\n", s);
    471 #endif
    472 		set_rndseed_path(s);
    473 		FreePool(s);
    474 	}
    475 }
    476 
    477 void
    478 boot(void)
    479 {
    480 	int currname, c;
    481 
    482 	read_env();
    483 	print_banner();
    484 	printf("Press return to boot now, any other key for boot prompt\n");
    485 
    486 	if (netbsd_path[0] != '\0')
    487 		currname = -1;
    488 	else
    489 		currname = 0;
    490 
    491 	for (; currname < (int)NUMNAMES; currname++) {
    492 		if (currname >= 0)
    493 			set_bootfile(names[currname]);
    494 		printf("booting %s%s%s - starting in ", netbsd_path,
    495 		    netbsd_args[0] != '\0' ? " " : "", netbsd_args);
    496 
    497 		c = awaitkey(DEFTIMEOUT, 1);
    498 		if (c != '\r' && c != '\n' && c != '\0')
    499 			bootprompt(); /* does not return */
    500 
    501 		exec_netbsd(netbsd_path, netbsd_args);
    502 	}
    503 
    504 	bootprompt();	/* does not return */
    505 }
    506