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