xref: /netbsd-src/sys/stand/efiboot/boot.c (revision d90047b5d07facf36e6c01dcc0bded8997ce9cc2)
1 /*	$NetBSD: boot.c,v 1.27 2020/06/28 11:39:50 jmcneill Exp $	*/
2 
3 /*-
4  * Copyright (c) 2016 Kimihiro Nonaka <nonaka@netbsd.org>
5  * Copyright (c) 2018 Jared McNeill <jmcneill@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 "efifile.h"
33 #include "efifdt.h"
34 #include "efiacpi.h"
35 #include "efirng.h"
36 #include "module.h"
37 #include "overlay.h"
38 #include "bootmenu.h"
39 
40 #include <sys/bootblock.h>
41 #include <sys/boot_flag.h>
42 #include <machine/limits.h>
43 
44 #include <loadfile.h>
45 #include <bootcfg.h>
46 
47 extern const char bootprog_name[], bootprog_rev[], bootprog_kernrev[];
48 
49 extern char twiddle_toggle;
50 
51 static const char * const names[] = {
52 	"netbsd", "netbsd.gz",
53 	"onetbsd", "onetbsd.gz",
54 	"netbsd.old", "netbsd.old.gz",
55 };
56 
57 #define NUMNAMES	__arraycount(names)
58 
59 static const char *efi_memory_type[] = {
60         [EfiReservedMemoryType]         = "Reserved Memory Type",
61         [EfiLoaderCode]                 = "Loader Code",
62         [EfiLoaderData]                 = "Loader Data",
63         [EfiBootServicesCode]           = "Boot Services Code",
64         [EfiBootServicesData]           = "Boot Services Data",
65         [EfiRuntimeServicesCode]        = "Runtime Services Code",
66         [EfiRuntimeServicesData]        = "Runtime Services Data",
67         [EfiConventionalMemory]         = "Conventional Memory",
68         [EfiUnusableMemory]             = "Unusable Memory",
69         [EfiACPIReclaimMemory]          = "ACPI Reclaim Memory",
70         [EfiACPIMemoryNVS]              = "ACPI Memory NVS",
71         [EfiMemoryMappedIO]             = "MMIO",
72         [EfiMemoryMappedIOPortSpace]    = "MMIO (Port Space)",
73         [EfiPalCode]                    = "Pal Code",
74         [EfiPersistentMemory]           = "Persistent Memory",
75 };
76 
77 static char default_device[32];
78 static char initrd_path[255];
79 static char dtb_path[255];
80 static char netbsd_path[255];
81 static char netbsd_args[255];
82 static char rndseed_path[255];
83 
84 #define	DEFTIMEOUT	5
85 #define DEFFILENAME	names[0]
86 
87 int	set_bootfile(const char *);
88 int	set_bootargs(const char *);
89 
90 void	command_boot(char *);
91 void	command_dev(char *);
92 void	command_dtb(char *);
93 void	command_initrd(char *);
94 void	command_rndseed(char *);
95 void	command_dtoverlay(char *);
96 void	command_dtoverlays(char *);
97 void	command_modules(char *);
98 void	command_load(char *);
99 void	command_unload(char *);
100 void	command_ls(char *);
101 void	command_mem(char *);
102 void	command_menu(char *);
103 void	command_reset(char *);
104 void	command_version(char *);
105 void	command_quit(char *);
106 
107 const struct boot_command commands[] = {
108 	{ "boot",	command_boot,		"boot [dev:][filename] [args]\n     (ex. \"hd0a:\\netbsd.old -s\"" },
109 	{ "dev",	command_dev,		"dev" },
110 	{ "dtb",	command_dtb,		"dtb [dev:][filename]" },
111 	{ "initrd",	command_initrd,		"initrd [dev:][filename]" },
112 	{ "rndseed",	command_rndseed,	"rndseed [dev:][filename]" },
113 	{ "dtoverlay",	command_dtoverlay,	"dtoverlay [dev:][filename]" },
114 	{ "dtoverlays",	command_dtoverlays,	"dtoverlays [{on|off|reset}]" },
115 	{ "modules",	command_modules,	"modules [{on|off|reset}]" },
116 	{ "load",	command_load,		"load <module_name>" },
117 	{ "unload",	command_unload,		"unload <module_name>" },
118 	{ "ls",		command_ls,		"ls [hdNn:/path]" },
119 	{ "mem",	command_mem,		"mem" },
120 	{ "menu",	command_menu,		"menu" },
121 	{ "reboot",	command_reset,		"reboot|reset" },
122 	{ "reset",	command_reset,		NULL },
123 	{ "version",	command_version,	"version" },
124 	{ "ver",	command_version,	NULL },
125 	{ "help",	command_help,		"help|?" },
126 	{ "?",		command_help,		NULL },
127 	{ "quit",	command_quit,		"quit" },
128 	{ NULL,		NULL },
129 };
130 
131 void
132 command_help(char *arg)
133 {
134 	int n;
135 
136 	printf("commands are:\n");
137 	for (n = 0; commands[n].c_name; n++) {
138 		if (commands[n].c_help)
139 			printf("%s\n", commands[n].c_help);
140 	}
141 }
142 
143 void
144 command_boot(char *arg)
145 {
146 	char *fname = arg;
147 	const char *kernel = *fname ? fname : bootfile;
148 	char *bootargs = gettrailer(arg);
149 
150 	if (!kernel || !*kernel)
151 		kernel = DEFFILENAME;
152 
153 	if (!*bootargs)
154 		bootargs = netbsd_args;
155 
156 	exec_netbsd(kernel, bootargs);
157 }
158 
159 void
160 command_dev(char *arg)
161 {
162 	if (arg && *arg) {
163 		set_default_device(arg);
164 	} else {
165 		efi_block_show();
166 		efi_net_show();
167 	}
168 
169 	if (strlen(default_device) > 0) {
170 		printf("\n");
171 		printf("default: %s\n", default_device);
172 	}
173 }
174 
175 void
176 command_dtb(char *arg)
177 {
178 	set_dtb_path(arg);
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_dtoverlays(char *arg)
195 {
196 	if (arg && *arg) {
197 		if (strcmp(arg, "on") == 0)
198 			dtoverlay_enable(1);
199 		else if (strcmp(arg, "off") == 0)
200 			dtoverlay_enable(0);
201 		else if (strcmp(arg, "reset") == 0)
202 			dtoverlay_remove_all();
203 		else {
204 			command_help("");
205 			return;
206 		}
207 	} else {
208 		printf("Device Tree overlays are %sabled\n",
209 		    dtoverlay_enabled ? "en" : "dis");
210 	}
211 }
212 
213 void
214 command_dtoverlay(char *arg)
215 {
216 	if (!arg || !*arg) {
217 		command_help("");
218 		return;
219 	}
220 
221 	dtoverlay_add(arg);
222 }
223 
224 void
225 command_modules(char *arg)
226 {
227 	if (arg && *arg) {
228 		if (strcmp(arg, "on") == 0)
229 			module_enable(1);
230 		else if (strcmp(arg, "off") == 0)
231 			module_enable(0);
232 		else if (strcmp(arg, "reset") == 0)
233 			module_remove_all();
234 		else {
235 			command_help("");
236 			return;
237 		}
238 	} else {
239 		printf("modules are %sabled\n", module_enabled ? "en" : "dis");
240 	}
241 }
242 
243 void
244 command_load(char *arg)
245 {
246 	if (!arg || !*arg) {
247 		command_help("");
248 		return;
249 	}
250 
251 	module_add(arg);
252 }
253 
254 void
255 command_unload(char *arg)
256 {
257 	if (!arg || !*arg) {
258 		command_help("");
259 		return;
260 	}
261 
262 	module_remove(arg);
263 }
264 
265 void
266 command_ls(char *arg)
267 {
268 	ls(arg);
269 }
270 
271 void
272 command_mem(char *arg)
273 {
274 	EFI_MEMORY_DESCRIPTOR *md, *memmap;
275 	UINTN nentries, mapkey, descsize;
276 	UINT32 descver;
277 	int n;
278 
279 	printf("Type                    Start             End               Attributes\n");
280 	printf("----------------------  ----------------  ----------------  ----------------\n");
281 	memmap = LibMemoryMap(&nentries, &mapkey, &descsize, &descver);
282 	for (n = 0, md = memmap; n < nentries; n++, md = NextMemoryDescriptor(md, descsize)) {
283 		const char *mem_type = "<unknown>";
284 		if (md->Type < __arraycount(efi_memory_type))
285 			mem_type = efi_memory_type[md->Type];
286 
287 		printf("%-22s  %016" PRIx64 "  %016" PRIx64 "  %016" PRIx64 "\n",
288 		    mem_type, md->PhysicalStart, md->PhysicalStart + (md->NumberOfPages * EFI_PAGE_SIZE) - 1,
289 		    md->Attribute);
290 	}
291 }
292 
293 void
294 command_menu(char *arg)
295 {
296 	if (bootcfg_info.nummenu == 0) {
297 		printf("No menu defined in boot.cfg\n");
298 		return;
299 	}
300 
301 	doboottypemenu();	/* Does not return */
302 }
303 
304 void
305 command_version(char *arg)
306 {
307 	char pathbuf[80];
308 	char *ufirmware;
309 	int rv;
310 
311 	printf("Version: %s (%s)\n", bootprog_rev, bootprog_kernrev);
312 	printf("EFI: %d.%02d\n",
313 	    ST->Hdr.Revision >> 16, ST->Hdr.Revision & 0xffff);
314 	ufirmware = NULL;
315 	rv = ucs2_to_utf8(ST->FirmwareVendor, &ufirmware);
316 	if (rv == 0) {
317 		printf("Firmware: %s (rev 0x%x)\n", ufirmware,
318 		    ST->FirmwareRevision);
319 		FreePool(ufirmware);
320 	}
321 	if (efi_bootdp != NULL &&
322 	    efi_file_path(efi_bootdp, BOOTCFG_FILENAME, pathbuf, sizeof(pathbuf)) == 0) {
323 		printf("Config path: %s\n", pathbuf);
324 	}
325 
326 	efi_fdt_show();
327 	efi_acpi_show();
328 	efi_rng_show();
329 }
330 
331 void
332 command_quit(char *arg)
333 {
334 	efi_exit();
335 }
336 
337 void
338 command_reset(char *arg)
339 {
340 	efi_reboot();
341 }
342 
343 int
344 set_default_device(const char *arg)
345 {
346 	if (strlen(arg) + 1 > sizeof(default_device))
347 		return ERANGE;
348 	strcpy(default_device, arg);
349 	return 0;
350 }
351 
352 char *
353 get_default_device(void)
354 {
355 	return default_device;
356 }
357 
358 int
359 set_initrd_path(const char *arg)
360 {
361 	if (strlen(arg) + 1 > sizeof(initrd_path))
362 		return ERANGE;
363 	strcpy(initrd_path, arg);
364 	return 0;
365 }
366 
367 char *
368 get_initrd_path(void)
369 {
370 	return initrd_path;
371 }
372 
373 int
374 set_dtb_path(const char *arg)
375 {
376 	if (strlen(arg) + 1 > sizeof(dtb_path))
377 		return ERANGE;
378 	strcpy(dtb_path, arg);
379 	return 0;
380 }
381 
382 char *
383 get_dtb_path(void)
384 {
385 	return dtb_path;
386 }
387 
388 int
389 set_rndseed_path(const char *arg)
390 {
391 	if (strlen(arg) + 1 > sizeof(rndseed_path))
392 		return ERANGE;
393 	strcpy(rndseed_path, arg);
394 	return 0;
395 }
396 
397 char *
398 get_rndseed_path(void)
399 {
400 	return rndseed_path;
401 }
402 
403 int
404 set_bootfile(const char *arg)
405 {
406 	if (strlen(arg) + 1 > sizeof(netbsd_path))
407 		return ERANGE;
408 	strcpy(netbsd_path, arg);
409 	return 0;
410 }
411 
412 int
413 set_bootargs(const char *arg)
414 {
415 	if (strlen(arg) + 1 > sizeof(netbsd_args))
416 		return ERANGE;
417 	strcpy(netbsd_args, arg);
418 	return 0;
419 }
420 
421 void
422 print_banner(void)
423 {
424 	printf("\n\n"
425 	    ">> %s, Revision %s\n",
426 	    bootprog_name, bootprog_rev);
427 }
428 
429 void
430 boot(void)
431 {
432 	char pathbuf[80];
433 	int currname, c;
434 
435 	if (efi_bootdp != NULL && efi_file_path(efi_bootdp, BOOTCFG_FILENAME, pathbuf, sizeof(pathbuf)) == 0) {
436 		twiddle_toggle = 1;
437 		parsebootconf(pathbuf);
438 	}
439 
440 	if (bootcfg_info.clear)
441 		uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut);
442 
443 	print_banner();
444 
445 	/* Display menu if configured */
446 	if (bootcfg_info.nummenu > 0) {
447 		doboottypemenu();	/* No return */
448 	}
449 
450 	printf("Press return to boot now, any other key for boot prompt\n");
451 
452 	if (netbsd_path[0] != '\0')
453 		currname = -1;
454 	else
455 		currname = 0;
456 
457 	for (; currname < (int)NUMNAMES; currname++) {
458 		if (currname >= 0)
459 			set_bootfile(names[currname]);
460 		printf("booting %s%s%s - starting in ", netbsd_path,
461 		    netbsd_args[0] != '\0' ? " " : "", netbsd_args);
462 
463 		c = awaitkey(DEFTIMEOUT, 1);
464 		if (c != '\r' && c != '\n' && c != '\0')
465 			bootprompt(); /* does not return */
466 
467 		exec_netbsd(netbsd_path, netbsd_args);
468 	}
469 
470 	bootprompt();	/* does not return */
471 }
472