xref: /openbsd/sys/arch/arm64/stand/efiboot/efiboot.c (revision bd928107)
1*bd928107Spatrick /*	$OpenBSD: efiboot.c,v 1.44 2022/11/05 19:00:31 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;
50f3468426Skettenis void			*fdt = NULL;
51f24071e5Spatrick 
52fa854029Spatrick EFI_PHYSICAL_ADDRESS	 heap;
53fa854029Spatrick UINTN			 heapsiz = 1 * 1024 * 1024;
54f673f4ddSkettenis EFI_MEMORY_DESCRIPTOR	*mmap;
55fa854029Spatrick UINTN			 mmap_key;
56fa854029Spatrick UINTN			 mmap_ndesc;
57fa854029Spatrick UINTN			 mmap_descsiz;
58f4dd1aebSkettenis UINT32			 mmap_version;
59f24071e5Spatrick 
60f24071e5Spatrick static EFI_GUID		 imgp_guid = LOADED_IMAGE_PROTOCOL;
61f24071e5Spatrick static EFI_GUID		 blkio_guid = BLOCK_IO_PROTOCOL;
62f24071e5Spatrick static EFI_GUID		 devp_guid = DEVICE_PATH_PROTOCOL;
631e44dc38Skettenis static EFI_GUID		 gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
64f3468426Skettenis static EFI_GUID		 fdt_guid = FDT_TABLE_GUID;
65f3468426Skettenis 
6649dff005Sderaadt #define efi_guidcmp(_a, _b)	memcmp((_a), (_b), sizeof(EFI_GUID))
67f24071e5Spatrick 
6833e5575aSpatrick int efi_device_path_depth(EFI_DEVICE_PATH *dp, int);
6933e5575aSpatrick int efi_device_path_ncmp(EFI_DEVICE_PATH *, EFI_DEVICE_PATH *, int);
70fa854029Spatrick static void efi_heap_init(void);
71fa854029Spatrick static void efi_memprobe_internal(void);
72f24071e5Spatrick static void efi_timer_init(void);
73f24071e5Spatrick static void efi_timer_cleanup(void);
742c32ef33Skettenis static EFI_STATUS efi_memprobe_find(UINTN, UINTN, EFI_MEMORY_TYPE,
752c32ef33Skettenis     EFI_PHYSICAL_ADDRESS *);
76f24071e5Spatrick 
77f24071e5Spatrick EFI_STATUS
78f24071e5Spatrick efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab)
79f24071e5Spatrick {
80f24071e5Spatrick 	extern char		*progname;
81f24071e5Spatrick 	EFI_LOADED_IMAGE	*imgp;
82f24071e5Spatrick 	EFI_DEVICE_PATH		*dp = NULL;
83f24071e5Spatrick 	EFI_STATUS		 status;
84f3468426Skettenis 	int			 i;
85f24071e5Spatrick 
86f24071e5Spatrick 	ST = systab;
87f24071e5Spatrick 	BS = ST->BootServices;
88496ffee0Spatrick 	RS = ST->RuntimeServices;
89f24071e5Spatrick 	IH = image;
90f24071e5Spatrick 
91f0da534cSjsg 	/* disable reset by watchdog after 5 minutes */
921f462730Skrw 	BS->SetWatchdogTimer(0, 0, 0, NULL);
93f0da534cSjsg 
941f462730Skrw 	status = BS->HandleProtocol(image, &imgp_guid,
95f24071e5Spatrick 	    (void **)&imgp);
96f24071e5Spatrick 	if (status == EFI_SUCCESS)
971f462730Skrw 		status = BS->HandleProtocol(imgp->DeviceHandle, &devp_guid,
981f462730Skrw 		    (void **)&dp);
99f24071e5Spatrick 	if (status == EFI_SUCCESS)
100f24071e5Spatrick 		efi_bootdp = dp;
101f24071e5Spatrick 
102f3468426Skettenis 	for (i = 0; i < ST->NumberOfTableEntries; i++) {
103f3468426Skettenis 		if (efi_guidcmp(&fdt_guid,
104f3468426Skettenis 		    &ST->ConfigurationTable[i].VendorGuid) == 0)
105f3468426Skettenis 			fdt = ST->ConfigurationTable[i].VendorTable;
106f3468426Skettenis 	}
107f3468426Skettenis 	fdt_init(fdt);
108f3468426Skettenis 
109f24071e5Spatrick 	progname = "BOOTAA64";
110f24071e5Spatrick 
111f24071e5Spatrick 	boot(0);
112f24071e5Spatrick 
113f24071e5Spatrick 	return (EFI_SUCCESS);
114f24071e5Spatrick }
115f24071e5Spatrick 
116f24071e5Spatrick static SIMPLE_TEXT_OUTPUT_INTERFACE *conout;
117f24071e5Spatrick static SIMPLE_INPUT_INTERFACE *conin;
118f24071e5Spatrick 
1195cfe0970Skettenis /*
1205cfe0970Skettenis  * The device majors for these don't match the ones used by the
1215cfe0970Skettenis  * kernel.  That's fine.  They're just used as an index into the cdevs
1225cfe0970Skettenis  * array and never passed on to the kernel.
1235cfe0970Skettenis  */
124c7045f51Skettenis static dev_t serial = makedev(1, 0);
125c7045f51Skettenis static dev_t framebuffer = makedev(2, 0);
1265cfe0970Skettenis 
1275f7ab753Skettenis static char framebuffer_path[128];
1285f7ab753Skettenis 
129f24071e5Spatrick void
130f24071e5Spatrick efi_cons_probe(struct consdev *cn)
131f24071e5Spatrick {
132f24071e5Spatrick 	cn->cn_pri = CN_MIDPRI;
133c7045f51Skettenis 	cn->cn_dev = makedev(0, 0);
134f24071e5Spatrick }
135f24071e5Spatrick 
136f24071e5Spatrick void
137f24071e5Spatrick efi_cons_init(struct consdev *cp)
138f24071e5Spatrick {
139f24071e5Spatrick 	conin = ST->ConIn;
140f24071e5Spatrick 	conout = ST->ConOut;
141f24071e5Spatrick }
142f24071e5Spatrick 
143f24071e5Spatrick int
144f24071e5Spatrick efi_cons_getc(dev_t dev)
145f24071e5Spatrick {
146f24071e5Spatrick 	EFI_INPUT_KEY	 key;
147f24071e5Spatrick 	EFI_STATUS	 status;
148f24071e5Spatrick #if 0
149f24071e5Spatrick 	UINTN		 dummy;
150f24071e5Spatrick #endif
151f24071e5Spatrick 	static int	 lastchar = 0;
152f24071e5Spatrick 
153f24071e5Spatrick 	if (lastchar) {
154f24071e5Spatrick 		int r = lastchar;
155f24071e5Spatrick 		if ((dev & 0x80) == 0)
156f24071e5Spatrick 			lastchar = 0;
157f24071e5Spatrick 		return (r);
158f24071e5Spatrick 	}
159f24071e5Spatrick 
160f24071e5Spatrick 	status = conin->ReadKeyStroke(conin, &key);
161678d37b9Syasuoka 	while (status == EFI_NOT_READY || key.UnicodeChar == 0) {
162f24071e5Spatrick 		if (dev & 0x80)
163f24071e5Spatrick 			return (0);
164f24071e5Spatrick 		/*
165f24071e5Spatrick 		 * XXX The implementation of WaitForEvent() in U-boot
166f24071e5Spatrick 		 * is broken and neverreturns.
167f24071e5Spatrick 		 */
168f24071e5Spatrick #if 0
169f24071e5Spatrick 		BS->WaitForEvent(1, &conin->WaitForKey, &dummy);
170f24071e5Spatrick #endif
171f24071e5Spatrick 		status = conin->ReadKeyStroke(conin, &key);
172f24071e5Spatrick 	}
173f24071e5Spatrick 
174f24071e5Spatrick 	if (dev & 0x80)
175f24071e5Spatrick 		lastchar = key.UnicodeChar;
176f24071e5Spatrick 
177f24071e5Spatrick 	return (key.UnicodeChar);
178f24071e5Spatrick }
179f24071e5Spatrick 
180f24071e5Spatrick void
181f24071e5Spatrick efi_cons_putc(dev_t dev, int c)
182f24071e5Spatrick {
183f24071e5Spatrick 	CHAR16	buf[2];
184f24071e5Spatrick 
185f24071e5Spatrick 	if (c == '\n')
186f24071e5Spatrick 		efi_cons_putc(dev, '\r');
187f24071e5Spatrick 
188f24071e5Spatrick 	buf[0] = c;
189f24071e5Spatrick 	buf[1] = 0;
190f24071e5Spatrick 
191f24071e5Spatrick 	conout->OutputString(conout, buf);
192f24071e5Spatrick }
193f24071e5Spatrick 
1945cfe0970Skettenis void
195c7045f51Skettenis efi_com_probe(struct consdev *cn)
196c7045f51Skettenis {
197c7045f51Skettenis 	cn->cn_pri = CN_LOWPRI;
198c7045f51Skettenis 	cn->cn_dev = serial;
199c7045f51Skettenis }
200c7045f51Skettenis 
201c7045f51Skettenis void
202c7045f51Skettenis efi_com_init(struct consdev *cn)
203c7045f51Skettenis {
204c7045f51Skettenis 	conin = ST->ConIn;
205c7045f51Skettenis 	conout = ST->ConOut;
206c7045f51Skettenis }
207c7045f51Skettenis 
208c7045f51Skettenis int
209c7045f51Skettenis efi_com_getc(dev_t dev)
210c7045f51Skettenis {
211c7045f51Skettenis 	return efi_cons_getc(dev);
212c7045f51Skettenis }
213c7045f51Skettenis 
214c7045f51Skettenis void
215c7045f51Skettenis efi_com_putc(dev_t dev, int c)
216c7045f51Skettenis {
217c7045f51Skettenis 	efi_cons_putc(dev, c);
218c7045f51Skettenis }
219c7045f51Skettenis 
220c7045f51Skettenis void
2215cfe0970Skettenis efi_fb_probe(struct consdev *cn)
2225cfe0970Skettenis {
2235cfe0970Skettenis 	cn->cn_pri = CN_LOWPRI;
2245cfe0970Skettenis 	cn->cn_dev = framebuffer;
2255cfe0970Skettenis }
2265cfe0970Skettenis 
2275cfe0970Skettenis void
2285cfe0970Skettenis efi_fb_init(struct consdev *cn)
2295cfe0970Skettenis {
2305cfe0970Skettenis 	conin = ST->ConIn;
2315cfe0970Skettenis 	conout = ST->ConOut;
2325cfe0970Skettenis }
2335cfe0970Skettenis 
2345cfe0970Skettenis int
2355cfe0970Skettenis efi_fb_getc(dev_t dev)
2365cfe0970Skettenis {
2375cfe0970Skettenis 	return efi_cons_getc(dev);
2385cfe0970Skettenis }
2395cfe0970Skettenis 
2405cfe0970Skettenis void
2415cfe0970Skettenis efi_fb_putc(dev_t dev, int c)
2425cfe0970Skettenis {
2435cfe0970Skettenis 	efi_cons_putc(dev, c);
2445cfe0970Skettenis }
2455cfe0970Skettenis 
246f24071e5Spatrick static void
247f24071e5Spatrick efi_heap_init(void)
248f24071e5Spatrick {
249f24071e5Spatrick 	EFI_STATUS	 status;
250f24071e5Spatrick 
2511f462730Skrw 	status = BS->AllocatePages(AllocateAnyPages, EfiLoaderData,
252f24071e5Spatrick 	    EFI_SIZE_TO_PAGES(heapsiz), &heap);
253f24071e5Spatrick 	if (status != EFI_SUCCESS)
254f24071e5Spatrick 		panic("BS->AllocatePages()");
255f24071e5Spatrick }
256f24071e5Spatrick 
2575b351376Spatrick struct disklist_lh disklist;
2585b351376Spatrick struct diskinfo *bootdev_dip;
259f24071e5Spatrick 
260f24071e5Spatrick void
261f24071e5Spatrick efi_diskprobe(void)
262f24071e5Spatrick {
2635b351376Spatrick 	int			 i, bootdev = 0, depth = -1;
264f24071e5Spatrick 	UINTN			 sz;
265f24071e5Spatrick 	EFI_STATUS		 status;
266f24071e5Spatrick 	EFI_HANDLE		*handles = NULL;
267f24071e5Spatrick 	EFI_BLOCK_IO		*blkio;
268f24071e5Spatrick 	EFI_BLOCK_IO_MEDIA	*media;
2695b351376Spatrick 	struct diskinfo		*di;
270c6d7d0adSpatrick 	EFI_DEVICE_PATH		*dp;
271f24071e5Spatrick 
2725b351376Spatrick 	TAILQ_INIT(&disklist);
2735b351376Spatrick 
274f24071e5Spatrick 	sz = 0;
2751f462730Skrw 	status = BS->LocateHandle(ByProtocol, &blkio_guid, 0, &sz, 0);
276f24071e5Spatrick 	if (status == EFI_BUFFER_TOO_SMALL) {
277f24071e5Spatrick 		handles = alloc(sz);
2781f462730Skrw 		status = BS->LocateHandle(ByProtocol, &blkio_guid, 0, &sz,
2791f462730Skrw 		    handles);
280f24071e5Spatrick 	}
281f24071e5Spatrick 	if (handles == NULL || EFI_ERROR(status))
28233e5575aSpatrick 		return;
283f24071e5Spatrick 
284c6d7d0adSpatrick 	if (efi_bootdp != NULL)
285c6d7d0adSpatrick 		depth = efi_device_path_depth(efi_bootdp, MEDIA_DEVICE_PATH);
286c6d7d0adSpatrick 
287c94e7257Skettenis 	/*
288c94e7257Skettenis 	 * U-Boot incorrectly represents devices with a single
289c94e7257Skettenis 	 * MEDIA_DEVICE_PATH component.  In that case include that
290c94e7257Skettenis 	 * component into the matching, otherwise we'll blindly select
291c94e7257Skettenis 	 * the first device.
292c94e7257Skettenis 	 */
293c94e7257Skettenis 	if (depth == 0)
294c94e7257Skettenis 		depth = 1;
295c94e7257Skettenis 
296f24071e5Spatrick 	for (i = 0; i < sz / sizeof(EFI_HANDLE); i++) {
2971f462730Skrw 		status = BS->HandleProtocol(handles[i], &blkio_guid,
298f24071e5Spatrick 		    (void **)&blkio);
299f24071e5Spatrick 		if (EFI_ERROR(status))
300f24071e5Spatrick 			panic("BS->HandleProtocol() returns %d", status);
301f24071e5Spatrick 
302f24071e5Spatrick 		media = blkio->Media;
303f24071e5Spatrick 		if (media->LogicalPartition || !media->MediaPresent)
304f24071e5Spatrick 			continue;
3055b351376Spatrick 		di = alloc(sizeof(struct diskinfo));
3065b351376Spatrick 		efid_init(di, blkio);
307f24071e5Spatrick 
3085b351376Spatrick 		if (efi_bootdp == NULL || depth == -1 || bootdev != 0)
3095b351376Spatrick 			goto next;
3101f462730Skrw 		status = BS->HandleProtocol(handles[i], &devp_guid,
311f24071e5Spatrick 		    (void **)&dp);
312f24071e5Spatrick 		if (EFI_ERROR(status))
3135b351376Spatrick 			goto next;
314c6d7d0adSpatrick 		if (efi_device_path_ncmp(efi_bootdp, dp, depth) == 0) {
3155b351376Spatrick 			TAILQ_INSERT_HEAD(&disklist, di, list);
3165b351376Spatrick 			bootdev_dip = di;
3175b351376Spatrick 			bootdev = 1;
3185b351376Spatrick 			continue;
319f24071e5Spatrick 		}
3205b351376Spatrick next:
3215b351376Spatrick 		TAILQ_INSERT_TAIL(&disklist, di, list);
322f24071e5Spatrick 	}
323f24071e5Spatrick 
324f24071e5Spatrick 	free(handles, sz);
3255b351376Spatrick 
3265b351376Spatrick 	/* Print available disks and probe for softraid. */
3275b351376Spatrick 	i = 0;
3285b351376Spatrick 	printf("disks:");
3295b351376Spatrick 	TAILQ_FOREACH(di, &disklist, list) {
3305b351376Spatrick 		printf(" sd%d%s", i, di == bootdev_dip ? "*" : "");
3315b351376Spatrick 		i++;
3325b351376Spatrick 	}
3335b351376Spatrick 	srprobe();
3345b351376Spatrick 	printf("\n");
335f24071e5Spatrick }
336f24071e5Spatrick 
337c94e7257Skettenis /*
338c94e7257Skettenis  * Determine the number of nodes up to, but not including, the first
339c94e7257Skettenis  * node of the specified type.
340c94e7257Skettenis  */
34133e5575aSpatrick int
342c6d7d0adSpatrick efi_device_path_depth(EFI_DEVICE_PATH *dp, int dptype)
343c6d7d0adSpatrick {
344c6d7d0adSpatrick 	int	i;
345c6d7d0adSpatrick 
346c6d7d0adSpatrick 	for (i = 0; !IsDevicePathEnd(dp); dp = NextDevicePathNode(dp), i++) {
347c6d7d0adSpatrick 		if (DevicePathType(dp) == dptype)
348c94e7257Skettenis 			return (i);
349c6d7d0adSpatrick 	}
350c6d7d0adSpatrick 
351d64e7de5Skettenis 	return (i);
352c6d7d0adSpatrick }
353c6d7d0adSpatrick 
35433e5575aSpatrick int
355c6d7d0adSpatrick efi_device_path_ncmp(EFI_DEVICE_PATH *dpa, EFI_DEVICE_PATH *dpb, int deptn)
356c6d7d0adSpatrick {
357c6d7d0adSpatrick 	int	 i, cmp;
358c6d7d0adSpatrick 
359c6d7d0adSpatrick 	for (i = 0; i < deptn; i++) {
360c6d7d0adSpatrick 		if (IsDevicePathEnd(dpa) || IsDevicePathEnd(dpb))
361c6d7d0adSpatrick 			return ((IsDevicePathEnd(dpa) && IsDevicePathEnd(dpb))
362c6d7d0adSpatrick 			    ? 0 : (IsDevicePathEnd(dpa))? -1 : 1);
363c6d7d0adSpatrick 		cmp = DevicePathNodeLength(dpa) - DevicePathNodeLength(dpb);
364c6d7d0adSpatrick 		if (cmp)
365c6d7d0adSpatrick 			return (cmp);
366c6d7d0adSpatrick 		cmp = memcmp(dpa, dpb, DevicePathNodeLength(dpa));
367c6d7d0adSpatrick 		if (cmp)
368c6d7d0adSpatrick 			return (cmp);
369c6d7d0adSpatrick 		dpa = NextDevicePathNode(dpa);
370c6d7d0adSpatrick 		dpb = NextDevicePathNode(dpb);
371c6d7d0adSpatrick 	}
372c6d7d0adSpatrick 
373c6d7d0adSpatrick 	return (0);
374c6d7d0adSpatrick }
375c6d7d0adSpatrick 
3761e44dc38Skettenis void
3771e44dc38Skettenis efi_framebuffer(void)
3781e44dc38Skettenis {
3791e44dc38Skettenis 	EFI_GRAPHICS_OUTPUT *gop;
3801e44dc38Skettenis 	EFI_STATUS status;
3811e44dc38Skettenis 	void *node, *child;
3821e44dc38Skettenis 	uint32_t acells, scells;
3831e44dc38Skettenis 	uint64_t base, size;
3841e44dc38Skettenis 	uint32_t reg[4];
3851e44dc38Skettenis 	uint32_t width, height, stride;
3861e44dc38Skettenis 	char *format;
3875cfe0970Skettenis 	char *prop;
3881e44dc38Skettenis 
3891e44dc38Skettenis 	/*
3901e44dc38Skettenis 	 * Don't create a "simple-framebuffer" node if we already have
3911e44dc38Skettenis 	 * one.  Besides "/chosen", we also check under "/" since that
3921e44dc38Skettenis 	 * is where the Raspberry Pi firmware puts it.
3931e44dc38Skettenis 	 */
3941e44dc38Skettenis 	node = fdt_find_node("/chosen");
3951e44dc38Skettenis 	for (child = fdt_child_node(node); child;
3961e44dc38Skettenis 	     child = fdt_next_node(child)) {
3975cfe0970Skettenis 		if (!fdt_node_is_compatible(child, "simple-framebuffer"))
3985cfe0970Skettenis 			continue;
3995028e024Skettenis 		if (!fdt_node_property(child, "status", &prop) ||
4005f7ab753Skettenis 		    strcmp(prop, "okay") == 0) {
4015f7ab753Skettenis 			strlcpy(framebuffer_path, "/chosen/",
4025f7ab753Skettenis 			    sizeof(framebuffer_path));
4035f7ab753Skettenis 			strlcat(framebuffer_path, fdt_node_name(child),
4045f7ab753Skettenis 			    sizeof(framebuffer_path));
4051e44dc38Skettenis 			return;
4061e44dc38Skettenis 		}
4075f7ab753Skettenis 	}
4081e44dc38Skettenis 	node = fdt_find_node("/");
4091e44dc38Skettenis 	for (child = fdt_child_node(node); child;
4101e44dc38Skettenis 	     child = fdt_next_node(child)) {
4115cfe0970Skettenis 		if (!fdt_node_is_compatible(child, "simple-framebuffer"))
4125cfe0970Skettenis 			continue;
4135028e024Skettenis 		if (!fdt_node_property(child, "status", &prop) ||
4145f7ab753Skettenis 		    strcmp(prop, "okay") == 0) {
4155f7ab753Skettenis 			strlcpy(framebuffer_path, "/",
4165f7ab753Skettenis 			    sizeof(framebuffer_path));
4175f7ab753Skettenis 			strlcat(framebuffer_path, fdt_node_name(child),
4185f7ab753Skettenis 			    sizeof(framebuffer_path));
4191e44dc38Skettenis 			return;
4201e44dc38Skettenis 		}
4215f7ab753Skettenis 	}
4221e44dc38Skettenis 
4231f462730Skrw 	status = BS->LocateProtocol(&gop_guid, NULL, (void **)&gop);
4241e44dc38Skettenis 	if (status != EFI_SUCCESS)
4251e44dc38Skettenis 		return;
4261e44dc38Skettenis 
4271e44dc38Skettenis 	/* Paranoia! */
4281e44dc38Skettenis 	if (gop == NULL || gop->Mode == NULL || gop->Mode->Info == NULL)
4291e44dc38Skettenis 		return;
4301e44dc38Skettenis 
4311e44dc38Skettenis 	/* We only support 32-bit pixel modes for now. */
4321e44dc38Skettenis 	switch (gop->Mode->Info->PixelFormat) {
4331e44dc38Skettenis 	case PixelRedGreenBlueReserved8BitPerColor:
434b870cd26Skettenis 		format = "x8b8g8r8";
4351e44dc38Skettenis 		break;
4361e44dc38Skettenis 	case PixelBlueGreenRedReserved8BitPerColor:
437b870cd26Skettenis 		format = "x8r8g8b8";
4381e44dc38Skettenis 		break;
4391e44dc38Skettenis 	default:
4401e44dc38Skettenis 		return;
4411e44dc38Skettenis 	}
4421e44dc38Skettenis 
4431e44dc38Skettenis 	base = gop->Mode->FrameBufferBase;
4441e44dc38Skettenis 	size = gop->Mode->FrameBufferSize;
4451e44dc38Skettenis 	width = htobe32(gop->Mode->Info->HorizontalResolution);
4461e44dc38Skettenis 	height = htobe32(gop->Mode->Info->VerticalResolution);
4471e44dc38Skettenis 	stride = htobe32(gop->Mode->Info->PixelsPerScanLine * 4);
4481e44dc38Skettenis 
4491e44dc38Skettenis 	node = fdt_find_node("/");
4501e44dc38Skettenis 	if (fdt_node_property_int(node, "#address-cells", &acells) != 1)
4511e44dc38Skettenis 		acells = 1;
4521e44dc38Skettenis 	if (fdt_node_property_int(node, "#size-cells", &scells) != 1)
4531e44dc38Skettenis 		scells = 1;
4541e44dc38Skettenis 	if (acells > 2 || scells > 2)
4551e44dc38Skettenis 		return;
4561e44dc38Skettenis 	if (acells >= 1)
4571e44dc38Skettenis 		reg[0] = htobe32(base);
4581e44dc38Skettenis 	if (acells == 2) {
4591e44dc38Skettenis 		reg[1] = reg[0];
4601e44dc38Skettenis 		reg[0] = htobe32(base >> 32);
4611e44dc38Skettenis 	}
4621e44dc38Skettenis 	if (scells >= 1)
4631e44dc38Skettenis 		reg[acells] = htobe32(size);
4641e44dc38Skettenis 	if (scells == 2) {
4651e44dc38Skettenis 		reg[acells + 1] = reg[acells];
4661e44dc38Skettenis 		reg[acells] = htobe32(size >> 32);
4671e44dc38Skettenis 	}
4681e44dc38Skettenis 
4691e44dc38Skettenis 	node = fdt_find_node("/chosen");
4701e44dc38Skettenis 	fdt_node_add_node(node, "framebuffer", &child);
4711e44dc38Skettenis 	fdt_node_add_property(child, "status", "okay", strlen("okay") + 1);
4721e44dc38Skettenis 	fdt_node_add_property(child, "format", format, strlen(format) + 1);
4731e44dc38Skettenis 	fdt_node_add_property(child, "stride", &stride, 4);
4741e44dc38Skettenis 	fdt_node_add_property(child, "height", &height, 4);
4751e44dc38Skettenis 	fdt_node_add_property(child, "width", &width, 4);
4761e44dc38Skettenis 	fdt_node_add_property(child, "reg", reg, (acells + scells) * 4);
4771e44dc38Skettenis 	fdt_node_add_property(child, "compatible",
4781e44dc38Skettenis 	    "simple-framebuffer", strlen("simple-framebuffer") + 1);
4795f7ab753Skettenis 
4805f7ab753Skettenis 	strlcpy(framebuffer_path, "/chosen/framebuffer",
4815f7ab753Skettenis 	    sizeof(framebuffer_path));
4821e44dc38Skettenis }
4831e44dc38Skettenis 
4845cfe0970Skettenis void
4855cfe0970Skettenis efi_console(void)
4865cfe0970Skettenis {
4875f7ab753Skettenis 	void *node;
4885cfe0970Skettenis 
489c7045f51Skettenis 	if (major(cn_tab->cn_dev) == major(serial)) {
490c7045f51Skettenis 		char *serial_path;
491c7045f51Skettenis 		char alias[16];
492c7045f51Skettenis 		int len;
493c7045f51Skettenis 
494c7045f51Skettenis 		/* Construct alias and resolve it. */
495c7045f51Skettenis 		snprintf(alias, sizeof(alias), "serial%d",
496c7045f51Skettenis 		    minor(cn_tab->cn_dev));
497c7045f51Skettenis 		node = fdt_find_node("/aliases");
498c7045f51Skettenis 		len = fdt_node_property(node, alias, &serial_path);
499c7045f51Skettenis 		if (len <= 0)
5005cfe0970Skettenis 			return;
5015cfe0970Skettenis 
502c7045f51Skettenis 		/* Point stdout-path at the serial node. */
503c7045f51Skettenis 		node = fdt_find_node("/chosen");
504c7045f51Skettenis 		fdt_node_add_property(node, "stdout-path",
505c7045f51Skettenis 		    serial_path, strlen(serial_path) + 1);
506c7045f51Skettenis 	} else if (major(cn_tab->cn_dev) == major(framebuffer)) {
5075f7ab753Skettenis 		if (strlen(framebuffer_path) == 0)
5085cfe0970Skettenis 			return;
5095cfe0970Skettenis 
5105cfe0970Skettenis 		/* Point stdout-path at the framebuffer node. */
5115f7ab753Skettenis 		node = fdt_find_node("/chosen");
5125f7ab753Skettenis 		fdt_node_add_property(node, "stdout-path",
5135f7ab753Skettenis 		    framebuffer_path, strlen(framebuffer_path) + 1);
5145cfe0970Skettenis 	}
515c7045f51Skettenis }
5165cfe0970Skettenis 
517a88d1494Skettenis uint64_t dma_constraint[2] = { 0, -1 };
518a88d1494Skettenis 
519a88d1494Skettenis void
520a88d1494Skettenis efi_dma_constraint(void)
521a88d1494Skettenis {
522a88d1494Skettenis 	void *node;
523cfb73cfeSpatrick 	char *prop;
524cfb73cfeSpatrick 	uint32_t *propint;
525cfb73cfeSpatrick 	uint64_t base, size;
526cfb73cfeSpatrick 	uint32_t pacells, pscells;
527cfb73cfeSpatrick 	uint32_t acells, scells;
528cfb73cfeSpatrick 	int len;
529cfb73cfeSpatrick 
530cfb73cfeSpatrick 	node = fdt_find_node("/");
531cfb73cfeSpatrick 	if (fdt_node_property_int(node, "#address-cells", &pacells) != 1)
532cfb73cfeSpatrick 		pacells = 1;
533cfb73cfeSpatrick 	if (fdt_node_property_int(node, "#size-cells", &pscells) != 1)
534cfb73cfeSpatrick 		pscells = 1;
535cfb73cfeSpatrick 	if (pacells > 2 || pscells > 2)
536cfb73cfeSpatrick 		return;
537cfb73cfeSpatrick 
538cfb73cfeSpatrick 	node = fdt_find_node("/soc");
539cfb73cfeSpatrick 	if (node != NULL) {
540cfb73cfeSpatrick 		if (fdt_node_property_int(node, "#address-cells", &acells) != 1)
541cfb73cfeSpatrick 			acells = pacells;
542cfb73cfeSpatrick 		if (fdt_node_property_int(node, "#size-cells", &scells) != 1)
543cfb73cfeSpatrick 			scells = pscells;
544cfb73cfeSpatrick 		if (acells > 2 || scells > 2)
545cfb73cfeSpatrick 			return;
546cfb73cfeSpatrick 
547cfb73cfeSpatrick 		len = fdt_node_property(node, "dma-ranges", &prop);
548cfb73cfeSpatrick 		propint = (uint32_t *)prop;
549cfb73cfeSpatrick 		if (len == (acells + pacells + scells) * sizeof(uint32_t)) {
550cfb73cfeSpatrick 			base = betoh32(propint[acells]);
551cfb73cfeSpatrick 			if (pacells == 2)
552cfb73cfeSpatrick 				base = (base << 32) |
553cfb73cfeSpatrick 				    betoh32(propint[acells + 1]);
554cfb73cfeSpatrick 			size = betoh32(propint[acells + pacells]);
555cfb73cfeSpatrick 			if (scells == 2)
556cfb73cfeSpatrick 				size = (size << 32) |
557cfb73cfeSpatrick 				    betoh32(propint[acells + pacells + 1]);
558cfb73cfeSpatrick 
559cfb73cfeSpatrick 			dma_constraint[0] = htobe64(base);
560cfb73cfeSpatrick 			dma_constraint[1] = htobe64(base + size - 1);
561cfb73cfeSpatrick 		}
562cfb73cfeSpatrick 	}
563a88d1494Skettenis 
564a88d1494Skettenis 	/* Raspberry Pi 4 is "special". */
565a88d1494Skettenis 	node = fdt_find_node("/");
566a88d1494Skettenis 	if (fdt_node_is_compatible(node, "brcm,bcm2711"))
567a88d1494Skettenis 		dma_constraint[1] = htobe64(0x3bffffff);
568a88d1494Skettenis 
569a88d1494Skettenis 	/* Pass DMA constraint. */
570a88d1494Skettenis 	node = fdt_find_node("/chosen");
571a88d1494Skettenis 	fdt_node_add_property(node, "openbsd,dma-constraint",
572a88d1494Skettenis 	    dma_constraint, sizeof(dma_constraint));
573a88d1494Skettenis }
574a88d1494Skettenis 
575be07ee62Skettenis int acpi = 0;
5769ccb13abSnaddy char *bootmac = NULL;
577f24071e5Spatrick 
578f24071e5Spatrick void *
5799419d8aaSkettenis efi_makebootargs(char *bootargs, int howto)
580f24071e5Spatrick {
5815b351376Spatrick 	struct sr_boot_volume *bv;
582f4dd1aebSkettenis 	u_char bootduid[8];
583f4dd1aebSkettenis 	u_char zero[8] = { 0 };
584f4dd1aebSkettenis 	uint64_t uefi_system_table = htobe64((uintptr_t)ST);
5859419d8aaSkettenis 	uint32_t boothowto = htobe32(howto);
58658554311Spatrick 	EFI_PHYSICAL_ADDRESS addr;
587f24071e5Spatrick 	void *node;
588f24071e5Spatrick 	size_t len;
589f24071e5Spatrick 
590be07ee62Skettenis 	if (fdt == NULL || acpi)
5919a1480b1Skettenis 		fdt = efi_acpi();
5929a1480b1Skettenis 
59358554311Spatrick 	if (!fdt_get_size(fdt))
59458554311Spatrick 		return NULL;
59558554311Spatrick 
59658554311Spatrick 	len = roundup(fdt_get_size(fdt) + PAGE_SIZE, PAGE_SIZE);
59758554311Spatrick 	if (BS->AllocatePages(AllocateAnyPages, EfiLoaderData,
59858554311Spatrick 	    EFI_SIZE_TO_PAGES(len), &addr) == EFI_SUCCESS) {
59958554311Spatrick 		memcpy((void *)addr, fdt, fdt_get_size(fdt));
600259d2111Skettenis 		((struct fdt_head *)addr)->fh_size = htobe32(len);
60158554311Spatrick 		fdt = (void *)addr;
60258554311Spatrick 	}
60358554311Spatrick 
604f24071e5Spatrick 	if (!fdt_init(fdt))
605f24071e5Spatrick 		return NULL;
606f24071e5Spatrick 
607*bd928107Spatrick 	/* Create common nodes which might not exist when using mach dtb */
608*bd928107Spatrick 	node = fdt_find_node("/aliases");
609*bd928107Spatrick 	if (node == NULL)
610*bd928107Spatrick 		fdt_node_add_node(fdt_find_node("/"), "aliases", &node);
611f24071e5Spatrick 	node = fdt_find_node("/chosen");
612*bd928107Spatrick 	if (node == NULL)
613*bd928107Spatrick 		fdt_node_add_node(fdt_find_node("/"), "chosen", &node);
614f24071e5Spatrick 
615*bd928107Spatrick 	node = fdt_find_node("/chosen");
616f24071e5Spatrick 	len = strlen(bootargs) + 1;
617f24071e5Spatrick 	fdt_node_add_property(node, "bootargs", bootargs, len);
6189419d8aaSkettenis 	fdt_node_add_property(node, "openbsd,boothowto",
6199419d8aaSkettenis 	    &boothowto, sizeof(boothowto));
620f24071e5Spatrick 
621f24071e5Spatrick 	/* Pass DUID of the boot disk. */
6225b351376Spatrick 	if (bootdev_dip) {
6235b351376Spatrick 		memcpy(&bootduid, bootdev_dip->disklabel.d_uid,
624f24071e5Spatrick 		    sizeof(bootduid));
6255b351376Spatrick 		if (memcmp(bootduid, zero, sizeof(bootduid)) != 0) {
6265b351376Spatrick 			fdt_node_add_property(node, "openbsd,bootduid",
6275b351376Spatrick 			    bootduid, sizeof(bootduid));
628f24071e5Spatrick 		}
629f24071e5Spatrick 
6305b351376Spatrick 		if (bootdev_dip->sr_vol != NULL) {
6315b351376Spatrick 			bv = bootdev_dip->sr_vol;
6325b351376Spatrick 			fdt_node_add_property(node, "openbsd,sr-bootuuid",
6335b351376Spatrick 			    &bv->sbv_uuid, sizeof(bv->sbv_uuid));
6345b351376Spatrick 			if (bv->sbv_maskkey != NULL)
6355b351376Spatrick 				fdt_node_add_property(node,
6365b351376Spatrick 				    "openbsd,sr-bootkey", bv->sbv_maskkey,
6375b351376Spatrick 				    SR_CRYPTO_MAXKEYBYTES);
6385b351376Spatrick 		}
6395b351376Spatrick 	}
6405b351376Spatrick 
6415b351376Spatrick 	sr_clear_keys();
6425b351376Spatrick 
6439ccb13abSnaddy 	/* Pass netboot interface address. */
6449ccb13abSnaddy 	if (bootmac)
6459ccb13abSnaddy 		fdt_node_add_property(node, "openbsd,bootmac", bootmac, 6);
6469ccb13abSnaddy 
647f4dd1aebSkettenis 	/* Pass EFI system table. */
648f4dd1aebSkettenis 	fdt_node_add_property(node, "openbsd,uefi-system-table",
649f4dd1aebSkettenis 	    &uefi_system_table, sizeof(uefi_system_table));
650f4dd1aebSkettenis 
651f4dd1aebSkettenis 	/* Placeholders for EFI memory map. */
652f4dd1aebSkettenis 	fdt_node_add_property(node, "openbsd,uefi-mmap-start", zero, 8);
653f4dd1aebSkettenis 	fdt_node_add_property(node, "openbsd,uefi-mmap-size", zero, 4);
654f4dd1aebSkettenis 	fdt_node_add_property(node, "openbsd,uefi-mmap-desc-size", zero, 4);
655f4dd1aebSkettenis 	fdt_node_add_property(node, "openbsd,uefi-mmap-desc-ver", zero, 4);
656f4dd1aebSkettenis 
6571e44dc38Skettenis 	efi_framebuffer();
6585cfe0970Skettenis 	efi_console();
659a88d1494Skettenis 	efi_dma_constraint();
6601e44dc38Skettenis 
661f24071e5Spatrick 	fdt_finalize();
662f24071e5Spatrick 
663f24071e5Spatrick 	return fdt;
664f24071e5Spatrick }
665f24071e5Spatrick 
666f4dd1aebSkettenis void
667f4dd1aebSkettenis efi_updatefdt(void)
668f4dd1aebSkettenis {
669f4dd1aebSkettenis 	uint64_t uefi_mmap_start = htobe64((uintptr_t)mmap);
670f4dd1aebSkettenis 	uint32_t uefi_mmap_size = htobe32(mmap_ndesc * mmap_descsiz);
671f4dd1aebSkettenis 	uint32_t uefi_mmap_desc_size = htobe32(mmap_descsiz);
672f4dd1aebSkettenis 	uint32_t uefi_mmap_desc_ver = htobe32(mmap_version);
673f4dd1aebSkettenis 	void *node;
674f4dd1aebSkettenis 
675f4dd1aebSkettenis 	node = fdt_find_node("/chosen");
676f4dd1aebSkettenis 	if (!node)
677f4dd1aebSkettenis 		return;
678f4dd1aebSkettenis 
679f4dd1aebSkettenis 	/* Pass EFI memory map. */
680f4dd1aebSkettenis 	fdt_node_set_property(node, "openbsd,uefi-mmap-start",
681f4dd1aebSkettenis 	    &uefi_mmap_start, sizeof(uefi_mmap_start));
682f4dd1aebSkettenis 	fdt_node_set_property(node, "openbsd,uefi-mmap-size",
683f4dd1aebSkettenis 	    &uefi_mmap_size, sizeof(uefi_mmap_size));
684f4dd1aebSkettenis 	fdt_node_set_property(node, "openbsd,uefi-mmap-desc-size",
685f4dd1aebSkettenis 	    &uefi_mmap_desc_size, sizeof(uefi_mmap_desc_size));
686f4dd1aebSkettenis 	fdt_node_set_property(node, "openbsd,uefi-mmap-desc-ver",
687f4dd1aebSkettenis 	    &uefi_mmap_desc_ver, sizeof(uefi_mmap_desc_ver));
688f4dd1aebSkettenis 
689f4dd1aebSkettenis 	fdt_finalize();
690f4dd1aebSkettenis }
691f4dd1aebSkettenis 
692f24071e5Spatrick u_long efi_loadaddr;
693f24071e5Spatrick 
694f24071e5Spatrick void
695f24071e5Spatrick machdep(void)
696f24071e5Spatrick {
697f24071e5Spatrick 	EFI_PHYSICAL_ADDRESS addr;
698f24071e5Spatrick 
699f24071e5Spatrick 	cninit();
700f24071e5Spatrick 	efi_heap_init();
701f24071e5Spatrick 
702f24071e5Spatrick 	/*
7039a118d7eSpatrick 	 * The kernel expects to be loaded into a block of memory aligned
7049a118d7eSpatrick 	 * on a 2MB boundary.  We allocate a block of 64MB of memory, which
7059a118d7eSpatrick 	 * gives us plenty of room for growth.
706f24071e5Spatrick 	 */
7079a118d7eSpatrick 	if (efi_memprobe_find(EFI_SIZE_TO_PAGES(64 * 1024 * 1024),
7082c32ef33Skettenis 	    0x200000, EfiLoaderCode, &addr) != EFI_SUCCESS)
709f24071e5Spatrick 		printf("Can't allocate memory\n");
710f24071e5Spatrick 	efi_loadaddr = addr;
711f24071e5Spatrick 
712f24071e5Spatrick 	efi_timer_init();
713f24071e5Spatrick 	efi_diskprobe();
71433e5575aSpatrick 	efi_pxeprobe();
715f24071e5Spatrick }
716f24071e5Spatrick 
717f24071e5Spatrick void
718f24071e5Spatrick efi_cleanup(void)
719f24071e5Spatrick {
720fa854029Spatrick 	int		 retry;
721fa854029Spatrick 	EFI_STATUS	 status;
722fa854029Spatrick 
723f24071e5Spatrick 	efi_timer_cleanup();
724f24071e5Spatrick 
725fa854029Spatrick 	/* retry once in case of failure */
726fa854029Spatrick 	for (retry = 1; retry >= 0; retry--) {
727fa854029Spatrick 		efi_memprobe_internal();	/* sync the current map */
728f4dd1aebSkettenis 		efi_updatefdt();
7291f462730Skrw 		status = BS->ExitBootServices(IH, mmap_key);
730fa854029Spatrick 		if (status == EFI_SUCCESS)
731fa854029Spatrick 			break;
732fa854029Spatrick 		if (retry == 0)
733fa854029Spatrick 			panic("ExitBootServices failed (%d)", status);
734fa854029Spatrick 	}
735f24071e5Spatrick }
736f24071e5Spatrick 
737f24071e5Spatrick void
738f24071e5Spatrick _rtt(void)
739f24071e5Spatrick {
740f24071e5Spatrick #ifdef EFI_DEBUG
741f24071e5Spatrick 	printf("Hit any key to reboot\n");
742f24071e5Spatrick 	efi_cons_getc(0);
743f24071e5Spatrick #endif
744f24071e5Spatrick 	RS->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL);
745111d6387Skettenis 	for (;;)
746111d6387Skettenis 		continue;
747f24071e5Spatrick }
748f24071e5Spatrick 
749f24071e5Spatrick /*
750f24071e5Spatrick  * U-Boot only implements the GetTime() Runtime Service if it has been
751f24071e5Spatrick  * configured with CONFIG_DM_RTC.  Most board configurations don't
752f24071e5Spatrick  * include that option, so we can't use it to implement our boot
753f24071e5Spatrick  * prompt timeout.  Instead we use timer events to simulate a clock
754f24071e5Spatrick  * that ticks ever second.
755f24071e5Spatrick  */
756f24071e5Spatrick 
757f24071e5Spatrick EFI_EVENT timer;
758f24071e5Spatrick int ticks;
759f24071e5Spatrick 
760f24071e5Spatrick static VOID
761f24071e5Spatrick efi_timer(EFI_EVENT event, VOID *context)
762f24071e5Spatrick {
763f24071e5Spatrick 	ticks++;
764f24071e5Spatrick }
765f24071e5Spatrick 
766f24071e5Spatrick static void
767f24071e5Spatrick efi_timer_init(void)
768f24071e5Spatrick {
769f24071e5Spatrick 	EFI_STATUS status;
770f24071e5Spatrick 
771a4d88df4Sjsg 	status = BS->CreateEvent(EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_CALLBACK,
772f24071e5Spatrick 	    efi_timer, NULL, &timer);
773f24071e5Spatrick 	if (status == EFI_SUCCESS)
774f24071e5Spatrick 		status = BS->SetTimer(timer, TimerPeriodic, 10000000);
775f24071e5Spatrick 	if (EFI_ERROR(status))
776f24071e5Spatrick 		printf("Can't create timer\n");
777f24071e5Spatrick }
778f24071e5Spatrick 
779f24071e5Spatrick static void
780f24071e5Spatrick efi_timer_cleanup(void)
781f24071e5Spatrick {
782f24071e5Spatrick 	BS->CloseEvent(timer);
783f24071e5Spatrick }
784f24071e5Spatrick 
785f24071e5Spatrick time_t
786f24071e5Spatrick getsecs(void)
787f24071e5Spatrick {
788f24071e5Spatrick 	return ticks;
789f24071e5Spatrick }
790f24071e5Spatrick 
791f24071e5Spatrick /*
792f24071e5Spatrick  * Various device-related bits.
793f24071e5Spatrick  */
794f24071e5Spatrick 
795f24071e5Spatrick void
796f24071e5Spatrick devboot(dev_t dev, char *p)
797f24071e5Spatrick {
7985b351376Spatrick 	struct sr_boot_volume *bv;
7995b351376Spatrick 	struct sr_boot_chunk *bc;
8005b351376Spatrick 	struct diskinfo *dip;
8015b351376Spatrick 	int sd_boot_vol = 0;
8025b351376Spatrick 	int sr_boot_vol = -1;
8035b351376Spatrick 	int part_type = FS_UNUSED;
8045b351376Spatrick 
8055b351376Spatrick 	if (bootdev_dip == NULL) {
80633e5575aSpatrick 		strlcpy(p, "tftp0a", 7);
8075b351376Spatrick 		return;
8085b351376Spatrick 	}
8095b351376Spatrick 
8105b351376Spatrick 	TAILQ_FOREACH(dip, &disklist, list) {
8115b351376Spatrick 		if (bootdev_dip == dip)
8125b351376Spatrick 			break;
8135b351376Spatrick 		sd_boot_vol++;
8145b351376Spatrick 	}
8155b351376Spatrick 
8165b351376Spatrick 	/*
8175b351376Spatrick 	 * Determine the partition type for the 'a' partition of the
8185b351376Spatrick 	 * boot device.
8195b351376Spatrick 	 */
8205b351376Spatrick 	if ((bootdev_dip->flags & DISKINFO_FLAG_GOODLABEL) != 0)
8215b351376Spatrick 		part_type = bootdev_dip->disklabel.d_partitions[0].p_fstype;
8225b351376Spatrick 
8235b351376Spatrick 	/*
8245b351376Spatrick 	 * See if we booted from a disk that is a member of a bootable
8255b351376Spatrick 	 * softraid volume.
8265b351376Spatrick 	 */
8275b351376Spatrick 	SLIST_FOREACH(bv, &sr_volumes, sbv_link) {
8285b351376Spatrick 		SLIST_FOREACH(bc, &bv->sbv_chunks, sbc_link)
8295b351376Spatrick 			if (bc->sbc_diskinfo == bootdev_dip)
8305b351376Spatrick 				sr_boot_vol = bv->sbv_unit;
8315b351376Spatrick 		if (sr_boot_vol != -1)
8325b351376Spatrick 			break;
8335b351376Spatrick 	}
8345b351376Spatrick 
8355b351376Spatrick 	if (sr_boot_vol != -1 && part_type != FS_BSDFFS) {
8365b351376Spatrick 		strlcpy(p, "sr0a", 5);
8375b351376Spatrick 		p[2] = '0' + sr_boot_vol;
8385b351376Spatrick 		return;
8395b351376Spatrick 	}
8405b351376Spatrick 
8415b351376Spatrick 	strlcpy(p, "sd0a", 5);
8425b351376Spatrick 	p[2] = '0' + sd_boot_vol;
843f24071e5Spatrick }
844f24071e5Spatrick 
845c7045f51Skettenis const char cdevs[][4] = { "cons", "com", "fb" };
8465cfe0970Skettenis const int ncdevs = nitems(cdevs);
8475cfe0970Skettenis 
848f24071e5Spatrick int
849f24071e5Spatrick cnspeed(dev_t dev, int sp)
850f24071e5Spatrick {
851f24071e5Spatrick 	return 115200;
852f24071e5Spatrick }
853f24071e5Spatrick 
8545cfe0970Skettenis char ttyname_buf[8];
8555cfe0970Skettenis 
856f24071e5Spatrick char *
857f24071e5Spatrick ttyname(int fd)
858f24071e5Spatrick {
8595cfe0970Skettenis 	snprintf(ttyname_buf, sizeof ttyname_buf, "%s%d",
8605cfe0970Skettenis 	    cdevs[major(cn_tab->cn_dev)], minor(cn_tab->cn_dev));
8615cfe0970Skettenis 
8625cfe0970Skettenis 	return ttyname_buf;
863f24071e5Spatrick }
864f24071e5Spatrick 
865f24071e5Spatrick dev_t
866f24071e5Spatrick ttydev(char *name)
867f24071e5Spatrick {
8685cfe0970Skettenis 	int i, unit = -1;
8695cfe0970Skettenis 	char *no = name + strlen(name) - 1;
8705cfe0970Skettenis 
8715cfe0970Skettenis 	while (no >= name && *no >= '0' && *no <= '9')
8725cfe0970Skettenis 		unit = (unit < 0 ? 0 : (unit * 10)) + *no-- - '0';
8735cfe0970Skettenis 	if (no < name || unit < 0)
8745cfe0970Skettenis 		return NODEV;
8755cfe0970Skettenis 	for (i = 0; i < ncdevs; i++)
8765cfe0970Skettenis 		if (strncmp(name, cdevs[i], no - name + 1) == 0)
8775cfe0970Skettenis 			return makedev(i, unit);
878f24071e5Spatrick 	return NODEV;
879f24071e5Spatrick }
880f24071e5Spatrick 
881f24071e5Spatrick #define MAXDEVNAME	16
882f24071e5Spatrick 
883f24071e5Spatrick /*
884f24071e5Spatrick  * Parse a device spec.
885f24071e5Spatrick  *
886f24071e5Spatrick  * [A-Za-z]*[0-9]*[A-Za-z]:file
887f24071e5Spatrick  *    dev   uint    part
888f24071e5Spatrick  */
889f24071e5Spatrick int
890f24071e5Spatrick devparse(const char *fname, int *dev, int *unit, int *part, const char **file)
891f24071e5Spatrick {
892f24071e5Spatrick 	const char *s;
893f24071e5Spatrick 
894f24071e5Spatrick 	*unit = 0;	/* default to wd0a */
895f24071e5Spatrick 	*part = 0;
896f24071e5Spatrick 	*dev  = 0;
897f24071e5Spatrick 
898f24071e5Spatrick 	s = strchr(fname, ':');
899f24071e5Spatrick 	if (s != NULL) {
900f24071e5Spatrick 		int devlen;
901f24071e5Spatrick 		int i, u, p = 0;
902f24071e5Spatrick 		struct devsw *dp;
903f24071e5Spatrick 		char devname[MAXDEVNAME];
904f24071e5Spatrick 
905f24071e5Spatrick 		devlen = s - fname;
906f24071e5Spatrick 		if (devlen > MAXDEVNAME)
907f24071e5Spatrick 			return (EINVAL);
908f24071e5Spatrick 
909f24071e5Spatrick 		/* extract device name */
910f24071e5Spatrick 		for (i = 0; isalpha(fname[i]) && (i < devlen); i++)
911f24071e5Spatrick 			devname[i] = fname[i];
912f24071e5Spatrick 		devname[i] = 0;
913f24071e5Spatrick 
914f24071e5Spatrick 		if (!isdigit(fname[i]))
915f24071e5Spatrick 			return (EUNIT);
916f24071e5Spatrick 
917f24071e5Spatrick 		/* device number */
918f24071e5Spatrick 		for (u = 0; isdigit(fname[i]) && (i < devlen); i++)
919f24071e5Spatrick 			u = u * 10 + (fname[i] - '0');
920f24071e5Spatrick 
921f24071e5Spatrick 		if (!isalpha(fname[i]))
922f24071e5Spatrick 			return (EPART);
923f24071e5Spatrick 
924f24071e5Spatrick 		/* partition number */
925f24071e5Spatrick 		if (i < devlen)
926f24071e5Spatrick 			p = fname[i++] - 'a';
927f24071e5Spatrick 
928f24071e5Spatrick 		if (i != devlen)
929f24071e5Spatrick 			return (ENXIO);
930f24071e5Spatrick 
931f24071e5Spatrick 		/* check device name */
932f24071e5Spatrick 		for (dp = devsw, i = 0; i < ndevs; dp++, i++) {
933f24071e5Spatrick 			if (dp->dv_name && !strcmp(devname, dp->dv_name))
934f24071e5Spatrick 				break;
935f24071e5Spatrick 		}
936f24071e5Spatrick 
937f24071e5Spatrick 		if (i >= ndevs)
938f24071e5Spatrick 			return (ENXIO);
939f24071e5Spatrick 
940f24071e5Spatrick 		*unit = u;
941f24071e5Spatrick 		*part = p;
942f24071e5Spatrick 		*dev  = i;
943f24071e5Spatrick 		fname = ++s;
944f24071e5Spatrick 	}
945f24071e5Spatrick 
946f24071e5Spatrick 	*file = fname;
947f24071e5Spatrick 
948f24071e5Spatrick 	return (0);
949f24071e5Spatrick }
950f24071e5Spatrick 
951f24071e5Spatrick int
952f24071e5Spatrick devopen(struct open_file *f, const char *fname, char **file)
953f24071e5Spatrick {
954f24071e5Spatrick 	struct devsw *dp;
955f24071e5Spatrick 	int dev, unit, part, error;
956f24071e5Spatrick 
957f24071e5Spatrick 	error = devparse(fname, &dev, &unit, &part, (const char **)file);
958f24071e5Spatrick 	if (error)
959f24071e5Spatrick 		return (error);
960f24071e5Spatrick 
96133e5575aSpatrick 	dp = &devsw[dev];
962f24071e5Spatrick 	f->f_dev = dp;
963f24071e5Spatrick 
964ad424d98Snaddy 	if (strcmp("tftp", dp->dv_name) != 0) {
965ad424d98Snaddy 		/*
966ad424d98Snaddy 		 * Clear bootmac, to signal that we loaded this file from a
967ad424d98Snaddy 		 * non-network device.
968ad424d98Snaddy 		 */
969ad424d98Snaddy 		bootmac = NULL;
970ad424d98Snaddy 	}
971ad424d98Snaddy 
972f24071e5Spatrick 	return (*dp->dv_open)(f, unit, part);
973f24071e5Spatrick }
974f24071e5Spatrick 
975fa854029Spatrick static void
976fa854029Spatrick efi_memprobe_internal(void)
977fa854029Spatrick {
978fa854029Spatrick 	EFI_STATUS		 status;
979fa854029Spatrick 	UINTN			 mapkey, mmsiz, siz;
980fa854029Spatrick 	UINT32			 mmver;
981fa854029Spatrick 	EFI_MEMORY_DESCRIPTOR	*mm;
982fa854029Spatrick 	int			 n;
983fa854029Spatrick 
984fa854029Spatrick 	free(mmap, mmap_ndesc * mmap_descsiz);
985fa854029Spatrick 
986fa854029Spatrick 	siz = 0;
9871f462730Skrw 	status = BS->GetMemoryMap(&siz, NULL, &mapkey, &mmsiz, &mmver);
988fa854029Spatrick 	if (status != EFI_BUFFER_TOO_SMALL)
989fa854029Spatrick 		panic("cannot get the size of memory map");
990fa854029Spatrick 	mm = alloc(siz);
9911f462730Skrw 	status = BS->GetMemoryMap(&siz, mm, &mapkey, &mmsiz, &mmver);
992fa854029Spatrick 	if (status != EFI_SUCCESS)
993fa854029Spatrick 		panic("cannot get the memory map");
994fa854029Spatrick 	n = siz / mmsiz;
995fa854029Spatrick 	mmap = mm;
996fa854029Spatrick 	mmap_key = mapkey;
997fa854029Spatrick 	mmap_ndesc = n;
998fa854029Spatrick 	mmap_descsiz = mmsiz;
999f4dd1aebSkettenis 	mmap_version = mmver;
1000fa854029Spatrick }
1001fa854029Spatrick 
1002f24071e5Spatrick /*
1003f24071e5Spatrick  * 64-bit ARMs can have a much wider memory mapping, as in somewhere
1004f24071e5Spatrick  * after the 32-bit region.  To cope with our alignment requirement,
1005f24071e5Spatrick  * use the memory table to find a place where we can fit.
1006f24071e5Spatrick  */
1007f24071e5Spatrick static EFI_STATUS
10082c32ef33Skettenis efi_memprobe_find(UINTN pages, UINTN align, EFI_MEMORY_TYPE type,
10092c32ef33Skettenis     EFI_PHYSICAL_ADDRESS *addr)
1010f24071e5Spatrick {
1011fa854029Spatrick 	EFI_MEMORY_DESCRIPTOR	*mm;
1012fa854029Spatrick 	int			 i, j;
1013f24071e5Spatrick 
1014f24071e5Spatrick 	if (align < EFI_PAGE_SIZE)
1015f24071e5Spatrick 		return EFI_INVALID_PARAMETER;
1016f24071e5Spatrick 
1017fa854029Spatrick 	efi_memprobe_internal();	/* sync the current map */
1018f24071e5Spatrick 
1019fa854029Spatrick 	for (i = 0, mm = mmap; i < mmap_ndesc;
1020fa854029Spatrick 	    i++, mm = NextMemoryDescriptor(mm, mmap_descsiz)) {
1021f24071e5Spatrick 		if (mm->Type != EfiConventionalMemory)
1022f24071e5Spatrick 			continue;
1023f24071e5Spatrick 
1024f24071e5Spatrick 		if (mm->NumberOfPages < pages)
1025f24071e5Spatrick 			continue;
1026f24071e5Spatrick 
1027f2c0e408Skettenis 		for (j = 0; j < mm->NumberOfPages; j++) {
1028f24071e5Spatrick 			EFI_PHYSICAL_ADDRESS paddr;
1029f24071e5Spatrick 
1030f24071e5Spatrick 			if (mm->NumberOfPages - j < pages)
1031f24071e5Spatrick 				break;
1032f24071e5Spatrick 
1033f24071e5Spatrick 			paddr = mm->PhysicalStart + (j * EFI_PAGE_SIZE);
103473dc1409Spatrick 			if (paddr & (align - 1))
103573dc1409Spatrick 				continue;
103673dc1409Spatrick 
10372c32ef33Skettenis 			if (BS->AllocatePages(AllocateAddress, type,
10381f462730Skrw 			    pages, &paddr) == EFI_SUCCESS) {
1039f24071e5Spatrick 				*addr = paddr;
1040f24071e5Spatrick 				return EFI_SUCCESS;
1041f24071e5Spatrick 			}
1042f24071e5Spatrick 		}
1043f24071e5Spatrick 	}
1044f24071e5Spatrick 	return EFI_OUT_OF_RESOURCES;
1045f24071e5Spatrick }
1046111d6387Skettenis 
1047f3468426Skettenis int
1048f3468426Skettenis mdrandom(char *buf, size_t buflen)
1049f3468426Skettenis {
1050f3468426Skettenis 	char *random;
1051f3468426Skettenis 	void *node;
1052f3468426Skettenis 	int i, len, ret = -1;
1053f3468426Skettenis 
1054f3468426Skettenis 	node = fdt_find_node("/chosen");
1055f3468426Skettenis 	if (!node)
1056f3468426Skettenis 		return -1;
1057f3468426Skettenis 
1058f3468426Skettenis 	len = fdt_node_property(node, "rng-seed", &random);
1059f3468426Skettenis 	if (len > 0) {
1060f3468426Skettenis 		for (i = 0; i < buflen; i++)
1061f3468426Skettenis 			buf[i] ^= random[i % len];
1062f3468426Skettenis 		ret = 0;
1063f3468426Skettenis 	}
1064f3468426Skettenis 
1065f3468426Skettenis 	len = fdt_node_property(node, "kaslr-seed", &random);
1066f3468426Skettenis 	if (len > 0) {
1067f3468426Skettenis 		for (i = 0; i < buflen; i++)
1068f3468426Skettenis 			buf[i] ^= random[i % len];
1069f3468426Skettenis 		ret = 0;
1070f3468426Skettenis 	}
1071f3468426Skettenis 
1072f3468426Skettenis 	return ret;
1073f3468426Skettenis }
1074f3468426Skettenis 
1075111d6387Skettenis /*
1076111d6387Skettenis  * Commands
1077111d6387Skettenis  */
1078111d6387Skettenis 
1079be07ee62Skettenis int Xacpi_efi(void);
10806f83097eSpatrick int Xdtb_efi(void);
1081111d6387Skettenis int Xexit_efi(void);
1082111d6387Skettenis int Xpoweroff_efi(void);
1083111d6387Skettenis 
1084111d6387Skettenis const struct cmd_table cmd_machine[] = {
1085be07ee62Skettenis 	{ "acpi",	CMDT_CMD, Xacpi_efi },
10866f83097eSpatrick 	{ "dtb",	CMDT_CMD, Xdtb_efi },
1087111d6387Skettenis 	{ "exit",	CMDT_CMD, Xexit_efi },
1088111d6387Skettenis 	{ "poweroff",	CMDT_CMD, Xpoweroff_efi },
1089111d6387Skettenis 	{ NULL, 0 }
1090111d6387Skettenis };
1091111d6387Skettenis 
1092111d6387Skettenis int
1093be07ee62Skettenis Xacpi_efi(void)
1094be07ee62Skettenis {
1095be07ee62Skettenis 	acpi = 1;
1096be07ee62Skettenis 	return (0);
1097be07ee62Skettenis }
1098be07ee62Skettenis 
1099be07ee62Skettenis int
11006f83097eSpatrick Xdtb_efi(void)
11016f83097eSpatrick {
11026f83097eSpatrick 	EFI_PHYSICAL_ADDRESS addr;
11036f83097eSpatrick 	char path[MAXPATHLEN];
11046f83097eSpatrick 	struct stat sb;
11056f83097eSpatrick 	int fd;
11066f83097eSpatrick 
1107fcf3d43cSkn 	if (cmd.argc != 2) {
1108fcf3d43cSkn 		printf("dtb file\n");
1109fcf3d43cSkn 		return (0);
1110fcf3d43cSkn 	}
11116f83097eSpatrick 
11126f83097eSpatrick 	snprintf(path, sizeof(path), "%s:%s", cmd.bootdev, cmd.argv[1]);
11136f83097eSpatrick 
11146f83097eSpatrick 	fd = open(path, O_RDONLY);
11156f83097eSpatrick 	if (fd < 0 || fstat(fd, &sb) == -1) {
11166f83097eSpatrick 		printf("cannot open %s\n", path);
1117fcf3d43cSkn 		return (0);
11186f83097eSpatrick 	}
11196f83097eSpatrick 	if (efi_memprobe_find(EFI_SIZE_TO_PAGES(sb.st_size),
11202c32ef33Skettenis 	    PAGE_SIZE, EfiLoaderData, &addr) != EFI_SUCCESS) {
11216f83097eSpatrick 		printf("cannot allocate memory for %s\n", path);
1122fcf3d43cSkn 		return (0);
11236f83097eSpatrick 	}
11246f83097eSpatrick 	if (read(fd, (void *)addr, sb.st_size) != sb.st_size) {
11256f83097eSpatrick 		printf("cannot read from %s\n", path);
1126fcf3d43cSkn 		return (0);
11276f83097eSpatrick 	}
11286f83097eSpatrick 
11296f83097eSpatrick 	fdt = (void *)addr;
11302b622a11Spatrick 	fdt_init(fdt);
11316f83097eSpatrick 	return (0);
11326f83097eSpatrick }
11336f83097eSpatrick 
11346f83097eSpatrick int
1135111d6387Skettenis Xexit_efi(void)
1136111d6387Skettenis {
11371f462730Skrw 	BS->Exit(IH, 0, 0, NULL);
1138111d6387Skettenis 	for (;;)
1139111d6387Skettenis 		continue;
1140111d6387Skettenis 	return (0);
1141111d6387Skettenis }
1142111d6387Skettenis 
1143111d6387Skettenis int
1144111d6387Skettenis Xpoweroff_efi(void)
1145111d6387Skettenis {
11461f462730Skrw 	RS->ResetSystem(EfiResetShutdown, EFI_SUCCESS, 0, NULL);
1147111d6387Skettenis 	return (0);
1148111d6387Skettenis }
1149