boot.c revision 1.5.2.4 1 /* $NetBSD: boot.c,v 1.5.2.4 2018/10/20 06:58:46 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[][2] = {
47 { "netbsd", "netbsd.gz" },
48 { "onetbsd", "onetbsd.gz" },
49 { "netbsd.old", "netbsd.old.gz" },
50 };
51
52 #define NUMNAMES __arraycount(names)
53 #define DEFFILENAME names[0][0]
54
55 #define DEFTIMEOUT 5
56
57 static char default_device[32];
58 static char initrd_path[255];
59 static char dtb_path[255];
60
61 void command_boot(char *);
62 void command_dev(char *);
63 void command_dtb(char *);
64 void command_initrd(char *);
65 void command_ls(char *);
66 void command_printenv(char *);
67 void command_setenv(char *);
68 void command_clearenv(char *);
69 void command_resetenv(char *);
70 void command_reset(char *);
71 void command_version(char *);
72 void command_quit(char *);
73
74 const struct boot_command commands[] = {
75 { "boot", command_boot, "boot [dev:][filename] [args]\n (ex. \"hd0a:\\netbsd.old -s\"" },
76 { "dev", command_dev, "dev" },
77 { "dtb", command_dtb, "dtb [dev:][filename]" },
78 { "initrd", command_initrd, "initrd [dev:][filename]" },
79 { "ls", command_ls, "ls [hdNn:/path]" },
80 { "printenv", command_printenv, "printenv [key]" },
81 { "setenv", command_setenv, "setenv <key> <value>" },
82 { "clearenv", command_clearenv, "clearenv <key>" },
83 { "resetenv", command_resetenv, "resetenv" },
84 { "reboot", command_reset, "reboot|reset" },
85 { "reset", command_reset, NULL },
86 { "version", command_version, "version" },
87 { "help", command_help, "help|?" },
88 { "?", command_help, NULL },
89 { "quit", command_quit, "quit" },
90 { NULL, NULL },
91 };
92
93 void
94 command_help(char *arg)
95 {
96 int n;
97
98 printf("commands are:\n");
99 for (n = 0; commands[n].c_name; n++) {
100 if (commands[n].c_help)
101 printf("%s\n", commands[n].c_help);
102 }
103 }
104
105 void
106 command_boot(char *arg)
107 {
108 char *fname = arg;
109 char *bootargs = gettrailer(arg);
110
111 exec_netbsd(*fname ? fname : DEFFILENAME, bootargs);
112 }
113
114 void
115 command_dev(char *arg)
116 {
117 if (arg && *arg) {
118 set_default_device(arg);
119 } else {
120 efi_block_show();
121 efi_net_show();
122 efi_pxe_show();
123 }
124
125 if (strlen(default_device) > 0) {
126 printf("\n");
127 printf("default: %s\n", default_device);
128 }
129 }
130
131 void
132 command_dtb(char *arg)
133 {
134 set_dtb_path(arg);
135 }
136
137 void
138 command_initrd(char *arg)
139 {
140 set_initrd_path(arg);
141 }
142
143 void
144 command_ls(char *arg)
145 {
146 ls(arg);
147 }
148
149 void
150 command_printenv(char *arg)
151 {
152 char *val;
153
154 if (arg && *arg) {
155 val = efi_env_get(arg);
156 if (val) {
157 printf("\"%s\" = \"%s\"\n", arg, val);
158 FreePool(val);
159 }
160 } else {
161 efi_env_print();
162 }
163 }
164
165 void
166 command_setenv(char *arg)
167 {
168 char *spc;
169
170 spc = strchr(arg, ' ');
171 if (spc == NULL || spc[1] == '\0') {
172 command_help("");
173 return;
174 }
175
176 *spc = '\0';
177 efi_env_set(arg, spc + 1);
178 }
179
180 void
181 command_clearenv(char *arg)
182 {
183 if (*arg == '\0') {
184 command_help("");
185 return;
186 }
187 efi_env_clear(arg);
188 }
189
190 void
191 command_resetenv(char *arg)
192 {
193 efi_env_reset();
194 }
195
196 void
197 command_version(char *arg)
198 {
199 char *ufirmware;
200 int rv;
201
202 printf("EFI version: %d.%02d\n",
203 ST->Hdr.Revision >> 16, ST->Hdr.Revision & 0xffff);
204 ufirmware = NULL;
205 rv = ucs2_to_utf8(ST->FirmwareVendor, &ufirmware);
206 if (rv == 0) {
207 printf("EFI Firmware: %s (rev %d.%02d)\n", ufirmware,
208 ST->FirmwareRevision >> 16,
209 ST->FirmwareRevision & 0xffff);
210 FreePool(ufirmware);
211 }
212
213 efi_fdt_show();
214 efi_acpi_show();
215 }
216
217 void
218 command_quit(char *arg)
219 {
220 efi_exit();
221 }
222
223 void
224 command_reset(char *arg)
225 {
226 efi_reboot();
227 }
228
229 int
230 set_default_device(char *arg)
231 {
232 if (strlen(arg) + 1 > sizeof(default_device))
233 return ERANGE;
234 strcpy(default_device, arg);
235 return 0;
236 }
237
238 char *
239 get_default_device(void)
240 {
241 return default_device;
242 }
243
244 int
245 set_initrd_path(char *arg)
246 {
247 if (strlen(arg) + 1 > sizeof(initrd_path))
248 return ERANGE;
249 strcpy(initrd_path, arg);
250 return 0;
251 }
252
253 char *
254 get_initrd_path(void)
255 {
256 return initrd_path;
257 }
258
259 int
260 set_dtb_path(char *arg)
261 {
262 if (strlen(arg) + 1 > sizeof(dtb_path))
263 return ERANGE;
264 strcpy(dtb_path, arg);
265 return 0;
266 }
267
268 char *
269 get_dtb_path(void)
270 {
271 return dtb_path;
272 }
273
274 void
275 print_banner(void)
276 {
277 printf("\n\n"
278 ">> %s, Revision %s (from NetBSD %s)\n",
279 bootprog_name, bootprog_rev, bootprog_kernrev);
280 }
281
282 static void
283 read_env(void)
284 {
285 char *s;
286
287 s = efi_env_get("fdtfile");
288 if (s) {
289 #ifdef EFIBOOT_DEBUG
290 printf(">> Setting DTB path to '%s' from environment\n", s);
291 #endif
292 set_dtb_path(s);
293 FreePool(s);
294 }
295
296 s = efi_env_get("initrd");
297 if (s) {
298 #ifdef EFIBOOT_DEBUG
299 printf(">> Setting initrd path to '%s' from environment\n", s);
300 #endif
301 set_initrd_path(s);
302 FreePool(s);
303 }
304
305 s = efi_env_get("rootdev");
306 if (s) {
307 #ifdef EFIBOOT_DEBUG
308 printf(">> Setting default device to '%s' from environment\n", s);
309 #endif
310 set_default_device(s);
311 FreePool(s);
312 }
313 }
314
315 void
316 boot(void)
317 {
318 int currname, c;
319
320 read_env();
321
322 print_banner();
323
324 printf("Press return to boot now, any other key for boot prompt\n");
325 for (currname = 0; currname < NUMNAMES; currname++) {
326 printf("booting %s - starting in ", names[currname][0]);
327
328 c = awaitkey(DEFTIMEOUT, 1);
329 if ((c != '\r') && (c != '\n') && (c != '\0')) {
330 bootprompt(); /* does not return */
331 }
332
333 /*
334 * try pairs of names[] entries, foo and foo.gz
335 */
336 exec_netbsd(names[currname][0], "");
337 exec_netbsd(names[currname][1], "");
338 }
339
340 bootprompt(); /* does not return */
341 }
342