boot.c revision 1.32 1 /* $NetBSD: boot.c,v 1.32 2021/06/21 21:18:47 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 "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 int default_fstype = FS_UNUSED;
79 static char initrd_path[255];
80 static char dtb_path[255];
81 static char netbsd_path[255];
82 static char netbsd_args[255];
83 static char rndseed_path[255];
84
85 #define DEFTIMEOUT 5
86 #define DEFFILENAME names[0]
87
88 int set_bootfile(const char *);
89 int set_bootargs(const char *);
90
91 void command_boot(char *);
92 void command_dev(char *);
93 void command_dtb(char *);
94 void command_initrd(char *);
95 void command_rndseed(char *);
96 void command_dtoverlay(char *);
97 void command_dtoverlays(char *);
98 void command_modules(char *);
99 void command_load(char *);
100 void command_unload(char *);
101 void command_ls(char *);
102 void command_mem(char *);
103 void command_menu(char *);
104 void command_reset(char *);
105 void command_version(char *);
106 void command_quit(char *);
107
108 const struct boot_command commands[] = {
109 { "boot", command_boot, "boot [dev:][filename] [args]\n (ex. \"hd0a:\\netbsd.old -s\"" },
110 { "dev", command_dev, "dev" },
111 { "dtb", command_dtb, "dtb [dev:][filename]" },
112 { "initrd", command_initrd, "initrd [dev:][filename]" },
113 { "rndseed", command_rndseed, "rndseed [dev:][filename]" },
114 { "dtoverlay", command_dtoverlay, "dtoverlay [dev:][filename]" },
115 { "dtoverlays", command_dtoverlays, "dtoverlays [{on|off|reset}]" },
116 { "modules", command_modules, "modules [{on|off|reset}]" },
117 { "load", command_load, "load <module_name>" },
118 { "unload", command_unload, "unload <module_name>" },
119 { "ls", command_ls, "ls [hdNn:/path]" },
120 { "mem", command_mem, "mem" },
121 { "menu", command_menu, "menu" },
122 { "reboot", command_reset, "reboot|reset" },
123 { "reset", command_reset, NULL },
124 { "version", command_version, "version" },
125 { "ver", command_version, NULL },
126 { "help", command_help, "help|?" },
127 { "?", command_help, NULL },
128 { "quit", command_quit, "quit" },
129 { NULL, NULL },
130 };
131
132 static int
133 bootcfg_path(char *pathbuf, size_t pathbuflen)
134 {
135
136 /*
137 * Fallback to default_device
138 * - for ISO9660 (efi_file_path() succeeds but does not work correctly)
139 * - or whenever efi_file_path() fails (due to broken firmware)
140 */
141 if (default_fstype == FS_ISO9660 || efi_bootdp == NULL ||
142 efi_file_path(efi_bootdp, BOOTCFG_FILENAME, pathbuf, pathbuflen))
143 snprintf(pathbuf, pathbuflen, "%s:%s", default_device,
144 BOOTCFG_FILENAME);
145
146 return 0;
147 }
148
149 void
150 command_help(char *arg)
151 {
152 int n;
153
154 printf("commands are:\n");
155 for (n = 0; commands[n].c_name; n++) {
156 if (commands[n].c_help)
157 printf("%s\n", commands[n].c_help);
158 }
159 }
160
161 void
162 command_boot(char *arg)
163 {
164 char *fname = arg;
165 const char *kernel = *fname ? fname : bootfile;
166 char *bootargs = gettrailer(arg);
167
168 if (!kernel || !*kernel)
169 kernel = DEFFILENAME;
170
171 if (!*bootargs)
172 bootargs = netbsd_args;
173
174 efi_block_set_readahead(true);
175 exec_netbsd(kernel, bootargs);
176 efi_block_set_readahead(false);
177 }
178
179 void
180 command_dev(char *arg)
181 {
182 if (arg && *arg) {
183 set_default_device(arg);
184 } else {
185 efi_block_show();
186 efi_net_show();
187 }
188
189 if (strlen(default_device) > 0) {
190 printf("\n");
191 printf("default: %s\n", default_device);
192 }
193 }
194
195 void
196 command_dtb(char *arg)
197 {
198 set_dtb_path(arg);
199 }
200
201 void
202 command_initrd(char *arg)
203 {
204 set_initrd_path(arg);
205 }
206
207 void
208 command_rndseed(char *arg)
209 {
210 set_rndseed_path(arg);
211 }
212
213 void
214 command_dtoverlays(char *arg)
215 {
216 if (arg && *arg) {
217 if (strcmp(arg, "on") == 0)
218 dtoverlay_enable(1);
219 else if (strcmp(arg, "off") == 0)
220 dtoverlay_enable(0);
221 else if (strcmp(arg, "reset") == 0)
222 dtoverlay_remove_all();
223 else {
224 command_help("");
225 return;
226 }
227 } else {
228 printf("Device Tree overlays are %sabled\n",
229 dtoverlay_enabled ? "en" : "dis");
230 }
231 }
232
233 void
234 command_dtoverlay(char *arg)
235 {
236 if (!arg || !*arg) {
237 command_help("");
238 return;
239 }
240
241 dtoverlay_add(arg);
242 }
243
244 void
245 command_modules(char *arg)
246 {
247 if (arg && *arg) {
248 if (strcmp(arg, "on") == 0)
249 module_enable(1);
250 else if (strcmp(arg, "off") == 0)
251 module_enable(0);
252 else if (strcmp(arg, "reset") == 0)
253 module_remove_all();
254 else {
255 command_help("");
256 return;
257 }
258 } else {
259 printf("modules are %sabled\n", module_enabled ? "en" : "dis");
260 }
261 }
262
263 void
264 command_load(char *arg)
265 {
266 if (!arg || !*arg) {
267 command_help("");
268 return;
269 }
270
271 module_add(arg);
272 }
273
274 void
275 command_unload(char *arg)
276 {
277 if (!arg || !*arg) {
278 command_help("");
279 return;
280 }
281
282 module_remove(arg);
283 }
284
285 void
286 command_ls(char *arg)
287 {
288 ls(arg);
289 }
290
291 void
292 command_mem(char *arg)
293 {
294 EFI_MEMORY_DESCRIPTOR *md, *memmap;
295 UINTN nentries, mapkey, descsize;
296 UINT32 descver;
297 int n;
298
299 printf("Type Start End Attributes\n");
300 printf("---------------------- ---------------- ---------------- ----------------\n");
301 memmap = LibMemoryMap(&nentries, &mapkey, &descsize, &descver);
302 for (n = 0, md = memmap; n < nentries; n++, md = NextMemoryDescriptor(md, descsize)) {
303 const char *mem_type = "<unknown>";
304 if (md->Type < __arraycount(efi_memory_type))
305 mem_type = efi_memory_type[md->Type];
306
307 printf("%-22s %016" PRIx64 " %016" PRIx64 " %016" PRIx64 "\n",
308 mem_type, md->PhysicalStart, md->PhysicalStart + (md->NumberOfPages * EFI_PAGE_SIZE) - 1,
309 md->Attribute);
310 }
311 }
312
313 void
314 command_menu(char *arg)
315 {
316 if (bootcfg_info.nummenu == 0) {
317 printf("No menu defined in boot.cfg\n");
318 return;
319 }
320
321 doboottypemenu(); /* Does not return */
322 }
323
324 void
325 command_version(char *arg)
326 {
327 char pathbuf[80];
328 char *ufirmware;
329 int rv;
330
331 printf("Version: %s (%s)\n", bootprog_rev, bootprog_kernrev);
332 printf("EFI: %d.%02d\n",
333 ST->Hdr.Revision >> 16, ST->Hdr.Revision & 0xffff);
334 ufirmware = NULL;
335 rv = ucs2_to_utf8(ST->FirmwareVendor, &ufirmware);
336 if (rv == 0) {
337 printf("Firmware: %s (rev 0x%x)\n", ufirmware,
338 ST->FirmwareRevision);
339 FreePool(ufirmware);
340 }
341 if (bootcfg_path(pathbuf, sizeof(pathbuf)) == 0) {
342 printf("Config path: %s\n", pathbuf);
343 }
344
345 efi_fdt_show();
346 efi_acpi_show();
347 efi_rng_show();
348 efi_md_show();
349 }
350
351 void
352 command_quit(char *arg)
353 {
354 efi_exit();
355 }
356
357 void
358 command_reset(char *arg)
359 {
360 efi_reboot();
361 }
362
363 int
364 set_default_device(const char *arg)
365 {
366 if (strlen(arg) + 1 > sizeof(default_device))
367 return ERANGE;
368 strcpy(default_device, arg);
369 return 0;
370 }
371
372 char *
373 get_default_device(void)
374 {
375 return default_device;
376 }
377
378 void
379 set_default_fstype(int fstype)
380 {
381 default_fstype = fstype;
382 }
383
384 int
385 get_default_fstype(void)
386 {
387 return default_fstype;
388 }
389
390 int
391 set_initrd_path(const char *arg)
392 {
393 if (strlen(arg) + 1 > sizeof(initrd_path))
394 return ERANGE;
395 strcpy(initrd_path, arg);
396 return 0;
397 }
398
399 char *
400 get_initrd_path(void)
401 {
402 return initrd_path;
403 }
404
405 int
406 set_dtb_path(const char *arg)
407 {
408 if (strlen(arg) + 1 > sizeof(dtb_path))
409 return ERANGE;
410 strcpy(dtb_path, arg);
411 return 0;
412 }
413
414 char *
415 get_dtb_path(void)
416 {
417 return dtb_path;
418 }
419
420 int
421 set_rndseed_path(const char *arg)
422 {
423 if (strlen(arg) + 1 > sizeof(rndseed_path))
424 return ERANGE;
425 strcpy(rndseed_path, arg);
426 return 0;
427 }
428
429 char *
430 get_rndseed_path(void)
431 {
432 return rndseed_path;
433 }
434
435 int
436 set_bootfile(const char *arg)
437 {
438 if (strlen(arg) + 1 > sizeof(netbsd_path))
439 return ERANGE;
440 strcpy(netbsd_path, arg);
441 return 0;
442 }
443
444 int
445 set_bootargs(const char *arg)
446 {
447 if (strlen(arg) + 1 > sizeof(netbsd_args))
448 return ERANGE;
449 strcpy(netbsd_args, arg);
450 return 0;
451 }
452
453 void
454 print_banner(void)
455 {
456 printf(" \\-__,------,___.\n");
457 printf(" \\ __,---` %s\n", bootprog_name);
458 printf(" \\ `---,_. Revision %s\n", bootprog_rev);
459 printf(" \\-,_____,.---`\n");
460 printf(" \\\n");
461 printf(" \\\n");
462 printf(" \\\n\n");
463 }
464
465 void
466 boot(void)
467 {
468 char pathbuf[80];
469 int currname, c;
470
471 if (bootcfg_path(pathbuf, sizeof(pathbuf)) == 0) {
472 twiddle_toggle = 1;
473 parsebootconf(pathbuf);
474 }
475
476 if (bootcfg_info.clear)
477 uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut);
478
479 print_banner();
480
481 /* Display menu if configured */
482 if (bootcfg_info.nummenu > 0) {
483 doboottypemenu(); /* No return */
484 }
485
486 printf("Press return to boot now, any other key for boot prompt\n");
487
488 if (netbsd_path[0] != '\0')
489 currname = -1;
490 else
491 currname = 0;
492
493 for (; currname < (int)NUMNAMES; currname++) {
494 if (currname >= 0)
495 set_bootfile(names[currname]);
496 printf("booting %s%s%s - starting in ", netbsd_path,
497 netbsd_args[0] != '\0' ? " " : "", netbsd_args);
498
499 c = awaitkey(DEFTIMEOUT, 1);
500 if (c != '\r' && c != '\n' && c != '\0')
501 bootprompt(); /* does not return */
502
503 efi_block_set_readahead(true);
504 exec_netbsd(netbsd_path, netbsd_args);
505 efi_block_set_readahead(false);
506 }
507
508 bootprompt(); /* does not return */
509 }
510