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