xref: /dflybsd-src/stand/boot/efi/boot1/boot1.c (revision 3d9fb4d44e4d8c28731888f3b27137c5c77dd097)
1479ab7f0SSascha Wildner /*-
2479ab7f0SSascha Wildner  * Copyright (c) 1998 Robert Nordier
3479ab7f0SSascha Wildner  * All rights reserved.
4479ab7f0SSascha Wildner  * Copyright (c) 2001 Robert Drehmel
5479ab7f0SSascha Wildner  * All rights reserved.
6479ab7f0SSascha Wildner  * Copyright (c) 2014 Nathan Whitehorn
7479ab7f0SSascha Wildner  * All rights reserved.
8479ab7f0SSascha Wildner  * Copyright (c) 2015 Eric McCorkle
9479ab7f0SSascha Wildner  * All rights reserved.
10479ab7f0SSascha Wildner  *
11479ab7f0SSascha Wildner  * Redistribution and use in source and binary forms are freely
12479ab7f0SSascha Wildner  * permitted provided that the above copyright notice and this
13479ab7f0SSascha Wildner  * paragraph and the following disclaimer are duplicated in all
14479ab7f0SSascha Wildner  * such forms.
15479ab7f0SSascha Wildner  *
16479ab7f0SSascha Wildner  * This software is provided "AS IS" and without any express or
17479ab7f0SSascha Wildner  * implied warranties, including, without limitation, the implied
18479ab7f0SSascha Wildner  * warranties of merchantability and fitness for a particular
19479ab7f0SSascha Wildner  * purpose.
20479ab7f0SSascha Wildner  *
21479ab7f0SSascha Wildner  * $FreeBSD: head/sys/boot/efi/boot1/boot1.c 296713 2016-03-12 06:50:16Z andrew $
22479ab7f0SSascha Wildner  */
23479ab7f0SSascha Wildner 
24479ab7f0SSascha Wildner #include <sys/param.h>
25479ab7f0SSascha Wildner #include <machine/elf.h>
26479ab7f0SSascha Wildner #include <machine/stdarg.h>
27479ab7f0SSascha Wildner #include <stand.h>
28479ab7f0SSascha Wildner #include <stdarg.h>
29479ab7f0SSascha Wildner 
30479ab7f0SSascha Wildner #include <efi.h>
31479ab7f0SSascha Wildner #include <eficonsctl.h>
32479ab7f0SSascha Wildner 
33479ab7f0SSascha Wildner #include "boot_module.h"
34479ab7f0SSascha Wildner #include "paths.h"
35479ab7f0SSascha Wildner 
36479ab7f0SSascha Wildner #define PATH_CONFIG	"/boot/config"
37479ab7f0SSascha Wildner #define PATH_DOTCONFIG	"/boot.config"
38479ab7f0SSascha Wildner #define PATH_LOADER	"/loader.efi"		/* /boot is dedicated */
39479ab7f0SSascha Wildner #define PATH_LOADER_ALT	"/boot/loader.efi"	/* /boot in root */
40479ab7f0SSascha Wildner 
41479ab7f0SSascha Wildner static const boot_module_t *boot_modules[] =
42479ab7f0SSascha Wildner {
43479ab7f0SSascha Wildner #ifdef EFI_UFS_BOOT
44479ab7f0SSascha Wildner 	&ufs_module
45479ab7f0SSascha Wildner #endif
46479ab7f0SSascha Wildner };
47479ab7f0SSascha Wildner 
48479ab7f0SSascha Wildner #define NUM_BOOT_MODULES NELEM(boot_modules)
49479ab7f0SSascha Wildner /* The initial number of handles used to query EFI for partitions. */
50479ab7f0SSascha Wildner #define NUM_HANDLES_INIT	24
51479ab7f0SSascha Wildner 
52479ab7f0SSascha Wildner static EFI_GUID BlockIoProtocolGUID = BLOCK_IO_PROTOCOL;
53479ab7f0SSascha Wildner static EFI_GUID DevicePathGUID = DEVICE_PATH_PROTOCOL;
54479ab7f0SSascha Wildner static EFI_GUID LoadedImageGUID = LOADED_IMAGE_PROTOCOL;
55479ab7f0SSascha Wildner static EFI_GUID ConsoleControlGUID = EFI_CONSOLE_CONTROL_PROTOCOL_GUID;
56479ab7f0SSascha Wildner 
57479ab7f0SSascha Wildner /*
58479ab7f0SSascha Wildner  * XXX DragonFly's libstand doesn't provide a way to override the malloc
59479ab7f0SSascha Wildner  *     implementation yet.
60479ab7f0SSascha Wildner  */
61479ab7f0SSascha Wildner #if 0
62479ab7f0SSascha Wildner 
63479ab7f0SSascha Wildner /*
64479ab7f0SSascha Wildner  * Provide Malloc / Free backed by EFIs AllocatePool / FreePool which ensures
65479ab7f0SSascha Wildner  * memory is correctly aligned avoiding EFI_INVALID_PARAMETER returns from
66479ab7f0SSascha Wildner  * EFI methods.
67479ab7f0SSascha Wildner  */
68479ab7f0SSascha Wildner void *
69479ab7f0SSascha Wildner Malloc(size_t len, const char *file __unused, int line __unused)
70479ab7f0SSascha Wildner {
71479ab7f0SSascha Wildner 	void *out;
72479ab7f0SSascha Wildner 
73479ab7f0SSascha Wildner 	if (BS->AllocatePool(EfiLoaderData, len, &out) == EFI_SUCCESS)
74479ab7f0SSascha Wildner 		return (out);
75479ab7f0SSascha Wildner 
76479ab7f0SSascha Wildner 	return (NULL);
77479ab7f0SSascha Wildner }
78479ab7f0SSascha Wildner 
79479ab7f0SSascha Wildner void
80479ab7f0SSascha Wildner Free(void *buf, const char *file __unused, int line __unused)
81479ab7f0SSascha Wildner {
82479ab7f0SSascha Wildner 	(void)BS->FreePool(buf);
83479ab7f0SSascha Wildner }
84479ab7f0SSascha Wildner 
85479ab7f0SSascha Wildner #endif
86479ab7f0SSascha Wildner 
87479ab7f0SSascha Wildner /*
88479ab7f0SSascha Wildner  * nodes_match returns TRUE if the imgpath isn't NULL and the nodes match,
89479ab7f0SSascha Wildner  * FALSE otherwise.
90479ab7f0SSascha Wildner  */
91479ab7f0SSascha Wildner static BOOLEAN
nodes_match(EFI_DEVICE_PATH * imgpath,EFI_DEVICE_PATH * devpath)92479ab7f0SSascha Wildner nodes_match(EFI_DEVICE_PATH *imgpath, EFI_DEVICE_PATH *devpath)
93479ab7f0SSascha Wildner {
94479ab7f0SSascha Wildner 	size_t len;
95479ab7f0SSascha Wildner 
96479ab7f0SSascha Wildner 	if (imgpath == NULL || imgpath->Type != devpath->Type ||
97479ab7f0SSascha Wildner 	    imgpath->SubType != devpath->SubType)
98479ab7f0SSascha Wildner 		return (FALSE);
99479ab7f0SSascha Wildner 
100479ab7f0SSascha Wildner 	len = DevicePathNodeLength(imgpath);
101479ab7f0SSascha Wildner 	if (len != DevicePathNodeLength(devpath))
102479ab7f0SSascha Wildner 		return (FALSE);
103479ab7f0SSascha Wildner 
104479ab7f0SSascha Wildner 	return (memcmp(imgpath, devpath, (size_t)len) == 0);
105479ab7f0SSascha Wildner }
106479ab7f0SSascha Wildner 
107479ab7f0SSascha Wildner /*
108479ab7f0SSascha Wildner  * device_paths_match returns TRUE if the imgpath isn't NULL and all nodes
109e782c7f6SSascha Wildner  * in imgpath and devpath match up to their respect occurrences of a media
110479ab7f0SSascha Wildner  * node, FALSE otherwise.
111479ab7f0SSascha Wildner  */
112479ab7f0SSascha Wildner static BOOLEAN
device_paths_match(EFI_DEVICE_PATH * imgpath,EFI_DEVICE_PATH * devpath)113479ab7f0SSascha Wildner device_paths_match(EFI_DEVICE_PATH *imgpath, EFI_DEVICE_PATH *devpath)
114479ab7f0SSascha Wildner {
115479ab7f0SSascha Wildner 
116479ab7f0SSascha Wildner 	if (imgpath == NULL)
117479ab7f0SSascha Wildner 		return (FALSE);
118479ab7f0SSascha Wildner 
119479ab7f0SSascha Wildner 	while (!IsDevicePathEnd(imgpath) && !IsDevicePathEnd(devpath)) {
120479ab7f0SSascha Wildner 		if (IsDevicePathType(imgpath, MEDIA_DEVICE_PATH) &&
121479ab7f0SSascha Wildner 		    IsDevicePathType(devpath, MEDIA_DEVICE_PATH))
122479ab7f0SSascha Wildner 			return (TRUE);
123479ab7f0SSascha Wildner 
124479ab7f0SSascha Wildner 		if (!nodes_match(imgpath, devpath))
125479ab7f0SSascha Wildner 			return (FALSE);
126479ab7f0SSascha Wildner 
127479ab7f0SSascha Wildner 		imgpath = NextDevicePathNode(imgpath);
128479ab7f0SSascha Wildner 		devpath = NextDevicePathNode(devpath);
129479ab7f0SSascha Wildner 	}
130479ab7f0SSascha Wildner 
131479ab7f0SSascha Wildner 	return (FALSE);
132479ab7f0SSascha Wildner }
133479ab7f0SSascha Wildner 
134479ab7f0SSascha Wildner /*
135479ab7f0SSascha Wildner  * devpath_last returns the last non-path end node in devpath.
136479ab7f0SSascha Wildner  */
137479ab7f0SSascha Wildner static EFI_DEVICE_PATH *
devpath_last(EFI_DEVICE_PATH * devpath)138479ab7f0SSascha Wildner devpath_last(EFI_DEVICE_PATH *devpath)
139479ab7f0SSascha Wildner {
140479ab7f0SSascha Wildner 
141479ab7f0SSascha Wildner 	while (!IsDevicePathEnd(NextDevicePathNode(devpath)))
142479ab7f0SSascha Wildner 		devpath = NextDevicePathNode(devpath);
143479ab7f0SSascha Wildner 
144479ab7f0SSascha Wildner 	return (devpath);
145479ab7f0SSascha Wildner }
146479ab7f0SSascha Wildner 
147479ab7f0SSascha Wildner /*
148479ab7f0SSascha Wildner  * devpath_node_str is a basic output method for a devpath node which
149479ab7f0SSascha Wildner  * only understands a subset of the available sub types.
150479ab7f0SSascha Wildner  *
151479ab7f0SSascha Wildner  * If we switch to UEFI 2.x then we should update it to use:
152479ab7f0SSascha Wildner  * EFI_DEVICE_PATH_TO_TEXT_PROTOCOL.
153479ab7f0SSascha Wildner  */
154479ab7f0SSascha Wildner static int
devpath_node_str(char * buf,size_t size,EFI_DEVICE_PATH * devpath)155479ab7f0SSascha Wildner devpath_node_str(char *buf, size_t size, EFI_DEVICE_PATH *devpath)
156479ab7f0SSascha Wildner {
157479ab7f0SSascha Wildner 
158479ab7f0SSascha Wildner 	switch (devpath->Type) {
159479ab7f0SSascha Wildner 	case MESSAGING_DEVICE_PATH:
160479ab7f0SSascha Wildner 		switch (devpath->SubType) {
161479ab7f0SSascha Wildner 		case MSG_ATAPI_DP: {
162479ab7f0SSascha Wildner 			ATAPI_DEVICE_PATH *atapi;
163479ab7f0SSascha Wildner 
164479ab7f0SSascha Wildner 			atapi = (ATAPI_DEVICE_PATH *)(void *)devpath;
165479ab7f0SSascha Wildner 			return snprintf(buf, size, "ata(%s,%s,0x%x)",
166479ab7f0SSascha Wildner 			    (atapi->PrimarySecondary == 1) ?  "Sec" : "Pri",
167479ab7f0SSascha Wildner 			    (atapi->SlaveMaster == 1) ?  "Slave" : "Master",
168479ab7f0SSascha Wildner 			    atapi->Lun);
169479ab7f0SSascha Wildner 		}
170479ab7f0SSascha Wildner 		case MSG_USB_DP: {
171479ab7f0SSascha Wildner 			USB_DEVICE_PATH *usb;
172479ab7f0SSascha Wildner 
173479ab7f0SSascha Wildner 			usb = (USB_DEVICE_PATH *)devpath;
174479ab7f0SSascha Wildner 			return snprintf(buf, size, "usb(0x%02x,0x%02x)",
175479ab7f0SSascha Wildner 			    usb->ParentPortNumber, usb->InterfaceNumber);
176479ab7f0SSascha Wildner 		}
177479ab7f0SSascha Wildner 		case MSG_SCSI_DP: {
178479ab7f0SSascha Wildner 			SCSI_DEVICE_PATH *scsi;
179479ab7f0SSascha Wildner 
180479ab7f0SSascha Wildner 			scsi = (SCSI_DEVICE_PATH *)(void *)devpath;
181479ab7f0SSascha Wildner 			return snprintf(buf, size, "scsi(0x%02x,0x%02x)",
182479ab7f0SSascha Wildner 			    scsi->Pun, scsi->Lun);
183479ab7f0SSascha Wildner 		}
184479ab7f0SSascha Wildner 		case MSG_SATA_DP: {
185479ab7f0SSascha Wildner 			SATA_DEVICE_PATH *sata;
186479ab7f0SSascha Wildner 
187479ab7f0SSascha Wildner 			sata = (SATA_DEVICE_PATH *)(void *)devpath;
188479ab7f0SSascha Wildner 			return snprintf(buf, size, "sata(0x%x,0x%x,0x%x)",
189479ab7f0SSascha Wildner 			    sata->HBAPortNumber, sata->PortMultiplierPortNumber,
190479ab7f0SSascha Wildner 			    sata->Lun);
191479ab7f0SSascha Wildner 		}
192479ab7f0SSascha Wildner 		default:
193479ab7f0SSascha Wildner 			return snprintf(buf, size, "msg(0x%02x)",
194479ab7f0SSascha Wildner 			    devpath->SubType);
195479ab7f0SSascha Wildner 		}
196479ab7f0SSascha Wildner 		break;
197479ab7f0SSascha Wildner 	case HARDWARE_DEVICE_PATH:
198479ab7f0SSascha Wildner 		switch (devpath->SubType) {
199479ab7f0SSascha Wildner 		case HW_PCI_DP: {
200479ab7f0SSascha Wildner 			PCI_DEVICE_PATH *pci;
201479ab7f0SSascha Wildner 
202479ab7f0SSascha Wildner 			pci = (PCI_DEVICE_PATH *)devpath;
203479ab7f0SSascha Wildner 			return snprintf(buf, size, "pci(0x%02x,0x%02x)",
204479ab7f0SSascha Wildner 			    pci->Device, pci->Function);
205479ab7f0SSascha Wildner 		}
206479ab7f0SSascha Wildner 		default:
207479ab7f0SSascha Wildner 			return snprintf(buf, size, "hw(0x%02x)",
208479ab7f0SSascha Wildner 			    devpath->SubType);
209479ab7f0SSascha Wildner 		}
210479ab7f0SSascha Wildner 		break;
211479ab7f0SSascha Wildner 	case ACPI_DEVICE_PATH: {
212479ab7f0SSascha Wildner 		ACPI_HID_DEVICE_PATH *acpi;
213479ab7f0SSascha Wildner 
214479ab7f0SSascha Wildner 		acpi = (ACPI_HID_DEVICE_PATH *)(void *)devpath;
215479ab7f0SSascha Wildner 		if ((acpi->HID & PNP_EISA_ID_MASK) == PNP_EISA_ID_CONST) {
216479ab7f0SSascha Wildner 			switch (EISA_ID_TO_NUM(acpi->HID)) {
217479ab7f0SSascha Wildner 			case 0x0a03:
218479ab7f0SSascha Wildner 				return snprintf(buf, size, "pciroot(0x%x)",
219479ab7f0SSascha Wildner 				    acpi->UID);
220479ab7f0SSascha Wildner 			case 0x0a08:
221479ab7f0SSascha Wildner 				return snprintf(buf, size, "pcieroot(0x%x)",
222479ab7f0SSascha Wildner 				    acpi->UID);
223479ab7f0SSascha Wildner 			case 0x0604:
224479ab7f0SSascha Wildner 				return snprintf(buf, size, "floppy(0x%x)",
225479ab7f0SSascha Wildner 				    acpi->UID);
226479ab7f0SSascha Wildner 			case 0x0301:
227479ab7f0SSascha Wildner 				return snprintf(buf, size, "keyboard(0x%x)",
228479ab7f0SSascha Wildner 				    acpi->UID);
229479ab7f0SSascha Wildner 			case 0x0501:
230479ab7f0SSascha Wildner 				return snprintf(buf, size, "serial(0x%x)",
231479ab7f0SSascha Wildner 				    acpi->UID);
232479ab7f0SSascha Wildner 			case 0x0401:
233479ab7f0SSascha Wildner 				return snprintf(buf, size, "parallelport(0x%x)",
234479ab7f0SSascha Wildner 				    acpi->UID);
235479ab7f0SSascha Wildner 			default:
236479ab7f0SSascha Wildner 				return snprintf(buf, size, "acpi(pnp%04x,0x%x)",
237479ab7f0SSascha Wildner 				    EISA_ID_TO_NUM(acpi->HID), acpi->UID);
238479ab7f0SSascha Wildner 			}
239479ab7f0SSascha Wildner 		}
240479ab7f0SSascha Wildner 
241479ab7f0SSascha Wildner 		return snprintf(buf, size, "acpi(0x%08x,0x%x)", acpi->HID,
242479ab7f0SSascha Wildner 		    acpi->UID);
243479ab7f0SSascha Wildner 	}
244479ab7f0SSascha Wildner 	case MEDIA_DEVICE_PATH:
245479ab7f0SSascha Wildner 		switch (devpath->SubType) {
246479ab7f0SSascha Wildner 		case MEDIA_CDROM_DP: {
247479ab7f0SSascha Wildner 			CDROM_DEVICE_PATH *cdrom;
248479ab7f0SSascha Wildner 
249479ab7f0SSascha Wildner 			cdrom = (CDROM_DEVICE_PATH *)(void *)devpath;
250479ab7f0SSascha Wildner 			return snprintf(buf, size, "cdrom(%x)",
251479ab7f0SSascha Wildner 			    cdrom->BootEntry);
252479ab7f0SSascha Wildner 		}
253479ab7f0SSascha Wildner 		case MEDIA_HARDDRIVE_DP: {
254479ab7f0SSascha Wildner 			HARDDRIVE_DEVICE_PATH *hd;
255479ab7f0SSascha Wildner 
256479ab7f0SSascha Wildner 			hd = (HARDDRIVE_DEVICE_PATH *)(void *)devpath;
257479ab7f0SSascha Wildner 			return snprintf(buf, size, "hd(%x)",
258479ab7f0SSascha Wildner 			    hd->PartitionNumber);
259479ab7f0SSascha Wildner 		}
260479ab7f0SSascha Wildner 		default:
261479ab7f0SSascha Wildner 			return snprintf(buf, size, "media(0x%02x)",
262479ab7f0SSascha Wildner 			    devpath->SubType);
263479ab7f0SSascha Wildner 		}
264479ab7f0SSascha Wildner 	case BBS_DEVICE_PATH:
265479ab7f0SSascha Wildner 		return snprintf(buf, size, "bbs(0x%02x)", devpath->SubType);
266479ab7f0SSascha Wildner 	case END_DEVICE_PATH_TYPE:
267479ab7f0SSascha Wildner 		return (0);
268479ab7f0SSascha Wildner 	}
269479ab7f0SSascha Wildner 
270479ab7f0SSascha Wildner 	return snprintf(buf, size, "type(0x%02x, 0x%02x)", devpath->Type,
271479ab7f0SSascha Wildner 	    devpath->SubType);
272479ab7f0SSascha Wildner }
273479ab7f0SSascha Wildner 
274479ab7f0SSascha Wildner /*
275479ab7f0SSascha Wildner  * devpath_strlcat appends a text description of devpath to buf but not more
276479ab7f0SSascha Wildner  * than size - 1 characters followed by NUL-terminator.
277479ab7f0SSascha Wildner  */
278479ab7f0SSascha Wildner int
devpath_strlcat(char * buf,size_t size,EFI_DEVICE_PATH * devpath)279479ab7f0SSascha Wildner devpath_strlcat(char *buf, size_t size, EFI_DEVICE_PATH *devpath)
280479ab7f0SSascha Wildner {
281479ab7f0SSascha Wildner 	size_t len, used;
282479ab7f0SSascha Wildner 	const char *sep;
283479ab7f0SSascha Wildner 
284479ab7f0SSascha Wildner 	sep = "";
285479ab7f0SSascha Wildner 	used = 0;
286479ab7f0SSascha Wildner 	while (!IsDevicePathEnd(devpath)) {
287479ab7f0SSascha Wildner 		len = snprintf(buf, size - used, "%s", sep);
288479ab7f0SSascha Wildner 		used += len;
289479ab7f0SSascha Wildner 		if (used > size)
290479ab7f0SSascha Wildner 			return (used);
291479ab7f0SSascha Wildner 		buf += len;
292479ab7f0SSascha Wildner 
293479ab7f0SSascha Wildner 		len = devpath_node_str(buf, size - used, devpath);
294479ab7f0SSascha Wildner 		used += len;
295479ab7f0SSascha Wildner 		if (used > size)
296479ab7f0SSascha Wildner 			return (used);
297479ab7f0SSascha Wildner 		buf += len;
298479ab7f0SSascha Wildner 		devpath = NextDevicePathNode(devpath);
299479ab7f0SSascha Wildner 		sep = ":";
300479ab7f0SSascha Wildner 	}
301479ab7f0SSascha Wildner 
302479ab7f0SSascha Wildner 	return (used);
303479ab7f0SSascha Wildner }
304479ab7f0SSascha Wildner 
305479ab7f0SSascha Wildner /*
306479ab7f0SSascha Wildner  * devpath_str is convenience method which returns the text description of
307479ab7f0SSascha Wildner  * devpath using a static buffer, so it isn't thread safe!
308479ab7f0SSascha Wildner  */
309479ab7f0SSascha Wildner char *
devpath_str(EFI_DEVICE_PATH * devpath)310479ab7f0SSascha Wildner devpath_str(EFI_DEVICE_PATH *devpath)
311479ab7f0SSascha Wildner {
312479ab7f0SSascha Wildner 	static char buf[256];
313479ab7f0SSascha Wildner 
314479ab7f0SSascha Wildner 	devpath_strlcat(buf, sizeof(buf), devpath);
315479ab7f0SSascha Wildner 
316479ab7f0SSascha Wildner 	return buf;
317479ab7f0SSascha Wildner }
318479ab7f0SSascha Wildner 
319479ab7f0SSascha Wildner /*
320479ab7f0SSascha Wildner  * load_loader attempts to load the loader image data.
321479ab7f0SSascha Wildner  *
322479ab7f0SSascha Wildner  * It tries each module and its respective devices, identified by mod->probe,
323479ab7f0SSascha Wildner  * in order until a successful load occurs at which point it returns EFI_SUCCESS
324479ab7f0SSascha Wildner  * and EFI_NOT_FOUND otherwise.
325479ab7f0SSascha Wildner  *
326479ab7f0SSascha Wildner  * Only devices which have preferred matching the preferred parameter are tried.
327479ab7f0SSascha Wildner  */
328479ab7f0SSascha Wildner static EFI_STATUS
load_loader(const boot_module_t ** modp,dev_info_t ** devinfop,void ** bufp,size_t * bufsize,BOOLEAN preferred)329479ab7f0SSascha Wildner load_loader(const boot_module_t **modp, dev_info_t **devinfop, void **bufp,
330479ab7f0SSascha Wildner 	    size_t *bufsize, BOOLEAN preferred)
331479ab7f0SSascha Wildner {
332479ab7f0SSascha Wildner 	UINTN i;
333479ab7f0SSascha Wildner 	dev_info_t *dev;
334479ab7f0SSascha Wildner 	const boot_module_t *mod;
335479ab7f0SSascha Wildner 	EFI_STATUS status;
336479ab7f0SSascha Wildner 
337479ab7f0SSascha Wildner 	for (i = 0; i < NUM_BOOT_MODULES; i++) {
338479ab7f0SSascha Wildner 		if (boot_modules[i] == NULL)
339479ab7f0SSascha Wildner 			continue;
340479ab7f0SSascha Wildner 		mod = boot_modules[i];
341479ab7f0SSascha Wildner 		for (dev = mod->devices(); dev != NULL; dev = dev->next) {
342479ab7f0SSascha Wildner 			if (dev->preferred != preferred)
343479ab7f0SSascha Wildner 				continue;
344479ab7f0SSascha Wildner 
345479ab7f0SSascha Wildner 			status = mod->load(PATH_LOADER, dev, bufp, bufsize);
346479ab7f0SSascha Wildner 			if (status == EFI_NOT_FOUND) {
347479ab7f0SSascha Wildner 				status = mod->load(PATH_LOADER_ALT, dev, bufp,
348479ab7f0SSascha Wildner 						   bufsize);
349479ab7f0SSascha Wildner 			}
350479ab7f0SSascha Wildner 			if (status == EFI_SUCCESS) {
351479ab7f0SSascha Wildner 				*devinfop = dev;
352479ab7f0SSascha Wildner 				*modp = mod;
353479ab7f0SSascha Wildner 				return (EFI_SUCCESS);
354479ab7f0SSascha Wildner 			}
355479ab7f0SSascha Wildner 		}
356479ab7f0SSascha Wildner 	}
357479ab7f0SSascha Wildner 
358479ab7f0SSascha Wildner 	return (EFI_NOT_FOUND);
359479ab7f0SSascha Wildner }
360479ab7f0SSascha Wildner 
361479ab7f0SSascha Wildner /*
362479ab7f0SSascha Wildner  * try_boot only returns if it fails to load the loader. If it succeeds
363479ab7f0SSascha Wildner  * it simply boots, otherwise it returns the status of last EFI call.
364479ab7f0SSascha Wildner  */
365479ab7f0SSascha Wildner static EFI_STATUS
try_boot(void)366479ab7f0SSascha Wildner try_boot(void)
367479ab7f0SSascha Wildner {
368479ab7f0SSascha Wildner 	size_t bufsize, loadersize, cmdsize;
369479ab7f0SSascha Wildner 	char *cmd;
370*3d9fb4d4SMatthew Dillon 	void *buf;
371*3d9fb4d4SMatthew Dillon 	void *loaderbuf;
372479ab7f0SSascha Wildner 	dev_info_t *dev;
373479ab7f0SSascha Wildner 	const boot_module_t *mod;
374479ab7f0SSascha Wildner 	EFI_HANDLE loaderhandle;
375479ab7f0SSascha Wildner 	EFI_LOADED_IMAGE *loaded_image;
376479ab7f0SSascha Wildner 	EFI_STATUS status;
377479ab7f0SSascha Wildner 
378*3d9fb4d4SMatthew Dillon 	loaderbuf = NULL;
379*3d9fb4d4SMatthew Dillon 	loadersize = 0;
380*3d9fb4d4SMatthew Dillon 
381479ab7f0SSascha Wildner 	status = load_loader(&mod, &dev, &loaderbuf, &loadersize, TRUE);
382479ab7f0SSascha Wildner 	if (status != EFI_SUCCESS) {
383*3d9fb4d4SMatthew Dillon 		status = load_loader(&mod, &dev, &loaderbuf,
384*3d9fb4d4SMatthew Dillon 				     &loadersize, FALSE);
385479ab7f0SSascha Wildner 		if (status != EFI_SUCCESS) {
386479ab7f0SSascha Wildner 			printf("Failed to load '%s' or '%s'\n",
387479ab7f0SSascha Wildner 			       PATH_LOADER, PATH_LOADER_ALT);
388479ab7f0SSascha Wildner 			return (status);
389479ab7f0SSascha Wildner 		}
390479ab7f0SSascha Wildner 	}
391479ab7f0SSascha Wildner 
392479ab7f0SSascha Wildner 	/*
393*3d9fb4d4SMatthew Dillon 	 * Funcions might not initialize response variables on error, make
394*3d9fb4d4SMatthew Dillon 	 * sure we have sanity.
395479ab7f0SSascha Wildner 	 */
396479ab7f0SSascha Wildner 	cmd = NULL;
397*3d9fb4d4SMatthew Dillon 	buf = NULL;
398479ab7f0SSascha Wildner 	cmdsize = 0;
399*3d9fb4d4SMatthew Dillon 	bufsize = 0;
400*3d9fb4d4SMatthew Dillon 
401*3d9fb4d4SMatthew Dillon 	/*
402*3d9fb4d4SMatthew Dillon 	 * Read in and parse the command line from /boot.config or
403*3d9fb4d4SMatthew Dillon 	 * /boot/config, if present.  We'll pass it the next stage via a
404*3d9fb4d4SMatthew Dillon 	 * simple ASCII string. loader.efi has a hack for ASCII strings, so
405*3d9fb4d4SMatthew Dillon 	 * we'll use that to keep the size down here. We only try to read the
406*3d9fb4d4SMatthew Dillon 	 * alternate file if we get EFI_NOT_FOUND because all other errors
407*3d9fb4d4SMatthew Dillon 	 * mean that the boot_module had troubles with the filesystem. We
408*3d9fb4d4SMatthew Dillon 	 * could return early, but we'll let loading the actual kernel sort
409*3d9fb4d4SMatthew Dillon 	 * all that out. Since these files are optional, we don't report
410*3d9fb4d4SMatthew Dillon 	 * errors in trying to read them.
411*3d9fb4d4SMatthew Dillon 	 */
412479ab7f0SSascha Wildner 	status = mod->load(PATH_DOTCONFIG, dev, &buf, &bufsize);
413479ab7f0SSascha Wildner 	if (status == EFI_NOT_FOUND)
414479ab7f0SSascha Wildner 		status = mod->load(PATH_CONFIG, dev, &buf, &bufsize);
415479ab7f0SSascha Wildner 	if (status == EFI_SUCCESS) {
416479ab7f0SSascha Wildner 		cmdsize = bufsize + 1;
417479ab7f0SSascha Wildner 		cmd = malloc(cmdsize);
418479ab7f0SSascha Wildner 		if (cmd == NULL)
419479ab7f0SSascha Wildner 			goto errout;
420479ab7f0SSascha Wildner 		memcpy(cmd, buf, bufsize);
421479ab7f0SSascha Wildner 		cmd[bufsize] = '\0';
422479ab7f0SSascha Wildner 		free(buf);
423479ab7f0SSascha Wildner 		buf = NULL;
424479ab7f0SSascha Wildner 	}
425479ab7f0SSascha Wildner 
426*3d9fb4d4SMatthew Dillon 	status = BS->LoadImage(TRUE, IH, devpath_last(dev->devpath),
427*3d9fb4d4SMatthew Dillon 			       loaderbuf, loadersize, &loaderhandle);
428*3d9fb4d4SMatthew Dillon 	if (status != EFI_SUCCESS) {
429*3d9fb4d4SMatthew Dillon 		printf("Failed to load image provided by %s, "
430*3d9fb4d4SMatthew Dillon 		       "size: %zu, (0x%llx)\n",
431479ab7f0SSascha Wildner 		       mod->name, loadersize, status);
432479ab7f0SSascha Wildner 		goto errout;
433479ab7f0SSascha Wildner 	}
434479ab7f0SSascha Wildner 
435*3d9fb4d4SMatthew Dillon 	status = OpenProtocolByHandle(loaderhandle, &LoadedImageGUID,
436*3d9fb4d4SMatthew Dillon 				      (VOID**)&loaded_image);
437*3d9fb4d4SMatthew Dillon 	if (status != EFI_SUCCESS) {
438*3d9fb4d4SMatthew Dillon 		printf("Failed to query LoadedImage provided by %s (0x%llx)\n",
439479ab7f0SSascha Wildner 		    mod->name, status);
440479ab7f0SSascha Wildner 		goto errout;
441479ab7f0SSascha Wildner 	}
442479ab7f0SSascha Wildner 
443479ab7f0SSascha Wildner 	if (cmd != NULL)
444479ab7f0SSascha Wildner 		printf("    command args: %s\n", cmd);
445479ab7f0SSascha Wildner 
446479ab7f0SSascha Wildner 	loaded_image->DeviceHandle = dev->devhandle;
447479ab7f0SSascha Wildner 	loaded_image->LoadOptionsSize = cmdsize;
448479ab7f0SSascha Wildner 	loaded_image->LoadOptions = cmd;
449479ab7f0SSascha Wildner 
450479ab7f0SSascha Wildner 	DPRINTF("Starting '%s' in 5 seconds...", PATH_LOADER_EFI);
451479ab7f0SSascha Wildner 	DSTALL(1000000);
452479ab7f0SSascha Wildner 	DPRINTF(".");
453479ab7f0SSascha Wildner 	DSTALL(1000000);
454479ab7f0SSascha Wildner 	DPRINTF(".");
455479ab7f0SSascha Wildner 	DSTALL(1000000);
456479ab7f0SSascha Wildner 	DPRINTF(".");
457479ab7f0SSascha Wildner 	DSTALL(1000000);
458479ab7f0SSascha Wildner 	DPRINTF(".");
459479ab7f0SSascha Wildner 	DSTALL(1000000);
460479ab7f0SSascha Wildner 	DPRINTF(".\n");
461479ab7f0SSascha Wildner 
462*3d9fb4d4SMatthew Dillon 	status = BS->StartImage(loaderhandle, NULL, NULL);
463*3d9fb4d4SMatthew Dillon 	if (status != EFI_SUCCESS) {
464*3d9fb4d4SMatthew Dillon 		printf("Failed to start image provided by %s (0x%llx)\n",
465479ab7f0SSascha Wildner 		       mod->name, status);
466479ab7f0SSascha Wildner 		loaded_image->LoadOptionsSize = 0;
467479ab7f0SSascha Wildner 		loaded_image->LoadOptions = NULL;
468479ab7f0SSascha Wildner 	}
469479ab7f0SSascha Wildner 
470*3d9fb4d4SMatthew Dillon 	/*
471*3d9fb4d4SMatthew Dillon 	 * Note that buf and loaderbuf were allocated via boot services,
472*3d9fb4d4SMatthew Dillon 	 * not our local allocator.
473*3d9fb4d4SMatthew Dillon 	 */
474479ab7f0SSascha Wildner errout:
475479ab7f0SSascha Wildner 	if (cmd != NULL)
476479ab7f0SSascha Wildner 		free(cmd);
477479ab7f0SSascha Wildner 	if (buf != NULL)
478*3d9fb4d4SMatthew Dillon 		 (void)BS->FreePool(buf);
479479ab7f0SSascha Wildner 	if (loaderbuf != NULL)
480*3d9fb4d4SMatthew Dillon 		 (void)BS->FreePool(loaderbuf);
481479ab7f0SSascha Wildner 
482479ab7f0SSascha Wildner 	return (status);
483479ab7f0SSascha Wildner }
484479ab7f0SSascha Wildner 
485479ab7f0SSascha Wildner /*
486479ab7f0SSascha Wildner  * probe_handle determines if the passed handle represents a logical partition
487479ab7f0SSascha Wildner  * if it does it uses each module in order to probe it and if successful it
488479ab7f0SSascha Wildner  * returns EFI_SUCCESS.
489479ab7f0SSascha Wildner  */
490479ab7f0SSascha Wildner static EFI_STATUS
probe_handle(EFI_HANDLE h,EFI_DEVICE_PATH * imgpath,BOOLEAN * preferred)491479ab7f0SSascha Wildner probe_handle(EFI_HANDLE h, EFI_DEVICE_PATH *imgpath, BOOLEAN *preferred)
492479ab7f0SSascha Wildner {
493479ab7f0SSascha Wildner 	dev_info_t *devinfo;
494479ab7f0SSascha Wildner 	EFI_BLOCK_IO *blkio;
495479ab7f0SSascha Wildner 	EFI_DEVICE_PATH *devpath;
496479ab7f0SSascha Wildner 	EFI_STATUS status;
497479ab7f0SSascha Wildner 	UINTN i;
498479ab7f0SSascha Wildner 
499479ab7f0SSascha Wildner 	/* Figure out if we're dealing with an actual partition. */
500479ab7f0SSascha Wildner 	status = OpenProtocolByHandle(h, &DevicePathGUID, (void **)&devpath);
501479ab7f0SSascha Wildner 	if (status == EFI_UNSUPPORTED)
502479ab7f0SSascha Wildner 		return (status);
503479ab7f0SSascha Wildner 
504479ab7f0SSascha Wildner 	if (status != EFI_SUCCESS) {
505*3d9fb4d4SMatthew Dillon 		DPRINTF("\nFailed to query DevicePath (0x%llx)\n",
506479ab7f0SSascha Wildner 		    status);
507479ab7f0SSascha Wildner 		return (status);
508479ab7f0SSascha Wildner 	}
509479ab7f0SSascha Wildner 
510479ab7f0SSascha Wildner 	DPRINTF("probing: %s\n", devpath_str(devpath));
511479ab7f0SSascha Wildner 
512479ab7f0SSascha Wildner 	status = OpenProtocolByHandle(h, &BlockIoProtocolGUID,
513479ab7f0SSascha Wildner 				      (void **)&blkio);
514479ab7f0SSascha Wildner 	if (status == EFI_UNSUPPORTED)
515479ab7f0SSascha Wildner 		return (status);
516479ab7f0SSascha Wildner 
517479ab7f0SSascha Wildner 	if (status != EFI_SUCCESS) {
518*3d9fb4d4SMatthew Dillon 		DPRINTF("\nFailed to query BlockIoProtocol (0x%llx)\n",
519479ab7f0SSascha Wildner 		    status);
520479ab7f0SSascha Wildner 		return (status);
521479ab7f0SSascha Wildner 	}
522479ab7f0SSascha Wildner 
523479ab7f0SSascha Wildner 	if (!blkio->Media->LogicalPartition)
524479ab7f0SSascha Wildner 		return (EFI_UNSUPPORTED);
525479ab7f0SSascha Wildner 
526479ab7f0SSascha Wildner 	*preferred = device_paths_match(imgpath, devpath);
527479ab7f0SSascha Wildner 
528479ab7f0SSascha Wildner 	/* Run through each module, see if it can load this partition */
529479ab7f0SSascha Wildner 	for (i = 0; i < NUM_BOOT_MODULES; i++) {
530479ab7f0SSascha Wildner 		if (boot_modules[i] == NULL)
531479ab7f0SSascha Wildner 			continue;
532479ab7f0SSascha Wildner 
533*3d9fb4d4SMatthew Dillon 		status = BS->AllocatePool(EfiLoaderData, sizeof(*devinfo),
534*3d9fb4d4SMatthew Dillon 					  (void **)&devinfo);
535*3d9fb4d4SMatthew Dillon 		if (status != EFI_SUCCESS) {
536*3d9fb4d4SMatthew Dillon 			DPRINTF("\nFailed to allocate devinfo (0x%llx)\n",
537479ab7f0SSascha Wildner 			    status);
538479ab7f0SSascha Wildner 			continue;
539479ab7f0SSascha Wildner 		}
540479ab7f0SSascha Wildner 		devinfo->dev = blkio;
541479ab7f0SSascha Wildner 		devinfo->devpath = devpath;
542479ab7f0SSascha Wildner 		devinfo->devhandle = h;
543479ab7f0SSascha Wildner 		devinfo->devdata = NULL;
544479ab7f0SSascha Wildner 		devinfo->preferred = *preferred;
545479ab7f0SSascha Wildner 		devinfo->next = NULL;
546479ab7f0SSascha Wildner 
547479ab7f0SSascha Wildner 		status = boot_modules[i]->probe(devinfo);
548479ab7f0SSascha Wildner 		if (status == EFI_SUCCESS)
549479ab7f0SSascha Wildner 			return (EFI_SUCCESS);
550479ab7f0SSascha Wildner 		(void)BS->FreePool(devinfo);
551479ab7f0SSascha Wildner 	}
552479ab7f0SSascha Wildner 
553479ab7f0SSascha Wildner 	return (EFI_UNSUPPORTED);
554479ab7f0SSascha Wildner }
555479ab7f0SSascha Wildner 
556479ab7f0SSascha Wildner /*
557479ab7f0SSascha Wildner  * probe_handle_status calls probe_handle and outputs the returned status
558479ab7f0SSascha Wildner  * of the call.
559479ab7f0SSascha Wildner  */
560479ab7f0SSascha Wildner static void
probe_handle_status(EFI_HANDLE h,EFI_DEVICE_PATH * imgpath)561479ab7f0SSascha Wildner probe_handle_status(EFI_HANDLE h, EFI_DEVICE_PATH *imgpath)
562479ab7f0SSascha Wildner {
563479ab7f0SSascha Wildner 	EFI_STATUS status;
564479ab7f0SSascha Wildner 	BOOLEAN preferred;
565479ab7f0SSascha Wildner 
566479ab7f0SSascha Wildner 	preferred = FALSE;
567479ab7f0SSascha Wildner 	status = probe_handle(h, imgpath, &preferred);
568479ab7f0SSascha Wildner 
569479ab7f0SSascha Wildner 	DPRINTF("probe: ");
570479ab7f0SSascha Wildner 	switch (status) {
571479ab7f0SSascha Wildner 	case EFI_UNSUPPORTED:
572479ab7f0SSascha Wildner 		printf(".");
573479ab7f0SSascha Wildner 		DPRINTF(" not supported\n");
574479ab7f0SSascha Wildner 		break;
575479ab7f0SSascha Wildner 	case EFI_SUCCESS:
576479ab7f0SSascha Wildner 		if (preferred) {
577479ab7f0SSascha Wildner 			printf("%c", '*');
578479ab7f0SSascha Wildner 			DPRINTF(" supported (preferred)\n");
579479ab7f0SSascha Wildner 		} else {
580479ab7f0SSascha Wildner 			printf("%c", '+');
581479ab7f0SSascha Wildner 			DPRINTF(" supported\n");
582479ab7f0SSascha Wildner 		}
583479ab7f0SSascha Wildner 		break;
584479ab7f0SSascha Wildner 	default:
585479ab7f0SSascha Wildner 		printf("x");
586*3d9fb4d4SMatthew Dillon 		DPRINTF(" error (0x%llx)\n", status);
587479ab7f0SSascha Wildner 		break;
588479ab7f0SSascha Wildner 	}
589479ab7f0SSascha Wildner 	DSTALL(500000);
590479ab7f0SSascha Wildner }
591479ab7f0SSascha Wildner 
592479ab7f0SSascha Wildner EFI_STATUS
efi_main(EFI_HANDLE Ximage,EFI_SYSTEM_TABLE * Xsystab)593479ab7f0SSascha Wildner efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE *Xsystab)
594479ab7f0SSascha Wildner {
595479ab7f0SSascha Wildner 	EFI_HANDLE *handles;
596479ab7f0SSascha Wildner 	EFI_LOADED_IMAGE *img;
597479ab7f0SSascha Wildner 	EFI_DEVICE_PATH *imgpath;
598479ab7f0SSascha Wildner 	EFI_STATUS status;
599479ab7f0SSascha Wildner 	EFI_CONSOLE_CONTROL_PROTOCOL *ConsoleControl = NULL;
600479ab7f0SSascha Wildner 	SIMPLE_TEXT_OUTPUT_INTERFACE *conout = NULL;
601479ab7f0SSascha Wildner 	UINTN i, max_dim, best_mode, cols, rows, hsize, nhandles;
602479ab7f0SSascha Wildner 
603479ab7f0SSascha Wildner 	/* Basic initialization*/
604479ab7f0SSascha Wildner 	ST = Xsystab;
605479ab7f0SSascha Wildner 	IH = Ximage;
606479ab7f0SSascha Wildner 	BS = ST->BootServices;
607479ab7f0SSascha Wildner 	RS = ST->RuntimeServices;
608479ab7f0SSascha Wildner 
609479ab7f0SSascha Wildner 	/* Set up the console, so printf works. */
610479ab7f0SSascha Wildner 	status = BS->LocateProtocol(&ConsoleControlGUID, NULL,
611479ab7f0SSascha Wildner 	    (VOID **)&ConsoleControl);
612479ab7f0SSascha Wildner 	if (status == EFI_SUCCESS)
613479ab7f0SSascha Wildner 		(void)ConsoleControl->SetMode(ConsoleControl,
614479ab7f0SSascha Wildner 		    EfiConsoleControlScreenText);
615479ab7f0SSascha Wildner 	/*
616479ab7f0SSascha Wildner 	 * Reset the console and find the best text mode.
617479ab7f0SSascha Wildner 	 */
618479ab7f0SSascha Wildner 	conout = ST->ConOut;
619479ab7f0SSascha Wildner 	conout->Reset(conout, TRUE);
620479ab7f0SSascha Wildner 	max_dim = best_mode = 0;
621479ab7f0SSascha Wildner 	for (i = 0; ; i++) {
622479ab7f0SSascha Wildner 		status = conout->QueryMode(conout, i, &cols, &rows);
623479ab7f0SSascha Wildner 		if (EFI_ERROR(status)) {
624479ab7f0SSascha Wildner 			/* Mode 1 (80x50) can be unsupported on some hw. */
625479ab7f0SSascha Wildner 			if (i == 1)
626479ab7f0SSascha Wildner 				continue;
627479ab7f0SSascha Wildner 			else
628479ab7f0SSascha Wildner 				break;
629479ab7f0SSascha Wildner 		}
630479ab7f0SSascha Wildner 		if (cols * rows > max_dim) {
631479ab7f0SSascha Wildner 			max_dim = cols * rows;
632479ab7f0SSascha Wildner 			best_mode = i;
633479ab7f0SSascha Wildner 		}
634479ab7f0SSascha Wildner 	}
635479ab7f0SSascha Wildner 	if (max_dim > 0)
636479ab7f0SSascha Wildner 		conout->SetMode(conout, best_mode);
637479ab7f0SSascha Wildner 	conout->EnableCursor(conout, TRUE);
638479ab7f0SSascha Wildner 	conout->ClearScreen(conout);
639479ab7f0SSascha Wildner 
640479ab7f0SSascha Wildner 	printf("\n>> DragonFly EFI boot block\n");
641479ab7f0SSascha Wildner 	printf("   Loader path: %s:%s\n\n", PATH_LOADER, PATH_LOADER_ALT);
642479ab7f0SSascha Wildner 	printf("   Initializing modules:");
643479ab7f0SSascha Wildner 	for (i = 0; i < NUM_BOOT_MODULES; i++) {
644479ab7f0SSascha Wildner 		if (boot_modules[i] == NULL)
645479ab7f0SSascha Wildner 			continue;
646479ab7f0SSascha Wildner 
647479ab7f0SSascha Wildner 		printf(" %s", boot_modules[i]->name);
648479ab7f0SSascha Wildner 		if (boot_modules[i]->init != NULL)
649479ab7f0SSascha Wildner 			boot_modules[i]->init();
650479ab7f0SSascha Wildner 	}
651479ab7f0SSascha Wildner 	putchar('\n');
652479ab7f0SSascha Wildner 
653479ab7f0SSascha Wildner 	/* Get all the device handles */
654479ab7f0SSascha Wildner 	hsize = (UINTN)NUM_HANDLES_INIT * sizeof(EFI_HANDLE);
655479ab7f0SSascha Wildner 	if ((status = BS->AllocatePool(EfiLoaderData, hsize, (void **)&handles))
656479ab7f0SSascha Wildner 	    != EFI_SUCCESS)
657*3d9fb4d4SMatthew Dillon 		panic("Failed to allocate %d handles (0x%llx)", NUM_HANDLES_INIT,
658479ab7f0SSascha Wildner 		    status);
659479ab7f0SSascha Wildner 
660479ab7f0SSascha Wildner 	status = BS->LocateHandle(ByProtocol, &BlockIoProtocolGUID, NULL,
661479ab7f0SSascha Wildner 	    &hsize, handles);
662479ab7f0SSascha Wildner 	switch (status) {
663479ab7f0SSascha Wildner 	case EFI_SUCCESS:
664479ab7f0SSascha Wildner 		break;
665479ab7f0SSascha Wildner 	case EFI_BUFFER_TOO_SMALL:
666479ab7f0SSascha Wildner 		(void)BS->FreePool(handles);
667479ab7f0SSascha Wildner 		if ((status = BS->AllocatePool(EfiLoaderData, hsize,
668479ab7f0SSascha Wildner 		    (void **)&handles)) != EFI_SUCCESS) {
669*3d9fb4d4SMatthew Dillon 			panic("Failed to allocate %llu handles (0x%llx)", hsize /
670479ab7f0SSascha Wildner 			    sizeof(*handles), status);
671479ab7f0SSascha Wildner 		}
672479ab7f0SSascha Wildner 		status = BS->LocateHandle(ByProtocol, &BlockIoProtocolGUID,
673479ab7f0SSascha Wildner 		    NULL, &hsize, handles);
674479ab7f0SSascha Wildner 		if (status != EFI_SUCCESS)
675*3d9fb4d4SMatthew Dillon 			panic("Failed to get device handles (0x%llx)\n",
676479ab7f0SSascha Wildner 			    status);
677479ab7f0SSascha Wildner 		break;
678479ab7f0SSascha Wildner 	default:
679*3d9fb4d4SMatthew Dillon 		panic("Failed to get device handles (0x%llx)",
680479ab7f0SSascha Wildner 		    status);
681479ab7f0SSascha Wildner 	}
682479ab7f0SSascha Wildner 
683479ab7f0SSascha Wildner 	/* Scan all partitions, probing with all modules. */
684479ab7f0SSascha Wildner 	nhandles = hsize / sizeof(*handles);
685479ab7f0SSascha Wildner 	printf("   Probing %llu block devices...", nhandles);
686479ab7f0SSascha Wildner 	DPRINTF("\n");
687479ab7f0SSascha Wildner 
688479ab7f0SSascha Wildner 	/* Determine the devpath of our image so we can prefer it. */
689479ab7f0SSascha Wildner 	status = OpenProtocolByHandle(IH, &LoadedImageGUID, (VOID**)&img);
690479ab7f0SSascha Wildner 	imgpath = NULL;
691479ab7f0SSascha Wildner 	if (status == EFI_SUCCESS) {
692479ab7f0SSascha Wildner 		status = OpenProtocolByHandle(img->DeviceHandle,
693*3d9fb4d4SMatthew Dillon 					      &DevicePathGUID,
694*3d9fb4d4SMatthew Dillon 					      (void **)&imgpath);
695*3d9fb4d4SMatthew Dillon 		if (status != EFI_SUCCESS) {
696*3d9fb4d4SMatthew Dillon 			DPRINTF("Failed to get image DevicePath (0x%llx)\n",
697479ab7f0SSascha Wildner 			    status);
698*3d9fb4d4SMatthew Dillon 		}
699479ab7f0SSascha Wildner 		DPRINTF("boot1 imagepath: %s\n", devpath_str(imgpath));
700479ab7f0SSascha Wildner 	}
701479ab7f0SSascha Wildner 
702479ab7f0SSascha Wildner 	for (i = 0; i < nhandles; i++)
703479ab7f0SSascha Wildner 		probe_handle_status(handles[i], imgpath);
704479ab7f0SSascha Wildner 	printf(" done\n");
705479ab7f0SSascha Wildner 
706479ab7f0SSascha Wildner 	/* Status summary. */
707479ab7f0SSascha Wildner 	for (i = 0; i < NUM_BOOT_MODULES; i++) {
708479ab7f0SSascha Wildner 		if (boot_modules[i] != NULL) {
709479ab7f0SSascha Wildner 			printf("    ");
710479ab7f0SSascha Wildner 			boot_modules[i]->status();
711479ab7f0SSascha Wildner 		}
712479ab7f0SSascha Wildner 	}
713479ab7f0SSascha Wildner 
714479ab7f0SSascha Wildner 	try_boot();
715479ab7f0SSascha Wildner 
716479ab7f0SSascha Wildner 	/* If we get here, we're out of luck... */
717479ab7f0SSascha Wildner 	panic("No bootable partitions found!");
718479ab7f0SSascha Wildner }
719479ab7f0SSascha Wildner 
720479ab7f0SSascha Wildner /*
721479ab7f0SSascha Wildner  * add_device adds a device to the passed devinfo list.
722479ab7f0SSascha Wildner  */
723479ab7f0SSascha Wildner void
add_device(dev_info_t ** devinfop,dev_info_t * devinfo)724479ab7f0SSascha Wildner add_device(dev_info_t **devinfop, dev_info_t *devinfo)
725479ab7f0SSascha Wildner {
726479ab7f0SSascha Wildner 	dev_info_t *dev;
727479ab7f0SSascha Wildner 
728479ab7f0SSascha Wildner 	if (*devinfop == NULL) {
729479ab7f0SSascha Wildner 		*devinfop = devinfo;
730479ab7f0SSascha Wildner 		return;
731479ab7f0SSascha Wildner 	}
732479ab7f0SSascha Wildner 
733479ab7f0SSascha Wildner 	for (dev = *devinfop; dev->next != NULL; dev = dev->next)
734479ab7f0SSascha Wildner 		;
735479ab7f0SSascha Wildner 
736479ab7f0SSascha Wildner 	dev->next = devinfo;
737479ab7f0SSascha Wildner }
738479ab7f0SSascha Wildner 
739479ab7f0SSascha Wildner void
panic(const char * fmt,...)740479ab7f0SSascha Wildner panic(const char *fmt, ...)
741479ab7f0SSascha Wildner {
742479ab7f0SSascha Wildner 	va_list ap;
743479ab7f0SSascha Wildner 
744479ab7f0SSascha Wildner 	printf("panic: ");
745479ab7f0SSascha Wildner 	va_start(ap, fmt);
746479ab7f0SSascha Wildner 	vprintf(fmt, ap);
747479ab7f0SSascha Wildner 	va_end(ap);
748479ab7f0SSascha Wildner 	printf("\n");
749479ab7f0SSascha Wildner 
750479ab7f0SSascha Wildner 	while (1) {}
751479ab7f0SSascha Wildner }
752479ab7f0SSascha Wildner 
753479ab7f0SSascha Wildner void
putchar(int c)754479ab7f0SSascha Wildner putchar(int c)
755479ab7f0SSascha Wildner {
756479ab7f0SSascha Wildner 	CHAR16 buf[2];
757479ab7f0SSascha Wildner 
758479ab7f0SSascha Wildner 	if (c == '\n') {
759479ab7f0SSascha Wildner 		buf[0] = '\r';
760479ab7f0SSascha Wildner 		buf[1] = 0;
761479ab7f0SSascha Wildner 		ST->ConOut->OutputString(ST->ConOut, buf);
762479ab7f0SSascha Wildner 	}
763479ab7f0SSascha Wildner 	buf[0] = c;
764479ab7f0SSascha Wildner 	buf[1] = 0;
765479ab7f0SSascha Wildner 	ST->ConOut->OutputString(ST->ConOut, buf);
766479ab7f0SSascha Wildner }
767