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