1/*	$OpenBSD: efiboot.c,v 1.40 2022/12/22 15:44:02 kettenis Exp $	*/
2
3/*
4 * Copyright (c) 2015 YASUOKA Masahiko <yasuoka@yasuoka.net>
5 * Copyright (c) 2016 Mark Kettenis
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20#include <sys/param.h>
21#include <sys/queue.h>
22#include <sys/stat.h>
23#include <dev/cons.h>
24#include <sys/disklabel.h>
25
26#include <efi.h>
27#include <efiapi.h>
28#include <efiprot.h>
29#include <eficonsctl.h>
30
31#include <lib/libkern/libkern.h>
32#include <stand/boot/cmd.h>
33
34#include "libsa.h"
35#include "disk.h"
36
37#include "efidev.h"
38#include "efiboot.h"
39#include "fdt.h"
40
41EFI_SYSTEM_TABLE	*ST;
42EFI_BOOT_SERVICES	*BS;
43EFI_RUNTIME_SERVICES	*RS;
44EFI_HANDLE		 IH, efi_bootdp;
45void			*fdt_sys = NULL;
46void			*fdt_override = NULL;
47size_t			 fdt_override_size;
48
49EFI_PHYSICAL_ADDRESS	 heap;
50UINTN			 heapsiz = 1 * 1024 * 1024;
51EFI_MEMORY_DESCRIPTOR	*mmap;
52UINTN			 mmap_key;
53UINTN			 mmap_ndesc;
54UINTN			 mmap_descsiz;
55UINT32			 mmap_version;
56
57static EFI_GUID		 imgp_guid = LOADED_IMAGE_PROTOCOL;
58static EFI_GUID		 blkio_guid = BLOCK_IO_PROTOCOL;
59static EFI_GUID		 devp_guid = DEVICE_PATH_PROTOCOL;
60static EFI_GUID		 gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
61static EFI_GUID		 fdt_guid = FDT_TABLE_GUID;
62
63#define efi_guidcmp(_a, _b)	memcmp((_a), (_b), sizeof(EFI_GUID))
64
65int efi_device_path_depth(EFI_DEVICE_PATH *dp, int);
66int efi_device_path_ncmp(EFI_DEVICE_PATH *, EFI_DEVICE_PATH *, int);
67static void efi_heap_init(void);
68static void efi_memprobe_internal(void);
69static void efi_timer_init(void);
70static void efi_timer_cleanup(void);
71static EFI_STATUS efi_memprobe_find(UINTN, UINTN, EFI_MEMORY_TYPE,
72    EFI_PHYSICAL_ADDRESS *);
73void *efi_fdt(void);
74int fdt_load_override(char *);
75
76EFI_STATUS
77efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab)
78{
79	extern char		*progname;
80	EFI_LOADED_IMAGE	*imgp;
81	EFI_DEVICE_PATH		*dp = NULL;
82	EFI_STATUS		 status;
83	int			 i;
84
85	ST = systab;
86	BS = ST->BootServices;
87	RS = ST->RuntimeServices;
88	IH = image;
89
90	/* disable reset by watchdog after 5 minutes */
91	BS->SetWatchdogTimer(0, 0, 0, NULL);
92
93	status = BS->HandleProtocol(image, &imgp_guid, (void **)&imgp);
94	if (status == EFI_SUCCESS)
95		status = BS->HandleProtocol(imgp->DeviceHandle, &devp_guid,
96		    (void **)&dp);
97	if (status == EFI_SUCCESS)
98		efi_bootdp = dp;
99
100	for (i = 0; i < ST->NumberOfTableEntries; i++) {
101		if (efi_guidcmp(&fdt_guid,
102		    &ST->ConfigurationTable[i].VendorGuid) == 0)
103			fdt_sys = ST->ConfigurationTable[i].VendorTable;
104	}
105	fdt_init(fdt_sys);
106
107	progname = "BOOTARM";
108
109	boot(0);
110
111	return (EFI_SUCCESS);
112}
113
114static SIMPLE_TEXT_OUTPUT_INTERFACE *conout;
115static SIMPLE_INPUT_INTERFACE *conin;
116
117/*
118 * The device majors for these don't match the ones used by the
119 * kernel.  That's fine.  They're just used as an index into the cdevs
120 * array and never passed on to the kernel.
121 */
122static dev_t serial = makedev(1, 0);
123static dev_t framebuffer = makedev(2, 0);
124
125static char framebuffer_path[128];
126
127void
128efi_cons_probe(struct consdev *cn)
129{
130	cn->cn_pri = CN_MIDPRI;
131	cn->cn_dev = makedev(0, 0);
132}
133
134void
135efi_cons_init(struct consdev *cp)
136{
137	conin = ST->ConIn;
138	conout = ST->ConOut;
139}
140
141int
142efi_cons_getc(dev_t dev)
143{
144	EFI_INPUT_KEY	 key;
145	EFI_STATUS	 status;
146#if 0
147	UINTN		 dummy;
148#endif
149	static int	 lastchar = 0;
150
151	if (lastchar) {
152		int r = lastchar;
153		if ((dev & 0x80) == 0)
154			lastchar = 0;
155		return (r);
156	}
157
158	status = conin->ReadKeyStroke(conin, &key);
159	while (status == EFI_NOT_READY || key.UnicodeChar == 0) {
160		if (dev & 0x80)
161			return (0);
162		/*
163		 * XXX The implementation of WaitForEvent() in U-boot
164		 * is broken and neverreturns.
165		 */
166#if 0
167		BS->WaitForEvent(1, &conin->WaitForKey, &dummy);
168#endif
169		status = conin->ReadKeyStroke(conin, &key);
170	}
171
172	if (dev & 0x80)
173		lastchar = key.UnicodeChar;
174
175	return (key.UnicodeChar);
176}
177
178void
179efi_cons_putc(dev_t dev, int c)
180{
181	CHAR16	buf[2];
182
183	if (c == '\n')
184		efi_cons_putc(dev, '\r');
185
186	buf[0] = c;
187	buf[1] = 0;
188
189	conout->OutputString(conout, buf);
190}
191
192void
193efi_com_probe(struct consdev *cn)
194{
195	cn->cn_pri = CN_LOWPRI;
196	cn->cn_dev = serial;
197}
198
199void
200efi_com_init(struct consdev *cn)
201{
202	conin = ST->ConIn;
203	conout = ST->ConOut;
204}
205
206int
207efi_com_getc(dev_t dev)
208{
209	return efi_cons_getc(dev);
210}
211
212void
213efi_com_putc(dev_t dev, int c)
214{
215	efi_cons_putc(dev, c);
216}
217
218void
219efi_fb_probe(struct consdev *cn)
220{
221	cn->cn_pri = CN_LOWPRI;
222	cn->cn_dev = framebuffer;
223}
224
225void
226efi_fb_init(struct consdev *cn)
227{
228	conin = ST->ConIn;
229	conout = ST->ConOut;
230}
231
232int
233efi_fb_getc(dev_t dev)
234{
235	return efi_cons_getc(dev);
236}
237
238void
239efi_fb_putc(dev_t dev, int c)
240{
241	efi_cons_putc(dev, c);
242}
243
244static void
245efi_heap_init(void)
246{
247	EFI_STATUS	 status;
248
249	status = BS->AllocatePages(AllocateAnyPages, EfiLoaderData,
250	    EFI_SIZE_TO_PAGES(heapsiz), &heap);
251	if (status != EFI_SUCCESS)
252		panic("BS->AllocatePages()");
253}
254
255struct disklist_lh disklist;
256struct diskinfo *bootdev_dip;
257
258void
259efi_diskprobe(void)
260{
261	int			 i, bootdev = 0, depth = -1;
262	UINTN			 sz;
263	EFI_STATUS		 status;
264	EFI_HANDLE		*handles = NULL;
265	EFI_BLOCK_IO		*blkio;
266	EFI_BLOCK_IO_MEDIA	*media;
267	struct diskinfo		*di;
268	EFI_DEVICE_PATH		*dp;
269
270	TAILQ_INIT(&disklist);
271
272	sz = 0;
273	status = BS->LocateHandle(ByProtocol, &blkio_guid, 0, &sz, 0);
274	if (status == EFI_BUFFER_TOO_SMALL) {
275		handles = alloc(sz);
276		status = BS->LocateHandle(ByProtocol, &blkio_guid, 0, &sz,
277		    handles);
278	}
279	if (handles == NULL || EFI_ERROR(status))
280		return;
281
282	if (efi_bootdp != NULL)
283		depth = efi_device_path_depth(efi_bootdp, MEDIA_DEVICE_PATH);
284
285	/*
286	 * U-Boot incorrectly represents devices with a single
287	 * MEDIA_DEVICE_PATH component.  In that case include that
288	 * component into the matching, otherwise we'll blindly select
289	 * the first device.
290	 */
291	if (depth == 0)
292		depth = 1;
293
294	for (i = 0; i < sz / sizeof(EFI_HANDLE); i++) {
295		status = BS->HandleProtocol(handles[i], &blkio_guid,
296		    (void **)&blkio);
297		if (EFI_ERROR(status))
298			panic("BS->HandleProtocol() returns %d", status);
299
300		media = blkio->Media;
301		if (media->LogicalPartition || !media->MediaPresent)
302			continue;
303		di = alloc(sizeof(struct diskinfo));
304		efid_init(di, blkio);
305
306		if (efi_bootdp == NULL || depth == -1 || bootdev != 0)
307			goto next;
308		status = BS->HandleProtocol(handles[i], &devp_guid,
309		    (void **)&dp);
310		if (EFI_ERROR(status))
311			goto next;
312		if (efi_device_path_ncmp(efi_bootdp, dp, depth) == 0) {
313			TAILQ_INSERT_HEAD(&disklist, di, list);
314			bootdev_dip = di;
315			bootdev = 1;
316			continue;
317		}
318next:
319		TAILQ_INSERT_TAIL(&disklist, di, list);
320	}
321
322	free(handles, sz);
323
324	/* Print available disks. */
325	i = 0;
326	printf("disks:");
327	TAILQ_FOREACH(di, &disklist, list) {
328		printf(" sd%d%s", i, di == bootdev_dip ? "*" : "");
329		i++;
330	}
331	printf("\n");
332}
333
334/*
335 * Determine the number of nodes up to, but not including, the first
336 * node of the specified type.
337 */
338int
339efi_device_path_depth(EFI_DEVICE_PATH *dp, int dptype)
340{
341	int	i;
342
343	for (i = 0; !IsDevicePathEnd(dp); dp = NextDevicePathNode(dp), i++) {
344		if (DevicePathType(dp) == dptype)
345			return (i);
346	}
347
348	return (i);
349}
350
351int
352efi_device_path_ncmp(EFI_DEVICE_PATH *dpa, EFI_DEVICE_PATH *dpb, int deptn)
353{
354	int	 i, cmp;
355
356	for (i = 0; i < deptn; i++) {
357		if (IsDevicePathEnd(dpa) || IsDevicePathEnd(dpb))
358			return ((IsDevicePathEnd(dpa) && IsDevicePathEnd(dpb))
359			    ? 0 : (IsDevicePathEnd(dpa))? -1 : 1);
360		cmp = DevicePathNodeLength(dpa) - DevicePathNodeLength(dpb);
361		if (cmp)
362			return (cmp);
363		cmp = memcmp(dpa, dpb, DevicePathNodeLength(dpa));
364		if (cmp)
365			return (cmp);
366		dpa = NextDevicePathNode(dpa);
367		dpb = NextDevicePathNode(dpb);
368	}
369
370	return (0);
371}
372
373void
374efi_framebuffer(void)
375{
376	EFI_GRAPHICS_OUTPUT *gop;
377	EFI_STATUS status;
378	void *node, *child;
379	uint32_t acells, scells;
380	uint64_t base, size;
381	uint32_t reg[4];
382	uint32_t width, height, stride;
383	char *format;
384	char *prop;
385
386	/*
387	 * Don't create a "simple-framebuffer" node if we already have
388	 * one.  Besides "/chosen", we also check under "/" since that
389	 * is where the Raspberry Pi firmware puts it.
390	 */
391	node = fdt_find_node("/chosen");
392	for (child = fdt_child_node(node); child;
393	     child = fdt_next_node(child)) {
394		if (!fdt_node_is_compatible(child, "simple-framebuffer"))
395			continue;
396		if (!fdt_node_property(child, "status", &prop) ||
397		    strcmp(prop, "okay") == 0) {
398			strlcpy(framebuffer_path, "/chosen/",
399			    sizeof(framebuffer_path));
400			strlcat(framebuffer_path, fdt_node_name(child),
401			    sizeof(framebuffer_path));
402			return;
403		}
404	}
405	node = fdt_find_node("/");
406	for (child = fdt_child_node(node); child;
407	     child = fdt_next_node(child)) {
408		if (!fdt_node_is_compatible(child, "simple-framebuffer"))
409			continue;
410		if (!fdt_node_property(child, "status", &prop) ||
411		    strcmp(prop, "okay") == 0) {
412			strlcpy(framebuffer_path, "/",
413			    sizeof(framebuffer_path));
414			strlcat(framebuffer_path, fdt_node_name(child),
415			    sizeof(framebuffer_path));
416			return;
417		}
418	}
419
420	status = BS->LocateProtocol(&gop_guid, NULL, (void **)&gop);
421	if (status != EFI_SUCCESS)
422		return;
423
424	/* Paranoia! */
425	if (gop == NULL || gop->Mode == NULL || gop->Mode->Info == NULL)
426		return;
427
428	/* We only support 32-bit pixel modes for now. */
429	switch (gop->Mode->Info->PixelFormat) {
430	case PixelRedGreenBlueReserved8BitPerColor:
431		format = "x8b8g8r8";
432		break;
433	case PixelBlueGreenRedReserved8BitPerColor:
434		format = "x8r8g8b8";
435		break;
436	default:
437		return;
438	}
439
440	base = gop->Mode->FrameBufferBase;
441	size = gop->Mode->FrameBufferSize;
442	width = htobe32(gop->Mode->Info->HorizontalResolution);
443	height = htobe32(gop->Mode->Info->VerticalResolution);
444	stride = htobe32(gop->Mode->Info->PixelsPerScanLine * 4);
445
446	node = fdt_find_node("/");
447	if (fdt_node_property_int(node, "#address-cells", &acells) != 1)
448		acells = 1;
449	if (fdt_node_property_int(node, "#size-cells", &scells) != 1)
450		scells = 1;
451	if (acells > 2 || scells > 2)
452		return;
453	if (acells >= 1)
454		reg[0] = htobe32(base);
455	if (acells == 2) {
456		reg[1] = reg[0];
457		reg[0] = htobe32(base >> 32);
458	}
459	if (scells >= 1)
460		reg[acells] = htobe32(size);
461	if (scells == 2) {
462		reg[acells + 1] = reg[acells];
463		reg[acells] = htobe32(size >> 32);
464	}
465
466	node = fdt_find_node("/chosen");
467	fdt_node_add_node(node, "framebuffer", &child);
468	fdt_node_add_property(child, "status", "okay", strlen("okay") + 1);
469	fdt_node_add_property(child, "format", format, strlen(format) + 1);
470	fdt_node_add_property(child, "stride", &stride, 4);
471	fdt_node_add_property(child, "height", &height, 4);
472	fdt_node_add_property(child, "width", &width, 4);
473	fdt_node_add_property(child, "reg", reg, (acells + scells) * 4);
474	fdt_node_add_property(child, "compatible",
475	    "simple-framebuffer", strlen("simple-framebuffer") + 1);
476
477	strlcpy(framebuffer_path, "/chosen/framebuffer",
478	    sizeof(framebuffer_path));
479}
480
481void
482efi_console(void)
483{
484	void *node;
485
486	if (major(cn_tab->cn_dev) == major(serial)) {
487		char *serial_path;
488		char alias[16];
489		int len;
490
491		/* Construct alias and resolve it. */
492		snprintf(alias, sizeof(alias), "serial%d",
493		    minor(cn_tab->cn_dev));
494		node = fdt_find_node("/aliases");
495		len = fdt_node_property(node, alias, &serial_path);
496		if (len <= 0)
497			return;
498
499		/* Point stdout-path at the serial node. */
500		node = fdt_find_node("/chosen");
501		fdt_node_add_property(node, "stdout-path",
502		    serial_path, strlen(serial_path) + 1);
503	} else if (major(cn_tab->cn_dev) == major(framebuffer)) {
504		if (strlen(framebuffer_path) == 0)
505			return;
506
507		/* Point stdout-path at the framebuffer node. */
508		node = fdt_find_node("/chosen");
509		fdt_node_add_property(node, "stdout-path",
510		    framebuffer_path, strlen(framebuffer_path) + 1);
511	}
512}
513
514uint64_t dma_constraint[2] = { 0, -1 };
515
516void
517efi_dma_constraint(void)
518{
519	void *node;
520
521	/* Raspberry Pi 4 is "special". */
522	node = fdt_find_node("/");
523	if (fdt_node_is_compatible(node, "brcm,bcm2711"))
524		dma_constraint[1] = htobe64(0x3bffffff);
525
526	/* Not all bus masters can access 0x0-0x7ffff on Zynq-7000. */
527	if (fdt_node_is_compatible(node, "xlnx,zynq-7000"))
528		dma_constraint[0] = htobe64(0x00080000);
529
530	/* Pass DMA constraint. */
531	node = fdt_find_node("/chosen");
532	fdt_node_add_property(node, "openbsd,dma-constraint",
533	    dma_constraint, sizeof(dma_constraint));
534}
535
536char *bootmac = NULL;
537
538void *
539efi_makebootargs(char *bootargs, int howto)
540{
541	u_char bootduid[8];
542	u_char zero[8] = { 0 };
543	uint64_t uefi_system_table = htobe64((uintptr_t)ST);
544	uint32_t boothowto = htobe32(howto);
545	EFI_PHYSICAL_ADDRESS addr;
546	void *node, *fdt;
547	size_t len;
548
549	fdt = efi_fdt();
550	if (fdt == NULL)
551		return NULL;
552
553	if (!fdt_get_size(fdt))
554		return NULL;
555
556	len = roundup(fdt_get_size(fdt) + PAGE_SIZE, PAGE_SIZE);
557	if (BS->AllocatePages(AllocateAnyPages, EfiLoaderData,
558	    EFI_SIZE_TO_PAGES(len), &addr) == EFI_SUCCESS) {
559		memcpy((void *)addr, fdt, fdt_get_size(fdt));
560		((struct fdt_head *)addr)->fh_size = htobe32(len);
561		fdt = (void *)addr;
562	}
563
564	if (!fdt_init(fdt))
565		return NULL;
566
567	/* Create common nodes which might not exist when using mach dtb */
568	node = fdt_find_node("/aliases");
569	if (node == NULL)
570		fdt_node_add_node(fdt_find_node("/"), "aliases", &node);
571	node = fdt_find_node("/chosen");
572	if (node == NULL)
573		fdt_node_add_node(fdt_find_node("/"), "chosen", &node);
574
575	node = fdt_find_node("/chosen");
576	len = strlen(bootargs) + 1;
577	fdt_node_add_property(node, "bootargs", bootargs, len);
578	fdt_node_add_property(node, "openbsd,boothowto",
579	    &boothowto, sizeof(boothowto));
580
581	/* Pass DUID of the boot disk. */
582	if (bootdev_dip) {
583		memcpy(&bootduid, bootdev_dip->disklabel.d_uid,
584		    sizeof(bootduid));
585		if (memcmp(bootduid, zero, sizeof(bootduid)) != 0) {
586			fdt_node_add_property(node, "openbsd,bootduid",
587			    bootduid, sizeof(bootduid));
588		}
589	}
590
591	/* Pass netboot interface address. */
592	if (bootmac)
593		fdt_node_add_property(node, "openbsd,bootmac", bootmac, 6);
594
595	/* Pass EFI system table. */
596	fdt_node_add_property(node, "openbsd,uefi-system-table",
597	    &uefi_system_table, sizeof(uefi_system_table));
598
599	/* Placeholders for EFI memory map. */
600	fdt_node_add_property(node, "openbsd,uefi-mmap-start", zero, 8);
601	fdt_node_add_property(node, "openbsd,uefi-mmap-size", zero, 4);
602	fdt_node_add_property(node, "openbsd,uefi-mmap-desc-size", zero, 4);
603	fdt_node_add_property(node, "openbsd,uefi-mmap-desc-ver", zero, 4);
604
605	efi_framebuffer();
606	efi_console();
607	efi_dma_constraint();
608
609	fdt_finalize();
610
611	return fdt;
612}
613
614void
615efi_updatefdt(void)
616{
617	uint64_t uefi_mmap_start = htobe64((uintptr_t)mmap);
618	uint32_t uefi_mmap_size = htobe32(mmap_ndesc * mmap_descsiz);
619	uint32_t uefi_mmap_desc_size = htobe32(mmap_descsiz);
620	uint32_t uefi_mmap_desc_ver = htobe32(mmap_version);
621	void *node;
622
623	node = fdt_find_node("/chosen");
624	if (!node)
625		return;
626
627	/* Pass EFI memory map. */
628	fdt_node_set_property(node, "openbsd,uefi-mmap-start",
629	    &uefi_mmap_start, sizeof(uefi_mmap_start));
630	fdt_node_set_property(node, "openbsd,uefi-mmap-size",
631	    &uefi_mmap_size, sizeof(uefi_mmap_size));
632	fdt_node_set_property(node, "openbsd,uefi-mmap-desc-size",
633	    &uefi_mmap_desc_size, sizeof(uefi_mmap_desc_size));
634	fdt_node_set_property(node, "openbsd,uefi-mmap-desc-ver",
635	    &uefi_mmap_desc_ver, sizeof(uefi_mmap_desc_ver));
636
637	fdt_finalize();
638}
639
640u_long efi_loadaddr;
641
642void
643machdep(void)
644{
645	EFI_PHYSICAL_ADDRESS addr;
646	EFI_STATUS status;
647
648	cninit();
649	efi_heap_init();
650
651	/*
652	 * The kernel expects to be loaded at offset 0x00300000 into a
653	 * block of memory aligned on a 256MB boundary.  We allocate a
654	 * block of 32MB of memory, which gives us plenty of room for
655	 * growth.
656	 */
657	for (addr = 0x10000000; addr <= 0xf0000000; addr += 0x10000000) {
658		status = BS->AllocatePages(AllocateAddress, EfiLoaderData,
659		    EFI_SIZE_TO_PAGES(32 * 1024 * 1024), &addr);
660		if (status == EFI_SUCCESS) {
661			efi_loadaddr = addr;
662			break;
663		}
664	}
665	if (efi_loadaddr == 0)
666		printf("Can't allocate memory\n");
667
668	efi_timer_init();
669	efi_diskprobe();
670	efi_pxeprobe();
671}
672
673void
674efi_cleanup(void)
675{
676	int		 retry;
677	EFI_STATUS	 status;
678
679	efi_timer_cleanup();
680
681	/* retry once in case of failure */
682	for (retry = 1; retry >= 0; retry--) {
683		efi_memprobe_internal();	/* sync the current map */
684		efi_updatefdt();
685		status = BS->ExitBootServices(IH, mmap_key);
686		if (status == EFI_SUCCESS)
687			break;
688		if (retry == 0)
689			panic("ExitBootServices failed (%d)", status);
690	}
691}
692
693void
694_rtt(void)
695{
696#ifdef EFI_DEBUG
697	printf("Hit any key to reboot\n");
698	efi_cons_getc(0);
699#endif
700	RS->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL);
701	for (;;)
702		continue;
703}
704
705/*
706 * U-Boot only implements the GetTime() Runtime Service if it has been
707 * configured with CONFIG_DM_RTC.  Most board configurations don't
708 * include that option, so we can't use it to implement our boot
709 * prompt timeout.  Instead we use timer events to simulate a clock
710 * that ticks ever second.
711 */
712
713EFI_EVENT timer;
714int ticks;
715
716static VOID
717efi_timer(EFI_EVENT event, VOID *context)
718{
719	ticks++;
720}
721
722static void
723efi_timer_init(void)
724{
725	EFI_STATUS status;
726
727	status = BS->CreateEvent(EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_CALLBACK,
728	    efi_timer, NULL, &timer);
729	if (status == EFI_SUCCESS)
730		status = BS->SetTimer(timer, TimerPeriodic, 10000000);
731	if (EFI_ERROR(status))
732		printf("Can't create timer\n");
733}
734
735static void
736efi_timer_cleanup(void)
737{
738	BS->CloseEvent(timer);
739}
740
741time_t
742getsecs(void)
743{
744	return ticks;
745}
746
747/*
748 * Various device-related bits.
749 */
750
751void
752devboot(dev_t dev, char *p)
753{
754	struct diskinfo *dip;
755	int sd_boot_vol = 0;
756
757	if (bootdev_dip == NULL) {
758		strlcpy(p, "tftp0a", 7);
759		return;
760	}
761
762	TAILQ_FOREACH(dip, &disklist, list) {
763		if (bootdev_dip == dip)
764			break;
765		sd_boot_vol++;
766	}
767
768	strlcpy(p, "sd0a", 5);
769	p[2] = '0' + sd_boot_vol;
770}
771
772const char cdevs[][4] = { "cons", "com", "fb" };
773const int ncdevs = nitems(cdevs);
774
775int
776cnspeed(dev_t dev, int sp)
777{
778	return 115200;
779}
780
781char ttyname_buf[8];
782
783char *
784ttyname(int fd)
785{
786	snprintf(ttyname_buf, sizeof ttyname_buf, "%s%d",
787	    cdevs[major(cn_tab->cn_dev)], minor(cn_tab->cn_dev));
788
789	return ttyname_buf;
790}
791
792dev_t
793ttydev(char *name)
794{
795	int i, unit = -1;
796	char *no = name + strlen(name) - 1;
797
798	while (no >= name && *no >= '0' && *no <= '9')
799		unit = (unit < 0 ? 0 : (unit * 10)) + *no-- - '0';
800	if (no < name || unit < 0)
801		return NODEV;
802	for (i = 0; i < ncdevs; i++)
803		if (strncmp(name, cdevs[i], no - name + 1) == 0)
804			return makedev(i, unit);
805	return NODEV;
806}
807
808#define MAXDEVNAME	16
809
810/*
811 * Parse a device spec.
812 *
813 * [A-Za-z]*[0-9]*[A-Za-z]:file
814 *    dev   uint    part
815 */
816int
817devparse(const char *fname, int *dev, int *unit, int *part, const char **file)
818{
819	const char *s;
820
821	*unit = 0;	/* default to wd0a */
822	*part = 0;
823	*dev  = 0;
824
825	s = strchr(fname, ':');
826	if (s != NULL) {
827		int devlen;
828		int i, u, p = 0;
829		struct devsw *dp;
830		char devname[MAXDEVNAME];
831
832		devlen = s - fname;
833		if (devlen > MAXDEVNAME)
834			return (EINVAL);
835
836		/* extract device name */
837		for (i = 0; isalpha(fname[i]) && (i < devlen); i++)
838			devname[i] = fname[i];
839		devname[i] = 0;
840
841		if (!isdigit(fname[i]))
842			return (EUNIT);
843
844		/* device number */
845		for (u = 0; isdigit(fname[i]) && (i < devlen); i++)
846			u = u * 10 + (fname[i] - '0');
847
848		if (!isalpha(fname[i]))
849			return (EPART);
850
851		/* partition number */
852		if (i < devlen)
853			p = fname[i++] - 'a';
854
855		if (i != devlen)
856			return (ENXIO);
857
858		/* check device name */
859		for (dp = devsw, i = 0; i < ndevs; dp++, i++) {
860			if (dp->dv_name && !strcmp(devname, dp->dv_name))
861				break;
862		}
863
864		if (i >= ndevs)
865			return (ENXIO);
866
867		*unit = u;
868		*part = p;
869		*dev  = i;
870		fname = ++s;
871	}
872
873	*file = fname;
874
875	return (0);
876}
877
878int
879devopen(struct open_file *f, const char *fname, char **file)
880{
881	struct devsw *dp;
882	int dev, unit, part, error;
883
884	error = devparse(fname, &dev, &unit, &part, (const char **)file);
885	if (error)
886		return (error);
887
888	dp = &devsw[dev];
889	f->f_dev = dp;
890
891	if (strcmp("tftp", dp->dv_name) != 0) {
892		/*
893		 * Clear bootmac, to signal that we loaded this file from a
894		 * non-network device.
895		 */
896		bootmac = NULL;
897	}
898
899	return (*dp->dv_open)(f, unit, part);
900}
901
902static void
903efi_memprobe_internal(void)
904{
905	EFI_STATUS		 status;
906	UINTN			 mapkey, mmsiz, siz;
907	UINT32			 mmver;
908	EFI_MEMORY_DESCRIPTOR	*mm;
909	int			 n;
910
911	free(mmap, mmap_ndesc * mmap_descsiz);
912
913	siz = 0;
914	status = BS->GetMemoryMap(&siz, NULL, &mapkey, &mmsiz, &mmver);
915	if (status != EFI_BUFFER_TOO_SMALL)
916		panic("cannot get the size of memory map");
917	mm = alloc(siz);
918	status = BS->GetMemoryMap(&siz, mm, &mapkey, &mmsiz, &mmver);
919	if (status != EFI_SUCCESS)
920		panic("cannot get the memory map");
921	n = siz / mmsiz;
922	mmap = mm;
923	mmap_key = mapkey;
924	mmap_ndesc = n;
925	mmap_descsiz = mmsiz;
926	mmap_version = mmver;
927}
928
929static EFI_STATUS
930efi_memprobe_find(UINTN pages, UINTN align, EFI_MEMORY_TYPE type,
931    EFI_PHYSICAL_ADDRESS *addr)
932{
933	EFI_MEMORY_DESCRIPTOR	*mm;
934	int			 i, j;
935
936	if (align < EFI_PAGE_SIZE)
937		return EFI_INVALID_PARAMETER;
938
939	efi_memprobe_internal();	/* sync the current map */
940
941	for (i = 0, mm = mmap; i < mmap_ndesc;
942	    i++, mm = NextMemoryDescriptor(mm, mmap_descsiz)) {
943		if (mm->Type != EfiConventionalMemory)
944			continue;
945
946		if (mm->NumberOfPages < pages)
947			continue;
948
949		for (j = 0; j < mm->NumberOfPages; j++) {
950			EFI_PHYSICAL_ADDRESS paddr;
951
952			if (mm->NumberOfPages - j < pages)
953				break;
954
955			paddr = mm->PhysicalStart + (j * EFI_PAGE_SIZE);
956			if (paddr & (align - 1))
957				continue;
958
959			if (BS->AllocatePages(AllocateAddress, type,
960			    pages, &paddr) == EFI_SUCCESS) {
961				*addr = paddr;
962				return EFI_SUCCESS;
963			}
964		}
965	}
966	return EFI_OUT_OF_RESOURCES;
967}
968
969int
970mdrandom(char *buf, size_t buflen)
971{
972	char *random;
973	void *node;
974	int i, len, ret = -1;
975
976	node = fdt_find_node("/chosen");
977	if (!node)
978		return -1;
979
980	len = fdt_node_property(node, "rng-seed", &random);
981	if (len > 0) {
982		for (i = 0; i < buflen; i++)
983			buf[i] ^= random[i % len];
984		ret = 0;
985	}
986
987	len = fdt_node_property(node, "kaslr-seed", &random);
988	if (len > 0) {
989		for (i = 0; i < buflen; i++)
990			buf[i] ^= random[i % len];
991		ret = 0;
992	}
993
994	return ret;
995}
996
997void *
998efi_fdt(void)
999{
1000	/* 'mach dtb' has precedence */
1001	if (fdt_override != NULL)
1002		return fdt_override;
1003
1004	return fdt_sys;
1005}
1006
1007int
1008fdt_load_override(char *file)
1009{
1010	EFI_PHYSICAL_ADDRESS addr;
1011	char path[MAXPATHLEN];
1012	struct stat sb;
1013	int fd;
1014
1015	if (file == NULL && fdt_override) {
1016		BS->FreePages((uint64_t)fdt_override,
1017		    EFI_SIZE_TO_PAGES(fdt_override_size));
1018		fdt_override = NULL;
1019		fdt_init(fdt_sys);
1020		return 0;
1021	}
1022
1023	snprintf(path, sizeof(path), "%s:%s", cmd.bootdev, file);
1024
1025	fd = open(path, O_RDONLY);
1026	if (fd < 0 || fstat(fd, &sb) == -1) {
1027		printf("cannot open %s\n", path);
1028		return 0;
1029	}
1030	if (efi_memprobe_find(EFI_SIZE_TO_PAGES(sb.st_size),
1031	    PAGE_SIZE, EfiLoaderData, &addr) != EFI_SUCCESS) {
1032		printf("cannot allocate memory for %s\n", path);
1033		return 0;
1034	}
1035	if (read(fd, (void *)addr, sb.st_size) != sb.st_size) {
1036		printf("cannot read from %s\n", path);
1037		return 0;
1038	}
1039
1040	if (!fdt_init((void *)addr)) {
1041		printf("invalid device tree\n");
1042		BS->FreePages(addr, EFI_SIZE_TO_PAGES(sb.st_size));
1043		return 0;
1044	}
1045
1046	if (fdt_override) {
1047		BS->FreePages((uint64_t)fdt_override,
1048		    EFI_SIZE_TO_PAGES(fdt_override_size));
1049		fdt_override = NULL;
1050	}
1051
1052	fdt_override = (void *)addr;
1053	fdt_override_size = sb.st_size;
1054	return 0;
1055}
1056
1057/*
1058 * Commands
1059 */
1060
1061int Xdtb_efi(void);
1062int Xexit_efi(void);
1063int Xpoweroff_efi(void);
1064
1065const struct cmd_table cmd_machine[] = {
1066	{ "dtb",	CMDT_CMD, Xdtb_efi },
1067	{ "exit",	CMDT_CMD, Xexit_efi },
1068	{ "poweroff",	CMDT_CMD, Xpoweroff_efi },
1069	{ NULL, 0 }
1070};
1071
1072int
1073Xdtb_efi(void)
1074{
1075	if (cmd.argc == 1) {
1076		fdt_load_override(NULL);
1077		return (0);
1078	}
1079
1080	if (cmd.argc != 2) {
1081		printf("dtb file\n");
1082		return (0);
1083	}
1084
1085	return fdt_load_override(cmd.argv[1]);
1086}
1087
1088int
1089Xexit_efi(void)
1090{
1091	BS->Exit(IH, 0, 0, NULL);
1092	for (;;)
1093		continue;
1094	return (0);
1095}
1096
1097int
1098Xpoweroff_efi(void)
1099{
1100	RS->ResetSystem(EfiResetShutdown, EFI_SUCCESS, 0, NULL);
1101	return (0);
1102}
1103