xref: /freebsd/stand/efi/boot1/boot1.c (revision daceb336172a6b0572de864b97e70b28451ca636)
1 /*-
2  * Copyright (c) 1998 Robert Nordier
3  * All rights reserved.
4  * Copyright (c) 2001 Robert Drehmel
5  * All rights reserved.
6  * Copyright (c) 2014 Nathan Whitehorn
7  * All rights reserved.
8  * Copyright (c) 2015 Eric McCorkle
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms are freely
12  * permitted provided that the above copyright notice and this
13  * paragraph and the following disclaimer are duplicated in all
14  * such forms.
15  *
16  * This software is provided "AS IS" and without any express or
17  * implied warranties, including, without limitation, the implied
18  * warranties of merchantability and fitness for a particular
19  * purpose.
20  */
21 
22 #include <sys/cdefs.h>
23 __FBSDID("$FreeBSD$");
24 
25 #include <sys/param.h>
26 #include <machine/elf.h>
27 #include <machine/stdarg.h>
28 #include <stand.h>
29 
30 #include <efi.h>
31 #include <eficonsctl.h>
32 #include <efichar.h>
33 
34 #include "boot_module.h"
35 #include "paths.h"
36 
37 static void efi_panic(EFI_STATUS s, const char *fmt, ...) __dead2 __printflike(2, 3);
38 
39 static const boot_module_t *boot_modules[] =
40 {
41 #ifdef EFI_ZFS_BOOT
42 	&zfs_module,
43 #endif
44 #ifdef EFI_UFS_BOOT
45 	&ufs_module
46 #endif
47 };
48 
49 #define	NUM_BOOT_MODULES	nitems(boot_modules)
50 
51 static EFI_GUID BlockIoProtocolGUID = BLOCK_IO_PROTOCOL;
52 static EFI_GUID DevicePathGUID = DEVICE_PATH_PROTOCOL;
53 static EFI_GUID LoadedImageGUID = LOADED_IMAGE_PROTOCOL;
54 static EFI_GUID ConsoleControlGUID = EFI_CONSOLE_CONTROL_PROTOCOL_GUID;
55 
56 /*
57  * Provide Malloc / Free backed by EFIs AllocatePool / FreePool which ensures
58  * memory is correctly aligned avoiding EFI_INVALID_PARAMETER returns from
59  * EFI methods.
60  */
61 void *
62 Malloc(size_t len, const char *file __unused, int line __unused)
63 {
64 	void *out;
65 
66 	if (BS->AllocatePool(EfiLoaderData, len, &out) == EFI_SUCCESS)
67 		return (out);
68 
69 	return (NULL);
70 }
71 
72 void
73 Free(void *buf, const char *file __unused, int line __unused)
74 {
75 	if (buf != NULL)
76 		(void)BS->FreePool(buf);
77 }
78 
79 /*
80  * load_loader attempts to load the loader image data.
81  *
82  * It tries each module and its respective devices, identified by mod->probe,
83  * in order until a successful load occurs at which point it returns EFI_SUCCESS
84  * and EFI_NOT_FOUND otherwise.
85  *
86  * Only devices which have preferred matching the preferred parameter are tried.
87  */
88 static EFI_STATUS
89 load_loader(const boot_module_t **modp, dev_info_t **devinfop, void **bufp,
90     size_t *bufsize, BOOLEAN preferred)
91 {
92 	UINTN i;
93 	dev_info_t *dev;
94 	const boot_module_t *mod;
95 
96 	for (i = 0; i < NUM_BOOT_MODULES; i++) {
97 		mod = boot_modules[i];
98 		for (dev = mod->devices(); dev != NULL; dev = dev->next) {
99 			if (dev->preferred != preferred)
100 				continue;
101 
102 			if (mod->load(PATH_LOADER_EFI, dev, bufp, bufsize) ==
103 			    EFI_SUCCESS) {
104 				*devinfop = dev;
105 				*modp = mod;
106 				return (EFI_SUCCESS);
107 			}
108 		}
109 	}
110 
111 	return (EFI_NOT_FOUND);
112 }
113 
114 /*
115  * try_boot only returns if it fails to load the loader. If it succeeds
116  * it simply boots, otherwise it returns the status of last EFI call.
117  */
118 static EFI_STATUS
119 try_boot(void)
120 {
121 	size_t bufsize, loadersize, cmdsize;
122 	void *buf, *loaderbuf;
123 	char *cmd;
124 	dev_info_t *dev;
125 	const boot_module_t *mod;
126 	EFI_HANDLE loaderhandle;
127 	EFI_LOADED_IMAGE *loaded_image;
128 	EFI_STATUS status;
129 
130 	status = load_loader(&mod, &dev, &loaderbuf, &loadersize, TRUE);
131 	if (status != EFI_SUCCESS) {
132 		status = load_loader(&mod, &dev, &loaderbuf, &loadersize,
133 		    FALSE);
134 		if (status != EFI_SUCCESS) {
135 			printf("Failed to load '%s'\n", PATH_LOADER_EFI);
136 			return (status);
137 		}
138 	}
139 
140 	/*
141 	 * Read in and parse the command line from /boot.config or /boot/config,
142 	 * if present. We'll pass it the next stage via a simple ASCII
143 	 * string. loader.efi has a hack for ASCII strings, so we'll use that to
144 	 * keep the size down here. We only try to read the alternate file if
145 	 * we get EFI_NOT_FOUND because all other errors mean that the boot_module
146 	 * had troubles with the filesystem. We could return early, but we'll let
147 	 * loading the actual kernel sort all that out. Since these files are
148 	 * optional, we don't report errors in trying to read them.
149 	 */
150 	cmd = NULL;
151 	cmdsize = 0;
152 	status = mod->load(PATH_DOTCONFIG, dev, &buf, &bufsize);
153 	if (status == EFI_NOT_FOUND)
154 		status = mod->load(PATH_CONFIG, dev, &buf, &bufsize);
155 	if (status == EFI_SUCCESS) {
156 		cmdsize = bufsize + 1;
157 		cmd = malloc(cmdsize);
158 		if (cmd == NULL)
159 			goto errout;
160 		memcpy(cmd, buf, bufsize);
161 		cmd[bufsize] = '\0';
162 		free(buf);
163 		buf = NULL;
164 	}
165 
166 	if ((status = BS->LoadImage(TRUE, IH, efi_devpath_last_node(dev->devpath),
167 	    loaderbuf, loadersize, &loaderhandle)) != EFI_SUCCESS) {
168 		printf("Failed to load image provided by %s, size: %zu, (%lu)\n",
169 		     mod->name, loadersize, EFI_ERROR_CODE(status));
170 		goto errout;
171 	}
172 
173 	if ((status = BS->HandleProtocol(loaderhandle, &LoadedImageGUID,
174 	    (VOID**)&loaded_image)) != EFI_SUCCESS) {
175 		printf("Failed to query LoadedImage provided by %s (%lu)\n",
176 		    mod->name, EFI_ERROR_CODE(status));
177 		goto errout;
178 	}
179 
180 	if (cmd != NULL)
181 		printf("    command args: %s\n", cmd);
182 
183 	loaded_image->DeviceHandle = dev->devhandle;
184 	loaded_image->LoadOptionsSize = cmdsize;
185 	loaded_image->LoadOptions = cmd;
186 
187 	DPRINTF("Starting '%s' in 5 seconds...", PATH_LOADER_EFI);
188 	DSTALL(1000000);
189 	DPRINTF(".");
190 	DSTALL(1000000);
191 	DPRINTF(".");
192 	DSTALL(1000000);
193 	DPRINTF(".");
194 	DSTALL(1000000);
195 	DPRINTF(".");
196 	DSTALL(1000000);
197 	DPRINTF(".\n");
198 
199 	if ((status = BS->StartImage(loaderhandle, NULL, NULL)) !=
200 	    EFI_SUCCESS) {
201 		printf("Failed to start image provided by %s (%lu)\n",
202 		    mod->name, EFI_ERROR_CODE(status));
203 		loaded_image->LoadOptionsSize = 0;
204 		loaded_image->LoadOptions = NULL;
205 	}
206 
207 errout:
208 	if (cmd != NULL)
209 		free(cmd);
210 	if (buf != NULL)
211 		free(buf);
212 	if (loaderbuf != NULL)
213 		free(loaderbuf);
214 
215 	return (status);
216 }
217 
218 /*
219  * probe_handle determines if the passed handle represents a logical partition
220  * if it does it uses each module in order to probe it and if successful it
221  * returns EFI_SUCCESS.
222  */
223 static EFI_STATUS
224 probe_handle(EFI_HANDLE h, EFI_DEVICE_PATH *imgpath, BOOLEAN *preferred)
225 {
226 	dev_info_t *devinfo;
227 	EFI_BLOCK_IO *blkio;
228 	EFI_DEVICE_PATH *devpath;
229 	EFI_STATUS status;
230 	UINTN i;
231 
232 	/* Figure out if we're dealing with an actual partition. */
233 	status = BS->HandleProtocol(h, &DevicePathGUID, (void **)&devpath);
234 	if (status == EFI_UNSUPPORTED)
235 		return (status);
236 
237 	if (status != EFI_SUCCESS) {
238 		DPRINTF("\nFailed to query DevicePath (%lu)\n",
239 		    EFI_ERROR_CODE(status));
240 		return (status);
241 	}
242 #ifdef EFI_DEBUG
243 	{
244 		CHAR16 *text = efi_devpath_name(devpath);
245 		DPRINTF("probing: %S\n", text);
246 		efi_free_devpath_name(text);
247 	}
248 #endif
249 	status = BS->HandleProtocol(h, &BlockIoProtocolGUID, (void **)&blkio);
250 	if (status == EFI_UNSUPPORTED)
251 		return (status);
252 
253 	if (status != EFI_SUCCESS) {
254 		DPRINTF("\nFailed to query BlockIoProtocol (%lu)\n",
255 		    EFI_ERROR_CODE(status));
256 		return (status);
257 	}
258 
259 	if (!blkio->Media->LogicalPartition)
260 		return (EFI_UNSUPPORTED);
261 
262 	*preferred = efi_devpath_match(imgpath, devpath);
263 
264 	/* Run through each module, see if it can load this partition */
265 	devinfo = malloc(sizeof(*devinfo));
266 	if (devinfo == NULL) {
267 		DPRINTF("\nFailed to allocate devinfo\n");
268 		return (EFI_UNSUPPORTED);
269 	}
270 	devinfo->dev = blkio;
271 	devinfo->devpath = devpath;
272 	devinfo->devhandle = h;
273 	devinfo->preferred = *preferred;
274 	devinfo->next = NULL;
275 
276 	for (i = 0; i < NUM_BOOT_MODULES; i++) {
277 		devinfo->devdata = NULL;
278 		status = boot_modules[i]->probe(devinfo);
279 		if (status == EFI_SUCCESS)
280 			return (EFI_SUCCESS);
281 	}
282 	free(devinfo);
283 
284 	return (EFI_UNSUPPORTED);
285 }
286 
287 /*
288  * probe_handle_status calls probe_handle and outputs the returned status
289  * of the call.
290  */
291 static void
292 probe_handle_status(EFI_HANDLE h, EFI_DEVICE_PATH *imgpath)
293 {
294 	EFI_STATUS status;
295 	BOOLEAN preferred;
296 
297 	preferred = FALSE;
298 	status = probe_handle(h, imgpath, &preferred);
299 
300 	DPRINTF("probe: ");
301 	switch (status) {
302 	case EFI_UNSUPPORTED:
303 		printf(".");
304 		DPRINTF(" not supported\n");
305 		break;
306 	case EFI_SUCCESS:
307 		if (preferred) {
308 			printf("%c", '*');
309 			DPRINTF(" supported (preferred)\n");
310 		} else {
311 			printf("%c", '+');
312 			DPRINTF(" supported\n");
313 		}
314 		break;
315 	default:
316 		printf("x");
317 		DPRINTF(" error (%lu)\n", EFI_ERROR_CODE(status));
318 		break;
319 	}
320 	DSTALL(500000);
321 }
322 
323 EFI_STATUS
324 efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE *Xsystab)
325 {
326 	EFI_HANDLE *handles;
327 	EFI_LOADED_IMAGE *img;
328 	EFI_DEVICE_PATH *imgpath;
329 	EFI_STATUS status;
330 	EFI_CONSOLE_CONTROL_PROTOCOL *ConsoleControl = NULL;
331 	SIMPLE_TEXT_OUTPUT_INTERFACE *conout = NULL;
332 	UINTN i, hsize, nhandles;
333 	CHAR16 *text;
334 	UINT16 boot_current;
335 	size_t sz;
336 	UINT16 boot_order[100];
337 
338 	/* Basic initialization*/
339 	ST = Xsystab;
340 	IH = Ximage;
341 	BS = ST->BootServices;
342 	RS = ST->RuntimeServices;
343 
344 	/* Set up the console, so printf works. */
345 	status = BS->LocateProtocol(&ConsoleControlGUID, NULL,
346 	    (VOID **)&ConsoleControl);
347 	if (status == EFI_SUCCESS)
348 		(void)ConsoleControl->SetMode(ConsoleControl,
349 		    EfiConsoleControlScreenText);
350 	/*
351 	 * Reset the console enable the cursor. Later we'll choose a better
352 	 * console size through GOP/UGA.
353 	 */
354 	conout = ST->ConOut;
355 	conout->Reset(conout, TRUE);
356 	/* Explicitly set conout to mode 0, 80x25 */
357 	conout->SetMode(conout, 0);
358 	conout->EnableCursor(conout, TRUE);
359 	conout->ClearScreen(conout);
360 
361 	printf("\n>> FreeBSD EFI boot block\n");
362 	printf("   Loader path: %s\n\n", PATH_LOADER_EFI);
363 	printf("   Initializing modules:");
364 	for (i = 0; i < NUM_BOOT_MODULES; i++) {
365 		printf(" %s", boot_modules[i]->name);
366 		if (boot_modules[i]->init != NULL)
367 			boot_modules[i]->init();
368 	}
369 	putchar('\n');
370 
371 	/* Determine the devpath of our image so we can prefer it. */
372 	status = BS->HandleProtocol(IH, &LoadedImageGUID, (VOID**)&img);
373 	imgpath = NULL;
374 	if (status == EFI_SUCCESS) {
375 		text = efi_devpath_name(img->FilePath);
376 		if (text != NULL) {
377 			printf("   Load Path: %S\n", text);
378 			efi_setenv_freebsd_wcs("Boot1Path", text);
379 			efi_free_devpath_name(text);
380 		}
381 
382 		status = BS->HandleProtocol(img->DeviceHandle, &DevicePathGUID,
383 		    (void **)&imgpath);
384 		if (status != EFI_SUCCESS) {
385 			DPRINTF("Failed to get image DevicePath (%lu)\n",
386 			    EFI_ERROR_CODE(status));
387 		} else {
388 			text = efi_devpath_name(imgpath);
389 			if (text != NULL) {
390 				printf("   Load Device: %S\n", text);
391 				efi_setenv_freebsd_wcs("Boot1Dev", text);
392 				efi_free_devpath_name(text);
393 			}
394 		}
395 	}
396 
397 	boot_current = 0;
398 	sz = sizeof(boot_current);
399 	if (efi_global_getenv("BootCurrent", &boot_current, &sz) == EFI_SUCCESS) {
400 		printf("   BootCurrent: %04x\n", boot_current);
401 
402 		sz = sizeof(boot_order);
403 		if (efi_global_getenv("BootOrder", &boot_order, &sz) == EFI_SUCCESS) {
404 			printf("   BootOrder:");
405 			for (i = 0; i < sz / sizeof(boot_order[0]); i++)
406 				printf(" %04x%s", boot_order[i],
407 				    boot_order[i] == boot_current ? "[*]" : "");
408 			printf("\n");
409 		}
410 	}
411 
412 #ifdef TEST_FAILURE
413 	/*
414 	 * For testing failover scenarios, it's nice to be able to fail fast.
415 	 * Define TEST_FAILURE to create a boot1.efi that always fails after
416 	 * reporting the boot manager protocol details.
417 	 */
418 	BS->Exit(IH, EFI_OUT_OF_RESOURCES, 0, NULL);
419 #endif
420 
421 	hsize = 0;
422 	BS->LocateHandle(ByProtocol, &BlockIoProtocolGUID, NULL,
423 	    &hsize, NULL);
424 	handles = malloc(hsize);
425 	if (handles == NULL)
426 		efi_panic(EFI_OUT_OF_RESOURCES, "Failed to allocate %d handles\n",
427 		    hsize);
428 	status = BS->LocateHandle(ByProtocol, &BlockIoProtocolGUID,
429 	    NULL, &hsize, handles);
430 	if (status != EFI_SUCCESS)
431 		efi_panic(status, "Failed to get device handles\n");
432 
433 	/* Scan all partitions, probing with all modules. */
434 	nhandles = hsize / sizeof(*handles);
435 	printf("   Probing %zu block devices...", nhandles);
436 	DPRINTF("\n");
437 
438 	for (i = 0; i < nhandles; i++)
439 		probe_handle_status(handles[i], imgpath);
440 	printf(" done\n");
441 
442 	/* Status summary. */
443 	for (i = 0; i < NUM_BOOT_MODULES; i++) {
444 		printf("    ");
445 		boot_modules[i]->status();
446 	}
447 
448 	try_boot();
449 
450 	/* If we get here, we're out of luck... */
451 	efi_panic(EFI_LOAD_ERROR, "No bootable partitions found!");
452 }
453 
454 /*
455  * add_device adds a device to the passed devinfo list.
456  */
457 void
458 add_device(dev_info_t **devinfop, dev_info_t *devinfo)
459 {
460 	dev_info_t *dev;
461 
462 	if (*devinfop == NULL) {
463 		*devinfop = devinfo;
464 		return;
465 	}
466 
467 	for (dev = *devinfop; dev->next != NULL; dev = dev->next)
468 		;
469 
470 	dev->next = devinfo;
471 }
472 
473 /*
474  * OK. We totally give up. Exit back to EFI with a sensible status so
475  * it can try the next option on the list.
476  */
477 static void
478 efi_panic(EFI_STATUS s, const char *fmt, ...)
479 {
480 	va_list ap;
481 
482 	printf("panic: ");
483 	va_start(ap, fmt);
484 	vprintf(fmt, ap);
485 	va_end(ap);
486 	printf("\n");
487 
488 	BS->Exit(IH, s, 0, NULL);
489 }
490 
491 void
492 putchar(int c)
493 {
494 	CHAR16 buf[2];
495 
496 	if (c == '\n') {
497 		buf[0] = '\r';
498 		buf[1] = 0;
499 		ST->ConOut->OutputString(ST->ConOut, buf);
500 	}
501 	buf[0] = c;
502 	buf[1] = 0;
503 	ST->ConOut->OutputString(ST->ConOut, buf);
504 }
505