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