xref: /openbsd/sys/arch/arm64/stand/efiboot/efiboot.c (revision d6abfaa7)
1*d6abfaa7Skettenis /*	$OpenBSD: efiboot.c,v 1.50 2024/02/23 21:52:12 kettenis 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;
504befd8f0Spatrick void			*fdt_sys = NULL;
514befd8f0Spatrick void			*fdt_override = NULL;
524befd8f0Spatrick size_t			 fdt_override_size;
534befd8f0Spatrick void			*smbios = NULL;
54f24071e5Spatrick 
55fa854029Spatrick EFI_PHYSICAL_ADDRESS	 heap;
56fa854029Spatrick UINTN			 heapsiz = 1 * 1024 * 1024;
57f673f4ddSkettenis EFI_MEMORY_DESCRIPTOR	*mmap;
58fa854029Spatrick UINTN			 mmap_key;
59fa854029Spatrick UINTN			 mmap_ndesc;
60fa854029Spatrick UINTN			 mmap_descsiz;
61f4dd1aebSkettenis UINT32			 mmap_version;
62f24071e5Spatrick 
63f24071e5Spatrick static EFI_GUID		 imgp_guid = LOADED_IMAGE_PROTOCOL;
64f24071e5Spatrick static EFI_GUID		 blkio_guid = BLOCK_IO_PROTOCOL;
65f24071e5Spatrick static EFI_GUID		 devp_guid = DEVICE_PATH_PROTOCOL;
661e44dc38Skettenis static EFI_GUID		 gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
67f3468426Skettenis static EFI_GUID		 fdt_guid = FDT_TABLE_GUID;
684befd8f0Spatrick static EFI_GUID		 smbios_guid = SMBIOS_TABLE_GUID;
694befd8f0Spatrick static EFI_GUID		 smbios3_guid = SMBIOS3_TABLE_GUID;
70f3468426Skettenis 
7149dff005Sderaadt #define efi_guidcmp(_a, _b)	memcmp((_a), (_b), sizeof(EFI_GUID))
72f24071e5Spatrick 
7333e5575aSpatrick int efi_device_path_depth(EFI_DEVICE_PATH *dp, int);
7433e5575aSpatrick int efi_device_path_ncmp(EFI_DEVICE_PATH *, EFI_DEVICE_PATH *, int);
75fa854029Spatrick static void efi_heap_init(void);
76fa854029Spatrick static void efi_memprobe_internal(void);
77f24071e5Spatrick static void efi_timer_init(void);
78f24071e5Spatrick static void efi_timer_cleanup(void);
792c32ef33Skettenis static EFI_STATUS efi_memprobe_find(UINTN, UINTN, EFI_MEMORY_TYPE,
802c32ef33Skettenis     EFI_PHYSICAL_ADDRESS *);
814befd8f0Spatrick void *efi_fdt(void);
824befd8f0Spatrick int fdt_load_override(char *);
834befd8f0Spatrick extern void smbios_init(void *);
84f24071e5Spatrick 
85f24071e5Spatrick EFI_STATUS
efi_main(EFI_HANDLE image,EFI_SYSTEM_TABLE * systab)86f24071e5Spatrick efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab)
87f24071e5Spatrick {
88f24071e5Spatrick 	extern char		*progname;
89f24071e5Spatrick 	EFI_LOADED_IMAGE	*imgp;
90f24071e5Spatrick 	EFI_DEVICE_PATH		*dp = NULL;
91f24071e5Spatrick 	EFI_STATUS		 status;
92f3468426Skettenis 	int			 i;
93f24071e5Spatrick 
94f24071e5Spatrick 	ST = systab;
95f24071e5Spatrick 	BS = ST->BootServices;
96496ffee0Spatrick 	RS = ST->RuntimeServices;
97f24071e5Spatrick 	IH = image;
98f24071e5Spatrick 
99f0da534cSjsg 	/* disable reset by watchdog after 5 minutes */
1001f462730Skrw 	BS->SetWatchdogTimer(0, 0, 0, NULL);
101f0da534cSjsg 
1021f462730Skrw 	status = BS->HandleProtocol(image, &imgp_guid,
103f24071e5Spatrick 	    (void **)&imgp);
104f24071e5Spatrick 	if (status == EFI_SUCCESS)
1051f462730Skrw 		status = BS->HandleProtocol(imgp->DeviceHandle, &devp_guid,
1061f462730Skrw 		    (void **)&dp);
107f24071e5Spatrick 	if (status == EFI_SUCCESS)
108f24071e5Spatrick 		efi_bootdp = dp;
109f24071e5Spatrick 
110f3468426Skettenis 	for (i = 0; i < ST->NumberOfTableEntries; i++) {
111f3468426Skettenis 		if (efi_guidcmp(&fdt_guid,
112f3468426Skettenis 		    &ST->ConfigurationTable[i].VendorGuid) == 0)
1134befd8f0Spatrick 			fdt_sys = ST->ConfigurationTable[i].VendorTable;
1144befd8f0Spatrick 		if (efi_guidcmp(&smbios_guid,
1154befd8f0Spatrick 		    &ST->ConfigurationTable[i].VendorGuid) == 0)
1164befd8f0Spatrick 			smbios = ST->ConfigurationTable[i].VendorTable;
1174befd8f0Spatrick 		if (efi_guidcmp(&smbios3_guid,
1184befd8f0Spatrick 		    &ST->ConfigurationTable[i].VendorGuid) == 0)
1194befd8f0Spatrick 			smbios = ST->ConfigurationTable[i].VendorTable;
120f3468426Skettenis 	}
1214befd8f0Spatrick 	fdt_init(fdt_sys);
122f3468426Skettenis 
123f24071e5Spatrick 	progname = "BOOTAA64";
124f24071e5Spatrick 
125f24071e5Spatrick 	boot(0);
126f24071e5Spatrick 
127f24071e5Spatrick 	return (EFI_SUCCESS);
128f24071e5Spatrick }
129f24071e5Spatrick 
130f24071e5Spatrick static SIMPLE_TEXT_OUTPUT_INTERFACE *conout;
131f24071e5Spatrick static SIMPLE_INPUT_INTERFACE *conin;
132f24071e5Spatrick 
1335cfe0970Skettenis /*
1345cfe0970Skettenis  * The device majors for these don't match the ones used by the
1355cfe0970Skettenis  * kernel.  That's fine.  They're just used as an index into the cdevs
1365cfe0970Skettenis  * array and never passed on to the kernel.
1375cfe0970Skettenis  */
138c7045f51Skettenis static dev_t serial = makedev(1, 0);
139c7045f51Skettenis static dev_t framebuffer = makedev(2, 0);
1405cfe0970Skettenis 
1415f7ab753Skettenis static char framebuffer_path[128];
1425f7ab753Skettenis 
143f24071e5Spatrick void
efi_cons_probe(struct consdev * cn)144f24071e5Spatrick efi_cons_probe(struct consdev *cn)
145f24071e5Spatrick {
146f24071e5Spatrick 	cn->cn_pri = CN_MIDPRI;
147c7045f51Skettenis 	cn->cn_dev = makedev(0, 0);
148f24071e5Spatrick }
149f24071e5Spatrick 
150f24071e5Spatrick void
efi_cons_init(struct consdev * cp)151f24071e5Spatrick efi_cons_init(struct consdev *cp)
152f24071e5Spatrick {
153f24071e5Spatrick 	conin = ST->ConIn;
154f24071e5Spatrick 	conout = ST->ConOut;
155f24071e5Spatrick }
156f24071e5Spatrick 
157f24071e5Spatrick int
efi_cons_getc(dev_t dev)158f24071e5Spatrick efi_cons_getc(dev_t dev)
159f24071e5Spatrick {
160f24071e5Spatrick 	EFI_INPUT_KEY	 key;
161f24071e5Spatrick 	EFI_STATUS	 status;
162f24071e5Spatrick #if 0
163f24071e5Spatrick 	UINTN		 dummy;
164f24071e5Spatrick #endif
165f24071e5Spatrick 	static int	 lastchar = 0;
166f24071e5Spatrick 
167f24071e5Spatrick 	if (lastchar) {
168f24071e5Spatrick 		int r = lastchar;
169f24071e5Spatrick 		if ((dev & 0x80) == 0)
170f24071e5Spatrick 			lastchar = 0;
171f24071e5Spatrick 		return (r);
172f24071e5Spatrick 	}
173f24071e5Spatrick 
174f24071e5Spatrick 	status = conin->ReadKeyStroke(conin, &key);
175678d37b9Syasuoka 	while (status == EFI_NOT_READY || key.UnicodeChar == 0) {
176f24071e5Spatrick 		if (dev & 0x80)
177f24071e5Spatrick 			return (0);
178f24071e5Spatrick 		/*
179f24071e5Spatrick 		 * XXX The implementation of WaitForEvent() in U-boot
180f24071e5Spatrick 		 * is broken and neverreturns.
181f24071e5Spatrick 		 */
182f24071e5Spatrick #if 0
183f24071e5Spatrick 		BS->WaitForEvent(1, &conin->WaitForKey, &dummy);
184f24071e5Spatrick #endif
185f24071e5Spatrick 		status = conin->ReadKeyStroke(conin, &key);
186f24071e5Spatrick 	}
187f24071e5Spatrick 
188f24071e5Spatrick 	if (dev & 0x80)
189f24071e5Spatrick 		lastchar = key.UnicodeChar;
190f24071e5Spatrick 
191f24071e5Spatrick 	return (key.UnicodeChar);
192f24071e5Spatrick }
193f24071e5Spatrick 
194f24071e5Spatrick void
efi_cons_putc(dev_t dev,int c)195f24071e5Spatrick efi_cons_putc(dev_t dev, int c)
196f24071e5Spatrick {
197f24071e5Spatrick 	CHAR16	buf[2];
198f24071e5Spatrick 
199f24071e5Spatrick 	if (c == '\n')
200f24071e5Spatrick 		efi_cons_putc(dev, '\r');
201f24071e5Spatrick 
202f24071e5Spatrick 	buf[0] = c;
203f24071e5Spatrick 	buf[1] = 0;
204f24071e5Spatrick 
205f24071e5Spatrick 	conout->OutputString(conout, buf);
206f24071e5Spatrick }
207f24071e5Spatrick 
2085cfe0970Skettenis void
efi_com_probe(struct consdev * cn)209c7045f51Skettenis efi_com_probe(struct consdev *cn)
210c7045f51Skettenis {
211c7045f51Skettenis 	cn->cn_pri = CN_LOWPRI;
212c7045f51Skettenis 	cn->cn_dev = serial;
213c7045f51Skettenis }
214c7045f51Skettenis 
215c7045f51Skettenis void
efi_com_init(struct consdev * cn)216c7045f51Skettenis efi_com_init(struct consdev *cn)
217c7045f51Skettenis {
218c7045f51Skettenis 	conin = ST->ConIn;
219c7045f51Skettenis 	conout = ST->ConOut;
220c7045f51Skettenis }
221c7045f51Skettenis 
222c7045f51Skettenis int
efi_com_getc(dev_t dev)223c7045f51Skettenis efi_com_getc(dev_t dev)
224c7045f51Skettenis {
225c7045f51Skettenis 	return efi_cons_getc(dev);
226c7045f51Skettenis }
227c7045f51Skettenis 
228c7045f51Skettenis void
efi_com_putc(dev_t dev,int c)229c7045f51Skettenis efi_com_putc(dev_t dev, int c)
230c7045f51Skettenis {
231c7045f51Skettenis 	efi_cons_putc(dev, c);
232c7045f51Skettenis }
233c7045f51Skettenis 
234c7045f51Skettenis void
efi_fb_probe(struct consdev * cn)2355cfe0970Skettenis efi_fb_probe(struct consdev *cn)
2365cfe0970Skettenis {
2375cfe0970Skettenis 	cn->cn_pri = CN_LOWPRI;
2385cfe0970Skettenis 	cn->cn_dev = framebuffer;
2395cfe0970Skettenis }
2405cfe0970Skettenis 
2415cfe0970Skettenis void
efi_fb_init(struct consdev * cn)2425cfe0970Skettenis efi_fb_init(struct consdev *cn)
2435cfe0970Skettenis {
2445cfe0970Skettenis 	conin = ST->ConIn;
2455cfe0970Skettenis 	conout = ST->ConOut;
2465cfe0970Skettenis }
2475cfe0970Skettenis 
2485cfe0970Skettenis int
efi_fb_getc(dev_t dev)2495cfe0970Skettenis efi_fb_getc(dev_t dev)
2505cfe0970Skettenis {
2515cfe0970Skettenis 	return efi_cons_getc(dev);
2525cfe0970Skettenis }
2535cfe0970Skettenis 
2545cfe0970Skettenis void
efi_fb_putc(dev_t dev,int c)2555cfe0970Skettenis efi_fb_putc(dev_t dev, int c)
2565cfe0970Skettenis {
2575cfe0970Skettenis 	efi_cons_putc(dev, c);
2585cfe0970Skettenis }
2595cfe0970Skettenis 
260f24071e5Spatrick static void
efi_heap_init(void)261f24071e5Spatrick efi_heap_init(void)
262f24071e5Spatrick {
263f24071e5Spatrick 	EFI_STATUS	 status;
264f24071e5Spatrick 
2651f462730Skrw 	status = BS->AllocatePages(AllocateAnyPages, EfiLoaderData,
266f24071e5Spatrick 	    EFI_SIZE_TO_PAGES(heapsiz), &heap);
267f24071e5Spatrick 	if (status != EFI_SUCCESS)
268f24071e5Spatrick 		panic("BS->AllocatePages()");
269f24071e5Spatrick }
270f24071e5Spatrick 
2715b351376Spatrick struct disklist_lh disklist;
2725b351376Spatrick struct diskinfo *bootdev_dip;
273f24071e5Spatrick 
274f24071e5Spatrick void
efi_diskprobe(void)275f24071e5Spatrick efi_diskprobe(void)
276f24071e5Spatrick {
2775b351376Spatrick 	int			 i, bootdev = 0, depth = -1;
278f24071e5Spatrick 	UINTN			 sz;
279f24071e5Spatrick 	EFI_STATUS		 status;
280f24071e5Spatrick 	EFI_HANDLE		*handles = NULL;
281f24071e5Spatrick 	EFI_BLOCK_IO		*blkio;
282f24071e5Spatrick 	EFI_BLOCK_IO_MEDIA	*media;
2835b351376Spatrick 	struct diskinfo		*di;
284c6d7d0adSpatrick 	EFI_DEVICE_PATH		*dp;
285f24071e5Spatrick 
2865b351376Spatrick 	TAILQ_INIT(&disklist);
2875b351376Spatrick 
288f24071e5Spatrick 	sz = 0;
2891f462730Skrw 	status = BS->LocateHandle(ByProtocol, &blkio_guid, 0, &sz, 0);
290f24071e5Spatrick 	if (status == EFI_BUFFER_TOO_SMALL) {
291f24071e5Spatrick 		handles = alloc(sz);
2921f462730Skrw 		status = BS->LocateHandle(ByProtocol, &blkio_guid, 0, &sz,
2931f462730Skrw 		    handles);
294f24071e5Spatrick 	}
295f24071e5Spatrick 	if (handles == NULL || EFI_ERROR(status))
29633e5575aSpatrick 		return;
297f24071e5Spatrick 
298c6d7d0adSpatrick 	if (efi_bootdp != NULL)
299c6d7d0adSpatrick 		depth = efi_device_path_depth(efi_bootdp, MEDIA_DEVICE_PATH);
300c6d7d0adSpatrick 
301c94e7257Skettenis 	/*
302c94e7257Skettenis 	 * U-Boot incorrectly represents devices with a single
303c94e7257Skettenis 	 * MEDIA_DEVICE_PATH component.  In that case include that
304c94e7257Skettenis 	 * component into the matching, otherwise we'll blindly select
305c94e7257Skettenis 	 * the first device.
306c94e7257Skettenis 	 */
307c94e7257Skettenis 	if (depth == 0)
308c94e7257Skettenis 		depth = 1;
309c94e7257Skettenis 
310f24071e5Spatrick 	for (i = 0; i < sz / sizeof(EFI_HANDLE); i++) {
3111f462730Skrw 		status = BS->HandleProtocol(handles[i], &blkio_guid,
312f24071e5Spatrick 		    (void **)&blkio);
313f24071e5Spatrick 		if (EFI_ERROR(status))
314f24071e5Spatrick 			panic("BS->HandleProtocol() returns %d", status);
315f24071e5Spatrick 
316f24071e5Spatrick 		media = blkio->Media;
317f24071e5Spatrick 		if (media->LogicalPartition || !media->MediaPresent)
318f24071e5Spatrick 			continue;
3195b351376Spatrick 		di = alloc(sizeof(struct diskinfo));
3205b351376Spatrick 		efid_init(di, blkio);
321f24071e5Spatrick 
3225b351376Spatrick 		if (efi_bootdp == NULL || depth == -1 || bootdev != 0)
3235b351376Spatrick 			goto next;
3241f462730Skrw 		status = BS->HandleProtocol(handles[i], &devp_guid,
325f24071e5Spatrick 		    (void **)&dp);
326f24071e5Spatrick 		if (EFI_ERROR(status))
3275b351376Spatrick 			goto next;
328c6d7d0adSpatrick 		if (efi_device_path_ncmp(efi_bootdp, dp, depth) == 0) {
3295b351376Spatrick 			TAILQ_INSERT_HEAD(&disklist, di, list);
3305b351376Spatrick 			bootdev_dip = di;
3315b351376Spatrick 			bootdev = 1;
3325b351376Spatrick 			continue;
333f24071e5Spatrick 		}
3345b351376Spatrick next:
3355b351376Spatrick 		TAILQ_INSERT_TAIL(&disklist, di, list);
336f24071e5Spatrick 	}
337f24071e5Spatrick 
338f24071e5Spatrick 	free(handles, sz);
3395b351376Spatrick 
3405b351376Spatrick 	/* Print available disks and probe for softraid. */
3415b351376Spatrick 	i = 0;
3425b351376Spatrick 	printf("disks:");
3435b351376Spatrick 	TAILQ_FOREACH(di, &disklist, list) {
3445b351376Spatrick 		printf(" sd%d%s", i, di == bootdev_dip ? "*" : "");
3455b351376Spatrick 		i++;
3465b351376Spatrick 	}
3475b351376Spatrick 	srprobe();
3485b351376Spatrick 	printf("\n");
349f24071e5Spatrick }
350f24071e5Spatrick 
351c94e7257Skettenis /*
352c94e7257Skettenis  * Determine the number of nodes up to, but not including, the first
353c94e7257Skettenis  * node of the specified type.
354c94e7257Skettenis  */
35533e5575aSpatrick int
efi_device_path_depth(EFI_DEVICE_PATH * dp,int dptype)356c6d7d0adSpatrick efi_device_path_depth(EFI_DEVICE_PATH *dp, int dptype)
357c6d7d0adSpatrick {
358c6d7d0adSpatrick 	int	i;
359c6d7d0adSpatrick 
360c6d7d0adSpatrick 	for (i = 0; !IsDevicePathEnd(dp); dp = NextDevicePathNode(dp), i++) {
361c6d7d0adSpatrick 		if (DevicePathType(dp) == dptype)
362c94e7257Skettenis 			return (i);
363c6d7d0adSpatrick 	}
364c6d7d0adSpatrick 
365d64e7de5Skettenis 	return (i);
366c6d7d0adSpatrick }
367c6d7d0adSpatrick 
36833e5575aSpatrick int
efi_device_path_ncmp(EFI_DEVICE_PATH * dpa,EFI_DEVICE_PATH * dpb,int deptn)369c6d7d0adSpatrick efi_device_path_ncmp(EFI_DEVICE_PATH *dpa, EFI_DEVICE_PATH *dpb, int deptn)
370c6d7d0adSpatrick {
371c6d7d0adSpatrick 	int	 i, cmp;
372c6d7d0adSpatrick 
373c6d7d0adSpatrick 	for (i = 0; i < deptn; i++) {
374c6d7d0adSpatrick 		if (IsDevicePathEnd(dpa) || IsDevicePathEnd(dpb))
375c6d7d0adSpatrick 			return ((IsDevicePathEnd(dpa) && IsDevicePathEnd(dpb))
376c6d7d0adSpatrick 			    ? 0 : (IsDevicePathEnd(dpa))? -1 : 1);
377c6d7d0adSpatrick 		cmp = DevicePathNodeLength(dpa) - DevicePathNodeLength(dpb);
378c6d7d0adSpatrick 		if (cmp)
379c6d7d0adSpatrick 			return (cmp);
380c6d7d0adSpatrick 		cmp = memcmp(dpa, dpb, DevicePathNodeLength(dpa));
381c6d7d0adSpatrick 		if (cmp)
382c6d7d0adSpatrick 			return (cmp);
383c6d7d0adSpatrick 		dpa = NextDevicePathNode(dpa);
384c6d7d0adSpatrick 		dpb = NextDevicePathNode(dpb);
385c6d7d0adSpatrick 	}
386c6d7d0adSpatrick 
387c6d7d0adSpatrick 	return (0);
388c6d7d0adSpatrick }
389c6d7d0adSpatrick 
3901e44dc38Skettenis void
efi_framebuffer(void)3911e44dc38Skettenis efi_framebuffer(void)
3921e44dc38Skettenis {
3931e44dc38Skettenis 	EFI_GRAPHICS_OUTPUT *gop;
3941e44dc38Skettenis 	EFI_STATUS status;
3951e44dc38Skettenis 	void *node, *child;
3961e44dc38Skettenis 	uint32_t acells, scells;
3971e44dc38Skettenis 	uint64_t base, size;
3981e44dc38Skettenis 	uint32_t reg[4];
3991e44dc38Skettenis 	uint32_t width, height, stride;
4001e44dc38Skettenis 	char *format;
4015cfe0970Skettenis 	char *prop;
4021e44dc38Skettenis 
4031e44dc38Skettenis 	/*
4041e44dc38Skettenis 	 * Don't create a "simple-framebuffer" node if we already have
4051e44dc38Skettenis 	 * one.  Besides "/chosen", we also check under "/" since that
4061e44dc38Skettenis 	 * is where the Raspberry Pi firmware puts it.
4071e44dc38Skettenis 	 */
4081e44dc38Skettenis 	node = fdt_find_node("/chosen");
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, "/chosen/",
4165f7ab753Skettenis 			    sizeof(framebuffer_path));
4175f7ab753Skettenis 			strlcat(framebuffer_path, fdt_node_name(child),
4185f7ab753Skettenis 			    sizeof(framebuffer_path));
4191e44dc38Skettenis 			return;
4201e44dc38Skettenis 		}
4215f7ab753Skettenis 	}
4221e44dc38Skettenis 	node = fdt_find_node("/");
4231e44dc38Skettenis 	for (child = fdt_child_node(node); child;
4241e44dc38Skettenis 	     child = fdt_next_node(child)) {
4255cfe0970Skettenis 		if (!fdt_node_is_compatible(child, "simple-framebuffer"))
4265cfe0970Skettenis 			continue;
4275028e024Skettenis 		if (!fdt_node_property(child, "status", &prop) ||
4285f7ab753Skettenis 		    strcmp(prop, "okay") == 0) {
4295f7ab753Skettenis 			strlcpy(framebuffer_path, "/",
4305f7ab753Skettenis 			    sizeof(framebuffer_path));
4315f7ab753Skettenis 			strlcat(framebuffer_path, fdt_node_name(child),
4325f7ab753Skettenis 			    sizeof(framebuffer_path));
4331e44dc38Skettenis 			return;
4341e44dc38Skettenis 		}
4355f7ab753Skettenis 	}
4361e44dc38Skettenis 
4371f462730Skrw 	status = BS->LocateProtocol(&gop_guid, NULL, (void **)&gop);
4381e44dc38Skettenis 	if (status != EFI_SUCCESS)
4391e44dc38Skettenis 		return;
4401e44dc38Skettenis 
4411e44dc38Skettenis 	/* Paranoia! */
4421e44dc38Skettenis 	if (gop == NULL || gop->Mode == NULL || gop->Mode->Info == NULL)
4431e44dc38Skettenis 		return;
4441e44dc38Skettenis 
4451e44dc38Skettenis 	/* We only support 32-bit pixel modes for now. */
4461e44dc38Skettenis 	switch (gop->Mode->Info->PixelFormat) {
4471e44dc38Skettenis 	case PixelRedGreenBlueReserved8BitPerColor:
448b870cd26Skettenis 		format = "x8b8g8r8";
4491e44dc38Skettenis 		break;
4501e44dc38Skettenis 	case PixelBlueGreenRedReserved8BitPerColor:
451b870cd26Skettenis 		format = "x8r8g8b8";
4521e44dc38Skettenis 		break;
4531e44dc38Skettenis 	default:
4541e44dc38Skettenis 		return;
4551e44dc38Skettenis 	}
4561e44dc38Skettenis 
4571e44dc38Skettenis 	base = gop->Mode->FrameBufferBase;
4581e44dc38Skettenis 	size = gop->Mode->FrameBufferSize;
4591e44dc38Skettenis 	width = htobe32(gop->Mode->Info->HorizontalResolution);
4601e44dc38Skettenis 	height = htobe32(gop->Mode->Info->VerticalResolution);
4611e44dc38Skettenis 	stride = htobe32(gop->Mode->Info->PixelsPerScanLine * 4);
4621e44dc38Skettenis 
4631e44dc38Skettenis 	node = fdt_find_node("/");
4641e44dc38Skettenis 	if (fdt_node_property_int(node, "#address-cells", &acells) != 1)
4651e44dc38Skettenis 		acells = 1;
4661e44dc38Skettenis 	if (fdt_node_property_int(node, "#size-cells", &scells) != 1)
4671e44dc38Skettenis 		scells = 1;
4681e44dc38Skettenis 	if (acells > 2 || scells > 2)
4691e44dc38Skettenis 		return;
4701e44dc38Skettenis 	if (acells >= 1)
4711e44dc38Skettenis 		reg[0] = htobe32(base);
4721e44dc38Skettenis 	if (acells == 2) {
4731e44dc38Skettenis 		reg[1] = reg[0];
4741e44dc38Skettenis 		reg[0] = htobe32(base >> 32);
4751e44dc38Skettenis 	}
4761e44dc38Skettenis 	if (scells >= 1)
4771e44dc38Skettenis 		reg[acells] = htobe32(size);
4781e44dc38Skettenis 	if (scells == 2) {
4791e44dc38Skettenis 		reg[acells + 1] = reg[acells];
4801e44dc38Skettenis 		reg[acells] = htobe32(size >> 32);
4811e44dc38Skettenis 	}
4821e44dc38Skettenis 
4831e44dc38Skettenis 	node = fdt_find_node("/chosen");
4841e44dc38Skettenis 	fdt_node_add_node(node, "framebuffer", &child);
4851e44dc38Skettenis 	fdt_node_add_property(child, "status", "okay", strlen("okay") + 1);
4861e44dc38Skettenis 	fdt_node_add_property(child, "format", format, strlen(format) + 1);
4871e44dc38Skettenis 	fdt_node_add_property(child, "stride", &stride, 4);
4881e44dc38Skettenis 	fdt_node_add_property(child, "height", &height, 4);
4891e44dc38Skettenis 	fdt_node_add_property(child, "width", &width, 4);
4901e44dc38Skettenis 	fdt_node_add_property(child, "reg", reg, (acells + scells) * 4);
4911e44dc38Skettenis 	fdt_node_add_property(child, "compatible",
4921e44dc38Skettenis 	    "simple-framebuffer", strlen("simple-framebuffer") + 1);
4935f7ab753Skettenis 
4945f7ab753Skettenis 	strlcpy(framebuffer_path, "/chosen/framebuffer",
4955f7ab753Skettenis 	    sizeof(framebuffer_path));
4961e44dc38Skettenis }
4971e44dc38Skettenis 
4985cfe0970Skettenis void
efi_console(void)4995cfe0970Skettenis efi_console(void)
5005cfe0970Skettenis {
5015f7ab753Skettenis 	void *node;
5025cfe0970Skettenis 
503c7045f51Skettenis 	if (major(cn_tab->cn_dev) == major(serial)) {
504c7045f51Skettenis 		char *serial_path;
505c7045f51Skettenis 		char alias[16];
506c7045f51Skettenis 		int len;
507c7045f51Skettenis 
508c7045f51Skettenis 		/* Construct alias and resolve it. */
509c7045f51Skettenis 		snprintf(alias, sizeof(alias), "serial%d",
510c7045f51Skettenis 		    minor(cn_tab->cn_dev));
511c7045f51Skettenis 		node = fdt_find_node("/aliases");
512c7045f51Skettenis 		len = fdt_node_property(node, alias, &serial_path);
513c7045f51Skettenis 		if (len <= 0)
5145cfe0970Skettenis 			return;
5155cfe0970Skettenis 
516c7045f51Skettenis 		/* Point stdout-path at the serial node. */
517c7045f51Skettenis 		node = fdt_find_node("/chosen");
518c7045f51Skettenis 		fdt_node_add_property(node, "stdout-path",
519c7045f51Skettenis 		    serial_path, strlen(serial_path) + 1);
520c7045f51Skettenis 	} else if (major(cn_tab->cn_dev) == major(framebuffer)) {
5215f7ab753Skettenis 		if (strlen(framebuffer_path) == 0)
5225cfe0970Skettenis 			return;
5235cfe0970Skettenis 
5245cfe0970Skettenis 		/* Point stdout-path at the framebuffer node. */
5255f7ab753Skettenis 		node = fdt_find_node("/chosen");
5265f7ab753Skettenis 		fdt_node_add_property(node, "stdout-path",
5275f7ab753Skettenis 		    framebuffer_path, strlen(framebuffer_path) + 1);
5285cfe0970Skettenis 	}
529c7045f51Skettenis }
5305cfe0970Skettenis 
531a88d1494Skettenis uint64_t dma_constraint[2] = { 0, -1 };
532a88d1494Skettenis 
533a88d1494Skettenis void
efi_dma_constraint(void)534a88d1494Skettenis efi_dma_constraint(void)
535a88d1494Skettenis {
536a88d1494Skettenis 	void *node;
537cfb73cfeSpatrick 	char *prop;
538cfb73cfeSpatrick 	uint32_t *propint;
539cfb73cfeSpatrick 	uint64_t base, size;
540cfb73cfeSpatrick 	uint32_t pacells, pscells;
541cfb73cfeSpatrick 	uint32_t acells, scells;
542cfb73cfeSpatrick 	int len;
543cfb73cfeSpatrick 
544cfb73cfeSpatrick 	node = fdt_find_node("/");
545cfb73cfeSpatrick 	if (fdt_node_property_int(node, "#address-cells", &pacells) != 1)
546cfb73cfeSpatrick 		pacells = 1;
547cfb73cfeSpatrick 	if (fdt_node_property_int(node, "#size-cells", &pscells) != 1)
548cfb73cfeSpatrick 		pscells = 1;
549cfb73cfeSpatrick 	if (pacells > 2 || pscells > 2)
550cfb73cfeSpatrick 		return;
551cfb73cfeSpatrick 
552cfb73cfeSpatrick 	node = fdt_find_node("/soc");
553cfb73cfeSpatrick 	if (node != NULL) {
554cfb73cfeSpatrick 		if (fdt_node_property_int(node, "#address-cells", &acells) != 1)
555cfb73cfeSpatrick 			acells = pacells;
556cfb73cfeSpatrick 		if (fdt_node_property_int(node, "#size-cells", &scells) != 1)
557cfb73cfeSpatrick 			scells = pscells;
558cfb73cfeSpatrick 		if (acells > 2 || scells > 2)
559cfb73cfeSpatrick 			return;
560cfb73cfeSpatrick 
561cfb73cfeSpatrick 		len = fdt_node_property(node, "dma-ranges", &prop);
562cfb73cfeSpatrick 		propint = (uint32_t *)prop;
563cfb73cfeSpatrick 		if (len == (acells + pacells + scells) * sizeof(uint32_t)) {
564cfb73cfeSpatrick 			base = betoh32(propint[acells]);
565cfb73cfeSpatrick 			if (pacells == 2)
566cfb73cfeSpatrick 				base = (base << 32) |
567cfb73cfeSpatrick 				    betoh32(propint[acells + 1]);
568cfb73cfeSpatrick 			size = betoh32(propint[acells + pacells]);
569cfb73cfeSpatrick 			if (scells == 2)
570cfb73cfeSpatrick 				size = (size << 32) |
571cfb73cfeSpatrick 				    betoh32(propint[acells + pacells + 1]);
572cfb73cfeSpatrick 
573cfb73cfeSpatrick 			dma_constraint[0] = htobe64(base);
574cfb73cfeSpatrick 			dma_constraint[1] = htobe64(base + size - 1);
575cfb73cfeSpatrick 		}
576cfb73cfeSpatrick 	}
577a88d1494Skettenis 
5782bc3fe80Skettenis 	/*
5792bc3fe80Skettenis 	 * Some SoC's have DMA constraints that aren't explicitly
5802bc3fe80Skettenis 	 * advertised.
5812bc3fe80Skettenis 	 */
582a88d1494Skettenis 	node = fdt_find_node("/");
583a88d1494Skettenis 	if (fdt_node_is_compatible(node, "brcm,bcm2711"))
584a88d1494Skettenis 		dma_constraint[1] = htobe64(0x3bffffff);
5852bc3fe80Skettenis 	if (fdt_node_is_compatible(node, "rockchip,rk3566") ||
5862bc3fe80Skettenis 	    fdt_node_is_compatible(node, "rockchip,rk3568") ||
5872bc3fe80Skettenis 	    fdt_node_is_compatible(node, "rockchip,rk3588") ||
5882bc3fe80Skettenis 	    fdt_node_is_compatible(node, "rockchip,rk3588s"))
5892bc3fe80Skettenis 		dma_constraint[1] = htobe64(0xffffffff);
5902ae6c737Skettenis 	if (fdt_node_is_compatible(node, "lenovo,thinkpad-x13s"))
5912ae6c737Skettenis 		dma_constraint[1] = htobe64(0xffffffff);
592a88d1494Skettenis 
593a88d1494Skettenis 	/* Pass DMA constraint. */
594a88d1494Skettenis 	node = fdt_find_node("/chosen");
595a88d1494Skettenis 	fdt_node_add_property(node, "openbsd,dma-constraint",
596a88d1494Skettenis 	    dma_constraint, sizeof(dma_constraint));
597a88d1494Skettenis }
598a88d1494Skettenis 
599be07ee62Skettenis int acpi = 0;
6009ccb13abSnaddy char *bootmac = NULL;
601f24071e5Spatrick 
602f24071e5Spatrick void *
efi_makebootargs(char * bootargs,int howto)6039419d8aaSkettenis efi_makebootargs(char *bootargs, int howto)
604f24071e5Spatrick {
6055b351376Spatrick 	struct sr_boot_volume *bv;
606f4dd1aebSkettenis 	u_char bootduid[8];
607f4dd1aebSkettenis 	u_char zero[8] = { 0 };
608f4dd1aebSkettenis 	uint64_t uefi_system_table = htobe64((uintptr_t)ST);
6099419d8aaSkettenis 	uint32_t boothowto = htobe32(howto);
61058554311Spatrick 	EFI_PHYSICAL_ADDRESS addr;
6114befd8f0Spatrick 	void *node, *fdt;
612f24071e5Spatrick 	size_t len;
613f24071e5Spatrick 
6144befd8f0Spatrick 	fdt = efi_fdt();
615be07ee62Skettenis 	if (fdt == NULL || acpi)
6169a1480b1Skettenis 		fdt = efi_acpi();
6179a1480b1Skettenis 
61858554311Spatrick 	if (!fdt_get_size(fdt))
61958554311Spatrick 		return NULL;
62058554311Spatrick 
62158554311Spatrick 	len = roundup(fdt_get_size(fdt) + PAGE_SIZE, PAGE_SIZE);
62258554311Spatrick 	if (BS->AllocatePages(AllocateAnyPages, EfiLoaderData,
62358554311Spatrick 	    EFI_SIZE_TO_PAGES(len), &addr) == EFI_SUCCESS) {
62458554311Spatrick 		memcpy((void *)addr, fdt, fdt_get_size(fdt));
625259d2111Skettenis 		((struct fdt_head *)addr)->fh_size = htobe32(len);
62658554311Spatrick 		fdt = (void *)addr;
62758554311Spatrick 	}
62858554311Spatrick 
629f24071e5Spatrick 	if (!fdt_init(fdt))
630f24071e5Spatrick 		return NULL;
631f24071e5Spatrick 
632bd928107Spatrick 	/* Create common nodes which might not exist when using mach dtb */
633bd928107Spatrick 	node = fdt_find_node("/aliases");
634bd928107Spatrick 	if (node == NULL)
635bd928107Spatrick 		fdt_node_add_node(fdt_find_node("/"), "aliases", &node);
636f24071e5Spatrick 	node = fdt_find_node("/chosen");
637bd928107Spatrick 	if (node == NULL)
638bd928107Spatrick 		fdt_node_add_node(fdt_find_node("/"), "chosen", &node);
639f24071e5Spatrick 
640bd928107Spatrick 	node = fdt_find_node("/chosen");
641f24071e5Spatrick 	len = strlen(bootargs) + 1;
642f24071e5Spatrick 	fdt_node_add_property(node, "bootargs", bootargs, len);
6439419d8aaSkettenis 	fdt_node_add_property(node, "openbsd,boothowto",
6449419d8aaSkettenis 	    &boothowto, sizeof(boothowto));
645f24071e5Spatrick 
646f24071e5Spatrick 	/* Pass DUID of the boot disk. */
6475b351376Spatrick 	if (bootdev_dip) {
6485b351376Spatrick 		memcpy(&bootduid, bootdev_dip->disklabel.d_uid,
649f24071e5Spatrick 		    sizeof(bootduid));
6505b351376Spatrick 		if (memcmp(bootduid, zero, sizeof(bootduid)) != 0) {
6515b351376Spatrick 			fdt_node_add_property(node, "openbsd,bootduid",
6525b351376Spatrick 			    bootduid, sizeof(bootduid));
653f24071e5Spatrick 		}
654f24071e5Spatrick 
6555b351376Spatrick 		if (bootdev_dip->sr_vol != NULL) {
6565b351376Spatrick 			bv = bootdev_dip->sr_vol;
6575b351376Spatrick 			fdt_node_add_property(node, "openbsd,sr-bootuuid",
6585b351376Spatrick 			    &bv->sbv_uuid, sizeof(bv->sbv_uuid));
6595b351376Spatrick 			if (bv->sbv_maskkey != NULL)
6605b351376Spatrick 				fdt_node_add_property(node,
6615b351376Spatrick 				    "openbsd,sr-bootkey", bv->sbv_maskkey,
6625b351376Spatrick 				    SR_CRYPTO_MAXKEYBYTES);
6635b351376Spatrick 		}
6645b351376Spatrick 	}
6655b351376Spatrick 
6665b351376Spatrick 	sr_clear_keys();
6675b351376Spatrick 
6689ccb13abSnaddy 	/* Pass netboot interface address. */
6699ccb13abSnaddy 	if (bootmac)
6709ccb13abSnaddy 		fdt_node_add_property(node, "openbsd,bootmac", bootmac, 6);
6719ccb13abSnaddy 
672f4dd1aebSkettenis 	/* Pass EFI system table. */
673f4dd1aebSkettenis 	fdt_node_add_property(node, "openbsd,uefi-system-table",
674f4dd1aebSkettenis 	    &uefi_system_table, sizeof(uefi_system_table));
675f4dd1aebSkettenis 
676f4dd1aebSkettenis 	/* Placeholders for EFI memory map. */
677f4dd1aebSkettenis 	fdt_node_add_property(node, "openbsd,uefi-mmap-start", zero, 8);
678f4dd1aebSkettenis 	fdt_node_add_property(node, "openbsd,uefi-mmap-size", zero, 4);
679f4dd1aebSkettenis 	fdt_node_add_property(node, "openbsd,uefi-mmap-desc-size", zero, 4);
680f4dd1aebSkettenis 	fdt_node_add_property(node, "openbsd,uefi-mmap-desc-ver", zero, 4);
681f4dd1aebSkettenis 
6821e44dc38Skettenis 	efi_framebuffer();
6835cfe0970Skettenis 	efi_console();
684a88d1494Skettenis 	efi_dma_constraint();
6851e44dc38Skettenis 
686f24071e5Spatrick 	fdt_finalize();
687f24071e5Spatrick 
688f24071e5Spatrick 	return fdt;
689f24071e5Spatrick }
690f24071e5Spatrick 
691f4dd1aebSkettenis void
efi_updatefdt(void)692f4dd1aebSkettenis efi_updatefdt(void)
693f4dd1aebSkettenis {
694f4dd1aebSkettenis 	uint64_t uefi_mmap_start = htobe64((uintptr_t)mmap);
695f4dd1aebSkettenis 	uint32_t uefi_mmap_size = htobe32(mmap_ndesc * mmap_descsiz);
696f4dd1aebSkettenis 	uint32_t uefi_mmap_desc_size = htobe32(mmap_descsiz);
697f4dd1aebSkettenis 	uint32_t uefi_mmap_desc_ver = htobe32(mmap_version);
698f4dd1aebSkettenis 	void *node;
699f4dd1aebSkettenis 
700f4dd1aebSkettenis 	node = fdt_find_node("/chosen");
701f4dd1aebSkettenis 	if (!node)
702f4dd1aebSkettenis 		return;
703f4dd1aebSkettenis 
704f4dd1aebSkettenis 	/* Pass EFI memory map. */
705f4dd1aebSkettenis 	fdt_node_set_property(node, "openbsd,uefi-mmap-start",
706f4dd1aebSkettenis 	    &uefi_mmap_start, sizeof(uefi_mmap_start));
707f4dd1aebSkettenis 	fdt_node_set_property(node, "openbsd,uefi-mmap-size",
708f4dd1aebSkettenis 	    &uefi_mmap_size, sizeof(uefi_mmap_size));
709f4dd1aebSkettenis 	fdt_node_set_property(node, "openbsd,uefi-mmap-desc-size",
710f4dd1aebSkettenis 	    &uefi_mmap_desc_size, sizeof(uefi_mmap_desc_size));
711f4dd1aebSkettenis 	fdt_node_set_property(node, "openbsd,uefi-mmap-desc-ver",
712f4dd1aebSkettenis 	    &uefi_mmap_desc_ver, sizeof(uefi_mmap_desc_ver));
713f4dd1aebSkettenis 
714f4dd1aebSkettenis 	fdt_finalize();
715f4dd1aebSkettenis }
716f4dd1aebSkettenis 
717f24071e5Spatrick u_long efi_loadaddr;
718f24071e5Spatrick 
719f24071e5Spatrick void
machdep(void)720f24071e5Spatrick machdep(void)
721f24071e5Spatrick {
722f24071e5Spatrick 	EFI_PHYSICAL_ADDRESS addr;
723f24071e5Spatrick 
724f24071e5Spatrick 	cninit();
725f24071e5Spatrick 	efi_heap_init();
7264befd8f0Spatrick 	smbios_init(smbios);
727f24071e5Spatrick 
728f24071e5Spatrick 	/*
7299a118d7eSpatrick 	 * The kernel expects to be loaded into a block of memory aligned
7309a118d7eSpatrick 	 * on a 2MB boundary.  We allocate a block of 64MB of memory, which
7319a118d7eSpatrick 	 * gives us plenty of room for growth.
732f24071e5Spatrick 	 */
7339a118d7eSpatrick 	if (efi_memprobe_find(EFI_SIZE_TO_PAGES(64 * 1024 * 1024),
7342c32ef33Skettenis 	    0x200000, EfiLoaderCode, &addr) != EFI_SUCCESS)
735f24071e5Spatrick 		printf("Can't allocate memory\n");
736f24071e5Spatrick 	efi_loadaddr = addr;
737f24071e5Spatrick 
738f24071e5Spatrick 	efi_timer_init();
739f24071e5Spatrick 	efi_diskprobe();
74033e5575aSpatrick 	efi_pxeprobe();
741f24071e5Spatrick }
742f24071e5Spatrick 
743f24071e5Spatrick void
efi_cleanup(void)744f24071e5Spatrick efi_cleanup(void)
745f24071e5Spatrick {
746fa854029Spatrick 	int		 retry;
747fa854029Spatrick 	EFI_STATUS	 status;
748fa854029Spatrick 
749f24071e5Spatrick 	efi_timer_cleanup();
750f24071e5Spatrick 
751fa854029Spatrick 	/* retry once in case of failure */
752fa854029Spatrick 	for (retry = 1; retry >= 0; retry--) {
753fa854029Spatrick 		efi_memprobe_internal();	/* sync the current map */
754f4dd1aebSkettenis 		efi_updatefdt();
7551f462730Skrw 		status = BS->ExitBootServices(IH, mmap_key);
756fa854029Spatrick 		if (status == EFI_SUCCESS)
757fa854029Spatrick 			break;
758fa854029Spatrick 		if (retry == 0)
759fa854029Spatrick 			panic("ExitBootServices failed (%d)", status);
760fa854029Spatrick 	}
761f24071e5Spatrick }
762f24071e5Spatrick 
763f24071e5Spatrick void
_rtt(void)764f24071e5Spatrick _rtt(void)
765f24071e5Spatrick {
766f24071e5Spatrick #ifdef EFI_DEBUG
767f24071e5Spatrick 	printf("Hit any key to reboot\n");
768f24071e5Spatrick 	efi_cons_getc(0);
769f24071e5Spatrick #endif
770f24071e5Spatrick 	RS->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL);
771111d6387Skettenis 	for (;;)
772111d6387Skettenis 		continue;
773f24071e5Spatrick }
774f24071e5Spatrick 
775f24071e5Spatrick /*
776f24071e5Spatrick  * U-Boot only implements the GetTime() Runtime Service if it has been
777f24071e5Spatrick  * configured with CONFIG_DM_RTC.  Most board configurations don't
778f24071e5Spatrick  * include that option, so we can't use it to implement our boot
779f24071e5Spatrick  * prompt timeout.  Instead we use timer events to simulate a clock
780f24071e5Spatrick  * that ticks ever second.
781f24071e5Spatrick  */
782f24071e5Spatrick 
783f24071e5Spatrick EFI_EVENT timer;
784f24071e5Spatrick int ticks;
785f24071e5Spatrick 
786f24071e5Spatrick static VOID
efi_timer(EFI_EVENT event,VOID * context)787f24071e5Spatrick efi_timer(EFI_EVENT event, VOID *context)
788f24071e5Spatrick {
789f24071e5Spatrick 	ticks++;
790f24071e5Spatrick }
791f24071e5Spatrick 
792f24071e5Spatrick static void
efi_timer_init(void)793f24071e5Spatrick efi_timer_init(void)
794f24071e5Spatrick {
795f24071e5Spatrick 	EFI_STATUS status;
796f24071e5Spatrick 
797a4d88df4Sjsg 	status = BS->CreateEvent(EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_CALLBACK,
798f24071e5Spatrick 	    efi_timer, NULL, &timer);
799f24071e5Spatrick 	if (status == EFI_SUCCESS)
800f24071e5Spatrick 		status = BS->SetTimer(timer, TimerPeriodic, 10000000);
801f24071e5Spatrick 	if (EFI_ERROR(status))
802f24071e5Spatrick 		printf("Can't create timer\n");
803f24071e5Spatrick }
804f24071e5Spatrick 
805f24071e5Spatrick static void
efi_timer_cleanup(void)806f24071e5Spatrick efi_timer_cleanup(void)
807f24071e5Spatrick {
808f24071e5Spatrick 	BS->CloseEvent(timer);
809f24071e5Spatrick }
810f24071e5Spatrick 
811f24071e5Spatrick time_t
getsecs(void)812f24071e5Spatrick getsecs(void)
813f24071e5Spatrick {
814f24071e5Spatrick 	return ticks;
815f24071e5Spatrick }
816f24071e5Spatrick 
817f24071e5Spatrick /*
818f24071e5Spatrick  * Various device-related bits.
819f24071e5Spatrick  */
820f24071e5Spatrick 
821f24071e5Spatrick void
devboot(dev_t dev,char * p)822f24071e5Spatrick devboot(dev_t dev, char *p)
823f24071e5Spatrick {
8245b351376Spatrick 	struct sr_boot_volume *bv;
8255b351376Spatrick 	struct sr_boot_chunk *bc;
8265b351376Spatrick 	struct diskinfo *dip;
8275b351376Spatrick 	int sd_boot_vol = 0;
8285b351376Spatrick 	int sr_boot_vol = -1;
8295b351376Spatrick 	int part_type = FS_UNUSED;
8305b351376Spatrick 
8315b351376Spatrick 	if (bootdev_dip == NULL) {
83233e5575aSpatrick 		strlcpy(p, "tftp0a", 7);
8335b351376Spatrick 		return;
8345b351376Spatrick 	}
8355b351376Spatrick 
8367db964dcSkettenis 	/*
8377db964dcSkettenis 	 * If there is no BSD disklabel on the boot device, boot from
8387db964dcSkettenis 	 * the ESP instead.
8397db964dcSkettenis 	 */
8407db964dcSkettenis 	if ((bootdev_dip->flags & DISKINFO_FLAG_GOODLABEL) == 0) {
8417db964dcSkettenis 		strlcpy(p, "esp0a", 6);
8427db964dcSkettenis 		return;
8437db964dcSkettenis 	}
8447db964dcSkettenis 
8455b351376Spatrick 	TAILQ_FOREACH(dip, &disklist, list) {
8465b351376Spatrick 		if (bootdev_dip == dip)
8475b351376Spatrick 			break;
8485b351376Spatrick 		sd_boot_vol++;
8495b351376Spatrick 	}
8505b351376Spatrick 
8515b351376Spatrick 	/*
8525b351376Spatrick 	 * Determine the partition type for the 'a' partition of the
8535b351376Spatrick 	 * boot device.
8545b351376Spatrick 	 */
8555b351376Spatrick 	part_type = bootdev_dip->disklabel.d_partitions[0].p_fstype;
8565b351376Spatrick 
8575b351376Spatrick 	/*
8585b351376Spatrick 	 * See if we booted from a disk that is a member of a bootable
8595b351376Spatrick 	 * softraid volume.
8605b351376Spatrick 	 */
8615b351376Spatrick 	SLIST_FOREACH(bv, &sr_volumes, sbv_link) {
8625b351376Spatrick 		SLIST_FOREACH(bc, &bv->sbv_chunks, sbc_link)
8635b351376Spatrick 			if (bc->sbc_diskinfo == bootdev_dip)
8645b351376Spatrick 				sr_boot_vol = bv->sbv_unit;
8655b351376Spatrick 		if (sr_boot_vol != -1)
8665b351376Spatrick 			break;
8675b351376Spatrick 	}
8685b351376Spatrick 
8695b351376Spatrick 	if (sr_boot_vol != -1 && part_type != FS_BSDFFS) {
8705b351376Spatrick 		strlcpy(p, "sr0a", 5);
8715b351376Spatrick 		p[2] = '0' + sr_boot_vol;
8725b351376Spatrick 		return;
8735b351376Spatrick 	}
8745b351376Spatrick 
8755b351376Spatrick 	strlcpy(p, "sd0a", 5);
8765b351376Spatrick 	p[2] = '0' + sd_boot_vol;
877f24071e5Spatrick }
878f24071e5Spatrick 
879c7045f51Skettenis const char cdevs[][4] = { "cons", "com", "fb" };
8805cfe0970Skettenis const int ncdevs = nitems(cdevs);
8815cfe0970Skettenis 
882f24071e5Spatrick int
cnspeed(dev_t dev,int sp)883f24071e5Spatrick cnspeed(dev_t dev, int sp)
884f24071e5Spatrick {
885f24071e5Spatrick 	return 115200;
886f24071e5Spatrick }
887f24071e5Spatrick 
8885cfe0970Skettenis char ttyname_buf[8];
8895cfe0970Skettenis 
890f24071e5Spatrick char *
ttyname(int fd)891f24071e5Spatrick ttyname(int fd)
892f24071e5Spatrick {
8935cfe0970Skettenis 	snprintf(ttyname_buf, sizeof ttyname_buf, "%s%d",
8945cfe0970Skettenis 	    cdevs[major(cn_tab->cn_dev)], minor(cn_tab->cn_dev));
8955cfe0970Skettenis 
8965cfe0970Skettenis 	return ttyname_buf;
897f24071e5Spatrick }
898f24071e5Spatrick 
899f24071e5Spatrick dev_t
ttydev(char * name)900f24071e5Spatrick ttydev(char *name)
901f24071e5Spatrick {
9025cfe0970Skettenis 	int i, unit = -1;
9035cfe0970Skettenis 	char *no = name + strlen(name) - 1;
9045cfe0970Skettenis 
9055cfe0970Skettenis 	while (no >= name && *no >= '0' && *no <= '9')
9065cfe0970Skettenis 		unit = (unit < 0 ? 0 : (unit * 10)) + *no-- - '0';
9075cfe0970Skettenis 	if (no < name || unit < 0)
9085cfe0970Skettenis 		return NODEV;
9095cfe0970Skettenis 	for (i = 0; i < ncdevs; i++)
9105cfe0970Skettenis 		if (strncmp(name, cdevs[i], no - name + 1) == 0)
9115cfe0970Skettenis 			return makedev(i, unit);
912f24071e5Spatrick 	return NODEV;
913f24071e5Spatrick }
914f24071e5Spatrick 
915f24071e5Spatrick #define MAXDEVNAME	16
916f24071e5Spatrick 
917f24071e5Spatrick /*
918f24071e5Spatrick  * Parse a device spec.
919f24071e5Spatrick  *
920f24071e5Spatrick  * [A-Za-z]*[0-9]*[A-Za-z]:file
921f24071e5Spatrick  *    dev   uint    part
922f24071e5Spatrick  */
923f24071e5Spatrick int
devparse(const char * fname,int * dev,int * unit,int * part,const char ** file)924f24071e5Spatrick devparse(const char *fname, int *dev, int *unit, int *part, const char **file)
925f24071e5Spatrick {
926f24071e5Spatrick 	const char *s;
927f24071e5Spatrick 
928f24071e5Spatrick 	*unit = 0;	/* default to wd0a */
929f24071e5Spatrick 	*part = 0;
930f24071e5Spatrick 	*dev  = 0;
931f24071e5Spatrick 
932f24071e5Spatrick 	s = strchr(fname, ':');
933f24071e5Spatrick 	if (s != NULL) {
934f24071e5Spatrick 		int devlen;
935f24071e5Spatrick 		int i, u, p = 0;
936f24071e5Spatrick 		struct devsw *dp;
937f24071e5Spatrick 		char devname[MAXDEVNAME];
938f24071e5Spatrick 
939f24071e5Spatrick 		devlen = s - fname;
940f24071e5Spatrick 		if (devlen > MAXDEVNAME)
941f24071e5Spatrick 			return (EINVAL);
942f24071e5Spatrick 
943f24071e5Spatrick 		/* extract device name */
944f24071e5Spatrick 		for (i = 0; isalpha(fname[i]) && (i < devlen); i++)
945f24071e5Spatrick 			devname[i] = fname[i];
946f24071e5Spatrick 		devname[i] = 0;
947f24071e5Spatrick 
948f24071e5Spatrick 		if (!isdigit(fname[i]))
949f24071e5Spatrick 			return (EUNIT);
950f24071e5Spatrick 
951f24071e5Spatrick 		/* device number */
952f24071e5Spatrick 		for (u = 0; isdigit(fname[i]) && (i < devlen); i++)
953f24071e5Spatrick 			u = u * 10 + (fname[i] - '0');
954f24071e5Spatrick 
955f24071e5Spatrick 		if (!isalpha(fname[i]))
956f24071e5Spatrick 			return (EPART);
957f24071e5Spatrick 
958f24071e5Spatrick 		/* partition number */
959f24071e5Spatrick 		if (i < devlen)
960f24071e5Spatrick 			p = fname[i++] - 'a';
961f24071e5Spatrick 
962f24071e5Spatrick 		if (i != devlen)
963f24071e5Spatrick 			return (ENXIO);
964f24071e5Spatrick 
965f24071e5Spatrick 		/* check device name */
966f24071e5Spatrick 		for (dp = devsw, i = 0; i < ndevs; dp++, i++) {
967f24071e5Spatrick 			if (dp->dv_name && !strcmp(devname, dp->dv_name))
968f24071e5Spatrick 				break;
969f24071e5Spatrick 		}
970f24071e5Spatrick 
971f24071e5Spatrick 		if (i >= ndevs)
972f24071e5Spatrick 			return (ENXIO);
973f24071e5Spatrick 
974f24071e5Spatrick 		*unit = u;
975f24071e5Spatrick 		*part = p;
976f24071e5Spatrick 		*dev  = i;
977f24071e5Spatrick 		fname = ++s;
978f24071e5Spatrick 	}
979f24071e5Spatrick 
980f24071e5Spatrick 	*file = fname;
981f24071e5Spatrick 
982f24071e5Spatrick 	return (0);
983f24071e5Spatrick }
984f24071e5Spatrick 
985f24071e5Spatrick int
devopen(struct open_file * f,const char * fname,char ** file)986f24071e5Spatrick devopen(struct open_file *f, const char *fname, char **file)
987f24071e5Spatrick {
988f24071e5Spatrick 	struct devsw *dp;
989f24071e5Spatrick 	int dev, unit, part, error;
990f24071e5Spatrick 
991f24071e5Spatrick 	error = devparse(fname, &dev, &unit, &part, (const char **)file);
992f24071e5Spatrick 	if (error)
993f24071e5Spatrick 		return (error);
994f24071e5Spatrick 
99533e5575aSpatrick 	dp = &devsw[dev];
996f24071e5Spatrick 	f->f_dev = dp;
997f24071e5Spatrick 
998ad424d98Snaddy 	if (strcmp("tftp", dp->dv_name) != 0) {
999ad424d98Snaddy 		/*
1000ad424d98Snaddy 		 * Clear bootmac, to signal that we loaded this file from a
1001ad424d98Snaddy 		 * non-network device.
1002ad424d98Snaddy 		 */
1003ad424d98Snaddy 		bootmac = NULL;
1004ad424d98Snaddy 	}
1005ad424d98Snaddy 
1006f24071e5Spatrick 	return (*dp->dv_open)(f, unit, part);
1007f24071e5Spatrick }
1008f24071e5Spatrick 
1009fa854029Spatrick static void
efi_memprobe_internal(void)1010fa854029Spatrick efi_memprobe_internal(void)
1011fa854029Spatrick {
1012fa854029Spatrick 	EFI_STATUS		 status;
1013fa854029Spatrick 	UINTN			 mapkey, mmsiz, siz;
1014fa854029Spatrick 	UINT32			 mmver;
1015fa854029Spatrick 	EFI_MEMORY_DESCRIPTOR	*mm;
1016fa854029Spatrick 	int			 n;
1017fa854029Spatrick 
1018fa854029Spatrick 	free(mmap, mmap_ndesc * mmap_descsiz);
1019fa854029Spatrick 
1020fa854029Spatrick 	siz = 0;
10211f462730Skrw 	status = BS->GetMemoryMap(&siz, NULL, &mapkey, &mmsiz, &mmver);
1022fa854029Spatrick 	if (status != EFI_BUFFER_TOO_SMALL)
1023fa854029Spatrick 		panic("cannot get the size of memory map");
1024fa854029Spatrick 	mm = alloc(siz);
10251f462730Skrw 	status = BS->GetMemoryMap(&siz, mm, &mapkey, &mmsiz, &mmver);
1026fa854029Spatrick 	if (status != EFI_SUCCESS)
1027fa854029Spatrick 		panic("cannot get the memory map");
1028fa854029Spatrick 	n = siz / mmsiz;
1029fa854029Spatrick 	mmap = mm;
1030fa854029Spatrick 	mmap_key = mapkey;
1031fa854029Spatrick 	mmap_ndesc = n;
1032fa854029Spatrick 	mmap_descsiz = mmsiz;
1033f4dd1aebSkettenis 	mmap_version = mmver;
1034fa854029Spatrick }
1035fa854029Spatrick 
1036f24071e5Spatrick /*
1037f24071e5Spatrick  * 64-bit ARMs can have a much wider memory mapping, as in somewhere
1038f24071e5Spatrick  * after the 32-bit region.  To cope with our alignment requirement,
1039f24071e5Spatrick  * use the memory table to find a place where we can fit.
1040f24071e5Spatrick  */
1041f24071e5Spatrick static EFI_STATUS
efi_memprobe_find(UINTN pages,UINTN align,EFI_MEMORY_TYPE type,EFI_PHYSICAL_ADDRESS * addr)10422c32ef33Skettenis efi_memprobe_find(UINTN pages, UINTN align, EFI_MEMORY_TYPE type,
10432c32ef33Skettenis     EFI_PHYSICAL_ADDRESS *addr)
1044f24071e5Spatrick {
1045fa854029Spatrick 	EFI_MEMORY_DESCRIPTOR	*mm;
1046fa854029Spatrick 	int			 i, j;
1047f24071e5Spatrick 
1048f24071e5Spatrick 	if (align < EFI_PAGE_SIZE)
1049f24071e5Spatrick 		return EFI_INVALID_PARAMETER;
1050f24071e5Spatrick 
1051fa854029Spatrick 	efi_memprobe_internal();	/* sync the current map */
1052f24071e5Spatrick 
1053fa854029Spatrick 	for (i = 0, mm = mmap; i < mmap_ndesc;
1054fa854029Spatrick 	    i++, mm = NextMemoryDescriptor(mm, mmap_descsiz)) {
1055f24071e5Spatrick 		if (mm->Type != EfiConventionalMemory)
1056f24071e5Spatrick 			continue;
1057f24071e5Spatrick 
1058f24071e5Spatrick 		if (mm->NumberOfPages < pages)
1059f24071e5Spatrick 			continue;
1060f24071e5Spatrick 
1061f2c0e408Skettenis 		for (j = 0; j < mm->NumberOfPages; j++) {
1062f24071e5Spatrick 			EFI_PHYSICAL_ADDRESS paddr;
1063f24071e5Spatrick 
1064f24071e5Spatrick 			if (mm->NumberOfPages - j < pages)
1065f24071e5Spatrick 				break;
1066f24071e5Spatrick 
1067f24071e5Spatrick 			paddr = mm->PhysicalStart + (j * EFI_PAGE_SIZE);
106873dc1409Spatrick 			if (paddr & (align - 1))
106973dc1409Spatrick 				continue;
107073dc1409Spatrick 
10712c32ef33Skettenis 			if (BS->AllocatePages(AllocateAddress, type,
10721f462730Skrw 			    pages, &paddr) == EFI_SUCCESS) {
1073f24071e5Spatrick 				*addr = paddr;
1074f24071e5Spatrick 				return EFI_SUCCESS;
1075f24071e5Spatrick 			}
1076f24071e5Spatrick 		}
1077f24071e5Spatrick 	}
1078f24071e5Spatrick 	return EFI_OUT_OF_RESOURCES;
1079f24071e5Spatrick }
1080111d6387Skettenis 
1081f3468426Skettenis int
mdrandom(char * buf,size_t buflen)1082f3468426Skettenis mdrandom(char *buf, size_t buflen)
1083f3468426Skettenis {
1084f3468426Skettenis 	char *random;
1085f3468426Skettenis 	void *node;
1086f3468426Skettenis 	int i, len, ret = -1;
1087f3468426Skettenis 
1088f3468426Skettenis 	node = fdt_find_node("/chosen");
1089f3468426Skettenis 	if (!node)
1090f3468426Skettenis 		return -1;
1091f3468426Skettenis 
1092f3468426Skettenis 	len = fdt_node_property(node, "rng-seed", &random);
1093f3468426Skettenis 	if (len > 0) {
1094f3468426Skettenis 		for (i = 0; i < buflen; i++)
1095f3468426Skettenis 			buf[i] ^= random[i % len];
1096f3468426Skettenis 		ret = 0;
1097f3468426Skettenis 	}
1098f3468426Skettenis 
1099f3468426Skettenis 	len = fdt_node_property(node, "kaslr-seed", &random);
1100f3468426Skettenis 	if (len > 0) {
1101f3468426Skettenis 		for (i = 0; i < buflen; i++)
1102f3468426Skettenis 			buf[i] ^= random[i % len];
1103f3468426Skettenis 		ret = 0;
1104f3468426Skettenis 	}
1105f3468426Skettenis 
1106f3468426Skettenis 	return ret;
1107f3468426Skettenis }
1108f3468426Skettenis 
11094befd8f0Spatrick #define FW_PATH "/etc/firmware/dtb/"
11104befd8f0Spatrick 
11114befd8f0Spatrick void *
efi_fdt(void)11124befd8f0Spatrick efi_fdt(void)
11134befd8f0Spatrick {
11144befd8f0Spatrick 	extern char *hw_vendor, *hw_prod;
11154befd8f0Spatrick 
11164befd8f0Spatrick 	/* 'mach dtb' has precedence */
11174befd8f0Spatrick 	if (fdt_override != NULL)
11184befd8f0Spatrick 		return fdt_override;
11194befd8f0Spatrick 
11204befd8f0Spatrick 	/* Return system provided one */
11214befd8f0Spatrick 	if (hw_vendor == NULL || hw_prod == NULL)
11224befd8f0Spatrick 		return fdt_sys;
11234befd8f0Spatrick 
1124*d6abfaa7Skettenis 	if (strcmp(hw_vendor, "LENOVO") == 0) {
1125*d6abfaa7Skettenis 		if (strncmp(hw_prod, "21BX", 4) == 0 ||
1126*d6abfaa7Skettenis 		    strncmp(hw_prod, "21BY", 4) == 0) {
11274befd8f0Spatrick 			fdt_load_override(FW_PATH
11284befd8f0Spatrick 			    "qcom/sc8280xp-lenovo-thinkpad-x13s.dtb");
1129a36d06b9Spatrick 			/* TODO: find a better mechanism */
1130a36d06b9Spatrick 			cnset(ttydev("fb0"));
1131a36d06b9Spatrick 		}
1132*d6abfaa7Skettenis 	}
11334befd8f0Spatrick 
11344befd8f0Spatrick 	return fdt_override ? fdt_override : fdt_sys;
11354befd8f0Spatrick }
11364befd8f0Spatrick 
11374befd8f0Spatrick int
fdt_load_override(char * file)11384befd8f0Spatrick fdt_load_override(char *file)
11394befd8f0Spatrick {
11404befd8f0Spatrick 	EFI_PHYSICAL_ADDRESS addr;
11414befd8f0Spatrick 	char path[MAXPATHLEN];
11424befd8f0Spatrick 	struct stat sb;
11434befd8f0Spatrick 	int fd;
11444befd8f0Spatrick 
11454befd8f0Spatrick 	if (file == NULL && fdt_override) {
11464befd8f0Spatrick 		BS->FreePages((uint64_t)fdt_override,
11474befd8f0Spatrick 		    EFI_SIZE_TO_PAGES(fdt_override_size));
11484befd8f0Spatrick 		fdt_override = NULL;
11494befd8f0Spatrick 		fdt_init(fdt_sys);
11504befd8f0Spatrick 		return 0;
11514befd8f0Spatrick 	}
11524befd8f0Spatrick 
11534befd8f0Spatrick 	snprintf(path, sizeof(path), "%s:%s", cmd.bootdev, file);
11544befd8f0Spatrick 
11554befd8f0Spatrick 	fd = open(path, O_RDONLY);
11564befd8f0Spatrick 	if (fd < 0 || fstat(fd, &sb) == -1) {
11574befd8f0Spatrick 		printf("cannot open %s\n", path);
11584befd8f0Spatrick 		return 0;
11594befd8f0Spatrick 	}
11604befd8f0Spatrick 	if (efi_memprobe_find(EFI_SIZE_TO_PAGES(sb.st_size),
11614befd8f0Spatrick 	    PAGE_SIZE, EfiLoaderData, &addr) != EFI_SUCCESS) {
11624befd8f0Spatrick 		printf("cannot allocate memory for %s\n", path);
11634befd8f0Spatrick 		return 0;
11644befd8f0Spatrick 	}
11654befd8f0Spatrick 	if (read(fd, (void *)addr, sb.st_size) != sb.st_size) {
11664befd8f0Spatrick 		printf("cannot read from %s\n", path);
11674befd8f0Spatrick 		return 0;
11684befd8f0Spatrick 	}
11694befd8f0Spatrick 
11704befd8f0Spatrick 	if (!fdt_init((void *)addr)) {
11714befd8f0Spatrick 		printf("invalid device tree\n");
11724befd8f0Spatrick 		BS->FreePages(addr, EFI_SIZE_TO_PAGES(sb.st_size));
11734befd8f0Spatrick 		return 0;
11744befd8f0Spatrick 	}
11754befd8f0Spatrick 
11764befd8f0Spatrick 	if (fdt_override) {
11774befd8f0Spatrick 		BS->FreePages((uint64_t)fdt_override,
11784befd8f0Spatrick 		    EFI_SIZE_TO_PAGES(fdt_override_size));
11794befd8f0Spatrick 		fdt_override = NULL;
11804befd8f0Spatrick 	}
11814befd8f0Spatrick 
11824befd8f0Spatrick 	fdt_override = (void *)addr;
11834befd8f0Spatrick 	fdt_override_size = sb.st_size;
11844befd8f0Spatrick 	return 0;
11854befd8f0Spatrick }
11864befd8f0Spatrick 
1187111d6387Skettenis /*
1188111d6387Skettenis  * Commands
1189111d6387Skettenis  */
1190111d6387Skettenis 
1191be07ee62Skettenis int Xacpi_efi(void);
11926f83097eSpatrick int Xdtb_efi(void);
1193111d6387Skettenis int Xexit_efi(void);
1194111d6387Skettenis int Xpoweroff_efi(void);
1195111d6387Skettenis 
1196111d6387Skettenis const struct cmd_table cmd_machine[] = {
1197be07ee62Skettenis 	{ "acpi",	CMDT_CMD, Xacpi_efi },
11986f83097eSpatrick 	{ "dtb",	CMDT_CMD, Xdtb_efi },
1199111d6387Skettenis 	{ "exit",	CMDT_CMD, Xexit_efi },
1200111d6387Skettenis 	{ "poweroff",	CMDT_CMD, Xpoweroff_efi },
1201111d6387Skettenis 	{ NULL, 0 }
1202111d6387Skettenis };
1203111d6387Skettenis 
1204111d6387Skettenis int
Xacpi_efi(void)1205be07ee62Skettenis Xacpi_efi(void)
1206be07ee62Skettenis {
1207be07ee62Skettenis 	acpi = 1;
1208be07ee62Skettenis 	return (0);
1209be07ee62Skettenis }
1210be07ee62Skettenis 
1211be07ee62Skettenis int
Xdtb_efi(void)12126f83097eSpatrick Xdtb_efi(void)
12136f83097eSpatrick {
12144befd8f0Spatrick 	if (cmd.argc == 1) {
12154befd8f0Spatrick 		fdt_load_override(NULL);
12164befd8f0Spatrick 		return (0);
12174befd8f0Spatrick 	}
12186f83097eSpatrick 
1219fcf3d43cSkn 	if (cmd.argc != 2) {
1220fcf3d43cSkn 		printf("dtb file\n");
1221fcf3d43cSkn 		return (0);
1222fcf3d43cSkn 	}
12236f83097eSpatrick 
12244befd8f0Spatrick 	return fdt_load_override(cmd.argv[1]);
12256f83097eSpatrick }
12266f83097eSpatrick 
12276f83097eSpatrick int
Xexit_efi(void)1228111d6387Skettenis Xexit_efi(void)
1229111d6387Skettenis {
12301f462730Skrw 	BS->Exit(IH, 0, 0, NULL);
1231111d6387Skettenis 	for (;;)
1232111d6387Skettenis 		continue;
1233111d6387Skettenis 	return (0);
1234111d6387Skettenis }
1235111d6387Skettenis 
1236111d6387Skettenis int
Xpoweroff_efi(void)1237111d6387Skettenis Xpoweroff_efi(void)
1238111d6387Skettenis {
12391f462730Skrw 	RS->ResetSystem(EfiResetShutdown, EFI_SUCCESS, 0, NULL);
1240111d6387Skettenis 	return (0);
1241111d6387Skettenis }
1242