Home | History | Annotate | Line # | Download | only in efiboot
boot.c revision 1.5.2.5
      1 /*	$NetBSD: boot.c,v 1.5.2.5 2018/11/26 01:52:52 pgoyette 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 netbsd_path[255];
     76 
     77 #define	DEFTIMEOUT	5
     78 #define DEFFILENAME	names[0]
     79 
     80 int	set_bootfile(const char *);
     81 
     82 void	command_boot(char *);
     83 void	command_dev(char *);
     84 void	command_dtb(char *);
     85 void	command_initrd(char *);
     86 void	command_ls(char *);
     87 void	command_mem(char *);
     88 void	command_printenv(char *);
     89 void	command_setenv(char *);
     90 void	command_clearenv(char *);
     91 void	command_resetenv(char *);
     92 void	command_reset(char *);
     93 void	command_version(char *);
     94 void	command_quit(char *);
     95 
     96 const struct boot_command commands[] = {
     97 	{ "boot",	command_boot,		"boot [dev:][filename] [args]\n     (ex. \"hd0a:\\netbsd.old -s\"" },
     98 	{ "dev",	command_dev,		"dev" },
     99 	{ "dtb",	command_dtb,		"dtb [dev:][filename]" },
    100 	{ "initrd",	command_initrd,		"initrd [dev:][filename]" },
    101 	{ "ls",		command_ls,		"ls [hdNn:/path]" },
    102 	{ "mem",	command_mem,		"mem" },
    103 	{ "printenv",	command_printenv,	"printenv [key]" },
    104 	{ "setenv",	command_setenv,		"setenv <key> <value>" },
    105 	{ "clearenv",	command_clearenv,	"clearenv <key>" },
    106 	{ "resetenv",	command_resetenv,	"resetenv" },
    107 	{ "reboot",	command_reset,		"reboot|reset" },
    108 	{ "reset",	command_reset,		NULL },
    109 	{ "version",	command_version,	"version" },
    110 	{ "help",	command_help,		"help|?" },
    111 	{ "?",		command_help,		NULL },
    112 	{ "quit",	command_quit,		"quit" },
    113 	{ NULL,		NULL },
    114 };
    115 
    116 void
    117 command_help(char *arg)
    118 {
    119 	int n;
    120 
    121 	printf("commands are:\n");
    122 	for (n = 0; commands[n].c_name; n++) {
    123 		if (commands[n].c_help)
    124 			printf("%s\n", commands[n].c_help);
    125 	}
    126 }
    127 
    128 void
    129 command_boot(char *arg)
    130 {
    131 	char *fname = arg;
    132 	const char *kernel = *fname ? fname : bootfile;
    133 	char *bootargs = gettrailer(arg);
    134 
    135 	if (!kernel || !*kernel)
    136 		kernel = DEFFILENAME;
    137 
    138 	exec_netbsd(kernel, bootargs);
    139 }
    140 
    141 void
    142 command_dev(char *arg)
    143 {
    144 	if (arg && *arg) {
    145 		set_default_device(arg);
    146 	} else {
    147 		efi_block_show();
    148 		efi_net_show();
    149 	}
    150 
    151 	if (strlen(default_device) > 0) {
    152 		printf("\n");
    153 		printf("default: %s\n", default_device);
    154 	}
    155 }
    156 
    157 void
    158 command_dtb(char *arg)
    159 {
    160 	set_dtb_path(arg);
    161 }
    162 
    163 void
    164 command_initrd(char *arg)
    165 {
    166 	set_initrd_path(arg);
    167 }
    168 
    169 void
    170 command_ls(char *arg)
    171 {
    172 	ls(arg);
    173 }
    174 
    175 void
    176 command_mem(char *arg)
    177 {
    178 	EFI_MEMORY_DESCRIPTOR *md, *memmap;
    179 	UINTN nentries, mapkey, descsize;
    180 	UINT32 descver;
    181 	int n;
    182 
    183 	printf("Type                    Start             End               Attributes\n");
    184 	printf("----------------------  ----------------  ----------------  ----------------\n");
    185 	memmap = LibMemoryMap(&nentries, &mapkey, &descsize, &descver);
    186 	for (n = 0, md = memmap; n < nentries; n++, md = NextMemoryDescriptor(md, descsize)) {
    187 		const char *mem_type = "<unknown>";
    188 		if (md->Type < __arraycount(efi_memory_type))
    189 			mem_type = efi_memory_type[md->Type];
    190 
    191 		printf("%-22s  %016" PRIx64 "  %016" PRIx64 "  %016" PRIx64 "\n",
    192 		    mem_type, md->PhysicalStart, md->PhysicalStart + (md->NumberOfPages * EFI_PAGE_SIZE) - 1,
    193 		    md->Attribute);
    194 	}
    195 }
    196 
    197 void
    198 command_printenv(char *arg)
    199 {
    200 	char *val;
    201 
    202 	if (arg && *arg) {
    203 		val = efi_env_get(arg);
    204 		if (val) {
    205 			printf("\"%s\" = \"%s\"\n", arg, val);
    206 			FreePool(val);
    207 		}
    208 	} else {
    209 		efi_env_print();
    210 	}
    211 }
    212 
    213 void
    214 command_setenv(char *arg)
    215 {
    216 	char *spc;
    217 
    218 	spc = strchr(arg, ' ');
    219 	if (spc == NULL || spc[1] == '\0') {
    220 		command_help("");
    221 		return;
    222 	}
    223 
    224 	*spc = '\0';
    225 	efi_env_set(arg, spc + 1);
    226 }
    227 
    228 void
    229 command_clearenv(char *arg)
    230 {
    231 	if (*arg == '\0') {
    232 		command_help("");
    233 		return;
    234 	}
    235 	efi_env_clear(arg);
    236 }
    237 
    238 void
    239 command_resetenv(char *arg)
    240 {
    241 	efi_env_reset();
    242 }
    243 
    244 void
    245 command_version(char *arg)
    246 {
    247 	char *ufirmware;
    248 	int rv;
    249 
    250 	printf("EFI version: %d.%02d\n",
    251 	    ST->Hdr.Revision >> 16, ST->Hdr.Revision & 0xffff);
    252 	ufirmware = NULL;
    253 	rv = ucs2_to_utf8(ST->FirmwareVendor, &ufirmware);
    254 	if (rv == 0) {
    255 		printf("EFI Firmware: %s (rev %d.%02d)\n", ufirmware,
    256 		    ST->FirmwareRevision >> 16,
    257 		    ST->FirmwareRevision & 0xffff);
    258 		FreePool(ufirmware);
    259 	}
    260 
    261 	efi_fdt_show();
    262 	efi_acpi_show();
    263 }
    264 
    265 void
    266 command_quit(char *arg)
    267 {
    268 	efi_exit();
    269 }
    270 
    271 void
    272 command_reset(char *arg)
    273 {
    274 	efi_reboot();
    275 }
    276 
    277 int
    278 set_default_device(const char *arg)
    279 {
    280 	if (strlen(arg) + 1 > sizeof(default_device))
    281 		return ERANGE;
    282 	strcpy(default_device, arg);
    283 	return 0;
    284 }
    285 
    286 char *
    287 get_default_device(void)
    288 {
    289 	return default_device;
    290 }
    291 
    292 int
    293 set_initrd_path(const char *arg)
    294 {
    295 	if (strlen(arg) + 1 > sizeof(initrd_path))
    296 		return ERANGE;
    297 	strcpy(initrd_path, arg);
    298 	return 0;
    299 }
    300 
    301 char *
    302 get_initrd_path(void)
    303 {
    304 	return initrd_path;
    305 }
    306 
    307 int
    308 set_dtb_path(const char *arg)
    309 {
    310 	if (strlen(arg) + 1 > sizeof(dtb_path))
    311 		return ERANGE;
    312 	strcpy(dtb_path, arg);
    313 	return 0;
    314 }
    315 
    316 char *
    317 get_dtb_path(void)
    318 {
    319 	return dtb_path;
    320 }
    321 
    322 int
    323 set_bootfile(const char *arg)
    324 {
    325 	if (strlen(arg) + 1 > sizeof(netbsd_path))
    326 		return ERANGE;
    327 	strcpy(netbsd_path, arg);
    328 	return 0;
    329 }
    330 
    331 void
    332 print_banner(void)
    333 {
    334 	printf("\n\n"
    335 	    ">> %s, Revision %s (from NetBSD %s)\n",
    336 	    bootprog_name, bootprog_rev, bootprog_kernrev);
    337 }
    338 
    339 static void
    340 read_env(void)
    341 {
    342 	char *s;
    343 
    344 	s = efi_env_get("fdtfile");
    345 	if (s) {
    346 #ifdef EFIBOOT_DEBUG
    347 		printf(">> Setting DTB path to '%s' from environment\n", s);
    348 #endif
    349 		set_dtb_path(s);
    350 		FreePool(s);
    351 	}
    352 
    353 	s = efi_env_get("initrd");
    354 	if (s) {
    355 #ifdef EFIBOOT_DEBUG
    356 		printf(">> Setting initrd path to '%s' from environment\n", s);
    357 #endif
    358 		set_initrd_path(s);
    359 		FreePool(s);
    360 	}
    361 
    362 	s = efi_env_get("bootfile");
    363 	if (s) {
    364 #ifdef EFIBOOT_DEBUG
    365 		printf(">> Setting bootfile path to '%s' from environment\n", s);
    366 #endif
    367 		set_bootfile(s);
    368 		FreePool(s);
    369 	}
    370 
    371 	s = efi_env_get("rootdev");
    372 	if (s) {
    373 #ifdef EFIBOOT_DEBUG
    374 		printf(">> Setting default device to '%s' from environment\n", s);
    375 #endif
    376 		set_default_device(s);
    377 		FreePool(s);
    378 	}
    379 }
    380 
    381 void
    382 boot(void)
    383 {
    384 	int currname, c;
    385 
    386 	read_env();
    387 	print_banner();
    388 	printf("Press return to boot now, any other key for boot prompt\n");
    389 
    390 	if (netbsd_path[0] != '\0')
    391 		currname = -1;
    392 	else
    393 		currname = 0;
    394 
    395 	for (; currname < (int)NUMNAMES; currname++) {
    396 		if (currname >= 0)
    397 			set_bootfile(names[currname]);
    398 		printf("booting %s - starting in ", netbsd_path);
    399 
    400 		c = awaitkey(DEFTIMEOUT, 1);
    401 		if (c != '\r' && c != '\n' && c != '\0')
    402 			bootprompt(); /* does not return */
    403 
    404 		exec_netbsd(netbsd_path, "");
    405 	}
    406 
    407 	bootprompt();	/* does not return */
    408 }
    409