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