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