boot.c revision 1.5.2.5 1 /* $NetBSD: boot.c,v 1.5.2.5 2018/11/26 01:52:52 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
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 }
150
151 if (strlen(default_device) > 0) {
152 printf("\n");
153 printf("default: %s\n", default_device);
154 }
155 }
156
157 void
158 command_dtb(char *arg)
159 {
160 set_dtb_path(arg);
161 }
162
163 void
164 command_initrd(char *arg)
165 {
166 set_initrd_path(arg);
167 }
168
169 void
170 command_ls(char *arg)
171 {
172 ls(arg);
173 }
174
175 void
176 command_mem(char *arg)
177 {
178 EFI_MEMORY_DESCRIPTOR *md, *memmap;
179 UINTN nentries, mapkey, descsize;
180 UINT32 descver;
181 int n;
182
183 printf("Type Start End Attributes\n");
184 printf("---------------------- ---------------- ---------------- ----------------\n");
185 memmap = LibMemoryMap(&nentries, &mapkey, &descsize, &descver);
186 for (n = 0, md = memmap; n < nentries; n++, md = NextMemoryDescriptor(md, descsize)) {
187 const char *mem_type = "<unknown>";
188 if (md->Type < __arraycount(efi_memory_type))
189 mem_type = efi_memory_type[md->Type];
190
191 printf("%-22s %016" PRIx64 " %016" PRIx64 " %016" PRIx64 "\n",
192 mem_type, md->PhysicalStart, md->PhysicalStart + (md->NumberOfPages * EFI_PAGE_SIZE) - 1,
193 md->Attribute);
194 }
195 }
196
197 void
198 command_printenv(char *arg)
199 {
200 char *val;
201
202 if (arg && *arg) {
203 val = efi_env_get(arg);
204 if (val) {
205 printf("\"%s\" = \"%s\"\n", arg, val);
206 FreePool(val);
207 }
208 } else {
209 efi_env_print();
210 }
211 }
212
213 void
214 command_setenv(char *arg)
215 {
216 char *spc;
217
218 spc = strchr(arg, ' ');
219 if (spc == NULL || spc[1] == '\0') {
220 command_help("");
221 return;
222 }
223
224 *spc = '\0';
225 efi_env_set(arg, spc + 1);
226 }
227
228 void
229 command_clearenv(char *arg)
230 {
231 if (*arg == '\0') {
232 command_help("");
233 return;
234 }
235 efi_env_clear(arg);
236 }
237
238 void
239 command_resetenv(char *arg)
240 {
241 efi_env_reset();
242 }
243
244 void
245 command_version(char *arg)
246 {
247 char *ufirmware;
248 int rv;
249
250 printf("EFI version: %d.%02d\n",
251 ST->Hdr.Revision >> 16, ST->Hdr.Revision & 0xffff);
252 ufirmware = NULL;
253 rv = ucs2_to_utf8(ST->FirmwareVendor, &ufirmware);
254 if (rv == 0) {
255 printf("EFI Firmware: %s (rev %d.%02d)\n", ufirmware,
256 ST->FirmwareRevision >> 16,
257 ST->FirmwareRevision & 0xffff);
258 FreePool(ufirmware);
259 }
260
261 efi_fdt_show();
262 efi_acpi_show();
263 }
264
265 void
266 command_quit(char *arg)
267 {
268 efi_exit();
269 }
270
271 void
272 command_reset(char *arg)
273 {
274 efi_reboot();
275 }
276
277 int
278 set_default_device(const char *arg)
279 {
280 if (strlen(arg) + 1 > sizeof(default_device))
281 return ERANGE;
282 strcpy(default_device, arg);
283 return 0;
284 }
285
286 char *
287 get_default_device(void)
288 {
289 return default_device;
290 }
291
292 int
293 set_initrd_path(const char *arg)
294 {
295 if (strlen(arg) + 1 > sizeof(initrd_path))
296 return ERANGE;
297 strcpy(initrd_path, arg);
298 return 0;
299 }
300
301 char *
302 get_initrd_path(void)
303 {
304 return initrd_path;
305 }
306
307 int
308 set_dtb_path(const char *arg)
309 {
310 if (strlen(arg) + 1 > sizeof(dtb_path))
311 return ERANGE;
312 strcpy(dtb_path, arg);
313 return 0;
314 }
315
316 char *
317 get_dtb_path(void)
318 {
319 return dtb_path;
320 }
321
322 int
323 set_bootfile(const char *arg)
324 {
325 if (strlen(arg) + 1 > sizeof(netbsd_path))
326 return ERANGE;
327 strcpy(netbsd_path, arg);
328 return 0;
329 }
330
331 void
332 print_banner(void)
333 {
334 printf("\n\n"
335 ">> %s, Revision %s (from NetBSD %s)\n",
336 bootprog_name, bootprog_rev, bootprog_kernrev);
337 }
338
339 static void
340 read_env(void)
341 {
342 char *s;
343
344 s = efi_env_get("fdtfile");
345 if (s) {
346 #ifdef EFIBOOT_DEBUG
347 printf(">> Setting DTB path to '%s' from environment\n", s);
348 #endif
349 set_dtb_path(s);
350 FreePool(s);
351 }
352
353 s = efi_env_get("initrd");
354 if (s) {
355 #ifdef EFIBOOT_DEBUG
356 printf(">> Setting initrd path to '%s' from environment\n", s);
357 #endif
358 set_initrd_path(s);
359 FreePool(s);
360 }
361
362 s = efi_env_get("bootfile");
363 if (s) {
364 #ifdef EFIBOOT_DEBUG
365 printf(">> Setting bootfile path to '%s' from environment\n", s);
366 #endif
367 set_bootfile(s);
368 FreePool(s);
369 }
370
371 s = efi_env_get("rootdev");
372 if (s) {
373 #ifdef EFIBOOT_DEBUG
374 printf(">> Setting default device to '%s' from environment\n", s);
375 #endif
376 set_default_device(s);
377 FreePool(s);
378 }
379 }
380
381 void
382 boot(void)
383 {
384 int currname, c;
385
386 read_env();
387 print_banner();
388 printf("Press return to boot now, any other key for boot prompt\n");
389
390 if (netbsd_path[0] != '\0')
391 currname = -1;
392 else
393 currname = 0;
394
395 for (; currname < (int)NUMNAMES; currname++) {
396 if (currname >= 0)
397 set_bootfile(names[currname]);
398 printf("booting %s - starting in ", netbsd_path);
399
400 c = awaitkey(DEFTIMEOUT, 1);
401 if (c != '\r' && c != '\n' && c != '\0')
402 bootprompt(); /* does not return */
403
404 exec_netbsd(netbsd_path, "");
405 }
406
407 bootprompt(); /* does not return */
408 }
409