boot1.c revision 323484
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 323484 2017-09-12 06:19:19Z rlibby $");
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>
32264391Snwhitehorn
33294060Ssmh#include "boot_module.h"
34294765Simp#include "paths.h"
35294060Ssmh
36294060Ssmhstatic const boot_module_t *boot_modules[] =
37294060Ssmh{
38294068Ssmh#ifdef EFI_ZFS_BOOT
39294068Ssmh	&zfs_module,
40294068Ssmh#endif
41294060Ssmh#ifdef EFI_UFS_BOOT
42294060Ssmh	&ufs_module
43294060Ssmh#endif
44294060Ssmh};
45264391Snwhitehorn
46323484Srlibby#define	NUM_BOOT_MODULES	nitems(boot_modules)
47294060Ssmh/* The initial number of handles used to query EFI for partitions. */
48294060Ssmh#define NUM_HANDLES_INIT	24
49294060Ssmh
50293724SsmhEFI_STATUS efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE* Xsystab);
51264391Snwhitehorn
52294060SsmhEFI_SYSTEM_TABLE *systab;
53294060SsmhEFI_BOOT_SERVICES *bs;
54281169Sandrewstatic EFI_HANDLE *image;
55264391Snwhitehorn
56264391Snwhitehornstatic EFI_GUID BlockIoProtocolGUID = BLOCK_IO_PROTOCOL;
57264391Snwhitehornstatic EFI_GUID DevicePathGUID = DEVICE_PATH_PROTOCOL;
58264391Snwhitehornstatic EFI_GUID LoadedImageGUID = LOADED_IMAGE_PROTOCOL;
59271762Semastestatic EFI_GUID ConsoleControlGUID = EFI_CONSOLE_CONTROL_PROTOCOL_GUID;
60264391Snwhitehorn
61294060Ssmh/*
62294060Ssmh * Provide Malloc / Free backed by EFIs AllocatePool / FreePool which ensures
63294060Ssmh * memory is correctly aligned avoiding EFI_INVALID_PARAMETER returns from
64294060Ssmh * EFI methods.
65294060Ssmh */
66294060Ssmhvoid *
67294060SsmhMalloc(size_t len, const char *file __unused, int line __unused)
68294060Ssmh{
69294060Ssmh	void *out;
70264391Snwhitehorn
71294060Ssmh	if (bs->AllocatePool(EfiLoaderData, len, &out) == EFI_SUCCESS)
72294060Ssmh		return (out);
73294060Ssmh
74294060Ssmh	return (NULL);
75294060Ssmh}
76294060Ssmh
77294060Ssmhvoid
78294060SsmhFree(void *buf, const char *file __unused, int line __unused)
79264391Snwhitehorn{
80294060Ssmh	(void)bs->FreePool(buf);
81294060Ssmh}
82294060Ssmh
83294060Ssmh/*
84295320Ssmh * nodes_match returns TRUE if the imgpath isn't NULL and the nodes match,
85295320Ssmh * FALSE otherwise.
86294060Ssmh */
87295320Ssmhstatic BOOLEAN
88295320Ssmhnodes_match(EFI_DEVICE_PATH *imgpath, EFI_DEVICE_PATH *devpath)
89294060Ssmh{
90295320Ssmh	int len;
91295320Ssmh
92295320Ssmh	if (imgpath == NULL || imgpath->Type != devpath->Type ||
93295320Ssmh	    imgpath->SubType != devpath->SubType)
94295320Ssmh		return (FALSE);
95295320Ssmh
96295320Ssmh	len = DevicePathNodeLength(imgpath);
97295320Ssmh	if (len != DevicePathNodeLength(devpath))
98295320Ssmh		return (FALSE);
99295320Ssmh
100295320Ssmh	return (memcmp(imgpath, devpath, (size_t)len) == 0);
101295320Ssmh}
102295320Ssmh
103295320Ssmh/*
104295320Ssmh * device_paths_match returns TRUE if the imgpath isn't NULL and all nodes
105298826Spfg * in imgpath and devpath match up to their respective occurrences of a
106298826Spfg * media node, FALSE otherwise.
107295320Ssmh */
108295320Ssmhstatic BOOLEAN
109295320Ssmhdevice_paths_match(EFI_DEVICE_PATH *imgpath, EFI_DEVICE_PATH *devpath)
110295320Ssmh{
111295320Ssmh
112295320Ssmh	if (imgpath == NULL)
113295320Ssmh		return (FALSE);
114295320Ssmh
115295320Ssmh	while (!IsDevicePathEnd(imgpath) && !IsDevicePathEnd(devpath)) {
116295320Ssmh		if (IsDevicePathType(imgpath, MEDIA_DEVICE_PATH) &&
117295320Ssmh		    IsDevicePathType(devpath, MEDIA_DEVICE_PATH))
118295320Ssmh			return (TRUE);
119295320Ssmh
120295320Ssmh		if (!nodes_match(imgpath, devpath))
121295320Ssmh			return (FALSE);
122295320Ssmh
123295320Ssmh		imgpath = NextDevicePathNode(imgpath);
124295320Ssmh		devpath = NextDevicePathNode(devpath);
125295320Ssmh	}
126295320Ssmh
127295320Ssmh	return (FALSE);
128295320Ssmh}
129295320Ssmh
130295320Ssmh/*
131295320Ssmh * devpath_last returns the last non-path end node in devpath.
132295320Ssmh */
133295320Ssmhstatic EFI_DEVICE_PATH *
134295320Ssmhdevpath_last(EFI_DEVICE_PATH *devpath)
135295320Ssmh{
136295320Ssmh
137295320Ssmh	while (!IsDevicePathEnd(NextDevicePathNode(devpath)))
138295320Ssmh		devpath = NextDevicePathNode(devpath);
139295320Ssmh
140295320Ssmh	return (devpath);
141295320Ssmh}
142295320Ssmh
143295320Ssmh/*
144295320Ssmh * devpath_node_str is a basic output method for a devpath node which
145295320Ssmh * only understands a subset of the available sub types.
146295320Ssmh *
147295320Ssmh * If we switch to UEFI 2.x then we should update it to use:
148295320Ssmh * EFI_DEVICE_PATH_TO_TEXT_PROTOCOL.
149295320Ssmh */
150295320Ssmhstatic int
151295320Ssmhdevpath_node_str(char *buf, size_t size, EFI_DEVICE_PATH *devpath)
152295320Ssmh{
153295320Ssmh
154295320Ssmh	switch (devpath->Type) {
155295320Ssmh	case MESSAGING_DEVICE_PATH:
156295320Ssmh		switch (devpath->SubType) {
157295320Ssmh		case MSG_ATAPI_DP: {
158295320Ssmh			ATAPI_DEVICE_PATH *atapi;
159295320Ssmh
160295320Ssmh			atapi = (ATAPI_DEVICE_PATH *)(void *)devpath;
161295320Ssmh			return snprintf(buf, size, "ata(%s,%s,0x%x)",
162295320Ssmh			    (atapi->PrimarySecondary == 1) ?  "Sec" : "Pri",
163295320Ssmh			    (atapi->SlaveMaster == 1) ?  "Slave" : "Master",
164295320Ssmh			    atapi->Lun);
165295320Ssmh		}
166295320Ssmh		case MSG_USB_DP: {
167295320Ssmh			USB_DEVICE_PATH *usb;
168295320Ssmh
169295320Ssmh			usb = (USB_DEVICE_PATH *)devpath;
170295320Ssmh			return snprintf(buf, size, "usb(0x%02x,0x%02x)",
171295320Ssmh			    usb->ParentPortNumber, usb->InterfaceNumber);
172295320Ssmh		}
173295320Ssmh		case MSG_SCSI_DP: {
174295320Ssmh			SCSI_DEVICE_PATH *scsi;
175295320Ssmh
176295320Ssmh			scsi = (SCSI_DEVICE_PATH *)(void *)devpath;
177295320Ssmh			return snprintf(buf, size, "scsi(0x%02x,0x%02x)",
178295320Ssmh			    scsi->Pun, scsi->Lun);
179295320Ssmh		}
180295320Ssmh		case MSG_SATA_DP: {
181295320Ssmh			SATA_DEVICE_PATH *sata;
182295320Ssmh
183295320Ssmh			sata = (SATA_DEVICE_PATH *)(void *)devpath;
184295320Ssmh			return snprintf(buf, size, "sata(0x%x,0x%x,0x%x)",
185295320Ssmh			    sata->HBAPortNumber, sata->PortMultiplierPortNumber,
186295320Ssmh			    sata->Lun);
187295320Ssmh		}
188295320Ssmh		default:
189295320Ssmh			return snprintf(buf, size, "msg(0x%02x)",
190295320Ssmh			    devpath->SubType);
191295320Ssmh		}
192295320Ssmh		break;
193295320Ssmh	case HARDWARE_DEVICE_PATH:
194295320Ssmh		switch (devpath->SubType) {
195295320Ssmh		case HW_PCI_DP: {
196295320Ssmh			PCI_DEVICE_PATH *pci;
197295320Ssmh
198295320Ssmh			pci = (PCI_DEVICE_PATH *)devpath;
199295320Ssmh			return snprintf(buf, size, "pci(0x%02x,0x%02x)",
200295320Ssmh			    pci->Device, pci->Function);
201295320Ssmh		}
202295320Ssmh		default:
203295320Ssmh			return snprintf(buf, size, "hw(0x%02x)",
204295320Ssmh			    devpath->SubType);
205295320Ssmh		}
206295320Ssmh		break;
207295320Ssmh	case ACPI_DEVICE_PATH: {
208295320Ssmh		ACPI_HID_DEVICE_PATH *acpi;
209295320Ssmh
210295320Ssmh		acpi = (ACPI_HID_DEVICE_PATH *)(void *)devpath;
211295320Ssmh		if ((acpi->HID & PNP_EISA_ID_MASK) == PNP_EISA_ID_CONST) {
212295320Ssmh			switch (EISA_ID_TO_NUM(acpi->HID)) {
213295320Ssmh			case 0x0a03:
214295320Ssmh				return snprintf(buf, size, "pciroot(0x%x)",
215295320Ssmh				    acpi->UID);
216295320Ssmh			case 0x0a08:
217295320Ssmh				return snprintf(buf, size, "pcieroot(0x%x)",
218295320Ssmh				    acpi->UID);
219295320Ssmh			case 0x0604:
220295320Ssmh				return snprintf(buf, size, "floppy(0x%x)",
221295320Ssmh				    acpi->UID);
222295320Ssmh			case 0x0301:
223295320Ssmh				return snprintf(buf, size, "keyboard(0x%x)",
224295320Ssmh				    acpi->UID);
225295320Ssmh			case 0x0501:
226295320Ssmh				return snprintf(buf, size, "serial(0x%x)",
227295320Ssmh				    acpi->UID);
228295320Ssmh			case 0x0401:
229295320Ssmh				return snprintf(buf, size, "parallelport(0x%x)",
230295320Ssmh				    acpi->UID);
231295320Ssmh			default:
232295320Ssmh				return snprintf(buf, size, "acpi(pnp%04x,0x%x)",
233295320Ssmh				    EISA_ID_TO_NUM(acpi->HID), acpi->UID);
234295320Ssmh			}
235295320Ssmh		}
236295320Ssmh
237295320Ssmh		return snprintf(buf, size, "acpi(0x%08x,0x%x)", acpi->HID,
238295320Ssmh		    acpi->UID);
239295320Ssmh	}
240295320Ssmh	case MEDIA_DEVICE_PATH:
241295320Ssmh		switch (devpath->SubType) {
242295320Ssmh		case MEDIA_CDROM_DP: {
243295320Ssmh			CDROM_DEVICE_PATH *cdrom;
244295320Ssmh
245295320Ssmh			cdrom = (CDROM_DEVICE_PATH *)(void *)devpath;
246295320Ssmh			return snprintf(buf, size, "cdrom(%x)",
247295320Ssmh			    cdrom->BootEntry);
248295320Ssmh		}
249295320Ssmh		case MEDIA_HARDDRIVE_DP: {
250295320Ssmh			HARDDRIVE_DEVICE_PATH *hd;
251295320Ssmh
252295320Ssmh			hd = (HARDDRIVE_DEVICE_PATH *)(void *)devpath;
253295320Ssmh			return snprintf(buf, size, "hd(%x)",
254295320Ssmh			    hd->PartitionNumber);
255295320Ssmh		}
256295320Ssmh		default:
257295320Ssmh			return snprintf(buf, size, "media(0x%02x)",
258295320Ssmh			    devpath->SubType);
259295320Ssmh		}
260295320Ssmh	case BBS_DEVICE_PATH:
261295320Ssmh		return snprintf(buf, size, "bbs(0x%02x)", devpath->SubType);
262295320Ssmh	case END_DEVICE_PATH_TYPE:
263295320Ssmh		return (0);
264295320Ssmh	}
265295320Ssmh
266295320Ssmh	return snprintf(buf, size, "type(0x%02x, 0x%02x)", devpath->Type,
267295320Ssmh	    devpath->SubType);
268295320Ssmh}
269295320Ssmh
270295320Ssmh/*
271295320Ssmh * devpath_strlcat appends a text description of devpath to buf but not more
272295320Ssmh * than size - 1 characters followed by NUL-terminator.
273295320Ssmh */
274295320Ssmhint
275295320Ssmhdevpath_strlcat(char *buf, size_t size, EFI_DEVICE_PATH *devpath)
276295320Ssmh{
277295320Ssmh	size_t len, used;
278295320Ssmh	const char *sep;
279295320Ssmh
280295320Ssmh	sep = "";
281295320Ssmh	used = 0;
282295320Ssmh	while (!IsDevicePathEnd(devpath)) {
283295320Ssmh		len = snprintf(buf, size - used, "%s", sep);
284295320Ssmh		used += len;
285295320Ssmh		if (used > size)
286295320Ssmh			return (used);
287295320Ssmh		buf += len;
288295320Ssmh
289295320Ssmh		len = devpath_node_str(buf, size - used, devpath);
290295320Ssmh		used += len;
291295320Ssmh		if (used > size)
292295320Ssmh			return (used);
293295320Ssmh		buf += len;
294295320Ssmh		devpath = NextDevicePathNode(devpath);
295295320Ssmh		sep = ":";
296295320Ssmh	}
297295320Ssmh
298295320Ssmh	return (used);
299295320Ssmh}
300295320Ssmh
301295320Ssmh/*
302295320Ssmh * devpath_str is convenience method which returns the text description of
303295320Ssmh * devpath using a static buffer, so it isn't thread safe!
304295320Ssmh */
305295320Ssmhchar *
306295320Ssmhdevpath_str(EFI_DEVICE_PATH *devpath)
307295320Ssmh{
308295320Ssmh	static char buf[256];
309295320Ssmh
310295320Ssmh	devpath_strlcat(buf, sizeof(buf), devpath);
311295320Ssmh
312295320Ssmh	return buf;
313295320Ssmh}
314295320Ssmh
315295320Ssmh/*
316295320Ssmh * load_loader attempts to load the loader image data.
317295320Ssmh *
318295320Ssmh * It tries each module and its respective devices, identified by mod->probe,
319295320Ssmh * in order until a successful load occurs at which point it returns EFI_SUCCESS
320295320Ssmh * and EFI_NOT_FOUND otherwise.
321295320Ssmh *
322295320Ssmh * Only devices which have preferred matching the preferred parameter are tried.
323295320Ssmh */
324295320Ssmhstatic EFI_STATUS
325295320Ssmhload_loader(const boot_module_t **modp, dev_info_t **devinfop, void **bufp,
326295320Ssmh    size_t *bufsize, BOOLEAN preferred)
327295320Ssmh{
328295320Ssmh	UINTN i;
329295320Ssmh	dev_info_t *dev;
330295320Ssmh	const boot_module_t *mod;
331295320Ssmh
332295320Ssmh	for (i = 0; i < NUM_BOOT_MODULES; i++) {
333295320Ssmh		mod = boot_modules[i];
334295320Ssmh		for (dev = mod->devices(); dev != NULL; dev = dev->next) {
335295320Ssmh			if (dev->preferred != preferred)
336295320Ssmh				continue;
337295320Ssmh
338295320Ssmh			if (mod->load(PATH_LOADER_EFI, dev, bufp, bufsize) ==
339295320Ssmh			    EFI_SUCCESS) {
340295320Ssmh				*devinfop = dev;
341295320Ssmh				*modp = mod;
342295320Ssmh				return (EFI_SUCCESS);
343295320Ssmh			}
344295320Ssmh		}
345295320Ssmh	}
346295320Ssmh
347295320Ssmh	return (EFI_NOT_FOUND);
348295320Ssmh}
349295320Ssmh
350295320Ssmh/*
351295320Ssmh * try_boot only returns if it fails to load the loader. If it succeeds
352295320Ssmh * it simply boots, otherwise it returns the status of last EFI call.
353295320Ssmh */
354295320Ssmhstatic EFI_STATUS
355323484Srlibbytry_boot(void)
356295320Ssmh{
357295320Ssmh	size_t bufsize, loadersize, cmdsize;
358295320Ssmh	void *buf, *loaderbuf;
359294768Simp	char *cmd;
360294060Ssmh	dev_info_t *dev;
361295320Ssmh	const boot_module_t *mod;
362294060Ssmh	EFI_HANDLE loaderhandle;
363294060Ssmh	EFI_LOADED_IMAGE *loaded_image;
364264391Snwhitehorn	EFI_STATUS status;
365294060Ssmh
366295320Ssmh	status = load_loader(&mod, &dev, &loaderbuf, &loadersize, TRUE);
367295320Ssmh	if (status != EFI_SUCCESS) {
368295320Ssmh		status = load_loader(&mod, &dev, &loaderbuf, &loadersize,
369295320Ssmh		    FALSE);
370295320Ssmh		if (status != EFI_SUCCESS) {
371295320Ssmh			printf("Failed to load '%s'\n", PATH_LOADER_EFI);
372295320Ssmh			return (status);
373295320Ssmh		}
374295320Ssmh	}
375295320Ssmh
376294768Simp	/*
377294768Simp	 * Read in and parse the command line from /boot.config or /boot/config,
378294768Simp	 * if present. We'll pass it the next stage via a simple ASCII
379294768Simp	 * string. loader.efi has a hack for ASCII strings, so we'll use that to
380294768Simp	 * keep the size down here. We only try to read the alternate file if
381294768Simp	 * we get EFI_NOT_FOUND because all other errors mean that the boot_module
382294768Simp	 * had troubles with the filesystem. We could return early, but we'll let
383294768Simp	 * loading the actual kernel sort all that out. Since these files are
384294768Simp	 * optional, we don't report errors in trying to read them.
385294768Simp	 */
386294768Simp	cmd = NULL;
387294768Simp	cmdsize = 0;
388295320Ssmh	status = mod->load(PATH_DOTCONFIG, dev, &buf, &bufsize);
389294768Simp	if (status == EFI_NOT_FOUND)
390295320Ssmh		status = mod->load(PATH_CONFIG, dev, &buf, &bufsize);
391294768Simp	if (status == EFI_SUCCESS) {
392294768Simp		cmdsize = bufsize + 1;
393294768Simp		cmd = malloc(cmdsize);
394295320Ssmh		if (cmd == NULL)
395295320Ssmh			goto errout;
396294768Simp		memcpy(cmd, buf, bufsize);
397294768Simp		cmd[bufsize] = '\0';
398294768Simp		free(buf);
399295320Ssmh		buf = NULL;
400294768Simp	}
401294768Simp
402295320Ssmh	if ((status = bs->LoadImage(TRUE, image, devpath_last(dev->devpath),
403295320Ssmh	    loaderbuf, loadersize, &loaderhandle)) != EFI_SUCCESS) {
404294060Ssmh		printf("Failed to load image provided by %s, size: %zu, (%lu)\n",
405296713Sandrew		     mod->name, loadersize, EFI_ERROR_CODE(status));
406295320Ssmh		goto errout;
407294060Ssmh	}
408294060Ssmh
409294060Ssmh	if ((status = bs->HandleProtocol(loaderhandle, &LoadedImageGUID,
410294060Ssmh	    (VOID**)&loaded_image)) != EFI_SUCCESS) {
411294060Ssmh		printf("Failed to query LoadedImage provided by %s (%lu)\n",
412294060Ssmh		    mod->name, EFI_ERROR_CODE(status));
413295320Ssmh		goto errout;
414294060Ssmh	}
415294060Ssmh
416295320Ssmh	if (cmd != NULL)
417295320Ssmh		printf("    command args: %s\n", cmd);
418295320Ssmh
419294060Ssmh	loaded_image->DeviceHandle = dev->devhandle;
420294768Simp	loaded_image->LoadOptionsSize = cmdsize;
421294768Simp	loaded_image->LoadOptions = cmd;
422294060Ssmh
423295320Ssmh	DPRINTF("Starting '%s' in 5 seconds...", PATH_LOADER_EFI);
424295320Ssmh	DSTALL(1000000);
425295320Ssmh	DPRINTF(".");
426295320Ssmh	DSTALL(1000000);
427295320Ssmh	DPRINTF(".");
428295320Ssmh	DSTALL(1000000);
429295320Ssmh	DPRINTF(".");
430295320Ssmh	DSTALL(1000000);
431295320Ssmh	DPRINTF(".");
432295320Ssmh	DSTALL(1000000);
433295320Ssmh	DPRINTF(".\n");
434295320Ssmh
435294060Ssmh	if ((status = bs->StartImage(loaderhandle, NULL, NULL)) !=
436294060Ssmh	    EFI_SUCCESS) {
437294284Semaste		printf("Failed to start image provided by %s (%lu)\n",
438294284Semaste		    mod->name, EFI_ERROR_CODE(status));
439294768Simp		loaded_image->LoadOptionsSize = 0;
440294768Simp		loaded_image->LoadOptions = NULL;
441294060Ssmh	}
442295320Ssmh
443295320Ssmherrout:
444295320Ssmh	if (cmd != NULL)
445295320Ssmh		free(cmd);
446295320Ssmh	if (buf != NULL)
447295320Ssmh		free(buf);
448295320Ssmh	if (loaderbuf != NULL)
449295320Ssmh		free(loaderbuf);
450295320Ssmh
451295320Ssmh	return (status);
452294060Ssmh}
453294060Ssmh
454295320Ssmh/*
455295320Ssmh * probe_handle determines if the passed handle represents a logical partition
456295320Ssmh * if it does it uses each module in order to probe it and if successful it
457295320Ssmh * returns EFI_SUCCESS.
458295320Ssmh */
459295320Ssmhstatic EFI_STATUS
460295320Ssmhprobe_handle(EFI_HANDLE h, EFI_DEVICE_PATH *imgpath, BOOLEAN *preferred)
461295320Ssmh{
462295320Ssmh	dev_info_t *devinfo;
463295320Ssmh	EFI_BLOCK_IO *blkio;
464295320Ssmh	EFI_DEVICE_PATH *devpath;
465295320Ssmh	EFI_STATUS status;
466295320Ssmh	UINTN i;
467295320Ssmh
468295320Ssmh	/* Figure out if we're dealing with an actual partition. */
469295320Ssmh	status = bs->HandleProtocol(h, &DevicePathGUID, (void **)&devpath);
470295320Ssmh	if (status == EFI_UNSUPPORTED)
471295320Ssmh		return (status);
472295320Ssmh
473295320Ssmh	if (status != EFI_SUCCESS) {
474295320Ssmh		DPRINTF("\nFailed to query DevicePath (%lu)\n",
475295320Ssmh		    EFI_ERROR_CODE(status));
476295320Ssmh		return (status);
477295320Ssmh	}
478295320Ssmh
479295320Ssmh	DPRINTF("probing: %s\n", devpath_str(devpath));
480295320Ssmh
481295320Ssmh	status = bs->HandleProtocol(h, &BlockIoProtocolGUID, (void **)&blkio);
482295320Ssmh	if (status == EFI_UNSUPPORTED)
483295320Ssmh		return (status);
484295320Ssmh
485295320Ssmh	if (status != EFI_SUCCESS) {
486295320Ssmh		DPRINTF("\nFailed to query BlockIoProtocol (%lu)\n",
487295320Ssmh		    EFI_ERROR_CODE(status));
488295320Ssmh		return (status);
489295320Ssmh	}
490295320Ssmh
491295320Ssmh	if (!blkio->Media->LogicalPartition)
492295320Ssmh		return (EFI_UNSUPPORTED);
493295320Ssmh
494295320Ssmh	*preferred = device_paths_match(imgpath, devpath);
495295320Ssmh
496295320Ssmh	/* Run through each module, see if it can load this partition */
497295320Ssmh	for (i = 0; i < NUM_BOOT_MODULES; i++) {
498295320Ssmh		if ((status = bs->AllocatePool(EfiLoaderData,
499295320Ssmh		    sizeof(*devinfo), (void **)&devinfo)) !=
500295320Ssmh		    EFI_SUCCESS) {
501295320Ssmh			DPRINTF("\nFailed to allocate devinfo (%lu)\n",
502295320Ssmh			    EFI_ERROR_CODE(status));
503295320Ssmh			continue;
504295320Ssmh		}
505295320Ssmh		devinfo->dev = blkio;
506295320Ssmh		devinfo->devpath = devpath;
507295320Ssmh		devinfo->devhandle = h;
508295320Ssmh		devinfo->devdata = NULL;
509295320Ssmh		devinfo->preferred = *preferred;
510295320Ssmh		devinfo->next = NULL;
511295320Ssmh
512295320Ssmh		status = boot_modules[i]->probe(devinfo);
513295320Ssmh		if (status == EFI_SUCCESS)
514295320Ssmh			return (EFI_SUCCESS);
515295320Ssmh		(void)bs->FreePool(devinfo);
516295320Ssmh	}
517295320Ssmh
518295320Ssmh	return (EFI_UNSUPPORTED);
519295320Ssmh}
520295320Ssmh
521295320Ssmh/*
522295320Ssmh * probe_handle_status calls probe_handle and outputs the returned status
523295320Ssmh * of the call.
524295320Ssmh */
525295320Ssmhstatic void
526295320Ssmhprobe_handle_status(EFI_HANDLE h, EFI_DEVICE_PATH *imgpath)
527295320Ssmh{
528295320Ssmh	EFI_STATUS status;
529295320Ssmh	BOOLEAN preferred;
530295320Ssmh
531295320Ssmh	status = probe_handle(h, imgpath, &preferred);
532295320Ssmh
533295320Ssmh	DPRINTF("probe: ");
534295320Ssmh	switch (status) {
535295320Ssmh	case EFI_UNSUPPORTED:
536295320Ssmh		printf(".");
537295320Ssmh		DPRINTF(" not supported\n");
538295320Ssmh		break;
539295320Ssmh	case EFI_SUCCESS:
540295320Ssmh		if (preferred) {
541295320Ssmh			printf("%c", '*');
542295320Ssmh			DPRINTF(" supported (preferred)\n");
543295320Ssmh		} else {
544295320Ssmh			printf("%c", '+');
545295320Ssmh			DPRINTF(" supported\n");
546295320Ssmh		}
547295320Ssmh		break;
548295320Ssmh	default:
549295320Ssmh		printf("x");
550295320Ssmh		DPRINTF(" error (%lu)\n", EFI_ERROR_CODE(status));
551295320Ssmh		break;
552295320Ssmh	}
553295320Ssmh	DSTALL(500000);
554295320Ssmh}
555295320Ssmh
556294060SsmhEFI_STATUS
557294060Ssmhefi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE *Xsystab)
558294060Ssmh{
559294060Ssmh	EFI_HANDLE *handles;
560295320Ssmh	EFI_LOADED_IMAGE *img;
561295320Ssmh	EFI_DEVICE_PATH *imgpath;
562294060Ssmh	EFI_STATUS status;
563271762Semaste	EFI_CONSOLE_CONTROL_PROTOCOL *ConsoleControl = NULL;
564281059Srpaulo	SIMPLE_TEXT_OUTPUT_INTERFACE *conout = NULL;
565294060Ssmh	UINTN i, max_dim, best_mode, cols, rows, hsize, nhandles;
566264391Snwhitehorn
567294060Ssmh	/* Basic initialization*/
568264391Snwhitehorn	systab = Xsystab;
569264391Snwhitehorn	image = Ximage;
570294060Ssmh	bs = Xsystab->BootServices;
571264391Snwhitehorn
572294060Ssmh	/* Set up the console, so printf works. */
573294060Ssmh	status = bs->LocateProtocol(&ConsoleControlGUID, NULL,
574271762Semaste	    (VOID **)&ConsoleControl);
575271762Semaste	if (status == EFI_SUCCESS)
576271762Semaste		(void)ConsoleControl->SetMode(ConsoleControl,
577271762Semaste		    EfiConsoleControlScreenText);
578281059Srpaulo	/*
579281059Srpaulo	 * Reset the console and find the best text mode.
580281059Srpaulo	 */
581281059Srpaulo	conout = systab->ConOut;
582281059Srpaulo	conout->Reset(conout, TRUE);
583281059Srpaulo	max_dim = best_mode = 0;
584281059Srpaulo	for (i = 0; ; i++) {
585293274Ssmh		status = conout->QueryMode(conout, i, &cols, &rows);
586281059Srpaulo		if (EFI_ERROR(status))
587281059Srpaulo			break;
588281059Srpaulo		if (cols * rows > max_dim) {
589281059Srpaulo			max_dim = cols * rows;
590281059Srpaulo			best_mode = i;
591281059Srpaulo		}
592281059Srpaulo	}
593281059Srpaulo	if (max_dim > 0)
594281059Srpaulo		conout->SetMode(conout, best_mode);
595281059Srpaulo	conout->EnableCursor(conout, TRUE);
596281059Srpaulo	conout->ClearScreen(conout);
597271762Semaste
598294060Ssmh	printf("\n>> FreeBSD EFI boot block\n");
599294765Simp	printf("   Loader path: %s\n\n", PATH_LOADER_EFI);
600294060Ssmh	printf("   Initializing modules:");
601294060Ssmh	for (i = 0; i < NUM_BOOT_MODULES; i++) {
602294060Ssmh		printf(" %s", boot_modules[i]->name);
603294060Ssmh		if (boot_modules[i]->init != NULL)
604294060Ssmh			boot_modules[i]->init();
605294060Ssmh	}
606294060Ssmh	putchar('\n');
607264391Snwhitehorn
608294060Ssmh	/* Get all the device handles */
609294060Ssmh	hsize = (UINTN)NUM_HANDLES_INIT * sizeof(EFI_HANDLE);
610294060Ssmh	if ((status = bs->AllocatePool(EfiLoaderData, hsize, (void **)&handles))
611294060Ssmh	    != EFI_SUCCESS)
612294060Ssmh		panic("Failed to allocate %d handles (%lu)", NUM_HANDLES_INIT,
613294060Ssmh		    EFI_ERROR_CODE(status));
614264391Snwhitehorn
615294060Ssmh	status = bs->LocateHandle(ByProtocol, &BlockIoProtocolGUID, NULL,
616294060Ssmh	    &hsize, handles);
617294060Ssmh	switch (status) {
618294060Ssmh	case EFI_SUCCESS:
619294060Ssmh		break;
620294060Ssmh	case EFI_BUFFER_TOO_SMALL:
621294060Ssmh		(void)bs->FreePool(handles);
622294060Ssmh		if ((status = bs->AllocatePool(EfiLoaderData, hsize,
623302335Semaste		    (void **)&handles)) != EFI_SUCCESS) {
624294060Ssmh			panic("Failed to allocate %zu handles (%lu)", hsize /
625294060Ssmh			    sizeof(*handles), EFI_ERROR_CODE(status));
626294060Ssmh		}
627294060Ssmh		status = bs->LocateHandle(ByProtocol, &BlockIoProtocolGUID,
628294060Ssmh		    NULL, &hsize, handles);
629294060Ssmh		if (status != EFI_SUCCESS)
630294060Ssmh			panic("Failed to get device handles (%lu)\n",
631294060Ssmh			    EFI_ERROR_CODE(status));
632294060Ssmh		break;
633294060Ssmh	default:
634294060Ssmh		panic("Failed to get device handles (%lu)",
635294060Ssmh		    EFI_ERROR_CODE(status));
636294060Ssmh	}
637264391Snwhitehorn
638294060Ssmh	/* Scan all partitions, probing with all modules. */
639294060Ssmh	nhandles = hsize / sizeof(*handles);
640294060Ssmh	printf("   Probing %zu block devices...", nhandles);
641295320Ssmh	DPRINTF("\n");
642295320Ssmh
643295320Ssmh	/* Determine the devpath of our image so we can prefer it. */
644295320Ssmh	status = bs->HandleProtocol(image, &LoadedImageGUID, (VOID**)&img);
645295320Ssmh	imgpath = NULL;
646295320Ssmh	if (status == EFI_SUCCESS) {
647295320Ssmh		status = bs->HandleProtocol(img->DeviceHandle, &DevicePathGUID,
648295320Ssmh		    (void **)&imgpath);
649295320Ssmh		if (status != EFI_SUCCESS)
650295320Ssmh			DPRINTF("Failed to get image DevicePath (%lu)\n",
651295320Ssmh			    EFI_ERROR_CODE(status));
652295320Ssmh		DPRINTF("boot1 imagepath: %s\n", devpath_str(imgpath));
653264391Snwhitehorn	}
654295320Ssmh
655295320Ssmh	for (i = 0; i < nhandles; i++)
656295320Ssmh		probe_handle_status(handles[i], imgpath);
657294060Ssmh	printf(" done\n");
658264391Snwhitehorn
659294060Ssmh	/* Status summary. */
660294060Ssmh	for (i = 0; i < NUM_BOOT_MODULES; i++) {
661323484Srlibby		printf("    ");
662323484Srlibby		boot_modules[i]->status();
663294060Ssmh	}
664264391Snwhitehorn
665295320Ssmh	try_boot();
666281058Srpaulo
667294060Ssmh	/* If we get here, we're out of luck... */
668294060Ssmh	panic("No bootable partitions found!");
669264391Snwhitehorn}
670264391Snwhitehorn
671295320Ssmh/*
672295320Ssmh * add_device adds a device to the passed devinfo list.
673295320Ssmh */
674294060Ssmhvoid
675294060Ssmhadd_device(dev_info_t **devinfop, dev_info_t *devinfo)
676264391Snwhitehorn{
677294060Ssmh	dev_info_t *dev;
678264391Snwhitehorn
679294060Ssmh	if (*devinfop == NULL) {
680294060Ssmh		*devinfop = devinfo;
681264391Snwhitehorn		return;
682264391Snwhitehorn	}
683264391Snwhitehorn
684294060Ssmh	for (dev = *devinfop; dev->next != NULL; dev = dev->next)
685294060Ssmh		;
686281058Srpaulo
687294060Ssmh	dev->next = devinfo;
688264391Snwhitehorn}
689264391Snwhitehorn
690293460Ssmhvoid
691264391Snwhitehornpanic(const char *fmt, ...)
692264391Snwhitehorn{
693264391Snwhitehorn	va_list ap;
694264391Snwhitehorn
695293460Ssmh	printf("panic: ");
696264391Snwhitehorn	va_start(ap, fmt);
697293460Ssmh	vprintf(fmt, ap);
698264391Snwhitehorn	va_end(ap);
699293460Ssmh	printf("\n");
700264391Snwhitehorn
701264391Snwhitehorn	while (1) {}
702264391Snwhitehorn}
703264391Snwhitehorn
704293460Ssmhvoid
705293460Ssmhputchar(int c)
706264391Snwhitehorn{
707264391Snwhitehorn	CHAR16 buf[2];
708264391Snwhitehorn
709264391Snwhitehorn	if (c == '\n') {
710264391Snwhitehorn		buf[0] = '\r';
711264391Snwhitehorn		buf[1] = 0;
712264391Snwhitehorn		systab->ConOut->OutputString(systab->ConOut, buf);
713264391Snwhitehorn	}
714264391Snwhitehorn	buf[0] = c;
715264391Snwhitehorn	buf[1] = 0;
716264391Snwhitehorn	systab->ConOut->OutputString(systab->ConOut, buf);
717264391Snwhitehorn}
718