boot1.c revision 329114
1264391Snwhitehorn/*-
2264391Snwhitehorn * Copyright (c) 1998 Robert Nordier
3264391Snwhitehorn * All rights reserved.
4264391Snwhitehorn * Copyright (c) 2001 Robert Drehmel
5264391Snwhitehorn * All rights reserved.
6264404Snwhitehorn * Copyright (c) 2014 Nathan Whitehorn
7264404Snwhitehorn * All rights reserved.
8294060Ssmh * Copyright (c) 2015 Eric McCorkle
9294060Ssmh * All rights reserved.
10264391Snwhitehorn *
11264391Snwhitehorn * Redistribution and use in source and binary forms are freely
12264391Snwhitehorn * permitted provided that the above copyright notice and this
13264391Snwhitehorn * paragraph and the following disclaimer are duplicated in all
14264391Snwhitehorn * such forms.
15264391Snwhitehorn *
16264391Snwhitehorn * This software is provided "AS IS" and without any express or
17264391Snwhitehorn * implied warranties, including, without limitation, the implied
18264391Snwhitehorn * warranties of merchantability and fitness for a particular
19264391Snwhitehorn * purpose.
20264391Snwhitehorn */
21264391Snwhitehorn
22264391Snwhitehorn#include <sys/cdefs.h>
23264391Snwhitehorn__FBSDID("$FreeBSD: stable/11/sys/boot/efi/boot1/boot1.c 329114 2018-02-11 02:27:50Z kevans $");
24264391Snwhitehorn
25264391Snwhitehorn#include <sys/param.h>
26264391Snwhitehorn#include <machine/elf.h>
27264391Snwhitehorn#include <machine/stdarg.h>
28293460Ssmh#include <stand.h>
29264391Snwhitehorn
30264391Snwhitehorn#include <efi.h>
31271762Semaste#include <eficonsctl.h>
32329114Skevanstypedef CHAR16 efi_char;
33329114Skevans#include <efichar.h>
34264391Snwhitehorn
35294060Ssmh#include "boot_module.h"
36294765Simp#include "paths.h"
37294060Ssmh
38329114Skevansstatic void efi_panic(EFI_STATUS s, const char *fmt, ...) __dead2 __printflike(2, 3);
39329114Skevans
40294060Ssmhstatic const boot_module_t *boot_modules[] =
41294060Ssmh{
42294068Ssmh#ifdef EFI_ZFS_BOOT
43294068Ssmh	&zfs_module,
44294068Ssmh#endif
45294060Ssmh#ifdef EFI_UFS_BOOT
46294060Ssmh	&ufs_module
47294060Ssmh#endif
48294060Ssmh};
49264391Snwhitehorn
50323484Srlibby#define	NUM_BOOT_MODULES	nitems(boot_modules)
51294060Ssmh/* The initial number of handles used to query EFI for partitions. */
52294060Ssmh#define NUM_HANDLES_INIT	24
53294060Ssmh
54264391Snwhitehornstatic EFI_GUID BlockIoProtocolGUID = BLOCK_IO_PROTOCOL;
55264391Snwhitehornstatic EFI_GUID DevicePathGUID = DEVICE_PATH_PROTOCOL;
56264391Snwhitehornstatic EFI_GUID LoadedImageGUID = LOADED_IMAGE_PROTOCOL;
57271762Semastestatic EFI_GUID ConsoleControlGUID = EFI_CONSOLE_CONTROL_PROTOCOL_GUID;
58329114Skevansstatic EFI_GUID FreeBSDBootVarGUID = FREEBSD_BOOT_VAR_GUID;
59264391Snwhitehorn
60294060Ssmh/*
61294060Ssmh * Provide Malloc / Free backed by EFIs AllocatePool / FreePool which ensures
62294060Ssmh * memory is correctly aligned avoiding EFI_INVALID_PARAMETER returns from
63294060Ssmh * EFI methods.
64294060Ssmh */
65294060Ssmhvoid *
66294060SsmhMalloc(size_t len, const char *file __unused, int line __unused)
67294060Ssmh{
68294060Ssmh	void *out;
69264391Snwhitehorn
70329114Skevans	if (BS->AllocatePool(EfiLoaderData, len, &out) == EFI_SUCCESS)
71294060Ssmh		return (out);
72294060Ssmh
73294060Ssmh	return (NULL);
74294060Ssmh}
75294060Ssmh
76294060Ssmhvoid
77294060SsmhFree(void *buf, const char *file __unused, int line __unused)
78264391Snwhitehorn{
79329010Skevans	if (buf != NULL)
80329114Skevans		(void)BS->FreePool(buf);
81294060Ssmh}
82294060Ssmh
83329114Skevansstatic EFI_STATUS
84329114Skevansefi_setenv_freebsd_wcs(const char *varname, CHAR16 *valstr)
85329114Skevans{
86329114Skevans	CHAR16 *var = NULL;
87329114Skevans	size_t len;
88329114Skevans	EFI_STATUS rv;
89329114Skevans
90329114Skevans	utf8_to_ucs2(varname, &var, &len);
91329114Skevans	if (var == NULL)
92329114Skevans		return (EFI_OUT_OF_RESOURCES);
93329114Skevans	rv = RS->SetVariable(var, &FreeBSDBootVarGUID,
94329114Skevans	    EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
95329114Skevans	    (ucs2len(valstr) + 1) * sizeof(efi_char), valstr);
96329114Skevans	free(var);
97329114Skevans	return (rv);
98329114Skevans}
99329114Skevans
100294060Ssmh/*
101295320Ssmh * nodes_match returns TRUE if the imgpath isn't NULL and the nodes match,
102295320Ssmh * FALSE otherwise.
103294060Ssmh */
104295320Ssmhstatic BOOLEAN
105295320Ssmhnodes_match(EFI_DEVICE_PATH *imgpath, EFI_DEVICE_PATH *devpath)
106294060Ssmh{
107329114Skevans	size_t len;
108295320Ssmh
109295320Ssmh	if (imgpath == NULL || imgpath->Type != devpath->Type ||
110295320Ssmh	    imgpath->SubType != devpath->SubType)
111295320Ssmh		return (FALSE);
112295320Ssmh
113295320Ssmh	len = DevicePathNodeLength(imgpath);
114295320Ssmh	if (len != DevicePathNodeLength(devpath))
115295320Ssmh		return (FALSE);
116295320Ssmh
117295320Ssmh	return (memcmp(imgpath, devpath, (size_t)len) == 0);
118295320Ssmh}
119295320Ssmh
120295320Ssmh/*
121295320Ssmh * device_paths_match returns TRUE if the imgpath isn't NULL and all nodes
122298826Spfg * in imgpath and devpath match up to their respective occurrences of a
123298826Spfg * media node, FALSE otherwise.
124295320Ssmh */
125295320Ssmhstatic BOOLEAN
126295320Ssmhdevice_paths_match(EFI_DEVICE_PATH *imgpath, EFI_DEVICE_PATH *devpath)
127295320Ssmh{
128295320Ssmh
129295320Ssmh	if (imgpath == NULL)
130295320Ssmh		return (FALSE);
131295320Ssmh
132295320Ssmh	while (!IsDevicePathEnd(imgpath) && !IsDevicePathEnd(devpath)) {
133295320Ssmh		if (IsDevicePathType(imgpath, MEDIA_DEVICE_PATH) &&
134295320Ssmh		    IsDevicePathType(devpath, MEDIA_DEVICE_PATH))
135295320Ssmh			return (TRUE);
136295320Ssmh
137295320Ssmh		if (!nodes_match(imgpath, devpath))
138295320Ssmh			return (FALSE);
139295320Ssmh
140295320Ssmh		imgpath = NextDevicePathNode(imgpath);
141295320Ssmh		devpath = NextDevicePathNode(devpath);
142295320Ssmh	}
143295320Ssmh
144295320Ssmh	return (FALSE);
145295320Ssmh}
146295320Ssmh
147295320Ssmh/*
148295320Ssmh * devpath_last returns the last non-path end node in devpath.
149295320Ssmh */
150295320Ssmhstatic EFI_DEVICE_PATH *
151295320Ssmhdevpath_last(EFI_DEVICE_PATH *devpath)
152295320Ssmh{
153295320Ssmh
154295320Ssmh	while (!IsDevicePathEnd(NextDevicePathNode(devpath)))
155295320Ssmh		devpath = NextDevicePathNode(devpath);
156295320Ssmh
157295320Ssmh	return (devpath);
158295320Ssmh}
159295320Ssmh
160295320Ssmh/*
161295320Ssmh * load_loader attempts to load the loader image data.
162295320Ssmh *
163295320Ssmh * It tries each module and its respective devices, identified by mod->probe,
164295320Ssmh * in order until a successful load occurs at which point it returns EFI_SUCCESS
165295320Ssmh * and EFI_NOT_FOUND otherwise.
166295320Ssmh *
167295320Ssmh * Only devices which have preferred matching the preferred parameter are tried.
168295320Ssmh */
169295320Ssmhstatic EFI_STATUS
170295320Ssmhload_loader(const boot_module_t **modp, dev_info_t **devinfop, void **bufp,
171295320Ssmh    size_t *bufsize, BOOLEAN preferred)
172295320Ssmh{
173295320Ssmh	UINTN i;
174295320Ssmh	dev_info_t *dev;
175295320Ssmh	const boot_module_t *mod;
176295320Ssmh
177295320Ssmh	for (i = 0; i < NUM_BOOT_MODULES; i++) {
178295320Ssmh		mod = boot_modules[i];
179295320Ssmh		for (dev = mod->devices(); dev != NULL; dev = dev->next) {
180295320Ssmh			if (dev->preferred != preferred)
181295320Ssmh				continue;
182295320Ssmh
183295320Ssmh			if (mod->load(PATH_LOADER_EFI, dev, bufp, bufsize) ==
184295320Ssmh			    EFI_SUCCESS) {
185295320Ssmh				*devinfop = dev;
186295320Ssmh				*modp = mod;
187295320Ssmh				return (EFI_SUCCESS);
188295320Ssmh			}
189295320Ssmh		}
190295320Ssmh	}
191295320Ssmh
192295320Ssmh	return (EFI_NOT_FOUND);
193295320Ssmh}
194295320Ssmh
195295320Ssmh/*
196295320Ssmh * try_boot only returns if it fails to load the loader. If it succeeds
197295320Ssmh * it simply boots, otherwise it returns the status of last EFI call.
198295320Ssmh */
199295320Ssmhstatic EFI_STATUS
200323484Srlibbytry_boot(void)
201295320Ssmh{
202295320Ssmh	size_t bufsize, loadersize, cmdsize;
203295320Ssmh	void *buf, *loaderbuf;
204294768Simp	char *cmd;
205294060Ssmh	dev_info_t *dev;
206295320Ssmh	const boot_module_t *mod;
207294060Ssmh	EFI_HANDLE loaderhandle;
208294060Ssmh	EFI_LOADED_IMAGE *loaded_image;
209264391Snwhitehorn	EFI_STATUS status;
210294060Ssmh
211295320Ssmh	status = load_loader(&mod, &dev, &loaderbuf, &loadersize, TRUE);
212295320Ssmh	if (status != EFI_SUCCESS) {
213295320Ssmh		status = load_loader(&mod, &dev, &loaderbuf, &loadersize,
214295320Ssmh		    FALSE);
215295320Ssmh		if (status != EFI_SUCCESS) {
216295320Ssmh			printf("Failed to load '%s'\n", PATH_LOADER_EFI);
217295320Ssmh			return (status);
218295320Ssmh		}
219295320Ssmh	}
220295320Ssmh
221294768Simp	/*
222294768Simp	 * Read in and parse the command line from /boot.config or /boot/config,
223294768Simp	 * if present. We'll pass it the next stage via a simple ASCII
224294768Simp	 * string. loader.efi has a hack for ASCII strings, so we'll use that to
225294768Simp	 * keep the size down here. We only try to read the alternate file if
226294768Simp	 * we get EFI_NOT_FOUND because all other errors mean that the boot_module
227294768Simp	 * had troubles with the filesystem. We could return early, but we'll let
228294768Simp	 * loading the actual kernel sort all that out. Since these files are
229294768Simp	 * optional, we don't report errors in trying to read them.
230294768Simp	 */
231294768Simp	cmd = NULL;
232294768Simp	cmdsize = 0;
233295320Ssmh	status = mod->load(PATH_DOTCONFIG, dev, &buf, &bufsize);
234294768Simp	if (status == EFI_NOT_FOUND)
235295320Ssmh		status = mod->load(PATH_CONFIG, dev, &buf, &bufsize);
236294768Simp	if (status == EFI_SUCCESS) {
237294768Simp		cmdsize = bufsize + 1;
238294768Simp		cmd = malloc(cmdsize);
239295320Ssmh		if (cmd == NULL)
240295320Ssmh			goto errout;
241294768Simp		memcpy(cmd, buf, bufsize);
242294768Simp		cmd[bufsize] = '\0';
243294768Simp		free(buf);
244295320Ssmh		buf = NULL;
245294768Simp	}
246294768Simp
247329114Skevans	if ((status = BS->LoadImage(TRUE, IH, devpath_last(dev->devpath),
248295320Ssmh	    loaderbuf, loadersize, &loaderhandle)) != EFI_SUCCESS) {
249294060Ssmh		printf("Failed to load image provided by %s, size: %zu, (%lu)\n",
250296713Sandrew		     mod->name, loadersize, EFI_ERROR_CODE(status));
251295320Ssmh		goto errout;
252294060Ssmh	}
253294060Ssmh
254329114Skevans	if ((status = BS->HandleProtocol(loaderhandle, &LoadedImageGUID,
255294060Ssmh	    (VOID**)&loaded_image)) != EFI_SUCCESS) {
256294060Ssmh		printf("Failed to query LoadedImage provided by %s (%lu)\n",
257294060Ssmh		    mod->name, EFI_ERROR_CODE(status));
258295320Ssmh		goto errout;
259294060Ssmh	}
260294060Ssmh
261295320Ssmh	if (cmd != NULL)
262295320Ssmh		printf("    command args: %s\n", cmd);
263295320Ssmh
264294060Ssmh	loaded_image->DeviceHandle = dev->devhandle;
265294768Simp	loaded_image->LoadOptionsSize = cmdsize;
266294768Simp	loaded_image->LoadOptions = cmd;
267294060Ssmh
268295320Ssmh	DPRINTF("Starting '%s' in 5 seconds...", PATH_LOADER_EFI);
269295320Ssmh	DSTALL(1000000);
270295320Ssmh	DPRINTF(".");
271295320Ssmh	DSTALL(1000000);
272295320Ssmh	DPRINTF(".");
273295320Ssmh	DSTALL(1000000);
274295320Ssmh	DPRINTF(".");
275295320Ssmh	DSTALL(1000000);
276295320Ssmh	DPRINTF(".");
277295320Ssmh	DSTALL(1000000);
278295320Ssmh	DPRINTF(".\n");
279295320Ssmh
280329114Skevans	if ((status = BS->StartImage(loaderhandle, NULL, NULL)) !=
281294060Ssmh	    EFI_SUCCESS) {
282294284Semaste		printf("Failed to start image provided by %s (%lu)\n",
283294284Semaste		    mod->name, EFI_ERROR_CODE(status));
284294768Simp		loaded_image->LoadOptionsSize = 0;
285294768Simp		loaded_image->LoadOptions = NULL;
286294060Ssmh	}
287295320Ssmh
288295320Ssmherrout:
289295320Ssmh	if (cmd != NULL)
290295320Ssmh		free(cmd);
291295320Ssmh	if (buf != NULL)
292295320Ssmh		free(buf);
293295320Ssmh	if (loaderbuf != NULL)
294295320Ssmh		free(loaderbuf);
295295320Ssmh
296295320Ssmh	return (status);
297294060Ssmh}
298294060Ssmh
299295320Ssmh/*
300295320Ssmh * probe_handle determines if the passed handle represents a logical partition
301295320Ssmh * if it does it uses each module in order to probe it and if successful it
302295320Ssmh * returns EFI_SUCCESS.
303295320Ssmh */
304295320Ssmhstatic EFI_STATUS
305295320Ssmhprobe_handle(EFI_HANDLE h, EFI_DEVICE_PATH *imgpath, BOOLEAN *preferred)
306295320Ssmh{
307295320Ssmh	dev_info_t *devinfo;
308295320Ssmh	EFI_BLOCK_IO *blkio;
309295320Ssmh	EFI_DEVICE_PATH *devpath;
310295320Ssmh	EFI_STATUS status;
311295320Ssmh	UINTN i;
312295320Ssmh
313295320Ssmh	/* Figure out if we're dealing with an actual partition. */
314329114Skevans	status = BS->HandleProtocol(h, &DevicePathGUID, (void **)&devpath);
315295320Ssmh	if (status == EFI_UNSUPPORTED)
316295320Ssmh		return (status);
317295320Ssmh
318295320Ssmh	if (status != EFI_SUCCESS) {
319295320Ssmh		DPRINTF("\nFailed to query DevicePath (%lu)\n",
320295320Ssmh		    EFI_ERROR_CODE(status));
321295320Ssmh		return (status);
322295320Ssmh	}
323329114Skevans#ifdef EFI_DEBUG
324329114Skevans	{
325329114Skevans		CHAR16 *text = efi_devpath_name(devpath);
326329114Skevans		DPRINTF("probing: %S\n", text);
327329114Skevans		efi_free_devpath_name(text);
328329114Skevans	}
329329114Skevans#endif
330329114Skevans	status = BS->HandleProtocol(h, &BlockIoProtocolGUID, (void **)&blkio);
331295320Ssmh	if (status == EFI_UNSUPPORTED)
332295320Ssmh		return (status);
333295320Ssmh
334295320Ssmh	if (status != EFI_SUCCESS) {
335295320Ssmh		DPRINTF("\nFailed to query BlockIoProtocol (%lu)\n",
336295320Ssmh		    EFI_ERROR_CODE(status));
337295320Ssmh		return (status);
338295320Ssmh	}
339295320Ssmh
340295320Ssmh	if (!blkio->Media->LogicalPartition)
341295320Ssmh		return (EFI_UNSUPPORTED);
342295320Ssmh
343295320Ssmh	*preferred = device_paths_match(imgpath, devpath);
344295320Ssmh
345295320Ssmh	/* Run through each module, see if it can load this partition */
346295320Ssmh	for (i = 0; i < NUM_BOOT_MODULES; i++) {
347329114Skevans		devinfo = malloc(sizeof(*devinfo));
348329114Skevans		if (devinfo == NULL) {
349329114Skevans			DPRINTF("\nFailed to allocate devinfo\n");
350295320Ssmh			continue;
351295320Ssmh		}
352295320Ssmh		devinfo->dev = blkio;
353295320Ssmh		devinfo->devpath = devpath;
354295320Ssmh		devinfo->devhandle = h;
355295320Ssmh		devinfo->devdata = NULL;
356295320Ssmh		devinfo->preferred = *preferred;
357295320Ssmh		devinfo->next = NULL;
358295320Ssmh
359295320Ssmh		status = boot_modules[i]->probe(devinfo);
360295320Ssmh		if (status == EFI_SUCCESS)
361295320Ssmh			return (EFI_SUCCESS);
362329114Skevans		free(devinfo);
363295320Ssmh	}
364295320Ssmh
365295320Ssmh	return (EFI_UNSUPPORTED);
366295320Ssmh}
367295320Ssmh
368295320Ssmh/*
369295320Ssmh * probe_handle_status calls probe_handle and outputs the returned status
370295320Ssmh * of the call.
371295320Ssmh */
372295320Ssmhstatic void
373295320Ssmhprobe_handle_status(EFI_HANDLE h, EFI_DEVICE_PATH *imgpath)
374295320Ssmh{
375295320Ssmh	EFI_STATUS status;
376295320Ssmh	BOOLEAN preferred;
377295320Ssmh
378329100Skevans	preferred = FALSE;
379295320Ssmh	status = probe_handle(h, imgpath, &preferred);
380295320Ssmh
381295320Ssmh	DPRINTF("probe: ");
382295320Ssmh	switch (status) {
383295320Ssmh	case EFI_UNSUPPORTED:
384295320Ssmh		printf(".");
385295320Ssmh		DPRINTF(" not supported\n");
386295320Ssmh		break;
387295320Ssmh	case EFI_SUCCESS:
388295320Ssmh		if (preferred) {
389295320Ssmh			printf("%c", '*');
390295320Ssmh			DPRINTF(" supported (preferred)\n");
391295320Ssmh		} else {
392295320Ssmh			printf("%c", '+');
393295320Ssmh			DPRINTF(" supported\n");
394295320Ssmh		}
395295320Ssmh		break;
396295320Ssmh	default:
397295320Ssmh		printf("x");
398295320Ssmh		DPRINTF(" error (%lu)\n", EFI_ERROR_CODE(status));
399295320Ssmh		break;
400295320Ssmh	}
401295320Ssmh	DSTALL(500000);
402295320Ssmh}
403295320Ssmh
404294060SsmhEFI_STATUS
405294060Ssmhefi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE *Xsystab)
406294060Ssmh{
407294060Ssmh	EFI_HANDLE *handles;
408295320Ssmh	EFI_LOADED_IMAGE *img;
409295320Ssmh	EFI_DEVICE_PATH *imgpath;
410294060Ssmh	EFI_STATUS status;
411271762Semaste	EFI_CONSOLE_CONTROL_PROTOCOL *ConsoleControl = NULL;
412281059Srpaulo	SIMPLE_TEXT_OUTPUT_INTERFACE *conout = NULL;
413294060Ssmh	UINTN i, max_dim, best_mode, cols, rows, hsize, nhandles;
414329114Skevans	CHAR16 *text;
415264391Snwhitehorn
416294060Ssmh	/* Basic initialization*/
417329114Skevans	ST = Xsystab;
418329114Skevans	IH = Ximage;
419329114Skevans	BS = ST->BootServices;
420329114Skevans	RS = ST->RuntimeServices;
421264391Snwhitehorn
422294060Ssmh	/* Set up the console, so printf works. */
423329114Skevans	status = BS->LocateProtocol(&ConsoleControlGUID, NULL,
424271762Semaste	    (VOID **)&ConsoleControl);
425271762Semaste	if (status == EFI_SUCCESS)
426271762Semaste		(void)ConsoleControl->SetMode(ConsoleControl,
427271762Semaste		    EfiConsoleControlScreenText);
428281059Srpaulo	/*
429281059Srpaulo	 * Reset the console and find the best text mode.
430281059Srpaulo	 */
431329114Skevans	conout = ST->ConOut;
432281059Srpaulo	conout->Reset(conout, TRUE);
433281059Srpaulo	max_dim = best_mode = 0;
434281059Srpaulo	for (i = 0; ; i++) {
435293274Ssmh		status = conout->QueryMode(conout, i, &cols, &rows);
436281059Srpaulo		if (EFI_ERROR(status))
437281059Srpaulo			break;
438281059Srpaulo		if (cols * rows > max_dim) {
439281059Srpaulo			max_dim = cols * rows;
440281059Srpaulo			best_mode = i;
441281059Srpaulo		}
442281059Srpaulo	}
443281059Srpaulo	if (max_dim > 0)
444281059Srpaulo		conout->SetMode(conout, best_mode);
445281059Srpaulo	conout->EnableCursor(conout, TRUE);
446281059Srpaulo	conout->ClearScreen(conout);
447271762Semaste
448294060Ssmh	printf("\n>> FreeBSD EFI boot block\n");
449294765Simp	printf("   Loader path: %s\n\n", PATH_LOADER_EFI);
450294060Ssmh	printf("   Initializing modules:");
451294060Ssmh	for (i = 0; i < NUM_BOOT_MODULES; i++) {
452294060Ssmh		printf(" %s", boot_modules[i]->name);
453294060Ssmh		if (boot_modules[i]->init != NULL)
454294060Ssmh			boot_modules[i]->init();
455294060Ssmh	}
456294060Ssmh	putchar('\n');
457264391Snwhitehorn
458329114Skevans	/* Determine the devpath of our image so we can prefer it. */
459329114Skevans	status = BS->HandleProtocol(IH, &LoadedImageGUID, (VOID**)&img);
460329114Skevans	imgpath = NULL;
461329114Skevans	if (status == EFI_SUCCESS) {
462329114Skevans		text = efi_devpath_name(img->FilePath);
463329114Skevans		printf("   Load Path: %S\n", text);
464329114Skevans		efi_setenv_freebsd_wcs("Boot1Path", text);
465329114Skevans		efi_free_devpath_name(text);
466329114Skevans
467329114Skevans		status = BS->HandleProtocol(img->DeviceHandle, &DevicePathGUID,
468329114Skevans		    (void **)&imgpath);
469329114Skevans		if (status != EFI_SUCCESS) {
470329114Skevans			DPRINTF("Failed to get image DevicePath (%lu)\n",
471329114Skevans			    EFI_ERROR_CODE(status));
472329114Skevans		} else {
473329114Skevans			text = efi_devpath_name(imgpath);
474329114Skevans			printf("   Load Device: %S\n", text);
475329114Skevans			efi_setenv_freebsd_wcs("Boot1Dev", text);
476329114Skevans			efi_free_devpath_name(text);
477329114Skevans		}
478329114Skevans
479329114Skevans	}
480329114Skevans
481294060Ssmh	/* Get all the device handles */
482294060Ssmh	hsize = (UINTN)NUM_HANDLES_INIT * sizeof(EFI_HANDLE);
483329114Skevans	handles = malloc(hsize);
484329114Skevans	if (handles == NULL) {
485329114Skevans		printf("Failed to allocate %d handles\n", NUM_HANDLES_INIT);
486329114Skevans	}
487264391Snwhitehorn
488329114Skevans	status = BS->LocateHandle(ByProtocol, &BlockIoProtocolGUID, NULL,
489294060Ssmh	    &hsize, handles);
490294060Ssmh	switch (status) {
491294060Ssmh	case EFI_SUCCESS:
492294060Ssmh		break;
493294060Ssmh	case EFI_BUFFER_TOO_SMALL:
494329114Skevans		free(handles);
495329114Skevans		handles = malloc(hsize);
496329114Skevans		if (handles == NULL)
497329114Skevans			efi_panic(EFI_OUT_OF_RESOURCES, "Failed to allocate %d handles\n",
498329114Skevans			    NUM_HANDLES_INIT);
499329114Skevans		status = BS->LocateHandle(ByProtocol, &BlockIoProtocolGUID,
500294060Ssmh		    NULL, &hsize, handles);
501294060Ssmh		if (status != EFI_SUCCESS)
502329114Skevans			efi_panic(status, "Failed to get device handles\n");
503294060Ssmh		break;
504294060Ssmh	default:
505329114Skevans		efi_panic(status, "Failed to get device handles\n");
506329114Skevans		break;
507294060Ssmh	}
508264391Snwhitehorn
509294060Ssmh	/* Scan all partitions, probing with all modules. */
510294060Ssmh	nhandles = hsize / sizeof(*handles);
511294060Ssmh	printf("   Probing %zu block devices...", nhandles);
512295320Ssmh	DPRINTF("\n");
513295320Ssmh
514295320Ssmh	for (i = 0; i < nhandles; i++)
515295320Ssmh		probe_handle_status(handles[i], imgpath);
516294060Ssmh	printf(" done\n");
517264391Snwhitehorn
518294060Ssmh	/* Status summary. */
519294060Ssmh	for (i = 0; i < NUM_BOOT_MODULES; i++) {
520323484Srlibby		printf("    ");
521323484Srlibby		boot_modules[i]->status();
522294060Ssmh	}
523264391Snwhitehorn
524295320Ssmh	try_boot();
525281058Srpaulo
526294060Ssmh	/* If we get here, we're out of luck... */
527329114Skevans	efi_panic(EFI_LOAD_ERROR, "No bootable partitions found!");
528264391Snwhitehorn}
529264391Snwhitehorn
530295320Ssmh/*
531295320Ssmh * add_device adds a device to the passed devinfo list.
532295320Ssmh */
533294060Ssmhvoid
534294060Ssmhadd_device(dev_info_t **devinfop, dev_info_t *devinfo)
535264391Snwhitehorn{
536294060Ssmh	dev_info_t *dev;
537264391Snwhitehorn
538294060Ssmh	if (*devinfop == NULL) {
539294060Ssmh		*devinfop = devinfo;
540264391Snwhitehorn		return;
541264391Snwhitehorn	}
542264391Snwhitehorn
543294060Ssmh	for (dev = *devinfop; dev->next != NULL; dev = dev->next)
544294060Ssmh		;
545281058Srpaulo
546294060Ssmh	dev->next = devinfo;
547264391Snwhitehorn}
548264391Snwhitehorn
549329114Skevans/*
550329114Skevans * OK. We totally give up. Exit back to EFI with a sensible status so
551329114Skevans * it can try the next option on the list.
552329114Skevans */
553329114Skevansstatic void
554329114Skevansefi_panic(EFI_STATUS s, const char *fmt, ...)
555264391Snwhitehorn{
556264391Snwhitehorn	va_list ap;
557264391Snwhitehorn
558293460Ssmh	printf("panic: ");
559264391Snwhitehorn	va_start(ap, fmt);
560293460Ssmh	vprintf(fmt, ap);
561264391Snwhitehorn	va_end(ap);
562293460Ssmh	printf("\n");
563264391Snwhitehorn
564329114Skevans	BS->Exit(IH, s, 0, NULL);
565264391Snwhitehorn}
566264391Snwhitehorn
567293460Ssmhvoid
568293460Ssmhputchar(int c)
569264391Snwhitehorn{
570264391Snwhitehorn	CHAR16 buf[2];
571264391Snwhitehorn
572264391Snwhitehorn	if (c == '\n') {
573264391Snwhitehorn		buf[0] = '\r';
574264391Snwhitehorn		buf[1] = 0;
575329114Skevans		ST->ConOut->OutputString(ST->ConOut, buf);
576264391Snwhitehorn	}
577264391Snwhitehorn	buf[0] = c;
578264391Snwhitehorn	buf[1] = 0;
579329114Skevans	ST->ConOut->OutputString(ST->ConOut, buf);
580264391Snwhitehorn}
581