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