Home | History | Annotate | Line # | Download | only in efiboot
boot.c revision 1.19
      1 /*	$NetBSD: boot.c,v 1.19 2019/12/18 21:46:03 riastradh 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 	{ "help",	command_help,		"help|?" },
    119 	{ "?",		command_help,		NULL },
    120 	{ "quit",	command_quit,		"quit" },
    121 	{ NULL,		NULL },
    122 };
    123 
    124 void
    125 command_help(char *arg)
    126 {
    127 	int n;
    128 
    129 	printf("commands are:\n");
    130 	for (n = 0; commands[n].c_name; n++) {
    131 		if (commands[n].c_help)
    132 			printf("%s\n", commands[n].c_help);
    133 	}
    134 }
    135 
    136 void
    137 command_boot(char *arg)
    138 {
    139 	char *fname = arg;
    140 	const char *kernel = *fname ? fname : bootfile;
    141 	char *bootargs = gettrailer(arg);
    142 
    143 	if (!kernel || !*kernel)
    144 		kernel = DEFFILENAME;
    145 
    146 	if (!*bootargs)
    147 		bootargs = netbsd_args;
    148 
    149 	exec_netbsd(kernel, bootargs);
    150 }
    151 
    152 void
    153 command_dev(char *arg)
    154 {
    155 	if (arg && *arg) {
    156 		set_default_device(arg);
    157 	} else {
    158 		efi_block_show();
    159 		efi_net_show();
    160 	}
    161 
    162 	if (strlen(default_device) > 0) {
    163 		printf("\n");
    164 		printf("default: %s\n", default_device);
    165 	}
    166 }
    167 
    168 void
    169 command_dtb(char *arg)
    170 {
    171 	set_dtb_path(arg);
    172 }
    173 
    174 void
    175 command_plist(char *arg)
    176 {
    177 	if (set_efibootplist_path(arg) == 0)
    178 		load_efibootplist(false);
    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_ls(char *arg)
    195 {
    196 	ls(arg);
    197 }
    198 
    199 void
    200 command_mem(char *arg)
    201 {
    202 	EFI_MEMORY_DESCRIPTOR *md, *memmap;
    203 	UINTN nentries, mapkey, descsize;
    204 	UINT32 descver;
    205 	int n;
    206 
    207 	printf("Type                    Start             End               Attributes\n");
    208 	printf("----------------------  ----------------  ----------------  ----------------\n");
    209 	memmap = LibMemoryMap(&nentries, &mapkey, &descsize, &descver);
    210 	for (n = 0, md = memmap; n < nentries; n++, md = NextMemoryDescriptor(md, descsize)) {
    211 		const char *mem_type = "<unknown>";
    212 		if (md->Type < __arraycount(efi_memory_type))
    213 			mem_type = efi_memory_type[md->Type];
    214 
    215 		printf("%-22s  %016" PRIx64 "  %016" PRIx64 "  %016" PRIx64 "\n",
    216 		    mem_type, md->PhysicalStart, md->PhysicalStart + (md->NumberOfPages * EFI_PAGE_SIZE) - 1,
    217 		    md->Attribute);
    218 	}
    219 }
    220 
    221 void
    222 command_printenv(char *arg)
    223 {
    224 	char *val;
    225 
    226 	if (arg && *arg) {
    227 		val = efi_env_get(arg);
    228 		if (val) {
    229 			printf("\"%s\" = \"%s\"\n", arg, val);
    230 			FreePool(val);
    231 		}
    232 	} else {
    233 		efi_env_print();
    234 	}
    235 }
    236 
    237 void
    238 command_setenv(char *arg)
    239 {
    240 	char *spc;
    241 
    242 	spc = strchr(arg, ' ');
    243 	if (spc == NULL || spc[1] == '\0') {
    244 		command_help("");
    245 		return;
    246 	}
    247 
    248 	*spc = '\0';
    249 	efi_env_set(arg, spc + 1);
    250 }
    251 
    252 void
    253 command_clearenv(char *arg)
    254 {
    255 	if (*arg == '\0') {
    256 		command_help("");
    257 		return;
    258 	}
    259 	efi_env_clear(arg);
    260 }
    261 
    262 void
    263 command_resetenv(char *arg)
    264 {
    265 	efi_env_reset();
    266 }
    267 
    268 void
    269 command_version(char *arg)
    270 {
    271 	char *ufirmware;
    272 	int rv;
    273 
    274 	printf("EFI version: %d.%02d\n",
    275 	    ST->Hdr.Revision >> 16, ST->Hdr.Revision & 0xffff);
    276 	ufirmware = NULL;
    277 	rv = ucs2_to_utf8(ST->FirmwareVendor, &ufirmware);
    278 	if (rv == 0) {
    279 		printf("EFI Firmware: %s (rev 0x%x)\n", ufirmware,
    280 		    ST->FirmwareRevision);
    281 		FreePool(ufirmware);
    282 	}
    283 
    284 	efi_fdt_show();
    285 	efi_acpi_show();
    286 }
    287 
    288 void
    289 command_quit(char *arg)
    290 {
    291 	efi_exit();
    292 }
    293 
    294 void
    295 command_reset(char *arg)
    296 {
    297 	efi_reboot();
    298 }
    299 
    300 int
    301 set_default_device(const char *arg)
    302 {
    303 	if (strlen(arg) + 1 > sizeof(default_device))
    304 		return ERANGE;
    305 	strcpy(default_device, arg);
    306 	return 0;
    307 }
    308 
    309 char *
    310 get_default_device(void)
    311 {
    312 	return default_device;
    313 }
    314 
    315 int
    316 set_initrd_path(const char *arg)
    317 {
    318 	if (strlen(arg) + 1 > sizeof(initrd_path))
    319 		return ERANGE;
    320 	strcpy(initrd_path, arg);
    321 	return 0;
    322 }
    323 
    324 char *
    325 get_initrd_path(void)
    326 {
    327 	return initrd_path;
    328 }
    329 
    330 int
    331 set_dtb_path(const char *arg)
    332 {
    333 	if (strlen(arg) + 1 > sizeof(dtb_path))
    334 		return ERANGE;
    335 	strcpy(dtb_path, arg);
    336 	return 0;
    337 }
    338 
    339 char *
    340 get_dtb_path(void)
    341 {
    342 	return dtb_path;
    343 }
    344 
    345 int
    346 set_efibootplist_path(const char *arg)
    347 {
    348 	if (strlen(arg) + 1 > sizeof(efibootplist_path))
    349 		return ERANGE;
    350 	strcpy(efibootplist_path, arg);
    351 	return 0;
    352 }
    353 
    354 char *get_efibootplist_path(void)
    355 {
    356 	return efibootplist_path;
    357 }
    358 
    359 int
    360 set_rndseed_path(const char *arg)
    361 {
    362 	if (strlen(arg) + 1 > sizeof(rndseed_path))
    363 		return ERANGE;
    364 	strcpy(rndseed_path, arg);
    365 	return 0;
    366 }
    367 
    368 char *
    369 get_rndseed_path(void)
    370 {
    371 	return rndseed_path;
    372 }
    373 
    374 int
    375 set_bootfile(const char *arg)
    376 {
    377 	if (strlen(arg) + 1 > sizeof(netbsd_path))
    378 		return ERANGE;
    379 	strcpy(netbsd_path, arg);
    380 	return 0;
    381 }
    382 
    383 int
    384 set_bootargs(const char *arg)
    385 {
    386 	if (strlen(arg) + 1 > sizeof(netbsd_args))
    387 		return ERANGE;
    388 	strcpy(netbsd_args, arg);
    389 	return 0;
    390 }
    391 
    392 void
    393 print_banner(void)
    394 {
    395 	printf("\n\n"
    396 	    ">> %s, Revision %s (from NetBSD %s)\n",
    397 	    bootprog_name, bootprog_rev, bootprog_kernrev);
    398 }
    399 
    400 static void
    401 read_env(void)
    402 {
    403 	char *s;
    404 
    405 	s = efi_env_get("efibootplist");
    406 	if (s) {
    407 #ifdef EFIBOOT_DEBUG
    408 		printf(">> Setting efiboot.plist path to '%s' from environment\n", s);
    409 #endif
    410 		set_efibootplist_path(s);
    411 		FreePool(s);
    412 	}
    413 
    414 	/*
    415 	 * Read the efiboot.plist now as it may contain additional
    416 	 * environment variables.
    417 	 */
    418 	load_efibootplist(true);
    419 
    420 	s = efi_env_get("fdtfile");
    421 	if (s) {
    422 #ifdef EFIBOOT_DEBUG
    423 		printf(">> Setting DTB path to '%s' from environment\n", s);
    424 #endif
    425 		set_dtb_path(s);
    426 		FreePool(s);
    427 	}
    428 
    429 	s = efi_env_get("initrd");
    430 	if (s) {
    431 #ifdef EFIBOOT_DEBUG
    432 		printf(">> Setting initrd path to '%s' from environment\n", s);
    433 #endif
    434 		set_initrd_path(s);
    435 		FreePool(s);
    436 	}
    437 
    438 	s = efi_env_get("bootfile");
    439 	if (s) {
    440 #ifdef EFIBOOT_DEBUG
    441 		printf(">> Setting bootfile path to '%s' from environment\n", s);
    442 #endif
    443 		set_bootfile(s);
    444 		FreePool(s);
    445 	}
    446 
    447 	s = efi_env_get("rootdev");
    448 	if (s) {
    449 #ifdef EFIBOOT_DEBUG
    450 		printf(">> Setting default device to '%s' from environment\n", s);
    451 #endif
    452 		set_default_device(s);
    453 		FreePool(s);
    454 	}
    455 
    456 	s = efi_env_get("bootargs");
    457 	if (s) {
    458 #ifdef EFIBOOT_DEBUG
    459 		printf(">> Setting default boot args to '%s' from environment\n", s);
    460 #endif
    461 		set_bootargs(s);
    462 		FreePool(s);
    463 	}
    464 
    465 	s = efi_env_get("rndseed");
    466 	if (s) {
    467 #ifdef EFIBOOT_DEBUG
    468 		printf(">> Setting rndseed path to '%s' from environment\n", s);
    469 #endif
    470 		set_rndseed_path(s);
    471 		FreePool(s);
    472 	}
    473 }
    474 
    475 void
    476 boot(void)
    477 {
    478 	int currname, c;
    479 
    480 	read_env();
    481 	print_banner();
    482 	printf("Press return to boot now, any other key for boot prompt\n");
    483 
    484 	if (netbsd_path[0] != '\0')
    485 		currname = -1;
    486 	else
    487 		currname = 0;
    488 
    489 	for (; currname < (int)NUMNAMES; currname++) {
    490 		if (currname >= 0)
    491 			set_bootfile(names[currname]);
    492 		printf("booting %s%s%s - starting in ", netbsd_path,
    493 		    netbsd_args[0] != '\0' ? " " : "", netbsd_args);
    494 
    495 		c = awaitkey(DEFTIMEOUT, 1);
    496 		if (c != '\r' && c != '\n' && c != '\0')
    497 			bootprompt(); /* does not return */
    498 
    499 		exec_netbsd(netbsd_path, netbsd_args);
    500 	}
    501 
    502 	bootprompt();	/* does not return */
    503 }
    504