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