boot.c revision 1.27 1 /* $NetBSD: boot.c,v 1.27 2020/06/28 11:39:50 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 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