xref: /openbsd/sys/arch/arm64/stand/efiboot/efiboot.c (revision 58554311)
1*58554311Spatrick /*	$OpenBSD: efiboot.c,v 1.36 2021/10/26 14:10:02 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>
226f83097eSpatrick #include <sys/stat.h>
23f24071e5Spatrick #include <dev/cons.h>
24f24071e5Spatrick #include <sys/disklabel.h>
25f24071e5Spatrick 
26f24071e5Spatrick #include <efi.h>
27f24071e5Spatrick #include <efiapi.h>
28f24071e5Spatrick #include <efiprot.h>
29f24071e5Spatrick #include <eficonsctl.h>
30f24071e5Spatrick 
315b351376Spatrick #include <dev/biovar.h>
325b351376Spatrick #include <dev/softraidvar.h>
335b351376Spatrick 
34f24071e5Spatrick #include <lib/libkern/libkern.h>
355b351376Spatrick #include <lib/libsa/softraid.h>
36f24071e5Spatrick #include <stand/boot/cmd.h>
37f24071e5Spatrick 
385b351376Spatrick #include "libsa.h"
39f24071e5Spatrick #include "disk.h"
405b351376Spatrick #include "softraid_arm64.h"
415b351376Spatrick 
425b351376Spatrick #include "efidev.h"
4333e5575aSpatrick #include "efiboot.h"
44f24071e5Spatrick #include "fdt.h"
45f24071e5Spatrick 
46f24071e5Spatrick EFI_SYSTEM_TABLE	*ST;
47f24071e5Spatrick EFI_BOOT_SERVICES	*BS;
48f24071e5Spatrick EFI_RUNTIME_SERVICES	*RS;
49f673f4ddSkettenis EFI_HANDLE		 IH, efi_bootdp;
50f24071e5Spatrick 
51fa854029Spatrick EFI_PHYSICAL_ADDRESS	 heap;
52fa854029Spatrick UINTN			 heapsiz = 1 * 1024 * 1024;
53f673f4ddSkettenis EFI_MEMORY_DESCRIPTOR	*mmap;
54fa854029Spatrick UINTN			 mmap_key;
55fa854029Spatrick UINTN			 mmap_ndesc;
56fa854029Spatrick UINTN			 mmap_descsiz;
57f4dd1aebSkettenis UINT32			 mmap_version;
58f24071e5Spatrick 
59f24071e5Spatrick static EFI_GUID		 imgp_guid = LOADED_IMAGE_PROTOCOL;
60f24071e5Spatrick static EFI_GUID		 blkio_guid = BLOCK_IO_PROTOCOL;
61f24071e5Spatrick static EFI_GUID		 devp_guid = DEVICE_PATH_PROTOCOL;
621e44dc38Skettenis static EFI_GUID		 gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
63f24071e5Spatrick 
6433e5575aSpatrick int efi_device_path_depth(EFI_DEVICE_PATH *dp, int);
6533e5575aSpatrick int efi_device_path_ncmp(EFI_DEVICE_PATH *, EFI_DEVICE_PATH *, int);
66fa854029Spatrick static void efi_heap_init(void);
67fa854029Spatrick static void efi_memprobe_internal(void);
68f24071e5Spatrick static void efi_timer_init(void);
69f24071e5Spatrick static void efi_timer_cleanup(void);
70f24071e5Spatrick static EFI_STATUS efi_memprobe_find(UINTN, UINTN, EFI_PHYSICAL_ADDRESS *);
71f24071e5Spatrick 
72f24071e5Spatrick EFI_STATUS
73f24071e5Spatrick efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab)
74f24071e5Spatrick {
75f24071e5Spatrick 	extern char		*progname;
76f24071e5Spatrick 	EFI_LOADED_IMAGE	*imgp;
77f24071e5Spatrick 	EFI_DEVICE_PATH		*dp = NULL;
78f24071e5Spatrick 	EFI_STATUS		 status;
79f24071e5Spatrick 
80f24071e5Spatrick 	ST = systab;
81f24071e5Spatrick 	BS = ST->BootServices;
82496ffee0Spatrick 	RS = ST->RuntimeServices;
83f24071e5Spatrick 	IH = image;
84f24071e5Spatrick 
85f0da534cSjsg 	/* disable reset by watchdog after 5 minutes */
861f462730Skrw 	BS->SetWatchdogTimer(0, 0, 0, NULL);
87f0da534cSjsg 
881f462730Skrw 	status = BS->HandleProtocol(image, &imgp_guid,
89f24071e5Spatrick 	    (void **)&imgp);
90f24071e5Spatrick 	if (status == EFI_SUCCESS)
911f462730Skrw 		status = BS->HandleProtocol(imgp->DeviceHandle, &devp_guid,
921f462730Skrw 		    (void **)&dp);
93f24071e5Spatrick 	if (status == EFI_SUCCESS)
94f24071e5Spatrick 		efi_bootdp = dp;
95f24071e5Spatrick 
96f24071e5Spatrick 	progname = "BOOTAA64";
97f24071e5Spatrick 
98f24071e5Spatrick 	boot(0);
99f24071e5Spatrick 
100f24071e5Spatrick 	return (EFI_SUCCESS);
101f24071e5Spatrick }
102f24071e5Spatrick 
103f24071e5Spatrick static SIMPLE_TEXT_OUTPUT_INTERFACE *conout;
104f24071e5Spatrick static SIMPLE_INPUT_INTERFACE *conin;
105f24071e5Spatrick 
1065cfe0970Skettenis /*
1075cfe0970Skettenis  * The device majors for these don't match the ones used by the
1085cfe0970Skettenis  * kernel.  That's fine.  They're just used as an index into the cdevs
1095cfe0970Skettenis  * array and never passed on to the kernel.
1105cfe0970Skettenis  */
1115cfe0970Skettenis static dev_t serial = makedev(0, 0);
1125cfe0970Skettenis static dev_t framebuffer = makedev(1, 0);
1135cfe0970Skettenis 
1145f7ab753Skettenis static char framebuffer_path[128];
1155f7ab753Skettenis 
116f24071e5Spatrick void
117f24071e5Spatrick efi_cons_probe(struct consdev *cn)
118f24071e5Spatrick {
119f24071e5Spatrick 	cn->cn_pri = CN_MIDPRI;
1205cfe0970Skettenis 	cn->cn_dev = serial;
121f24071e5Spatrick }
122f24071e5Spatrick 
123f24071e5Spatrick void
124f24071e5Spatrick efi_cons_init(struct consdev *cp)
125f24071e5Spatrick {
126f24071e5Spatrick 	conin = ST->ConIn;
127f24071e5Spatrick 	conout = ST->ConOut;
128f24071e5Spatrick }
129f24071e5Spatrick 
130f24071e5Spatrick int
131f24071e5Spatrick efi_cons_getc(dev_t dev)
132f24071e5Spatrick {
133f24071e5Spatrick 	EFI_INPUT_KEY	 key;
134f24071e5Spatrick 	EFI_STATUS	 status;
135f24071e5Spatrick #if 0
136f24071e5Spatrick 	UINTN		 dummy;
137f24071e5Spatrick #endif
138f24071e5Spatrick 	static int	 lastchar = 0;
139f24071e5Spatrick 
140f24071e5Spatrick 	if (lastchar) {
141f24071e5Spatrick 		int r = lastchar;
142f24071e5Spatrick 		if ((dev & 0x80) == 0)
143f24071e5Spatrick 			lastchar = 0;
144f24071e5Spatrick 		return (r);
145f24071e5Spatrick 	}
146f24071e5Spatrick 
147f24071e5Spatrick 	status = conin->ReadKeyStroke(conin, &key);
148678d37b9Syasuoka 	while (status == EFI_NOT_READY || key.UnicodeChar == 0) {
149f24071e5Spatrick 		if (dev & 0x80)
150f24071e5Spatrick 			return (0);
151f24071e5Spatrick 		/*
152f24071e5Spatrick 		 * XXX The implementation of WaitForEvent() in U-boot
153f24071e5Spatrick 		 * is broken and neverreturns.
154f24071e5Spatrick 		 */
155f24071e5Spatrick #if 0
156f24071e5Spatrick 		BS->WaitForEvent(1, &conin->WaitForKey, &dummy);
157f24071e5Spatrick #endif
158f24071e5Spatrick 		status = conin->ReadKeyStroke(conin, &key);
159f24071e5Spatrick 	}
160f24071e5Spatrick 
161f24071e5Spatrick 	if (dev & 0x80)
162f24071e5Spatrick 		lastchar = key.UnicodeChar;
163f24071e5Spatrick 
164f24071e5Spatrick 	return (key.UnicodeChar);
165f24071e5Spatrick }
166f24071e5Spatrick 
167f24071e5Spatrick void
168f24071e5Spatrick efi_cons_putc(dev_t dev, int c)
169f24071e5Spatrick {
170f24071e5Spatrick 	CHAR16	buf[2];
171f24071e5Spatrick 
172f24071e5Spatrick 	if (c == '\n')
173f24071e5Spatrick 		efi_cons_putc(dev, '\r');
174f24071e5Spatrick 
175f24071e5Spatrick 	buf[0] = c;
176f24071e5Spatrick 	buf[1] = 0;
177f24071e5Spatrick 
178f24071e5Spatrick 	conout->OutputString(conout, buf);
179f24071e5Spatrick }
180f24071e5Spatrick 
1815cfe0970Skettenis void
1825cfe0970Skettenis efi_fb_probe(struct consdev *cn)
1835cfe0970Skettenis {
1845cfe0970Skettenis 	cn->cn_pri = CN_LOWPRI;
1855cfe0970Skettenis 	cn->cn_dev = framebuffer;
1865cfe0970Skettenis }
1875cfe0970Skettenis 
1885cfe0970Skettenis void
1895cfe0970Skettenis efi_fb_init(struct consdev *cn)
1905cfe0970Skettenis {
1915cfe0970Skettenis 	conin = ST->ConIn;
1925cfe0970Skettenis 	conout = ST->ConOut;
1935cfe0970Skettenis }
1945cfe0970Skettenis 
1955cfe0970Skettenis int
1965cfe0970Skettenis efi_fb_getc(dev_t dev)
1975cfe0970Skettenis {
1985cfe0970Skettenis 	return efi_cons_getc(dev);
1995cfe0970Skettenis }
2005cfe0970Skettenis 
2015cfe0970Skettenis void
2025cfe0970Skettenis efi_fb_putc(dev_t dev, int c)
2035cfe0970Skettenis {
2045cfe0970Skettenis 	efi_cons_putc(dev, c);
2055cfe0970Skettenis }
2065cfe0970Skettenis 
207f24071e5Spatrick static void
208f24071e5Spatrick efi_heap_init(void)
209f24071e5Spatrick {
210f24071e5Spatrick 	EFI_STATUS	 status;
211f24071e5Spatrick 
2121f462730Skrw 	status = BS->AllocatePages(AllocateAnyPages, EfiLoaderData,
213f24071e5Spatrick 	    EFI_SIZE_TO_PAGES(heapsiz), &heap);
214f24071e5Spatrick 	if (status != EFI_SUCCESS)
215f24071e5Spatrick 		panic("BS->AllocatePages()");
216f24071e5Spatrick }
217f24071e5Spatrick 
2185b351376Spatrick struct disklist_lh disklist;
2195b351376Spatrick struct diskinfo *bootdev_dip;
220f24071e5Spatrick 
221f24071e5Spatrick void
222f24071e5Spatrick efi_diskprobe(void)
223f24071e5Spatrick {
2245b351376Spatrick 	int			 i, bootdev = 0, depth = -1;
225f24071e5Spatrick 	UINTN			 sz;
226f24071e5Spatrick 	EFI_STATUS		 status;
227f24071e5Spatrick 	EFI_HANDLE		*handles = NULL;
228f24071e5Spatrick 	EFI_BLOCK_IO		*blkio;
229f24071e5Spatrick 	EFI_BLOCK_IO_MEDIA	*media;
2305b351376Spatrick 	struct diskinfo		*di;
231c6d7d0adSpatrick 	EFI_DEVICE_PATH		*dp;
232f24071e5Spatrick 
2335b351376Spatrick 	TAILQ_INIT(&disklist);
2345b351376Spatrick 
235f24071e5Spatrick 	sz = 0;
2361f462730Skrw 	status = BS->LocateHandle(ByProtocol, &blkio_guid, 0, &sz, 0);
237f24071e5Spatrick 	if (status == EFI_BUFFER_TOO_SMALL) {
238f24071e5Spatrick 		handles = alloc(sz);
2391f462730Skrw 		status = BS->LocateHandle(ByProtocol, &blkio_guid, 0, &sz,
2401f462730Skrw 		    handles);
241f24071e5Spatrick 	}
242f24071e5Spatrick 	if (handles == NULL || EFI_ERROR(status))
24333e5575aSpatrick 		return;
244f24071e5Spatrick 
245c6d7d0adSpatrick 	if (efi_bootdp != NULL)
246c6d7d0adSpatrick 		depth = efi_device_path_depth(efi_bootdp, MEDIA_DEVICE_PATH);
247c6d7d0adSpatrick 
248c94e7257Skettenis 	/*
249c94e7257Skettenis 	 * U-Boot incorrectly represents devices with a single
250c94e7257Skettenis 	 * MEDIA_DEVICE_PATH component.  In that case include that
251c94e7257Skettenis 	 * component into the matching, otherwise we'll blindly select
252c94e7257Skettenis 	 * the first device.
253c94e7257Skettenis 	 */
254c94e7257Skettenis 	if (depth == 0)
255c94e7257Skettenis 		depth = 1;
256c94e7257Skettenis 
257f24071e5Spatrick 	for (i = 0; i < sz / sizeof(EFI_HANDLE); i++) {
2581f462730Skrw 		status = BS->HandleProtocol(handles[i], &blkio_guid,
259f24071e5Spatrick 		    (void **)&blkio);
260f24071e5Spatrick 		if (EFI_ERROR(status))
261f24071e5Spatrick 			panic("BS->HandleProtocol() returns %d", status);
262f24071e5Spatrick 
263f24071e5Spatrick 		media = blkio->Media;
264f24071e5Spatrick 		if (media->LogicalPartition || !media->MediaPresent)
265f24071e5Spatrick 			continue;
2665b351376Spatrick 		di = alloc(sizeof(struct diskinfo));
2675b351376Spatrick 		efid_init(di, blkio);
268f24071e5Spatrick 
2695b351376Spatrick 		if (efi_bootdp == NULL || depth == -1 || bootdev != 0)
2705b351376Spatrick 			goto next;
2711f462730Skrw 		status = BS->HandleProtocol(handles[i], &devp_guid,
272f24071e5Spatrick 		    (void **)&dp);
273f24071e5Spatrick 		if (EFI_ERROR(status))
2745b351376Spatrick 			goto next;
275c6d7d0adSpatrick 		if (efi_device_path_ncmp(efi_bootdp, dp, depth) == 0) {
2765b351376Spatrick 			TAILQ_INSERT_HEAD(&disklist, di, list);
2775b351376Spatrick 			bootdev_dip = di;
2785b351376Spatrick 			bootdev = 1;
2795b351376Spatrick 			continue;
280f24071e5Spatrick 		}
2815b351376Spatrick next:
2825b351376Spatrick 		TAILQ_INSERT_TAIL(&disklist, di, list);
283f24071e5Spatrick 	}
284f24071e5Spatrick 
285f24071e5Spatrick 	free(handles, sz);
2865b351376Spatrick 
2875b351376Spatrick 	/* Print available disks and probe for softraid. */
2885b351376Spatrick 	i = 0;
2895b351376Spatrick 	printf("disks:");
2905b351376Spatrick 	TAILQ_FOREACH(di, &disklist, list) {
2915b351376Spatrick 		printf(" sd%d%s", i, di == bootdev_dip ? "*" : "");
2925b351376Spatrick 		i++;
2935b351376Spatrick 	}
2945b351376Spatrick 	srprobe();
2955b351376Spatrick 	printf("\n");
296f24071e5Spatrick }
297f24071e5Spatrick 
298c94e7257Skettenis /*
299c94e7257Skettenis  * Determine the number of nodes up to, but not including, the first
300c94e7257Skettenis  * node of the specified type.
301c94e7257Skettenis  */
30233e5575aSpatrick int
303c6d7d0adSpatrick efi_device_path_depth(EFI_DEVICE_PATH *dp, int dptype)
304c6d7d0adSpatrick {
305c6d7d0adSpatrick 	int	i;
306c6d7d0adSpatrick 
307c6d7d0adSpatrick 	for (i = 0; !IsDevicePathEnd(dp); dp = NextDevicePathNode(dp), i++) {
308c6d7d0adSpatrick 		if (DevicePathType(dp) == dptype)
309c94e7257Skettenis 			return (i);
310c6d7d0adSpatrick 	}
311c6d7d0adSpatrick 
312d64e7de5Skettenis 	return (i);
313c6d7d0adSpatrick }
314c6d7d0adSpatrick 
31533e5575aSpatrick int
316c6d7d0adSpatrick efi_device_path_ncmp(EFI_DEVICE_PATH *dpa, EFI_DEVICE_PATH *dpb, int deptn)
317c6d7d0adSpatrick {
318c6d7d0adSpatrick 	int	 i, cmp;
319c6d7d0adSpatrick 
320c6d7d0adSpatrick 	for (i = 0; i < deptn; i++) {
321c6d7d0adSpatrick 		if (IsDevicePathEnd(dpa) || IsDevicePathEnd(dpb))
322c6d7d0adSpatrick 			return ((IsDevicePathEnd(dpa) && IsDevicePathEnd(dpb))
323c6d7d0adSpatrick 			    ? 0 : (IsDevicePathEnd(dpa))? -1 : 1);
324c6d7d0adSpatrick 		cmp = DevicePathNodeLength(dpa) - DevicePathNodeLength(dpb);
325c6d7d0adSpatrick 		if (cmp)
326c6d7d0adSpatrick 			return (cmp);
327c6d7d0adSpatrick 		cmp = memcmp(dpa, dpb, DevicePathNodeLength(dpa));
328c6d7d0adSpatrick 		if (cmp)
329c6d7d0adSpatrick 			return (cmp);
330c6d7d0adSpatrick 		dpa = NextDevicePathNode(dpa);
331c6d7d0adSpatrick 		dpb = NextDevicePathNode(dpb);
332c6d7d0adSpatrick 	}
333c6d7d0adSpatrick 
334c6d7d0adSpatrick 	return (0);
335c6d7d0adSpatrick }
336c6d7d0adSpatrick 
3371e44dc38Skettenis void
3381e44dc38Skettenis efi_framebuffer(void)
3391e44dc38Skettenis {
3401e44dc38Skettenis 	EFI_GRAPHICS_OUTPUT *gop;
3411e44dc38Skettenis 	EFI_STATUS status;
3421e44dc38Skettenis 	void *node, *child;
3431e44dc38Skettenis 	uint32_t acells, scells;
3441e44dc38Skettenis 	uint64_t base, size;
3451e44dc38Skettenis 	uint32_t reg[4];
3461e44dc38Skettenis 	uint32_t width, height, stride;
3471e44dc38Skettenis 	char *format;
3485cfe0970Skettenis 	char *prop;
3491e44dc38Skettenis 
3501e44dc38Skettenis 	/*
3511e44dc38Skettenis 	 * Don't create a "simple-framebuffer" node if we already have
3521e44dc38Skettenis 	 * one.  Besides "/chosen", we also check under "/" since that
3531e44dc38Skettenis 	 * is where the Raspberry Pi firmware puts it.
3541e44dc38Skettenis 	 */
3551e44dc38Skettenis 	node = fdt_find_node("/chosen");
3561e44dc38Skettenis 	for (child = fdt_child_node(node); child;
3571e44dc38Skettenis 	     child = fdt_next_node(child)) {
3585cfe0970Skettenis 		if (!fdt_node_is_compatible(child, "simple-framebuffer"))
3595cfe0970Skettenis 			continue;
3605028e024Skettenis 		if (!fdt_node_property(child, "status", &prop) ||
3615f7ab753Skettenis 		    strcmp(prop, "okay") == 0) {
3625f7ab753Skettenis 			strlcpy(framebuffer_path, "/chosen/",
3635f7ab753Skettenis 			    sizeof(framebuffer_path));
3645f7ab753Skettenis 			strlcat(framebuffer_path, fdt_node_name(child),
3655f7ab753Skettenis 			    sizeof(framebuffer_path));
3661e44dc38Skettenis 			return;
3671e44dc38Skettenis 		}
3685f7ab753Skettenis 	}
3691e44dc38Skettenis 	node = fdt_find_node("/");
3701e44dc38Skettenis 	for (child = fdt_child_node(node); child;
3711e44dc38Skettenis 	     child = fdt_next_node(child)) {
3725cfe0970Skettenis 		if (!fdt_node_is_compatible(child, "simple-framebuffer"))
3735cfe0970Skettenis 			continue;
3745028e024Skettenis 		if (!fdt_node_property(child, "status", &prop) ||
3755f7ab753Skettenis 		    strcmp(prop, "okay") == 0) {
3765f7ab753Skettenis 			strlcpy(framebuffer_path, "/",
3775f7ab753Skettenis 			    sizeof(framebuffer_path));
3785f7ab753Skettenis 			strlcat(framebuffer_path, fdt_node_name(child),
3795f7ab753Skettenis 			    sizeof(framebuffer_path));
3801e44dc38Skettenis 			return;
3811e44dc38Skettenis 		}
3825f7ab753Skettenis 	}
3831e44dc38Skettenis 
3841f462730Skrw 	status = BS->LocateProtocol(&gop_guid, NULL, (void **)&gop);
3851e44dc38Skettenis 	if (status != EFI_SUCCESS)
3861e44dc38Skettenis 		return;
3871e44dc38Skettenis 
3881e44dc38Skettenis 	/* Paranoia! */
3891e44dc38Skettenis 	if (gop == NULL || gop->Mode == NULL || gop->Mode->Info == NULL)
3901e44dc38Skettenis 		return;
3911e44dc38Skettenis 
3921e44dc38Skettenis 	/* We only support 32-bit pixel modes for now. */
3931e44dc38Skettenis 	switch (gop->Mode->Info->PixelFormat) {
3941e44dc38Skettenis 	case PixelRedGreenBlueReserved8BitPerColor:
395b870cd26Skettenis 		format = "x8b8g8r8";
3961e44dc38Skettenis 		break;
3971e44dc38Skettenis 	case PixelBlueGreenRedReserved8BitPerColor:
398b870cd26Skettenis 		format = "x8r8g8b8";
3991e44dc38Skettenis 		break;
4001e44dc38Skettenis 	default:
4011e44dc38Skettenis 		return;
4021e44dc38Skettenis 	}
4031e44dc38Skettenis 
4041e44dc38Skettenis 	base = gop->Mode->FrameBufferBase;
4051e44dc38Skettenis 	size = gop->Mode->FrameBufferSize;
4061e44dc38Skettenis 	width = htobe32(gop->Mode->Info->HorizontalResolution);
4071e44dc38Skettenis 	height = htobe32(gop->Mode->Info->VerticalResolution);
4081e44dc38Skettenis 	stride = htobe32(gop->Mode->Info->PixelsPerScanLine * 4);
4091e44dc38Skettenis 
4101e44dc38Skettenis 	node = fdt_find_node("/");
4111e44dc38Skettenis 	if (fdt_node_property_int(node, "#address-cells", &acells) != 1)
4121e44dc38Skettenis 		acells = 1;
4131e44dc38Skettenis 	if (fdt_node_property_int(node, "#size-cells", &scells) != 1)
4141e44dc38Skettenis 		scells = 1;
4151e44dc38Skettenis 	if (acells > 2 || scells > 2)
4161e44dc38Skettenis 		return;
4171e44dc38Skettenis 	if (acells >= 1)
4181e44dc38Skettenis 		reg[0] = htobe32(base);
4191e44dc38Skettenis 	if (acells == 2) {
4201e44dc38Skettenis 		reg[1] = reg[0];
4211e44dc38Skettenis 		reg[0] = htobe32(base >> 32);
4221e44dc38Skettenis 	}
4231e44dc38Skettenis 	if (scells >= 1)
4241e44dc38Skettenis 		reg[acells] = htobe32(size);
4251e44dc38Skettenis 	if (scells == 2) {
4261e44dc38Skettenis 		reg[acells + 1] = reg[acells];
4271e44dc38Skettenis 		reg[acells] = htobe32(size >> 32);
4281e44dc38Skettenis 	}
4291e44dc38Skettenis 
4301e44dc38Skettenis 	node = fdt_find_node("/chosen");
4311e44dc38Skettenis 	fdt_node_add_node(node, "framebuffer", &child);
4321e44dc38Skettenis 	fdt_node_add_property(child, "status", "okay", strlen("okay") + 1);
4331e44dc38Skettenis 	fdt_node_add_property(child, "format", format, strlen(format) + 1);
4341e44dc38Skettenis 	fdt_node_add_property(child, "stride", &stride, 4);
4351e44dc38Skettenis 	fdt_node_add_property(child, "height", &height, 4);
4361e44dc38Skettenis 	fdt_node_add_property(child, "width", &width, 4);
4371e44dc38Skettenis 	fdt_node_add_property(child, "reg", reg, (acells + scells) * 4);
4381e44dc38Skettenis 	fdt_node_add_property(child, "compatible",
4391e44dc38Skettenis 	    "simple-framebuffer", strlen("simple-framebuffer") + 1);
4405f7ab753Skettenis 
4415f7ab753Skettenis 	strlcpy(framebuffer_path, "/chosen/framebuffer",
4425f7ab753Skettenis 	    sizeof(framebuffer_path));
4431e44dc38Skettenis }
4441e44dc38Skettenis 
4455cfe0970Skettenis void
4465cfe0970Skettenis efi_console(void)
4475cfe0970Skettenis {
4485f7ab753Skettenis 	void *node;
4495cfe0970Skettenis 
4505cfe0970Skettenis 	if (cn_tab->cn_dev != framebuffer)
4515cfe0970Skettenis 		return;
4525cfe0970Skettenis 
4535f7ab753Skettenis 	if (strlen(framebuffer_path) == 0)
4545cfe0970Skettenis 		return;
4555cfe0970Skettenis 
4565cfe0970Skettenis 	/* Point stdout-path at the framebuffer node. */
4575f7ab753Skettenis 	node = fdt_find_node("/chosen");
4585f7ab753Skettenis 	fdt_node_add_property(node, "stdout-path",
4595f7ab753Skettenis 	    framebuffer_path, strlen(framebuffer_path) + 1);
4605cfe0970Skettenis }
4615cfe0970Skettenis 
462a88d1494Skettenis uint64_t dma_constraint[2] = { 0, -1 };
463a88d1494Skettenis 
464a88d1494Skettenis void
465a88d1494Skettenis efi_dma_constraint(void)
466a88d1494Skettenis {
467a88d1494Skettenis 	void *node;
468cfb73cfeSpatrick 	char *prop;
469cfb73cfeSpatrick 	uint32_t *propint;
470cfb73cfeSpatrick 	uint64_t base, size;
471cfb73cfeSpatrick 	uint32_t pacells, pscells;
472cfb73cfeSpatrick 	uint32_t acells, scells;
473cfb73cfeSpatrick 	int len;
474cfb73cfeSpatrick 
475cfb73cfeSpatrick 	node = fdt_find_node("/");
476cfb73cfeSpatrick 	if (fdt_node_property_int(node, "#address-cells", &pacells) != 1)
477cfb73cfeSpatrick 		pacells = 1;
478cfb73cfeSpatrick 	if (fdt_node_property_int(node, "#size-cells", &pscells) != 1)
479cfb73cfeSpatrick 		pscells = 1;
480cfb73cfeSpatrick 	if (pacells > 2 || pscells > 2)
481cfb73cfeSpatrick 		return;
482cfb73cfeSpatrick 
483cfb73cfeSpatrick 	node = fdt_find_node("/soc");
484cfb73cfeSpatrick 	if (node != NULL) {
485cfb73cfeSpatrick 		if (fdt_node_property_int(node, "#address-cells", &acells) != 1)
486cfb73cfeSpatrick 			acells = pacells;
487cfb73cfeSpatrick 		if (fdt_node_property_int(node, "#size-cells", &scells) != 1)
488cfb73cfeSpatrick 			scells = pscells;
489cfb73cfeSpatrick 		if (acells > 2 || scells > 2)
490cfb73cfeSpatrick 			return;
491cfb73cfeSpatrick 
492cfb73cfeSpatrick 		len = fdt_node_property(node, "dma-ranges", &prop);
493cfb73cfeSpatrick 		propint = (uint32_t *)prop;
494cfb73cfeSpatrick 		if (len == (acells + pacells + scells) * sizeof(uint32_t)) {
495cfb73cfeSpatrick 			base = betoh32(propint[acells]);
496cfb73cfeSpatrick 			if (pacells == 2)
497cfb73cfeSpatrick 				base = (base << 32) |
498cfb73cfeSpatrick 				    betoh32(propint[acells + 1]);
499cfb73cfeSpatrick 			size = betoh32(propint[acells + pacells]);
500cfb73cfeSpatrick 			if (scells == 2)
501cfb73cfeSpatrick 				size = (size << 32) |
502cfb73cfeSpatrick 				    betoh32(propint[acells + pacells + 1]);
503cfb73cfeSpatrick 
504cfb73cfeSpatrick 			dma_constraint[0] = htobe64(base);
505cfb73cfeSpatrick 			dma_constraint[1] = htobe64(base + size - 1);
506cfb73cfeSpatrick 		}
507cfb73cfeSpatrick 	}
508a88d1494Skettenis 
509a88d1494Skettenis 	/* Raspberry Pi 4 is "special". */
510a88d1494Skettenis 	node = fdt_find_node("/");
511a88d1494Skettenis 	if (fdt_node_is_compatible(node, "brcm,bcm2711"))
512a88d1494Skettenis 		dma_constraint[1] = htobe64(0x3bffffff);
513a88d1494Skettenis 
514a88d1494Skettenis 	/* Pass DMA constraint. */
515a88d1494Skettenis 	node = fdt_find_node("/chosen");
516a88d1494Skettenis 	fdt_node_add_property(node, "openbsd,dma-constraint",
517a88d1494Skettenis 	    dma_constraint, sizeof(dma_constraint));
518a88d1494Skettenis }
519a88d1494Skettenis 
520be07ee62Skettenis int acpi = 0;
5216f83097eSpatrick void *fdt = NULL;
5229ccb13abSnaddy char *bootmac = NULL;
523f24071e5Spatrick static EFI_GUID fdt_guid = FDT_TABLE_GUID;
524f24071e5Spatrick 
525f24071e5Spatrick #define	efi_guidcmp(_a, _b)	memcmp((_a), (_b), sizeof(EFI_GUID))
526f24071e5Spatrick 
527f24071e5Spatrick void *
5289419d8aaSkettenis efi_makebootargs(char *bootargs, int howto)
529f24071e5Spatrick {
5305b351376Spatrick 	struct sr_boot_volume *bv;
531f4dd1aebSkettenis 	u_char bootduid[8];
532f4dd1aebSkettenis 	u_char zero[8] = { 0 };
533f4dd1aebSkettenis 	uint64_t uefi_system_table = htobe64((uintptr_t)ST);
5349419d8aaSkettenis 	uint32_t boothowto = htobe32(howto);
535*58554311Spatrick 	EFI_PHYSICAL_ADDRESS addr;
536f24071e5Spatrick 	void *node;
537f24071e5Spatrick 	size_t len;
538f24071e5Spatrick 	int i;
539f24071e5Spatrick 
5406f83097eSpatrick 	if (fdt == NULL) {
541f24071e5Spatrick 		for (i = 0; i < ST->NumberOfTableEntries; i++) {
542f24071e5Spatrick 			if (efi_guidcmp(&fdt_guid,
543f24071e5Spatrick 			    &ST->ConfigurationTable[i].VendorGuid) == 0)
544f24071e5Spatrick 				fdt = ST->ConfigurationTable[i].VendorTable;
545f24071e5Spatrick 		}
5466f83097eSpatrick 	}
547f24071e5Spatrick 
548be07ee62Skettenis 	if (fdt == NULL || acpi)
5499a1480b1Skettenis 		fdt = efi_acpi();
5509a1480b1Skettenis 
551*58554311Spatrick 	if (!fdt_get_size(fdt))
552*58554311Spatrick 		return NULL;
553*58554311Spatrick 
554*58554311Spatrick 	len = roundup(fdt_get_size(fdt) + PAGE_SIZE, PAGE_SIZE);
555*58554311Spatrick 	if (BS->AllocatePages(AllocateAnyPages, EfiLoaderData,
556*58554311Spatrick 	    EFI_SIZE_TO_PAGES(len), &addr) == EFI_SUCCESS) {
557*58554311Spatrick 		memcpy((void *)addr, fdt, fdt_get_size(fdt));
558*58554311Spatrick 		fdt = (void *)addr;
559*58554311Spatrick 	}
560*58554311Spatrick 
561f24071e5Spatrick 	if (!fdt_init(fdt))
562f24071e5Spatrick 		return NULL;
563f24071e5Spatrick 
564f24071e5Spatrick 	node = fdt_find_node("/chosen");
565f24071e5Spatrick 	if (!node)
566f24071e5Spatrick 		return NULL;
567f24071e5Spatrick 
568f24071e5Spatrick 	len = strlen(bootargs) + 1;
569f24071e5Spatrick 	fdt_node_add_property(node, "bootargs", bootargs, len);
5709419d8aaSkettenis 	fdt_node_add_property(node, "openbsd,boothowto",
5719419d8aaSkettenis 	    &boothowto, sizeof(boothowto));
572f24071e5Spatrick 
573f24071e5Spatrick 	/* Pass DUID of the boot disk. */
5745b351376Spatrick 	if (bootdev_dip) {
5755b351376Spatrick 		memcpy(&bootduid, bootdev_dip->disklabel.d_uid,
576f24071e5Spatrick 		    sizeof(bootduid));
5775b351376Spatrick 		if (memcmp(bootduid, zero, sizeof(bootduid)) != 0) {
5785b351376Spatrick 			fdt_node_add_property(node, "openbsd,bootduid",
5795b351376Spatrick 			    bootduid, sizeof(bootduid));
580f24071e5Spatrick 		}
581f24071e5Spatrick 
5825b351376Spatrick 		if (bootdev_dip->sr_vol != NULL) {
5835b351376Spatrick 			bv = bootdev_dip->sr_vol;
5845b351376Spatrick 			fdt_node_add_property(node, "openbsd,sr-bootuuid",
5855b351376Spatrick 			    &bv->sbv_uuid, sizeof(bv->sbv_uuid));
5865b351376Spatrick 			if (bv->sbv_maskkey != NULL)
5875b351376Spatrick 				fdt_node_add_property(node,
5885b351376Spatrick 				    "openbsd,sr-bootkey", bv->sbv_maskkey,
5895b351376Spatrick 				    SR_CRYPTO_MAXKEYBYTES);
5905b351376Spatrick 		}
5915b351376Spatrick 	}
5925b351376Spatrick 
5935b351376Spatrick 	sr_clear_keys();
5945b351376Spatrick 
5959ccb13abSnaddy 	/* Pass netboot interface address. */
5969ccb13abSnaddy 	if (bootmac)
5979ccb13abSnaddy 		fdt_node_add_property(node, "openbsd,bootmac", bootmac, 6);
5989ccb13abSnaddy 
599f4dd1aebSkettenis 	/* Pass EFI system table. */
600f4dd1aebSkettenis 	fdt_node_add_property(node, "openbsd,uefi-system-table",
601f4dd1aebSkettenis 	    &uefi_system_table, sizeof(uefi_system_table));
602f4dd1aebSkettenis 
603f4dd1aebSkettenis 	/* Placeholders for EFI memory map. */
604f4dd1aebSkettenis 	fdt_node_add_property(node, "openbsd,uefi-mmap-start", zero, 8);
605f4dd1aebSkettenis 	fdt_node_add_property(node, "openbsd,uefi-mmap-size", zero, 4);
606f4dd1aebSkettenis 	fdt_node_add_property(node, "openbsd,uefi-mmap-desc-size", zero, 4);
607f4dd1aebSkettenis 	fdt_node_add_property(node, "openbsd,uefi-mmap-desc-ver", zero, 4);
608f4dd1aebSkettenis 
6091e44dc38Skettenis 	efi_framebuffer();
6105cfe0970Skettenis 	efi_console();
611a88d1494Skettenis 	efi_dma_constraint();
6121e44dc38Skettenis 
613f24071e5Spatrick 	fdt_finalize();
614f24071e5Spatrick 
615f24071e5Spatrick 	return fdt;
616f24071e5Spatrick }
617f24071e5Spatrick 
618f4dd1aebSkettenis void
619f4dd1aebSkettenis efi_updatefdt(void)
620f4dd1aebSkettenis {
621f4dd1aebSkettenis 	uint64_t uefi_mmap_start = htobe64((uintptr_t)mmap);
622f4dd1aebSkettenis 	uint32_t uefi_mmap_size = htobe32(mmap_ndesc * mmap_descsiz);
623f4dd1aebSkettenis 	uint32_t uefi_mmap_desc_size = htobe32(mmap_descsiz);
624f4dd1aebSkettenis 	uint32_t uefi_mmap_desc_ver = htobe32(mmap_version);
625f4dd1aebSkettenis 	void *node;
626f4dd1aebSkettenis 
627f4dd1aebSkettenis 	node = fdt_find_node("/chosen");
628f4dd1aebSkettenis 	if (!node)
629f4dd1aebSkettenis 		return;
630f4dd1aebSkettenis 
631f4dd1aebSkettenis 	/* Pass EFI memory map. */
632f4dd1aebSkettenis 	fdt_node_set_property(node, "openbsd,uefi-mmap-start",
633f4dd1aebSkettenis 	    &uefi_mmap_start, sizeof(uefi_mmap_start));
634f4dd1aebSkettenis 	fdt_node_set_property(node, "openbsd,uefi-mmap-size",
635f4dd1aebSkettenis 	    &uefi_mmap_size, sizeof(uefi_mmap_size));
636f4dd1aebSkettenis 	fdt_node_set_property(node, "openbsd,uefi-mmap-desc-size",
637f4dd1aebSkettenis 	    &uefi_mmap_desc_size, sizeof(uefi_mmap_desc_size));
638f4dd1aebSkettenis 	fdt_node_set_property(node, "openbsd,uefi-mmap-desc-ver",
639f4dd1aebSkettenis 	    &uefi_mmap_desc_ver, sizeof(uefi_mmap_desc_ver));
640f4dd1aebSkettenis 
641f4dd1aebSkettenis 	fdt_finalize();
642f4dd1aebSkettenis }
643f4dd1aebSkettenis 
644f24071e5Spatrick u_long efi_loadaddr;
645f24071e5Spatrick 
646f24071e5Spatrick void
647f24071e5Spatrick machdep(void)
648f24071e5Spatrick {
649f24071e5Spatrick 	EFI_PHYSICAL_ADDRESS addr;
650f24071e5Spatrick 
651f24071e5Spatrick 	cninit();
652f24071e5Spatrick 	efi_heap_init();
653f24071e5Spatrick 
654f24071e5Spatrick 	/*
6559a118d7eSpatrick 	 * The kernel expects to be loaded into a block of memory aligned
6569a118d7eSpatrick 	 * on a 2MB boundary.  We allocate a block of 64MB of memory, which
6579a118d7eSpatrick 	 * gives us plenty of room for growth.
658f24071e5Spatrick 	 */
6599a118d7eSpatrick 	if (efi_memprobe_find(EFI_SIZE_TO_PAGES(64 * 1024 * 1024),
6609a118d7eSpatrick 	    0x200000, &addr) != EFI_SUCCESS)
661f24071e5Spatrick 		printf("Can't allocate memory\n");
662f24071e5Spatrick 	efi_loadaddr = addr;
663f24071e5Spatrick 
664f24071e5Spatrick 	efi_timer_init();
665f24071e5Spatrick 	efi_diskprobe();
66633e5575aSpatrick 	efi_pxeprobe();
667f24071e5Spatrick }
668f24071e5Spatrick 
669f24071e5Spatrick void
670f24071e5Spatrick efi_cleanup(void)
671f24071e5Spatrick {
672fa854029Spatrick 	int		 retry;
673fa854029Spatrick 	EFI_STATUS	 status;
674fa854029Spatrick 
675f24071e5Spatrick 	efi_timer_cleanup();
676f24071e5Spatrick 
677fa854029Spatrick 	/* retry once in case of failure */
678fa854029Spatrick 	for (retry = 1; retry >= 0; retry--) {
679fa854029Spatrick 		efi_memprobe_internal();	/* sync the current map */
680f4dd1aebSkettenis 		efi_updatefdt();
6811f462730Skrw 		status = BS->ExitBootServices(IH, mmap_key);
682fa854029Spatrick 		if (status == EFI_SUCCESS)
683fa854029Spatrick 			break;
684fa854029Spatrick 		if (retry == 0)
685fa854029Spatrick 			panic("ExitBootServices failed (%d)", status);
686fa854029Spatrick 	}
687f24071e5Spatrick }
688f24071e5Spatrick 
689f24071e5Spatrick void
690f24071e5Spatrick _rtt(void)
691f24071e5Spatrick {
692f24071e5Spatrick #ifdef EFI_DEBUG
693f24071e5Spatrick 	printf("Hit any key to reboot\n");
694f24071e5Spatrick 	efi_cons_getc(0);
695f24071e5Spatrick #endif
696f24071e5Spatrick 	RS->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL);
697111d6387Skettenis 	for (;;)
698111d6387Skettenis 		continue;
699f24071e5Spatrick }
700f24071e5Spatrick 
701f24071e5Spatrick /*
702f24071e5Spatrick  * U-Boot only implements the GetTime() Runtime Service if it has been
703f24071e5Spatrick  * configured with CONFIG_DM_RTC.  Most board configurations don't
704f24071e5Spatrick  * include that option, so we can't use it to implement our boot
705f24071e5Spatrick  * prompt timeout.  Instead we use timer events to simulate a clock
706f24071e5Spatrick  * that ticks ever second.
707f24071e5Spatrick  */
708f24071e5Spatrick 
709f24071e5Spatrick EFI_EVENT timer;
710f24071e5Spatrick int ticks;
711f24071e5Spatrick 
712f24071e5Spatrick static VOID
713f24071e5Spatrick efi_timer(EFI_EVENT event, VOID *context)
714f24071e5Spatrick {
715f24071e5Spatrick 	ticks++;
716f24071e5Spatrick }
717f24071e5Spatrick 
718f24071e5Spatrick static void
719f24071e5Spatrick efi_timer_init(void)
720f24071e5Spatrick {
721f24071e5Spatrick 	EFI_STATUS status;
722f24071e5Spatrick 
723a4d88df4Sjsg 	status = BS->CreateEvent(EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_CALLBACK,
724f24071e5Spatrick 	    efi_timer, NULL, &timer);
725f24071e5Spatrick 	if (status == EFI_SUCCESS)
726f24071e5Spatrick 		status = BS->SetTimer(timer, TimerPeriodic, 10000000);
727f24071e5Spatrick 	if (EFI_ERROR(status))
728f24071e5Spatrick 		printf("Can't create timer\n");
729f24071e5Spatrick }
730f24071e5Spatrick 
731f24071e5Spatrick static void
732f24071e5Spatrick efi_timer_cleanup(void)
733f24071e5Spatrick {
734f24071e5Spatrick 	BS->CloseEvent(timer);
735f24071e5Spatrick }
736f24071e5Spatrick 
737f24071e5Spatrick time_t
738f24071e5Spatrick getsecs(void)
739f24071e5Spatrick {
740f24071e5Spatrick 	return ticks;
741f24071e5Spatrick }
742f24071e5Spatrick 
743f24071e5Spatrick /*
744f24071e5Spatrick  * Various device-related bits.
745f24071e5Spatrick  */
746f24071e5Spatrick 
747f24071e5Spatrick void
748f24071e5Spatrick devboot(dev_t dev, char *p)
749f24071e5Spatrick {
7505b351376Spatrick 	struct sr_boot_volume *bv;
7515b351376Spatrick 	struct sr_boot_chunk *bc;
7525b351376Spatrick 	struct diskinfo *dip;
7535b351376Spatrick 	int sd_boot_vol = 0;
7545b351376Spatrick 	int sr_boot_vol = -1;
7555b351376Spatrick 	int part_type = FS_UNUSED;
7565b351376Spatrick 
7575b351376Spatrick 	if (bootdev_dip == NULL) {
75833e5575aSpatrick 		strlcpy(p, "tftp0a", 7);
7595b351376Spatrick 		return;
7605b351376Spatrick 	}
7615b351376Spatrick 
7625b351376Spatrick 	TAILQ_FOREACH(dip, &disklist, list) {
7635b351376Spatrick 		if (bootdev_dip == dip)
7645b351376Spatrick 			break;
7655b351376Spatrick 		sd_boot_vol++;
7665b351376Spatrick 	}
7675b351376Spatrick 
7685b351376Spatrick 	/*
7695b351376Spatrick 	 * Determine the partition type for the 'a' partition of the
7705b351376Spatrick 	 * boot device.
7715b351376Spatrick 	 */
7725b351376Spatrick 	if ((bootdev_dip->flags & DISKINFO_FLAG_GOODLABEL) != 0)
7735b351376Spatrick 		part_type = bootdev_dip->disklabel.d_partitions[0].p_fstype;
7745b351376Spatrick 
7755b351376Spatrick 	/*
7765b351376Spatrick 	 * See if we booted from a disk that is a member of a bootable
7775b351376Spatrick 	 * softraid volume.
7785b351376Spatrick 	 */
7795b351376Spatrick 	SLIST_FOREACH(bv, &sr_volumes, sbv_link) {
7805b351376Spatrick 		SLIST_FOREACH(bc, &bv->sbv_chunks, sbc_link)
7815b351376Spatrick 			if (bc->sbc_diskinfo == bootdev_dip)
7825b351376Spatrick 				sr_boot_vol = bv->sbv_unit;
7835b351376Spatrick 		if (sr_boot_vol != -1)
7845b351376Spatrick 			break;
7855b351376Spatrick 	}
7865b351376Spatrick 
7875b351376Spatrick 	if (sr_boot_vol != -1 && part_type != FS_BSDFFS) {
7885b351376Spatrick 		strlcpy(p, "sr0a", 5);
7895b351376Spatrick 		p[2] = '0' + sr_boot_vol;
7905b351376Spatrick 		return;
7915b351376Spatrick 	}
7925b351376Spatrick 
7935b351376Spatrick 	strlcpy(p, "sd0a", 5);
7945b351376Spatrick 	p[2] = '0' + sd_boot_vol;
795f24071e5Spatrick }
796f24071e5Spatrick 
7975cfe0970Skettenis const char cdevs[][4] = { "com", "fb" };
7985cfe0970Skettenis const int ncdevs = nitems(cdevs);
7995cfe0970Skettenis 
800f24071e5Spatrick int
801f24071e5Spatrick cnspeed(dev_t dev, int sp)
802f24071e5Spatrick {
803f24071e5Spatrick 	return 115200;
804f24071e5Spatrick }
805f24071e5Spatrick 
8065cfe0970Skettenis char ttyname_buf[8];
8075cfe0970Skettenis 
808f24071e5Spatrick char *
809f24071e5Spatrick ttyname(int fd)
810f24071e5Spatrick {
8115cfe0970Skettenis 	snprintf(ttyname_buf, sizeof ttyname_buf, "%s%d",
8125cfe0970Skettenis 	    cdevs[major(cn_tab->cn_dev)], minor(cn_tab->cn_dev));
8135cfe0970Skettenis 
8145cfe0970Skettenis 	return ttyname_buf;
815f24071e5Spatrick }
816f24071e5Spatrick 
817f24071e5Spatrick dev_t
818f24071e5Spatrick ttydev(char *name)
819f24071e5Spatrick {
8205cfe0970Skettenis 	int i, unit = -1;
8215cfe0970Skettenis 	char *no = name + strlen(name) - 1;
8225cfe0970Skettenis 
8235cfe0970Skettenis 	while (no >= name && *no >= '0' && *no <= '9')
8245cfe0970Skettenis 		unit = (unit < 0 ? 0 : (unit * 10)) + *no-- - '0';
8255cfe0970Skettenis 	if (no < name || unit < 0)
8265cfe0970Skettenis 		return NODEV;
8275cfe0970Skettenis 	for (i = 0; i < ncdevs; i++)
8285cfe0970Skettenis 		if (strncmp(name, cdevs[i], no - name + 1) == 0)
8295cfe0970Skettenis 			return makedev(i, unit);
830f24071e5Spatrick 	return NODEV;
831f24071e5Spatrick }
832f24071e5Spatrick 
833f24071e5Spatrick #define MAXDEVNAME	16
834f24071e5Spatrick 
835f24071e5Spatrick /*
836f24071e5Spatrick  * Parse a device spec.
837f24071e5Spatrick  *
838f24071e5Spatrick  * [A-Za-z]*[0-9]*[A-Za-z]:file
839f24071e5Spatrick  *    dev   uint    part
840f24071e5Spatrick  */
841f24071e5Spatrick int
842f24071e5Spatrick devparse(const char *fname, int *dev, int *unit, int *part, const char **file)
843f24071e5Spatrick {
844f24071e5Spatrick 	const char *s;
845f24071e5Spatrick 
846f24071e5Spatrick 	*unit = 0;	/* default to wd0a */
847f24071e5Spatrick 	*part = 0;
848f24071e5Spatrick 	*dev  = 0;
849f24071e5Spatrick 
850f24071e5Spatrick 	s = strchr(fname, ':');
851f24071e5Spatrick 	if (s != NULL) {
852f24071e5Spatrick 		int devlen;
853f24071e5Spatrick 		int i, u, p = 0;
854f24071e5Spatrick 		struct devsw *dp;
855f24071e5Spatrick 		char devname[MAXDEVNAME];
856f24071e5Spatrick 
857f24071e5Spatrick 		devlen = s - fname;
858f24071e5Spatrick 		if (devlen > MAXDEVNAME)
859f24071e5Spatrick 			return (EINVAL);
860f24071e5Spatrick 
861f24071e5Spatrick 		/* extract device name */
862f24071e5Spatrick 		for (i = 0; isalpha(fname[i]) && (i < devlen); i++)
863f24071e5Spatrick 			devname[i] = fname[i];
864f24071e5Spatrick 		devname[i] = 0;
865f24071e5Spatrick 
866f24071e5Spatrick 		if (!isdigit(fname[i]))
867f24071e5Spatrick 			return (EUNIT);
868f24071e5Spatrick 
869f24071e5Spatrick 		/* device number */
870f24071e5Spatrick 		for (u = 0; isdigit(fname[i]) && (i < devlen); i++)
871f24071e5Spatrick 			u = u * 10 + (fname[i] - '0');
872f24071e5Spatrick 
873f24071e5Spatrick 		if (!isalpha(fname[i]))
874f24071e5Spatrick 			return (EPART);
875f24071e5Spatrick 
876f24071e5Spatrick 		/* partition number */
877f24071e5Spatrick 		if (i < devlen)
878f24071e5Spatrick 			p = fname[i++] - 'a';
879f24071e5Spatrick 
880f24071e5Spatrick 		if (i != devlen)
881f24071e5Spatrick 			return (ENXIO);
882f24071e5Spatrick 
883f24071e5Spatrick 		/* check device name */
884f24071e5Spatrick 		for (dp = devsw, i = 0; i < ndevs; dp++, i++) {
885f24071e5Spatrick 			if (dp->dv_name && !strcmp(devname, dp->dv_name))
886f24071e5Spatrick 				break;
887f24071e5Spatrick 		}
888f24071e5Spatrick 
889f24071e5Spatrick 		if (i >= ndevs)
890f24071e5Spatrick 			return (ENXIO);
891f24071e5Spatrick 
892f24071e5Spatrick 		*unit = u;
893f24071e5Spatrick 		*part = p;
894f24071e5Spatrick 		*dev  = i;
895f24071e5Spatrick 		fname = ++s;
896f24071e5Spatrick 	}
897f24071e5Spatrick 
898f24071e5Spatrick 	*file = fname;
899f24071e5Spatrick 
900f24071e5Spatrick 	return (0);
901f24071e5Spatrick }
902f24071e5Spatrick 
903f24071e5Spatrick int
904f24071e5Spatrick devopen(struct open_file *f, const char *fname, char **file)
905f24071e5Spatrick {
906f24071e5Spatrick 	struct devsw *dp;
907f24071e5Spatrick 	int dev, unit, part, error;
908f24071e5Spatrick 
909f24071e5Spatrick 	error = devparse(fname, &dev, &unit, &part, (const char **)file);
910f24071e5Spatrick 	if (error)
911f24071e5Spatrick 		return (error);
912f24071e5Spatrick 
91333e5575aSpatrick 	dp = &devsw[dev];
914f24071e5Spatrick 	f->f_dev = dp;
915f24071e5Spatrick 
916ad424d98Snaddy 	if (strcmp("tftp", dp->dv_name) != 0) {
917ad424d98Snaddy 		/*
918ad424d98Snaddy 		 * Clear bootmac, to signal that we loaded this file from a
919ad424d98Snaddy 		 * non-network device.
920ad424d98Snaddy 		 */
921ad424d98Snaddy 		bootmac = NULL;
922ad424d98Snaddy 	}
923ad424d98Snaddy 
924f24071e5Spatrick 	return (*dp->dv_open)(f, unit, part);
925f24071e5Spatrick }
926f24071e5Spatrick 
927fa854029Spatrick static void
928fa854029Spatrick efi_memprobe_internal(void)
929fa854029Spatrick {
930fa854029Spatrick 	EFI_STATUS		 status;
931fa854029Spatrick 	UINTN			 mapkey, mmsiz, siz;
932fa854029Spatrick 	UINT32			 mmver;
933fa854029Spatrick 	EFI_MEMORY_DESCRIPTOR	*mm;
934fa854029Spatrick 	int			 n;
935fa854029Spatrick 
936fa854029Spatrick 	free(mmap, mmap_ndesc * mmap_descsiz);
937fa854029Spatrick 
938fa854029Spatrick 	siz = 0;
9391f462730Skrw 	status = BS->GetMemoryMap(&siz, NULL, &mapkey, &mmsiz, &mmver);
940fa854029Spatrick 	if (status != EFI_BUFFER_TOO_SMALL)
941fa854029Spatrick 		panic("cannot get the size of memory map");
942fa854029Spatrick 	mm = alloc(siz);
9431f462730Skrw 	status = BS->GetMemoryMap(&siz, mm, &mapkey, &mmsiz, &mmver);
944fa854029Spatrick 	if (status != EFI_SUCCESS)
945fa854029Spatrick 		panic("cannot get the memory map");
946fa854029Spatrick 	n = siz / mmsiz;
947fa854029Spatrick 	mmap = mm;
948fa854029Spatrick 	mmap_key = mapkey;
949fa854029Spatrick 	mmap_ndesc = n;
950fa854029Spatrick 	mmap_descsiz = mmsiz;
951f4dd1aebSkettenis 	mmap_version = mmver;
952fa854029Spatrick }
953fa854029Spatrick 
954f24071e5Spatrick /*
955f24071e5Spatrick  * 64-bit ARMs can have a much wider memory mapping, as in somewhere
956f24071e5Spatrick  * after the 32-bit region.  To cope with our alignment requirement,
957f24071e5Spatrick  * use the memory table to find a place where we can fit.
958f24071e5Spatrick  */
959f24071e5Spatrick static EFI_STATUS
960f24071e5Spatrick efi_memprobe_find(UINTN pages, UINTN align, EFI_PHYSICAL_ADDRESS *addr)
961f24071e5Spatrick {
962fa854029Spatrick 	EFI_MEMORY_DESCRIPTOR	*mm;
963fa854029Spatrick 	int			 i, j;
964f24071e5Spatrick 
965f24071e5Spatrick 	if (align < EFI_PAGE_SIZE)
966f24071e5Spatrick 		return EFI_INVALID_PARAMETER;
967f24071e5Spatrick 
968fa854029Spatrick 	efi_memprobe_internal();	/* sync the current map */
969f24071e5Spatrick 
970fa854029Spatrick 	for (i = 0, mm = mmap; i < mmap_ndesc;
971fa854029Spatrick 	    i++, mm = NextMemoryDescriptor(mm, mmap_descsiz)) {
972f24071e5Spatrick 		if (mm->Type != EfiConventionalMemory)
973f24071e5Spatrick 			continue;
974f24071e5Spatrick 
975f24071e5Spatrick 		if (mm->NumberOfPages < pages)
976f24071e5Spatrick 			continue;
977f24071e5Spatrick 
978f2c0e408Skettenis 		for (j = 0; j < mm->NumberOfPages; j++) {
979f24071e5Spatrick 			EFI_PHYSICAL_ADDRESS paddr;
980f24071e5Spatrick 
981f24071e5Spatrick 			if (mm->NumberOfPages - j < pages)
982f24071e5Spatrick 				break;
983f24071e5Spatrick 
984f24071e5Spatrick 			paddr = mm->PhysicalStart + (j * EFI_PAGE_SIZE);
98573dc1409Spatrick 			if (paddr & (align - 1))
98673dc1409Spatrick 				continue;
98773dc1409Spatrick 
9881f462730Skrw 			if (BS->AllocatePages(AllocateAddress, EfiLoaderData,
9891f462730Skrw 			    pages, &paddr) == EFI_SUCCESS) {
990f24071e5Spatrick 				*addr = paddr;
991f24071e5Spatrick 				return EFI_SUCCESS;
992f24071e5Spatrick 			}
993f24071e5Spatrick 		}
994f24071e5Spatrick 	}
995f24071e5Spatrick 	return EFI_OUT_OF_RESOURCES;
996f24071e5Spatrick }
997111d6387Skettenis 
998111d6387Skettenis /*
999111d6387Skettenis  * Commands
1000111d6387Skettenis  */
1001111d6387Skettenis 
1002be07ee62Skettenis int Xacpi_efi(void);
10036f83097eSpatrick int Xdtb_efi(void);
1004111d6387Skettenis int Xexit_efi(void);
1005111d6387Skettenis int Xpoweroff_efi(void);
1006111d6387Skettenis 
1007111d6387Skettenis const struct cmd_table cmd_machine[] = {
1008be07ee62Skettenis 	{ "acpi",	CMDT_CMD, Xacpi_efi },
10096f83097eSpatrick 	{ "dtb",	CMDT_CMD, Xdtb_efi },
1010111d6387Skettenis 	{ "exit",	CMDT_CMD, Xexit_efi },
1011111d6387Skettenis 	{ "poweroff",	CMDT_CMD, Xpoweroff_efi },
1012111d6387Skettenis 	{ NULL, 0 }
1013111d6387Skettenis };
1014111d6387Skettenis 
1015111d6387Skettenis int
1016be07ee62Skettenis Xacpi_efi(void)
1017be07ee62Skettenis {
1018be07ee62Skettenis 	acpi = 1;
1019be07ee62Skettenis 	return (0);
1020be07ee62Skettenis }
1021be07ee62Skettenis 
1022be07ee62Skettenis int
10236f83097eSpatrick Xdtb_efi(void)
10246f83097eSpatrick {
10256f83097eSpatrick 	EFI_PHYSICAL_ADDRESS addr;
10266f83097eSpatrick 	char path[MAXPATHLEN];
10276f83097eSpatrick 	struct stat sb;
10286f83097eSpatrick 	int fd;
10296f83097eSpatrick 
1030fcf3d43cSkn 	if (cmd.argc != 2) {
1031fcf3d43cSkn 		printf("dtb file\n");
1032fcf3d43cSkn 		return (0);
1033fcf3d43cSkn 	}
10346f83097eSpatrick 
10356f83097eSpatrick 	snprintf(path, sizeof(path), "%s:%s", cmd.bootdev, cmd.argv[1]);
10366f83097eSpatrick 
10376f83097eSpatrick 	fd = open(path, O_RDONLY);
10386f83097eSpatrick 	if (fd < 0 || fstat(fd, &sb) == -1) {
10396f83097eSpatrick 		printf("cannot open %s\n", path);
1040fcf3d43cSkn 		return (0);
10416f83097eSpatrick 	}
10426f83097eSpatrick 	if (efi_memprobe_find(EFI_SIZE_TO_PAGES(sb.st_size),
10436f83097eSpatrick 	    0x1000, &addr) != EFI_SUCCESS) {
10446f83097eSpatrick 		printf("cannot allocate memory for %s\n", path);
1045fcf3d43cSkn 		return (0);
10466f83097eSpatrick 	}
10476f83097eSpatrick 	if (read(fd, (void *)addr, sb.st_size) != sb.st_size) {
10486f83097eSpatrick 		printf("cannot read from %s\n", path);
1049fcf3d43cSkn 		return (0);
10506f83097eSpatrick 	}
10516f83097eSpatrick 
10526f83097eSpatrick 	fdt = (void *)addr;
10536f83097eSpatrick 	return (0);
10546f83097eSpatrick }
10556f83097eSpatrick 
10566f83097eSpatrick int
1057111d6387Skettenis Xexit_efi(void)
1058111d6387Skettenis {
10591f462730Skrw 	BS->Exit(IH, 0, 0, NULL);
1060111d6387Skettenis 	for (;;)
1061111d6387Skettenis 		continue;
1062111d6387Skettenis 	return (0);
1063111d6387Skettenis }
1064111d6387Skettenis 
1065111d6387Skettenis int
1066111d6387Skettenis Xpoweroff_efi(void)
1067111d6387Skettenis {
10681f462730Skrw 	RS->ResetSystem(EfiResetShutdown, EFI_SUCCESS, 0, NULL);
1069111d6387Skettenis 	return (0);
1070111d6387Skettenis }
1071