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