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