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