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