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