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