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