xref: /openbsd/sys/arch/armv7/stand/efiboot/efiboot.c (revision 864fc787)
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 
41 EFI_SYSTEM_TABLE	*ST;
42 EFI_BOOT_SERVICES	*BS;
43 EFI_RUNTIME_SERVICES	*RS;
44 EFI_HANDLE		 IH, efi_bootdp;
45 void			*fdt_sys = NULL;
46 void			*fdt_override = NULL;
47 size_t			 fdt_override_size;
48 
49 EFI_PHYSICAL_ADDRESS	 heap;
50 UINTN			 heapsiz = 1 * 1024 * 1024;
51 EFI_MEMORY_DESCRIPTOR	*mmap;
52 UINTN			 mmap_key;
53 UINTN			 mmap_ndesc;
54 UINTN			 mmap_descsiz;
55 UINT32			 mmap_version;
56 
57 static EFI_GUID		 imgp_guid = LOADED_IMAGE_PROTOCOL;
58 static EFI_GUID		 blkio_guid = BLOCK_IO_PROTOCOL;
59 static EFI_GUID		 devp_guid = DEVICE_PATH_PROTOCOL;
60 static EFI_GUID		 gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
61 static EFI_GUID		 fdt_guid = FDT_TABLE_GUID;
62 
63 #define efi_guidcmp(_a, _b)	memcmp((_a), (_b), sizeof(EFI_GUID))
64 
65 int efi_device_path_depth(EFI_DEVICE_PATH *dp, int);
66 int efi_device_path_ncmp(EFI_DEVICE_PATH *, EFI_DEVICE_PATH *, int);
67 static void efi_heap_init(void);
68 static void efi_memprobe_internal(void);
69 static void efi_timer_init(void);
70 static void efi_timer_cleanup(void);
71 static EFI_STATUS efi_memprobe_find(UINTN, UINTN, EFI_MEMORY_TYPE,
72     EFI_PHYSICAL_ADDRESS *);
73 void *efi_fdt(void);
74 int fdt_load_override(char *);
75 
76 EFI_STATUS
efi_main(EFI_HANDLE image,EFI_SYSTEM_TABLE * systab)77 efi_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 
114 static SIMPLE_TEXT_OUTPUT_INTERFACE *conout;
115 static 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  */
122 static dev_t serial = makedev(1, 0);
123 static dev_t framebuffer = makedev(2, 0);
124 
125 static char framebuffer_path[128];
126 
127 void
efi_cons_probe(struct consdev * cn)128 efi_cons_probe(struct consdev *cn)
129 {
130 	cn->cn_pri = CN_MIDPRI;
131 	cn->cn_dev = makedev(0, 0);
132 }
133 
134 void
efi_cons_init(struct consdev * cp)135 efi_cons_init(struct consdev *cp)
136 {
137 	conin = ST->ConIn;
138 	conout = ST->ConOut;
139 }
140 
141 int
efi_cons_getc(dev_t dev)142 efi_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 
178 void
efi_cons_putc(dev_t dev,int c)179 efi_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 
192 void
efi_com_probe(struct consdev * cn)193 efi_com_probe(struct consdev *cn)
194 {
195 	cn->cn_pri = CN_LOWPRI;
196 	cn->cn_dev = serial;
197 }
198 
199 void
efi_com_init(struct consdev * cn)200 efi_com_init(struct consdev *cn)
201 {
202 	conin = ST->ConIn;
203 	conout = ST->ConOut;
204 }
205 
206 int
efi_com_getc(dev_t dev)207 efi_com_getc(dev_t dev)
208 {
209 	return efi_cons_getc(dev);
210 }
211 
212 void
efi_com_putc(dev_t dev,int c)213 efi_com_putc(dev_t dev, int c)
214 {
215 	efi_cons_putc(dev, c);
216 }
217 
218 void
efi_fb_probe(struct consdev * cn)219 efi_fb_probe(struct consdev *cn)
220 {
221 	cn->cn_pri = CN_LOWPRI;
222 	cn->cn_dev = framebuffer;
223 }
224 
225 void
efi_fb_init(struct consdev * cn)226 efi_fb_init(struct consdev *cn)
227 {
228 	conin = ST->ConIn;
229 	conout = ST->ConOut;
230 }
231 
232 int
efi_fb_getc(dev_t dev)233 efi_fb_getc(dev_t dev)
234 {
235 	return efi_cons_getc(dev);
236 }
237 
238 void
efi_fb_putc(dev_t dev,int c)239 efi_fb_putc(dev_t dev, int c)
240 {
241 	efi_cons_putc(dev, c);
242 }
243 
244 static void
efi_heap_init(void)245 efi_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 
255 struct disklist_lh disklist;
256 struct diskinfo *bootdev_dip;
257 
258 void
efi_diskprobe(void)259 efi_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 		}
318 next:
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  */
338 int
efi_device_path_depth(EFI_DEVICE_PATH * dp,int dptype)339 efi_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 
351 int
efi_device_path_ncmp(EFI_DEVICE_PATH * dpa,EFI_DEVICE_PATH * dpb,int deptn)352 efi_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 
373 void
efi_framebuffer(void)374 efi_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 
481 void
efi_console(void)482 efi_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 
514 uint64_t dma_constraint[2] = { 0, -1 };
515 
516 void
efi_dma_constraint(void)517 efi_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 
536 char *bootmac = NULL;
537 
538 void *
efi_makebootargs(char * bootargs,int howto)539 efi_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 
614 void
efi_updatefdt(void)615 efi_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 
640 u_long efi_loadaddr;
641 
642 void
machdep(void)643 machdep(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 
673 void
efi_cleanup(void)674 efi_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 
693 void
_rtt(void)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 
713 EFI_EVENT timer;
714 int ticks;
715 
716 static VOID
efi_timer(EFI_EVENT event,VOID * context)717 efi_timer(EFI_EVENT event, VOID *context)
718 {
719 	ticks++;
720 }
721 
722 static void
efi_timer_init(void)723 efi_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 
735 static void
efi_timer_cleanup(void)736 efi_timer_cleanup(void)
737 {
738 	BS->CloseEvent(timer);
739 }
740 
741 time_t
getsecs(void)742 getsecs(void)
743 {
744 	return ticks;
745 }
746 
747 /*
748  * Various device-related bits.
749  */
750 
751 void
devboot(dev_t dev,char * p)752 devboot(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 
772 const char cdevs[][4] = { "cons", "com", "fb" };
773 const int ncdevs = nitems(cdevs);
774 
775 int
cnspeed(dev_t dev,int sp)776 cnspeed(dev_t dev, int sp)
777 {
778 	return 115200;
779 }
780 
781 char ttyname_buf[8];
782 
783 char *
ttyname(int fd)784 ttyname(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 
792 dev_t
ttydev(char * name)793 ttydev(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  */
816 int
devparse(const char * fname,int * dev,int * unit,int * part,const char ** file)817 devparse(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 
878 int
devopen(struct open_file * f,const char * fname,char ** file)879 devopen(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 
902 static void
efi_memprobe_internal(void)903 efi_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 
929 static EFI_STATUS
efi_memprobe_find(UINTN pages,UINTN align,EFI_MEMORY_TYPE type,EFI_PHYSICAL_ADDRESS * addr)930 efi_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 
969 int
mdrandom(char * buf,size_t buflen)970 mdrandom(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 
997 void *
efi_fdt(void)998 efi_fdt(void)
999 {
1000 	/* 'mach dtb' has precedence */
1001 	if (fdt_override != NULL)
1002 		return fdt_override;
1003 
1004 	return fdt_sys;
1005 }
1006 
1007 int
fdt_load_override(char * file)1008 fdt_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 
1061 int Xdtb_efi(void);
1062 int Xexit_efi(void);
1063 int Xpoweroff_efi(void);
1064 
1065 const 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 
1072 int
Xdtb_efi(void)1073 Xdtb_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 
1088 int
Xexit_efi(void)1089 Xexit_efi(void)
1090 {
1091 	BS->Exit(IH, 0, 0, NULL);
1092 	for (;;)
1093 		continue;
1094 	return (0);
1095 }
1096 
1097 int
Xpoweroff_efi(void)1098 Xpoweroff_efi(void)
1099 {
1100 	RS->ResetSystem(EfiResetShutdown, EFI_SUCCESS, 0, NULL);
1101 	return (0);
1102 }
1103