xref: /openbsd/sys/arch/arm64/stand/efiboot/efiboot.c (revision 73dc1409)
1*73dc1409Spatrick /*	$OpenBSD: efiboot.c,v 1.3 2017/02/03 08:48:40 patrick Exp $	*/
2f24071e5Spatrick 
3f24071e5Spatrick /*
4f24071e5Spatrick  * Copyright (c) 2015 YASUOKA Masahiko <yasuoka@yasuoka.net>
5f24071e5Spatrick  * Copyright (c) 2016 Mark Kettenis
6f24071e5Spatrick  *
7f24071e5Spatrick  * Permission to use, copy, modify, and distribute this software for any
8f24071e5Spatrick  * purpose with or without fee is hereby granted, provided that the above
9f24071e5Spatrick  * copyright notice and this permission notice appear in all copies.
10f24071e5Spatrick  *
11f24071e5Spatrick  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12f24071e5Spatrick  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13f24071e5Spatrick  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14f24071e5Spatrick  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15f24071e5Spatrick  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16f24071e5Spatrick  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17f24071e5Spatrick  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18f24071e5Spatrick  */
19f24071e5Spatrick 
20f24071e5Spatrick #include <sys/param.h>
21f24071e5Spatrick #include <sys/queue.h>
22f24071e5Spatrick #include <dev/cons.h>
23f24071e5Spatrick #include <sys/disklabel.h>
24f24071e5Spatrick 
25f24071e5Spatrick #include <efi.h>
26f24071e5Spatrick #include <efiapi.h>
27f24071e5Spatrick #include <efiprot.h>
28f24071e5Spatrick #include <eficonsctl.h>
29f24071e5Spatrick 
30f24071e5Spatrick #include <lib/libkern/libkern.h>
31f24071e5Spatrick #include <stand/boot/cmd.h>
32f24071e5Spatrick 
33f24071e5Spatrick #include "disk.h"
34f24071e5Spatrick #include "eficall.h"
35f24071e5Spatrick #include "fdt.h"
36f24071e5Spatrick #include "libsa.h"
37f24071e5Spatrick 
38f24071e5Spatrick EFI_SYSTEM_TABLE	*ST;
39f24071e5Spatrick EFI_BOOT_SERVICES	*BS;
40f24071e5Spatrick EFI_RUNTIME_SERVICES	*RS;
41f24071e5Spatrick EFI_HANDLE		 IH;
42f24071e5Spatrick 
43f24071e5Spatrick EFI_HANDLE		 efi_bootdp;
44f24071e5Spatrick 
45f24071e5Spatrick static EFI_GUID		 imgp_guid = LOADED_IMAGE_PROTOCOL;
46f24071e5Spatrick static EFI_GUID		 blkio_guid = BLOCK_IO_PROTOCOL;
47f24071e5Spatrick static EFI_GUID		 devp_guid = DEVICE_PATH_PROTOCOL;
48f24071e5Spatrick 
49f24071e5Spatrick static void efi_timer_init(void);
50f24071e5Spatrick static void efi_timer_cleanup(void);
51f24071e5Spatrick static EFI_STATUS efi_memprobe_find(UINTN, UINTN, EFI_PHYSICAL_ADDRESS *);
52f24071e5Spatrick 
53f24071e5Spatrick EFI_STATUS
54f24071e5Spatrick efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab)
55f24071e5Spatrick {
56f24071e5Spatrick 	extern char		*progname;
57f24071e5Spatrick 	EFI_LOADED_IMAGE	*imgp;
58f24071e5Spatrick 	EFI_DEVICE_PATH		*dp = NULL;
59f24071e5Spatrick 	EFI_STATUS		 status;
60f24071e5Spatrick 
61f24071e5Spatrick 	ST = systab;
62f24071e5Spatrick 	BS = ST->BootServices;
63f24071e5Spatrick 	IH = image;
64f24071e5Spatrick 
65f24071e5Spatrick 	status = EFI_CALL(BS->HandleProtocol, image, &imgp_guid,
66f24071e5Spatrick 	    (void **)&imgp);
67f24071e5Spatrick 	if (status == EFI_SUCCESS)
68f24071e5Spatrick 		status = EFI_CALL(BS->HandleProtocol, imgp->DeviceHandle,
69f24071e5Spatrick 		    &devp_guid, (void **)&dp);
70f24071e5Spatrick 	if (status == EFI_SUCCESS)
71f24071e5Spatrick 		efi_bootdp = dp;
72f24071e5Spatrick 
73f24071e5Spatrick 	progname = "BOOTAA64";
74f24071e5Spatrick 
75f24071e5Spatrick 	boot(0);
76f24071e5Spatrick 
77f24071e5Spatrick 	return (EFI_SUCCESS);
78f24071e5Spatrick }
79f24071e5Spatrick 
80f24071e5Spatrick static SIMPLE_TEXT_OUTPUT_INTERFACE *conout;
81f24071e5Spatrick static SIMPLE_INPUT_INTERFACE *conin;
82f24071e5Spatrick 
83f24071e5Spatrick void
84f24071e5Spatrick efi_cons_probe(struct consdev *cn)
85f24071e5Spatrick {
86f24071e5Spatrick 	cn->cn_pri = CN_MIDPRI;
87f24071e5Spatrick 	cn->cn_dev = makedev(12, 0);
88f24071e5Spatrick }
89f24071e5Spatrick 
90f24071e5Spatrick void
91f24071e5Spatrick efi_cons_init(struct consdev *cp)
92f24071e5Spatrick {
93f24071e5Spatrick 	conin = ST->ConIn;
94f24071e5Spatrick 	conout = ST->ConOut;
95f24071e5Spatrick }
96f24071e5Spatrick 
97f24071e5Spatrick int
98f24071e5Spatrick efi_cons_getc(dev_t dev)
99f24071e5Spatrick {
100f24071e5Spatrick 	EFI_INPUT_KEY	 key;
101f24071e5Spatrick 	EFI_STATUS	 status;
102f24071e5Spatrick #if 0
103f24071e5Spatrick 	UINTN		 dummy;
104f24071e5Spatrick #endif
105f24071e5Spatrick 	static int	 lastchar = 0;
106f24071e5Spatrick 
107f24071e5Spatrick 	if (lastchar) {
108f24071e5Spatrick 		int r = lastchar;
109f24071e5Spatrick 		if ((dev & 0x80) == 0)
110f24071e5Spatrick 			lastchar = 0;
111f24071e5Spatrick 		return (r);
112f24071e5Spatrick 	}
113f24071e5Spatrick 
114f24071e5Spatrick 	status = conin->ReadKeyStroke(conin, &key);
115f24071e5Spatrick 	while (status == EFI_NOT_READY) {
116f24071e5Spatrick 		if (dev & 0x80)
117f24071e5Spatrick 			return (0);
118f24071e5Spatrick 		/*
119f24071e5Spatrick 		 * XXX The implementation of WaitForEvent() in U-boot
120f24071e5Spatrick 		 * is broken and neverreturns.
121f24071e5Spatrick 		 */
122f24071e5Spatrick #if 0
123f24071e5Spatrick 		BS->WaitForEvent(1, &conin->WaitForKey, &dummy);
124f24071e5Spatrick #endif
125f24071e5Spatrick 		status = conin->ReadKeyStroke(conin, &key);
126f24071e5Spatrick 	}
127f24071e5Spatrick 
128f24071e5Spatrick 	if (dev & 0x80)
129f24071e5Spatrick 		lastchar = key.UnicodeChar;
130f24071e5Spatrick 
131f24071e5Spatrick 	return (key.UnicodeChar);
132f24071e5Spatrick }
133f24071e5Spatrick 
134f24071e5Spatrick void
135f24071e5Spatrick efi_cons_putc(dev_t dev, int c)
136f24071e5Spatrick {
137f24071e5Spatrick 	CHAR16	buf[2];
138f24071e5Spatrick 
139f24071e5Spatrick 	if (c == '\n')
140f24071e5Spatrick 		efi_cons_putc(dev, '\r');
141f24071e5Spatrick 
142f24071e5Spatrick 	buf[0] = c;
143f24071e5Spatrick 	buf[1] = 0;
144f24071e5Spatrick 
145f24071e5Spatrick 	conout->OutputString(conout, buf);
146f24071e5Spatrick }
147f24071e5Spatrick 
148f24071e5Spatrick EFI_PHYSICAL_ADDRESS	 heap;
149f24071e5Spatrick UINTN			 heapsiz = 1 * 1024 * 1024;
150f24071e5Spatrick 
151f24071e5Spatrick static void
152f24071e5Spatrick efi_heap_init(void)
153f24071e5Spatrick {
154f24071e5Spatrick 	EFI_STATUS	 status;
155f24071e5Spatrick 
156f24071e5Spatrick 	status = EFI_CALL(BS->AllocatePages, AllocateAnyPages, EfiLoaderData,
157f24071e5Spatrick 	    EFI_SIZE_TO_PAGES(heapsiz), &heap);
158f24071e5Spatrick 	if (status != EFI_SUCCESS)
159f24071e5Spatrick 		panic("BS->AllocatePages()");
160f24071e5Spatrick }
161f24071e5Spatrick 
162f24071e5Spatrick EFI_BLOCK_IO	*disk;
163f24071e5Spatrick 
164f24071e5Spatrick void
165f24071e5Spatrick efi_diskprobe(void)
166f24071e5Spatrick {
167f24071e5Spatrick 	int			 i, bootdev;
168f24071e5Spatrick 	UINTN			 sz;
169f24071e5Spatrick 	EFI_STATUS		 status;
170f24071e5Spatrick 	EFI_HANDLE		*handles = NULL;
171f24071e5Spatrick 	EFI_BLOCK_IO		*blkio;
172f24071e5Spatrick 	EFI_BLOCK_IO_MEDIA	*media;
173f24071e5Spatrick 	EFI_DEVICE_PATH		*dp, *bp;
174f24071e5Spatrick 
175f24071e5Spatrick 	sz = 0;
176f24071e5Spatrick 	status = EFI_CALL(BS->LocateHandle, ByProtocol, &blkio_guid, 0, &sz, 0);
177f24071e5Spatrick 	if (status == EFI_BUFFER_TOO_SMALL) {
178f24071e5Spatrick 		handles = alloc(sz);
179f24071e5Spatrick 		status = EFI_CALL(BS->LocateHandle, ByProtocol, &blkio_guid,
180f24071e5Spatrick 		    0, &sz, handles);
181f24071e5Spatrick 	}
182f24071e5Spatrick 	if (handles == NULL || EFI_ERROR(status))
183f24071e5Spatrick 		panic("BS->LocateHandle() returns %d", status);
184f24071e5Spatrick 
185f24071e5Spatrick 	for (i = 0; i < sz / sizeof(EFI_HANDLE); i++) {
186f24071e5Spatrick 		bootdev = 0;
187f24071e5Spatrick 		status = EFI_CALL(BS->HandleProtocol, handles[i], &blkio_guid,
188f24071e5Spatrick 		    (void **)&blkio);
189f24071e5Spatrick 		if (EFI_ERROR(status))
190f24071e5Spatrick 			panic("BS->HandleProtocol() returns %d", status);
191f24071e5Spatrick 
192f24071e5Spatrick 		media = blkio->Media;
193f24071e5Spatrick 		if (media->LogicalPartition || !media->MediaPresent)
194f24071e5Spatrick 			continue;
195f24071e5Spatrick 
196f24071e5Spatrick 		if (efi_bootdp == NULL)
197f24071e5Spatrick 			goto next;
198f24071e5Spatrick 		status = EFI_CALL(BS->HandleProtocol, handles[i], &devp_guid,
199f24071e5Spatrick 		    (void **)&dp);
200f24071e5Spatrick 		if (EFI_ERROR(status))
201f24071e5Spatrick 			goto next;
202f24071e5Spatrick 		bp = efi_bootdp;
203f24071e5Spatrick 		while (1) {
204f24071e5Spatrick 			if (IsDevicePathEnd(dp)) {
205f24071e5Spatrick 				bootdev = 1;
206f24071e5Spatrick 				break;
207f24071e5Spatrick 			}
208f24071e5Spatrick 			if (memcmp(dp, bp, sizeof(EFI_DEVICE_PATH)) != 0 ||
209f24071e5Spatrick 			    memcmp(dp, bp, DevicePathNodeLength(dp)) != 0)
210f24071e5Spatrick 				break;
211f24071e5Spatrick 			dp = NextDevicePathNode(dp);
212f24071e5Spatrick 			bp = NextDevicePathNode(bp);
213f24071e5Spatrick 		}
214f24071e5Spatrick next:
215f24071e5Spatrick 		if (bootdev) {
216f24071e5Spatrick 			disk = blkio;
217f24071e5Spatrick 			break;
218f24071e5Spatrick 		}
219f24071e5Spatrick 	}
220f24071e5Spatrick 
221f24071e5Spatrick 	free(handles, sz);
222f24071e5Spatrick }
223f24071e5Spatrick 
224f24071e5Spatrick static EFI_GUID fdt_guid = FDT_TABLE_GUID;
225f24071e5Spatrick 
226f24071e5Spatrick #define	efi_guidcmp(_a, _b)	memcmp((_a), (_b), sizeof(EFI_GUID))
227f24071e5Spatrick 
228f24071e5Spatrick void *
229f24071e5Spatrick efi_makebootargs(char *bootargs)
230f24071e5Spatrick {
231f24071e5Spatrick 	void *fdt = NULL;
232f24071e5Spatrick 	char bootduid[8];
233f24071e5Spatrick 	u_char zero[8];
234f24071e5Spatrick 	void *node;
235f24071e5Spatrick 	size_t len;
236f24071e5Spatrick 	int i;
237f24071e5Spatrick 
238f24071e5Spatrick 	for (i = 0; i < ST->NumberOfTableEntries; i++) {
239f24071e5Spatrick 		if (efi_guidcmp(&fdt_guid,
240f24071e5Spatrick 		    &ST->ConfigurationTable[i].VendorGuid) == 0)
241f24071e5Spatrick 			fdt = ST->ConfigurationTable[i].VendorTable;
242f24071e5Spatrick 	}
243f24071e5Spatrick 
244f24071e5Spatrick 	if (!fdt_init(fdt))
245f24071e5Spatrick 		return NULL;
246f24071e5Spatrick 
247f24071e5Spatrick 	node = fdt_find_node("/chosen");
248f24071e5Spatrick 	if (!node)
249f24071e5Spatrick 		return NULL;
250f24071e5Spatrick 
251f24071e5Spatrick 	len = strlen(bootargs) + 1;
252f24071e5Spatrick 	fdt_node_add_property(node, "bootargs", bootargs, len);
253f24071e5Spatrick 
254f24071e5Spatrick 	/* Pass DUID of the boot disk. */
255f24071e5Spatrick 	memset(&zero, 0, sizeof(zero));
256f24071e5Spatrick 	memcpy(&bootduid, diskinfo.disklabel.d_uid, sizeof(bootduid));
257f24071e5Spatrick 	if (memcmp(bootduid, zero, sizeof(bootduid)) != 0) {
258f24071e5Spatrick 		fdt_node_add_property(node, "openbsd,bootduid", bootduid,
259f24071e5Spatrick 		    sizeof(bootduid));
260f24071e5Spatrick 	}
261f24071e5Spatrick 
262f24071e5Spatrick 	fdt_finalize();
263f24071e5Spatrick 
264f24071e5Spatrick 	return fdt;
265f24071e5Spatrick }
266f24071e5Spatrick 
267f24071e5Spatrick u_long efi_loadaddr;
268f24071e5Spatrick 
269f24071e5Spatrick void
270f24071e5Spatrick machdep(void)
271f24071e5Spatrick {
272f24071e5Spatrick 	EFI_PHYSICAL_ADDRESS addr;
273f24071e5Spatrick 
274f24071e5Spatrick 	cninit();
275f24071e5Spatrick 	efi_heap_init();
276f24071e5Spatrick 
277f24071e5Spatrick 	/*
278f24071e5Spatrick 	 * The kernel expects to be loaded at offset 0x00200000 into a
279f24071e5Spatrick 	 * block of memory aligned on a 256MB boundary.  We allocate a
280f24071e5Spatrick 	 * block of 32MB of memory, which gives us plenty of room for
281f24071e5Spatrick 	 * growth.
282f24071e5Spatrick 	 */
283f24071e5Spatrick 	if (efi_memprobe_find(EFI_SIZE_TO_PAGES(32 * 1024 * 1024),
284f24071e5Spatrick 	    0x10000000, &addr) != EFI_SUCCESS)
285f24071e5Spatrick 		printf("Can't allocate memory\n");
286f24071e5Spatrick 	efi_loadaddr = addr;
287f24071e5Spatrick 
288f24071e5Spatrick 	efi_timer_init();
289f24071e5Spatrick 	efi_diskprobe();
290f24071e5Spatrick }
291f24071e5Spatrick 
292f24071e5Spatrick void
293f24071e5Spatrick efi_cleanup(void)
294f24071e5Spatrick {
295f24071e5Spatrick 	efi_timer_cleanup();
296f24071e5Spatrick 
297f24071e5Spatrick 	BS->ExitBootServices(NULL, 0);
298f24071e5Spatrick }
299f24071e5Spatrick 
300f24071e5Spatrick void
301f24071e5Spatrick _rtt(void)
302f24071e5Spatrick {
303f24071e5Spatrick #ifdef EFI_DEBUG
304f24071e5Spatrick 	printf("Hit any key to reboot\n");
305f24071e5Spatrick 	efi_cons_getc(0);
306f24071e5Spatrick #endif
307f24071e5Spatrick 	/*
308f24071e5Spatrick 	 * XXX ResetSystem doesn't seem to work on U-Boot 2016.05 on
309f24071e5Spatrick 	 * the CuBox-i.  So trigger an unimplemented instruction trap
310f24071e5Spatrick 	 * instead.
311f24071e5Spatrick 	 */
312f24071e5Spatrick #if 1
313f24071e5Spatrick 	asm volatile(".word 0xa000f7f0\n");
314f24071e5Spatrick #else
315f24071e5Spatrick 	RS->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL);
316f24071e5Spatrick #endif
317f24071e5Spatrick 	while (1) { }
318f24071e5Spatrick }
319f24071e5Spatrick 
320f24071e5Spatrick /*
321f24071e5Spatrick  * U-Boot only implements the GetTime() Runtime Service if it has been
322f24071e5Spatrick  * configured with CONFIG_DM_RTC.  Most board configurations don't
323f24071e5Spatrick  * include that option, so we can't use it to implement our boot
324f24071e5Spatrick  * prompt timeout.  Instead we use timer events to simulate a clock
325f24071e5Spatrick  * that ticks ever second.
326f24071e5Spatrick  */
327f24071e5Spatrick 
328f24071e5Spatrick EFI_EVENT timer;
329f24071e5Spatrick int ticks;
330f24071e5Spatrick 
331f24071e5Spatrick static VOID
332f24071e5Spatrick efi_timer(EFI_EVENT event, VOID *context)
333f24071e5Spatrick {
334f24071e5Spatrick 	ticks++;
335f24071e5Spatrick }
336f24071e5Spatrick 
337f24071e5Spatrick static void
338f24071e5Spatrick efi_timer_init(void)
339f24071e5Spatrick {
340f24071e5Spatrick 	EFI_STATUS status;
341f24071e5Spatrick 
342f24071e5Spatrick 	status = BS->CreateEvent(EVT_TIMER, TPL_CALLBACK,
343f24071e5Spatrick 	    efi_timer, NULL, &timer);
344f24071e5Spatrick 	if (status == EFI_SUCCESS)
345f24071e5Spatrick 		status = BS->SetTimer(timer, TimerPeriodic, 10000000);
346f24071e5Spatrick 	if (EFI_ERROR(status))
347f24071e5Spatrick 		printf("Can't create timer\n");
348f24071e5Spatrick }
349f24071e5Spatrick 
350f24071e5Spatrick static void
351f24071e5Spatrick efi_timer_cleanup(void)
352f24071e5Spatrick {
353f24071e5Spatrick 	BS->CloseEvent(timer);
354f24071e5Spatrick }
355f24071e5Spatrick 
356f24071e5Spatrick time_t
357f24071e5Spatrick getsecs(void)
358f24071e5Spatrick {
359f24071e5Spatrick 	return ticks;
360f24071e5Spatrick }
361f24071e5Spatrick 
362f24071e5Spatrick /*
363f24071e5Spatrick  * Various device-related bits.
364f24071e5Spatrick  */
365f24071e5Spatrick 
366f24071e5Spatrick void
367f24071e5Spatrick devboot(dev_t dev, char *p)
368f24071e5Spatrick {
369f24071e5Spatrick 	strlcpy(p, "sd0a", 5);
370f24071e5Spatrick }
371f24071e5Spatrick 
372f24071e5Spatrick int
373f24071e5Spatrick cnspeed(dev_t dev, int sp)
374f24071e5Spatrick {
375f24071e5Spatrick 	return 115200;
376f24071e5Spatrick }
377f24071e5Spatrick 
378f24071e5Spatrick char *
379f24071e5Spatrick ttyname(int fd)
380f24071e5Spatrick {
381f24071e5Spatrick 	return "com0";
382f24071e5Spatrick }
383f24071e5Spatrick 
384f24071e5Spatrick dev_t
385f24071e5Spatrick ttydev(char *name)
386f24071e5Spatrick {
387f24071e5Spatrick 	return NODEV;
388f24071e5Spatrick }
389f24071e5Spatrick 
390f24071e5Spatrick #define MAXDEVNAME	16
391f24071e5Spatrick 
392f24071e5Spatrick /*
393f24071e5Spatrick  * Parse a device spec.
394f24071e5Spatrick  *
395f24071e5Spatrick  * [A-Za-z]*[0-9]*[A-Za-z]:file
396f24071e5Spatrick  *    dev   uint    part
397f24071e5Spatrick  */
398f24071e5Spatrick int
399f24071e5Spatrick devparse(const char *fname, int *dev, int *unit, int *part, const char **file)
400f24071e5Spatrick {
401f24071e5Spatrick 	const char *s;
402f24071e5Spatrick 
403f24071e5Spatrick 	*unit = 0;	/* default to wd0a */
404f24071e5Spatrick 	*part = 0;
405f24071e5Spatrick 	*dev  = 0;
406f24071e5Spatrick 
407f24071e5Spatrick 	s = strchr(fname, ':');
408f24071e5Spatrick 	if (s != NULL) {
409f24071e5Spatrick 		int devlen;
410f24071e5Spatrick 		int i, u, p = 0;
411f24071e5Spatrick 		struct devsw *dp;
412f24071e5Spatrick 		char devname[MAXDEVNAME];
413f24071e5Spatrick 
414f24071e5Spatrick 		devlen = s - fname;
415f24071e5Spatrick 		if (devlen > MAXDEVNAME)
416f24071e5Spatrick 			return (EINVAL);
417f24071e5Spatrick 
418f24071e5Spatrick 		/* extract device name */
419f24071e5Spatrick 		for (i = 0; isalpha(fname[i]) && (i < devlen); i++)
420f24071e5Spatrick 			devname[i] = fname[i];
421f24071e5Spatrick 		devname[i] = 0;
422f24071e5Spatrick 
423f24071e5Spatrick 		if (!isdigit(fname[i]))
424f24071e5Spatrick 			return (EUNIT);
425f24071e5Spatrick 
426f24071e5Spatrick 		/* device number */
427f24071e5Spatrick 		for (u = 0; isdigit(fname[i]) && (i < devlen); i++)
428f24071e5Spatrick 			u = u * 10 + (fname[i] - '0');
429f24071e5Spatrick 
430f24071e5Spatrick 		if (!isalpha(fname[i]))
431f24071e5Spatrick 			return (EPART);
432f24071e5Spatrick 
433f24071e5Spatrick 		/* partition number */
434f24071e5Spatrick 		if (i < devlen)
435f24071e5Spatrick 			p = fname[i++] - 'a';
436f24071e5Spatrick 
437f24071e5Spatrick 		if (i != devlen)
438f24071e5Spatrick 			return (ENXIO);
439f24071e5Spatrick 
440f24071e5Spatrick 		/* check device name */
441f24071e5Spatrick 		for (dp = devsw, i = 0; i < ndevs; dp++, i++) {
442f24071e5Spatrick 			if (dp->dv_name && !strcmp(devname, dp->dv_name))
443f24071e5Spatrick 				break;
444f24071e5Spatrick 		}
445f24071e5Spatrick 
446f24071e5Spatrick 		if (i >= ndevs)
447f24071e5Spatrick 			return (ENXIO);
448f24071e5Spatrick 
449f24071e5Spatrick 		*unit = u;
450f24071e5Spatrick 		*part = p;
451f24071e5Spatrick 		*dev  = i;
452f24071e5Spatrick 		fname = ++s;
453f24071e5Spatrick 	}
454f24071e5Spatrick 
455f24071e5Spatrick 	*file = fname;
456f24071e5Spatrick 
457f24071e5Spatrick 	return (0);
458f24071e5Spatrick }
459f24071e5Spatrick 
460f24071e5Spatrick int
461f24071e5Spatrick devopen(struct open_file *f, const char *fname, char **file)
462f24071e5Spatrick {
463f24071e5Spatrick 	struct devsw *dp;
464f24071e5Spatrick 	int dev, unit, part, error;
465f24071e5Spatrick 
466f24071e5Spatrick 	error = devparse(fname, &dev, &unit, &part, (const char **)file);
467f24071e5Spatrick 	if (error)
468f24071e5Spatrick 		return (error);
469f24071e5Spatrick 
470f24071e5Spatrick 	dp = &devsw[0];
471f24071e5Spatrick 	f->f_dev = dp;
472f24071e5Spatrick 
473f24071e5Spatrick 	return (*dp->dv_open)(f, unit, part);
474f24071e5Spatrick }
475f24071e5Spatrick 
476f24071e5Spatrick /*
477f24071e5Spatrick  * 64-bit ARMs can have a much wider memory mapping, as in somewhere
478f24071e5Spatrick  * after the 32-bit region.  To cope with our alignment requirement,
479f24071e5Spatrick  * use the memory table to find a place where we can fit.
480f24071e5Spatrick  */
481f24071e5Spatrick static EFI_STATUS
482f24071e5Spatrick efi_memprobe_find(UINTN pages, UINTN align, EFI_PHYSICAL_ADDRESS *addr)
483f24071e5Spatrick {
484f24071e5Spatrick 	EFI_STATUS		 status;
485f24071e5Spatrick 	UINTN			 mapkey, mmsiz, siz;
486f24071e5Spatrick 	UINT32			 mmver;
487f24071e5Spatrick 	EFI_MEMORY_DESCRIPTOR	*mm0, *mm;
488f24071e5Spatrick 	int			 i, j, n;
489f24071e5Spatrick 
490f24071e5Spatrick 	if (align < EFI_PAGE_SIZE)
491f24071e5Spatrick 		return EFI_INVALID_PARAMETER;
492f24071e5Spatrick 
493f24071e5Spatrick 	siz = 0;
494f24071e5Spatrick 	status = EFI_CALL(BS->GetMemoryMap, &siz, NULL, &mapkey, &mmsiz,
495f24071e5Spatrick 	    &mmver);
496f24071e5Spatrick 	if (status != EFI_BUFFER_TOO_SMALL)
497f24071e5Spatrick 		panic("cannot get the size of memory map");
498f24071e5Spatrick 	mm0 = alloc(siz);
499f24071e5Spatrick 	status = EFI_CALL(BS->GetMemoryMap, &siz, mm0, &mapkey, &mmsiz, &mmver);
500f24071e5Spatrick 	if (status != EFI_SUCCESS)
501f24071e5Spatrick 		panic("cannot get the memory map");
502f24071e5Spatrick 	n = siz / mmsiz;
503f24071e5Spatrick 
504f24071e5Spatrick 	for (i = 0, mm = mm0; i < n; i++, mm = NextMemoryDescriptor(mm, mmsiz)) {
505f24071e5Spatrick 		if (mm->Type != EfiConventionalMemory)
506f24071e5Spatrick 			continue;
507f24071e5Spatrick 
508f24071e5Spatrick 		if (mm->NumberOfPages < pages)
509f24071e5Spatrick 			continue;
510f24071e5Spatrick 
511f2c0e408Skettenis 		for (j = 0; j < mm->NumberOfPages; j++) {
512f24071e5Spatrick 			EFI_PHYSICAL_ADDRESS paddr;
513f24071e5Spatrick 
514f24071e5Spatrick 			if (mm->NumberOfPages - j < pages)
515f24071e5Spatrick 				break;
516f24071e5Spatrick 
517f24071e5Spatrick 			paddr = mm->PhysicalStart + (j * EFI_PAGE_SIZE);
518*73dc1409Spatrick 			if (paddr & (align - 1))
519*73dc1409Spatrick 				continue;
520*73dc1409Spatrick 
521*73dc1409Spatrick 			if (EFI_CALL(BS->AllocatePages, AllocateAddress,
522*73dc1409Spatrick 			    EfiLoaderData, pages, &paddr) == EFI_SUCCESS) {
523f24071e5Spatrick 				*addr = paddr;
524f24071e5Spatrick 				free(mm0, siz);
525f24071e5Spatrick 				return EFI_SUCCESS;
526f24071e5Spatrick 			}
527f24071e5Spatrick 		}
528f24071e5Spatrick 	}
529f24071e5Spatrick 	free(mm0, siz);
530f24071e5Spatrick 	return EFI_OUT_OF_RESOURCES;
531f24071e5Spatrick }
532