1 /* $OpenBSD: efiboot.c,v 1.62 2024/11/12 20:49:42 tobhe 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 47 EFI_SYSTEM_TABLE *ST; 48 EFI_BOOT_SERVICES *BS; 49 EFI_RUNTIME_SERVICES *RS; 50 EFI_HANDLE IH, efi_bootdp; 51 void *fdt_sys = NULL; 52 void *fdt_override = NULL; 53 size_t fdt_override_size; 54 void *smbios = NULL; 55 56 EFI_PHYSICAL_ADDRESS heap; 57 UINTN heapsiz = 1 * 1024 * 1024; 58 EFI_MEMORY_DESCRIPTOR *mmap; 59 UINTN mmap_key; 60 UINTN mmap_ndesc; 61 UINTN mmap_descsiz; 62 UINT32 mmap_version; 63 64 static EFI_GUID imgp_guid = LOADED_IMAGE_PROTOCOL; 65 static EFI_GUID blkio_guid = BLOCK_IO_PROTOCOL; 66 static EFI_GUID devp_guid = DEVICE_PATH_PROTOCOL; 67 static EFI_GUID gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID; 68 static EFI_GUID fdt_guid = FDT_TABLE_GUID; 69 static EFI_GUID smbios_guid = SMBIOS_TABLE_GUID; 70 static EFI_GUID smbios3_guid = SMBIOS3_TABLE_GUID; 71 static EFI_GUID dt_fixup_guid = EFI_DT_FIXUP_PROTOCOL_GUID; 72 73 #define efi_guidcmp(_a, _b) memcmp((_a), (_b), sizeof(EFI_GUID)) 74 75 int efi_device_path_depth(EFI_DEVICE_PATH *dp, int); 76 int efi_device_path_ncmp(EFI_DEVICE_PATH *, EFI_DEVICE_PATH *, int); 77 static void efi_heap_init(void); 78 static void efi_memprobe_internal(void); 79 static void efi_timer_init(void); 80 static void efi_timer_cleanup(void); 81 static EFI_STATUS efi_memprobe_find(UINTN, UINTN, EFI_MEMORY_TYPE, 82 EFI_PHYSICAL_ADDRESS *); 83 void *efi_fdt(void); 84 int fdt_load_override(char *); 85 extern void smbios_init(void *); 86 87 EFI_STATUS 88 efi_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 131 static SIMPLE_TEXT_OUTPUT_INTERFACE *conout; 132 static 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 */ 139 static dev_t serial = makedev(1, 0); 140 static dev_t framebuffer = makedev(2, 0); 141 142 static char framebuffer_path[128]; 143 144 void 145 efi_cons_probe(struct consdev *cn) 146 { 147 cn->cn_pri = CN_MIDPRI; 148 cn->cn_dev = makedev(0, 0); 149 } 150 151 void 152 efi_cons_init(struct consdev *cp) 153 { 154 conin = ST->ConIn; 155 conout = ST->ConOut; 156 } 157 158 int 159 efi_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 195 void 196 efi_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 209 void 210 efi_com_probe(struct consdev *cn) 211 { 212 cn->cn_pri = CN_LOWPRI; 213 cn->cn_dev = serial; 214 } 215 216 void 217 efi_com_init(struct consdev *cn) 218 { 219 conin = ST->ConIn; 220 conout = ST->ConOut; 221 } 222 223 int 224 efi_com_getc(dev_t dev) 225 { 226 return efi_cons_getc(dev); 227 } 228 229 void 230 efi_com_putc(dev_t dev, int c) 231 { 232 efi_cons_putc(dev, c); 233 } 234 235 void 236 efi_fb_probe(struct consdev *cn) 237 { 238 cn->cn_pri = CN_LOWPRI; 239 cn->cn_dev = framebuffer; 240 } 241 242 void 243 efi_fb_init(struct consdev *cn) 244 { 245 conin = ST->ConIn; 246 conout = ST->ConOut; 247 } 248 249 int 250 efi_fb_getc(dev_t dev) 251 { 252 return efi_cons_getc(dev); 253 } 254 255 void 256 efi_fb_putc(dev_t dev, int c) 257 { 258 efi_cons_putc(dev, c); 259 } 260 261 static void 262 efi_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 272 struct disklist_lh disklist; 273 struct diskinfo *bootdev_dip; 274 275 void 276 efi_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 } 335 next: 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 */ 356 int 357 efi_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 369 int 370 efi_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 391 void 392 efi_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, pxsize; 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 switch (gop->Mode->Info->PixelFormat) { 447 case PixelRedGreenBlueReserved8BitPerColor: 448 format = "x8b8g8r8"; 449 pxsize = 4; 450 break; 451 case PixelBlueGreenRedReserved8BitPerColor: 452 format = "x8r8g8b8"; 453 pxsize = 4; 454 break; 455 case PixelBitMask: { 456 EFI_PIXEL_BITMASK *bm = &gop->Mode->Info->PixelInformation; 457 if (bm->RedMask == 0xf800 && 458 bm->GreenMask == 0x07e0 && 459 bm->BlueMask == 0x001f) { 460 format = "r5g6b5"; 461 pxsize = 2; 462 break; 463 } 464 printf("Unsupported PixelInformation bitmasks\n"); 465 /* FALLTHROUGH */ 466 } 467 default: 468 printf("Unsupported PixelFormat %d, not adding " 469 "\"simple-framebuffer\" DT node\n", 470 gop->Mode->Info->PixelFormat); 471 return; 472 } 473 474 base = gop->Mode->FrameBufferBase; 475 size = gop->Mode->FrameBufferSize; 476 width = htobe32(gop->Mode->Info->HorizontalResolution); 477 height = htobe32(gop->Mode->Info->VerticalResolution); 478 stride = htobe32(gop->Mode->Info->PixelsPerScanLine * pxsize); 479 480 node = fdt_find_node("/"); 481 if (fdt_node_property_int(node, "#address-cells", &acells) != 1) 482 acells = 1; 483 if (fdt_node_property_int(node, "#size-cells", &scells) != 1) 484 scells = 1; 485 if (acells > 2 || scells > 2) 486 return; 487 if (acells >= 1) 488 reg[0] = htobe32(base); 489 if (acells == 2) { 490 reg[1] = reg[0]; 491 reg[0] = htobe32(base >> 32); 492 } 493 if (scells >= 1) 494 reg[acells] = htobe32(size); 495 if (scells == 2) { 496 reg[acells + 1] = reg[acells]; 497 reg[acells] = htobe32(size >> 32); 498 } 499 500 node = fdt_find_node("/chosen"); 501 fdt_node_add_node(node, "framebuffer", &child); 502 fdt_node_add_property(child, "status", "okay", strlen("okay") + 1); 503 fdt_node_add_property(child, "format", format, strlen(format) + 1); 504 fdt_node_add_property(child, "stride", &stride, 4); 505 fdt_node_add_property(child, "height", &height, 4); 506 fdt_node_add_property(child, "width", &width, 4); 507 fdt_node_add_property(child, "reg", reg, (acells + scells) * 4); 508 fdt_node_add_property(child, "compatible", 509 "simple-framebuffer", strlen("simple-framebuffer") + 1); 510 511 strlcpy(framebuffer_path, "/chosen/framebuffer", 512 sizeof(framebuffer_path)); 513 } 514 515 void 516 efi_console(void) 517 { 518 void *node; 519 520 if (major(cn_tab->cn_dev) == major(serial)) { 521 char *serial_path; 522 char alias[16]; 523 int len; 524 525 /* Construct alias and resolve it. */ 526 snprintf(alias, sizeof(alias), "serial%d", 527 minor(cn_tab->cn_dev)); 528 node = fdt_find_node("/aliases"); 529 len = fdt_node_property(node, alias, &serial_path); 530 if (len <= 0) 531 return; 532 533 /* Point stdout-path at the serial node. */ 534 node = fdt_find_node("/chosen"); 535 fdt_node_add_property(node, "stdout-path", 536 serial_path, strlen(serial_path) + 1); 537 } else if (major(cn_tab->cn_dev) == major(framebuffer)) { 538 if (strlen(framebuffer_path) == 0) 539 return; 540 541 /* Point stdout-path at the framebuffer node. */ 542 node = fdt_find_node("/chosen"); 543 fdt_node_add_property(node, "stdout-path", 544 framebuffer_path, strlen(framebuffer_path) + 1); 545 } 546 } 547 548 uint64_t dma_constraint[2] = { 0, -1 }; 549 550 void 551 efi_dma_constraint(void) 552 { 553 void *node; 554 char *prop; 555 uint32_t *propint; 556 uint64_t base, size; 557 uint32_t pacells, pscells; 558 uint32_t acells, scells; 559 int len; 560 561 node = fdt_find_node("/"); 562 if (fdt_node_property_int(node, "#address-cells", &pacells) != 1) 563 pacells = 1; 564 if (fdt_node_property_int(node, "#size-cells", &pscells) != 1) 565 pscells = 1; 566 if (pacells > 2 || pscells > 2) 567 return; 568 569 node = fdt_find_node("/soc"); 570 if (node != NULL) { 571 if (fdt_node_property_int(node, "#address-cells", &acells) != 1) 572 acells = pacells; 573 if (fdt_node_property_int(node, "#size-cells", &scells) != 1) 574 scells = pscells; 575 if (acells > 2 || scells > 2) 576 return; 577 578 len = fdt_node_property(node, "dma-ranges", &prop); 579 propint = (uint32_t *)prop; 580 if (len == (acells + pacells + scells) * sizeof(uint32_t)) { 581 base = betoh32(propint[acells]); 582 if (pacells == 2) 583 base = (base << 32) | 584 betoh32(propint[acells + 1]); 585 size = betoh32(propint[acells + pacells]); 586 if (scells == 2) 587 size = (size << 32) | 588 betoh32(propint[acells + pacells + 1]); 589 590 dma_constraint[0] = htobe64(base); 591 dma_constraint[1] = htobe64(base + size - 1); 592 } 593 } 594 595 /* 596 * Some SoC's have DMA constraints that aren't explicitly 597 * advertised. 598 */ 599 node = fdt_find_node("/"); 600 if (fdt_node_is_compatible(node, "brcm,bcm2711")) 601 dma_constraint[1] = htobe64(0x3bffffff); 602 if (fdt_node_is_compatible(node, "rockchip,rk3566") || 603 fdt_node_is_compatible(node, "rockchip,rk3568") || 604 fdt_node_is_compatible(node, "rockchip,rk3588") || 605 fdt_node_is_compatible(node, "rockchip,rk3588s")) 606 dma_constraint[1] = htobe64(0xffffffff); 607 if (fdt_node_is_compatible(node, "qcom,sc8280xp") || 608 fdt_node_is_compatible(node, "qcom,x1e80100")) 609 dma_constraint[1] = htobe64(0xffffffff); 610 611 /* Pass DMA constraint. */ 612 node = fdt_find_node("/chosen"); 613 fdt_node_add_property(node, "openbsd,dma-constraint", 614 dma_constraint, sizeof(dma_constraint)); 615 } 616 617 int acpi = 0; 618 char *bootmac = NULL; 619 620 void * 621 efi_makebootargs(char *bootargs, int howto) 622 { 623 struct sr_boot_volume *bv; 624 u_char bootduid[8]; 625 u_char zero[8] = { 0 }; 626 uint64_t uefi_system_table = htobe64((uintptr_t)ST); 627 uint32_t boothowto = htobe32(howto); 628 EFI_PHYSICAL_ADDRESS addr; 629 void *node, *fdt; 630 size_t len; 631 632 fdt = efi_fdt(); 633 if (fdt == NULL || acpi) 634 fdt = efi_acpi(); 635 636 if (!fdt_get_size(fdt)) 637 return NULL; 638 639 len = roundup(fdt_get_size(fdt) + PAGE_SIZE, PAGE_SIZE); 640 if (BS->AllocatePages(AllocateAnyPages, EfiLoaderData, 641 EFI_SIZE_TO_PAGES(len), &addr) == EFI_SUCCESS) { 642 memcpy((void *)addr, fdt, fdt_get_size(fdt)); 643 ((struct fdt_head *)addr)->fh_size = htobe32(len); 644 fdt = (void *)addr; 645 } 646 647 if (!fdt_init(fdt)) 648 return NULL; 649 650 /* Create common nodes which might not exist when using mach dtb */ 651 node = fdt_find_node("/aliases"); 652 if (node == NULL) 653 fdt_node_add_node(fdt_find_node("/"), "aliases", &node); 654 node = fdt_find_node("/chosen"); 655 if (node == NULL) 656 fdt_node_add_node(fdt_find_node("/"), "chosen", &node); 657 658 node = fdt_find_node("/chosen"); 659 len = strlen(bootargs) + 1; 660 fdt_node_add_property(node, "bootargs", bootargs, len); 661 fdt_node_add_property(node, "openbsd,boothowto", 662 &boothowto, sizeof(boothowto)); 663 664 /* Pass DUID of the boot disk. */ 665 if (bootdev_dip) { 666 memcpy(&bootduid, bootdev_dip->disklabel.d_uid, 667 sizeof(bootduid)); 668 if (memcmp(bootduid, zero, sizeof(bootduid)) != 0) { 669 fdt_node_add_property(node, "openbsd,bootduid", 670 bootduid, sizeof(bootduid)); 671 } 672 673 if (bootdev_dip->sr_vol != NULL) { 674 bv = bootdev_dip->sr_vol; 675 fdt_node_add_property(node, "openbsd,sr-bootuuid", 676 &bv->sbv_uuid, sizeof(bv->sbv_uuid)); 677 if (bv->sbv_maskkey != NULL) 678 fdt_node_add_property(node, 679 "openbsd,sr-bootkey", bv->sbv_maskkey, 680 SR_CRYPTO_MAXKEYBYTES); 681 } 682 } 683 684 sr_clear_keys(); 685 686 /* Pass netboot interface address. */ 687 if (bootmac) 688 fdt_node_add_property(node, "openbsd,bootmac", bootmac, 6); 689 690 /* Pass EFI system table. */ 691 fdt_node_add_property(node, "openbsd,uefi-system-table", 692 &uefi_system_table, sizeof(uefi_system_table)); 693 694 /* Placeholders for EFI memory map. */ 695 fdt_node_add_property(node, "openbsd,uefi-mmap-start", zero, 8); 696 fdt_node_add_property(node, "openbsd,uefi-mmap-size", zero, 4); 697 fdt_node_add_property(node, "openbsd,uefi-mmap-desc-size", zero, 4); 698 fdt_node_add_property(node, "openbsd,uefi-mmap-desc-ver", zero, 4); 699 700 efi_framebuffer(); 701 efi_console(); 702 efi_dma_constraint(); 703 704 fdt_finalize(); 705 706 return fdt; 707 } 708 709 void 710 efi_updatefdt(void) 711 { 712 uint64_t uefi_mmap_start = htobe64((uintptr_t)mmap); 713 uint32_t uefi_mmap_size = htobe32(mmap_ndesc * mmap_descsiz); 714 uint32_t uefi_mmap_desc_size = htobe32(mmap_descsiz); 715 uint32_t uefi_mmap_desc_ver = htobe32(mmap_version); 716 void *node; 717 718 node = fdt_find_node("/chosen"); 719 if (!node) 720 return; 721 722 /* Pass EFI memory map. */ 723 fdt_node_set_property(node, "openbsd,uefi-mmap-start", 724 &uefi_mmap_start, sizeof(uefi_mmap_start)); 725 fdt_node_set_property(node, "openbsd,uefi-mmap-size", 726 &uefi_mmap_size, sizeof(uefi_mmap_size)); 727 fdt_node_set_property(node, "openbsd,uefi-mmap-desc-size", 728 &uefi_mmap_desc_size, sizeof(uefi_mmap_desc_size)); 729 fdt_node_set_property(node, "openbsd,uefi-mmap-desc-ver", 730 &uefi_mmap_desc_ver, sizeof(uefi_mmap_desc_ver)); 731 732 fdt_finalize(); 733 } 734 735 u_long efi_loadaddr; 736 737 void 738 machdep(void) 739 { 740 EFI_PHYSICAL_ADDRESS addr; 741 742 cninit(); 743 efi_heap_init(); 744 smbios_init(smbios); 745 746 /* 747 * The kernel expects to be loaded into a block of memory aligned 748 * on a 2MB boundary. We allocate a block of 64MB of memory, which 749 * gives us plenty of room for growth. 750 */ 751 if (efi_memprobe_find(EFI_SIZE_TO_PAGES(64 * 1024 * 1024), 752 0x200000, EfiLoaderCode, &addr) != EFI_SUCCESS) 753 printf("Can't allocate memory\n"); 754 efi_loadaddr = addr; 755 756 efi_timer_init(); 757 efi_diskprobe(); 758 efi_pxeprobe(); 759 } 760 761 void 762 efi_cleanup(void) 763 { 764 int retry; 765 EFI_STATUS status; 766 767 efi_timer_cleanup(); 768 769 /* retry once in case of failure */ 770 for (retry = 1; retry >= 0; retry--) { 771 efi_memprobe_internal(); /* sync the current map */ 772 efi_updatefdt(); 773 status = BS->ExitBootServices(IH, mmap_key); 774 if (status == EFI_SUCCESS) 775 break; 776 if (retry == 0) 777 panic("ExitBootServices failed (%d)", status); 778 } 779 } 780 781 void 782 _rtt(void) 783 { 784 #ifdef EFI_DEBUG 785 printf("Hit any key to reboot\n"); 786 efi_cons_getc(0); 787 #endif 788 RS->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL); 789 for (;;) 790 continue; 791 } 792 793 /* 794 * U-Boot only implements the GetTime() Runtime Service if it has been 795 * configured with CONFIG_DM_RTC. Most board configurations don't 796 * include that option, so we can't use it to implement our boot 797 * prompt timeout. Instead we use timer events to simulate a clock 798 * that ticks ever second. 799 */ 800 801 EFI_EVENT timer; 802 int ticks; 803 804 static VOID 805 efi_timer(EFI_EVENT event, VOID *context) 806 { 807 ticks++; 808 } 809 810 static void 811 efi_timer_init(void) 812 { 813 EFI_STATUS status; 814 815 status = BS->CreateEvent(EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_CALLBACK, 816 efi_timer, NULL, &timer); 817 if (status == EFI_SUCCESS) 818 status = BS->SetTimer(timer, TimerPeriodic, 10000000); 819 if (EFI_ERROR(status)) 820 printf("Can't create timer\n"); 821 } 822 823 static void 824 efi_timer_cleanup(void) 825 { 826 BS->CloseEvent(timer); 827 } 828 829 time_t 830 getsecs(void) 831 { 832 return ticks; 833 } 834 835 /* 836 * Various device-related bits. 837 */ 838 839 void 840 devboot(dev_t dev, char *p) 841 { 842 struct sr_boot_volume *bv; 843 struct sr_boot_chunk *bc; 844 struct diskinfo *dip; 845 int sd_boot_vol = 0; 846 int sr_boot_vol = -1; 847 int part_type = FS_UNUSED; 848 849 if (bootdev_dip == NULL) { 850 strlcpy(p, "tftp0a", 7); 851 return; 852 } 853 854 /* 855 * If there is no BSD disklabel on the boot device, boot from 856 * the ESP instead. 857 */ 858 if ((bootdev_dip->flags & DISKINFO_FLAG_GOODLABEL) == 0) { 859 strlcpy(p, "esp0a", 6); 860 return; 861 } 862 863 TAILQ_FOREACH(dip, &disklist, list) { 864 if (bootdev_dip == dip) 865 break; 866 sd_boot_vol++; 867 } 868 869 /* 870 * Determine the partition type for the 'a' partition of the 871 * boot device. 872 */ 873 part_type = bootdev_dip->disklabel.d_partitions[0].p_fstype; 874 875 /* 876 * See if we booted from a disk that is a member of a bootable 877 * softraid volume. 878 */ 879 SLIST_FOREACH(bv, &sr_volumes, sbv_link) { 880 SLIST_FOREACH(bc, &bv->sbv_chunks, sbc_link) 881 if (bc->sbc_diskinfo == bootdev_dip) 882 sr_boot_vol = bv->sbv_unit; 883 if (sr_boot_vol != -1) 884 break; 885 } 886 887 if (sr_boot_vol != -1 && part_type != FS_BSDFFS) { 888 strlcpy(p, "sr0a", 5); 889 p[2] = '0' + sr_boot_vol; 890 return; 891 } 892 893 strlcpy(p, "sd0a", 5); 894 p[2] = '0' + sd_boot_vol; 895 } 896 897 const char cdevs[][4] = { "cons", "com", "fb" }; 898 const int ncdevs = nitems(cdevs); 899 900 int 901 cnspeed(dev_t dev, int sp) 902 { 903 return 115200; 904 } 905 906 char ttyname_buf[8]; 907 908 char * 909 ttyname(int fd) 910 { 911 snprintf(ttyname_buf, sizeof ttyname_buf, "%s%d", 912 cdevs[major(cn_tab->cn_dev)], minor(cn_tab->cn_dev)); 913 914 return ttyname_buf; 915 } 916 917 dev_t 918 ttydev(char *name) 919 { 920 int i, unit = -1; 921 char *no = name + strlen(name) - 1; 922 923 while (no >= name && *no >= '0' && *no <= '9') 924 unit = (unit < 0 ? 0 : (unit * 10)) + *no-- - '0'; 925 if (no < name || unit < 0) 926 return NODEV; 927 for (i = 0; i < ncdevs; i++) 928 if (strncmp(name, cdevs[i], no - name + 1) == 0) 929 return makedev(i, unit); 930 return NODEV; 931 } 932 933 #define MAXDEVNAME 16 934 935 /* 936 * Parse a device spec. 937 * 938 * [A-Za-z]*[0-9]*[A-Za-z]:file 939 * dev uint part 940 */ 941 int 942 devparse(const char *fname, int *dev, int *unit, int *part, const char **file) 943 { 944 const char *s; 945 946 *unit = 0; /* default to wd0a */ 947 *part = 0; 948 *dev = 0; 949 950 s = strchr(fname, ':'); 951 if (s != NULL) { 952 int devlen; 953 int i, u, p = 0; 954 struct devsw *dp; 955 char devname[MAXDEVNAME]; 956 957 devlen = s - fname; 958 if (devlen > MAXDEVNAME) 959 return (EINVAL); 960 961 /* extract device name */ 962 for (i = 0; isalpha(fname[i]) && (i < devlen); i++) 963 devname[i] = fname[i]; 964 devname[i] = 0; 965 966 if (!isdigit(fname[i])) 967 return (EUNIT); 968 969 /* device number */ 970 for (u = 0; isdigit(fname[i]) && (i < devlen); i++) 971 u = u * 10 + (fname[i] - '0'); 972 973 if (!isalpha(fname[i])) 974 return (EPART); 975 976 /* partition number */ 977 if (i < devlen) 978 p = fname[i++] - 'a'; 979 980 if (i != devlen) 981 return (ENXIO); 982 983 /* check device name */ 984 for (dp = devsw, i = 0; i < ndevs; dp++, i++) { 985 if (dp->dv_name && !strcmp(devname, dp->dv_name)) 986 break; 987 } 988 989 if (i >= ndevs) 990 return (ENXIO); 991 992 *unit = u; 993 *part = p; 994 *dev = i; 995 fname = ++s; 996 } 997 998 *file = fname; 999 1000 return (0); 1001 } 1002 1003 int 1004 devopen(struct open_file *f, const char *fname, char **file) 1005 { 1006 struct devsw *dp; 1007 int dev, unit, part, error; 1008 1009 error = devparse(fname, &dev, &unit, &part, (const char **)file); 1010 if (error) 1011 return (error); 1012 1013 dp = &devsw[dev]; 1014 f->f_dev = dp; 1015 1016 if (strcmp("tftp", dp->dv_name) != 0) { 1017 /* 1018 * Clear bootmac, to signal that we loaded this file from a 1019 * non-network device. 1020 */ 1021 bootmac = NULL; 1022 } 1023 1024 return (*dp->dv_open)(f, unit, part); 1025 } 1026 1027 static void 1028 efi_memprobe_internal(void) 1029 { 1030 EFI_STATUS status; 1031 UINTN mapkey, mmsiz, siz; 1032 UINT32 mmver; 1033 EFI_MEMORY_DESCRIPTOR *mm; 1034 int n; 1035 1036 free(mmap, mmap_ndesc * mmap_descsiz); 1037 1038 siz = 0; 1039 status = BS->GetMemoryMap(&siz, NULL, &mapkey, &mmsiz, &mmver); 1040 if (status != EFI_BUFFER_TOO_SMALL) 1041 panic("cannot get the size of memory map"); 1042 mm = alloc(siz); 1043 status = BS->GetMemoryMap(&siz, mm, &mapkey, &mmsiz, &mmver); 1044 if (status != EFI_SUCCESS) 1045 panic("cannot get the memory map"); 1046 n = siz / mmsiz; 1047 mmap = mm; 1048 mmap_key = mapkey; 1049 mmap_ndesc = n; 1050 mmap_descsiz = mmsiz; 1051 mmap_version = mmver; 1052 } 1053 1054 /* 1055 * 64-bit ARMs can have a much wider memory mapping, as in somewhere 1056 * after the 32-bit region. To cope with our alignment requirement, 1057 * use the memory table to find a place where we can fit. 1058 */ 1059 static EFI_STATUS 1060 efi_memprobe_find(UINTN pages, UINTN align, EFI_MEMORY_TYPE type, 1061 EFI_PHYSICAL_ADDRESS *addr) 1062 { 1063 EFI_MEMORY_DESCRIPTOR *mm; 1064 int i, j; 1065 1066 if (align < EFI_PAGE_SIZE) 1067 return EFI_INVALID_PARAMETER; 1068 1069 efi_memprobe_internal(); /* sync the current map */ 1070 1071 for (i = 0, mm = mmap; i < mmap_ndesc; 1072 i++, mm = NextMemoryDescriptor(mm, mmap_descsiz)) { 1073 if (mm->Type != EfiConventionalMemory) 1074 continue; 1075 1076 if (mm->NumberOfPages < pages) 1077 continue; 1078 1079 for (j = 0; j < mm->NumberOfPages; j++) { 1080 EFI_PHYSICAL_ADDRESS paddr; 1081 1082 if (mm->NumberOfPages - j < pages) 1083 break; 1084 1085 paddr = mm->PhysicalStart + (j * EFI_PAGE_SIZE); 1086 if (paddr & (align - 1)) 1087 continue; 1088 1089 if (BS->AllocatePages(AllocateAddress, type, 1090 pages, &paddr) == EFI_SUCCESS) { 1091 *addr = paddr; 1092 return EFI_SUCCESS; 1093 } 1094 } 1095 } 1096 return EFI_OUT_OF_RESOURCES; 1097 } 1098 1099 int 1100 mdrandom(char *buf, size_t buflen) 1101 { 1102 char *random; 1103 void *node; 1104 int i, len, ret = -1; 1105 1106 node = fdt_find_node("/chosen"); 1107 if (!node) 1108 return -1; 1109 1110 len = fdt_node_property(node, "rng-seed", &random); 1111 if (len > 0) { 1112 for (i = 0; i < buflen; i++) 1113 buf[i] ^= random[i % len]; 1114 ret = 0; 1115 } 1116 1117 len = fdt_node_property(node, "kaslr-seed", &random); 1118 if (len > 0) { 1119 for (i = 0; i < buflen; i++) 1120 buf[i] ^= random[i % len]; 1121 ret = 0; 1122 } 1123 1124 return ret; 1125 } 1126 1127 #define FW_PATH "/etc/firmware/dtb/" 1128 1129 struct smbios_dtb { 1130 const char *vendor; 1131 const char *prod; 1132 const char *dtb; 1133 } smbios_dtb[] = { 1134 /* Keep the list below sorted by vendor */ 1135 { "ASUS", "ASUS Vivobook S 15 S5507", 1136 "qcom/x1e80100-asus-vivobook-s15.dtb" }, 1137 { "HP", "HP OmniBook X Laptop 14-fe0xxx", 1138 "qcom/x1e80100-hp-omnibook-x14.dtb" }, 1139 { "LENOVO", "21BX", 1140 "qcom/sc8280xp-lenovo-thinkpad-x13s.dtb" }, 1141 { "LENOVO", "21BY", 1142 "qcom/sc8280xp-lenovo-thinkpad-x13s.dtb" }, 1143 { "LENOVO", "21N1", 1144 "qcom/x1e78100-lenovo-thinkpad-t14s.dtb" }, 1145 { "LENOVO", "21N2", 1146 "qcom/x1e78100-lenovo-thinkpad-t14s.dtb" }, 1147 { "LENOVO", "83ED", 1148 "qcom/x1e80100-lenovo-yoga-slim7x.dtb" }, 1149 { "SAMSUNG", "Galaxy Book4 Edge", 1150 "qcom/x1e80100-samsung-galaxy-book4-edge.dtb" }, 1151 }; 1152 1153 void * 1154 efi_fdt(void) 1155 { 1156 extern char *hw_vendor, *hw_prod; 1157 size_t vendorlen, prodlen; 1158 char dtb[256]; 1159 int i; 1160 1161 /* 'mach dtb' has precedence */ 1162 if (fdt_override != NULL) 1163 return fdt_override; 1164 1165 /* Return system provided one */ 1166 if (hw_vendor == NULL || hw_prod == NULL) 1167 return fdt_sys; 1168 1169 for (i = 0; i < nitems(smbios_dtb); i++) { 1170 vendorlen = strlen(smbios_dtb[i].vendor); 1171 prodlen = strlen(smbios_dtb[i].prod); 1172 if (strncmp(hw_vendor, smbios_dtb[i].vendor, vendorlen) == 0 && 1173 strncmp(hw_prod, smbios_dtb[i].prod, prodlen) == 0) { 1174 snprintf(dtb, sizeof(dtb), "%s%s", FW_PATH, 1175 smbios_dtb[i].dtb); 1176 fdt_load_override(dtb); 1177 /* TODO: find a better mechanism */ 1178 cnset(ttydev("fb0")); 1179 } 1180 } 1181 1182 return fdt_override ? fdt_override : fdt_sys; 1183 } 1184 1185 int 1186 fdt_load_override(char *file) 1187 { 1188 EFI_DT_FIXUP_PROTOCOL *dt_fixup; 1189 EFI_PHYSICAL_ADDRESS addr; 1190 char path[MAXPATHLEN]; 1191 EFI_STATUS status; 1192 struct stat sb; 1193 size_t dt_size; 1194 UINTN sz; 1195 int fd; 1196 1197 if (file == NULL && fdt_override) { 1198 BS->FreePages((uint64_t)fdt_override, 1199 EFI_SIZE_TO_PAGES(fdt_override_size)); 1200 fdt_override = NULL; 1201 fdt_init(fdt_sys); 1202 return 0; 1203 } 1204 1205 snprintf(path, sizeof(path), "%s:%s", cmd.bootdev, file); 1206 1207 fd = open(path, O_RDONLY); 1208 if (fd < 0 || fstat(fd, &sb) == -1) { 1209 printf("cannot open %s\n", path); 1210 return 0; 1211 } 1212 dt_size = sb.st_size; 1213 retry: 1214 if (efi_memprobe_find(EFI_SIZE_TO_PAGES(dt_size), 1215 PAGE_SIZE, EfiLoaderData, &addr) != EFI_SUCCESS) { 1216 printf("cannot allocate memory for %s\n", path); 1217 return 0; 1218 } 1219 if (read(fd, (void *)addr, sb.st_size) != sb.st_size) { 1220 printf("cannot read from %s\n", path); 1221 return 0; 1222 } 1223 1224 status = BS->LocateProtocol(&dt_fixup_guid, NULL, (void **)&dt_fixup); 1225 if (status == EFI_SUCCESS) { 1226 sz = dt_size; 1227 status = dt_fixup->Fixup(dt_fixup, (void *)addr, &sz, 1228 EFI_DT_APPLY_FIXUPS | EFI_DT_RESERVE_MEMORY); 1229 if (status == EFI_BUFFER_TOO_SMALL) { 1230 BS->FreePages(addr, EFI_SIZE_TO_PAGES(dt_size)); 1231 lseek(fd, 0, SEEK_SET); 1232 dt_size = sz; 1233 goto retry; 1234 } 1235 if (status != EFI_SUCCESS) 1236 panic("DT fixup failed: 0x%lx", status); 1237 } 1238 1239 if (!fdt_init((void *)addr)) { 1240 printf("invalid device tree\n"); 1241 BS->FreePages(addr, EFI_SIZE_TO_PAGES(dt_size)); 1242 return 0; 1243 } 1244 1245 if (fdt_override) { 1246 BS->FreePages((uint64_t)fdt_override, 1247 EFI_SIZE_TO_PAGES(fdt_override_size)); 1248 fdt_override = NULL; 1249 } 1250 1251 fdt_override = (void *)addr; 1252 fdt_override_size = dt_size; 1253 return 0; 1254 } 1255 1256 /* 1257 * Commands 1258 */ 1259 1260 int Xacpi_efi(void); 1261 int Xdtb_efi(void); 1262 int Xexit_efi(void); 1263 int Xpoweroff_efi(void); 1264 1265 const struct cmd_table cmd_machine[] = { 1266 { "acpi", CMDT_CMD, Xacpi_efi }, 1267 { "dtb", CMDT_CMD, Xdtb_efi }, 1268 { "exit", CMDT_CMD, Xexit_efi }, 1269 { "poweroff", CMDT_CMD, Xpoweroff_efi }, 1270 { NULL, 0 } 1271 }; 1272 1273 int 1274 Xacpi_efi(void) 1275 { 1276 acpi = 1; 1277 return (0); 1278 } 1279 1280 int 1281 Xdtb_efi(void) 1282 { 1283 if (cmd.argc == 1) { 1284 fdt_load_override(NULL); 1285 return (0); 1286 } 1287 1288 if (cmd.argc != 2) { 1289 printf("dtb file\n"); 1290 return (0); 1291 } 1292 1293 return fdt_load_override(cmd.argv[1]); 1294 } 1295 1296 int 1297 Xexit_efi(void) 1298 { 1299 BS->Exit(IH, 0, 0, NULL); 1300 for (;;) 1301 continue; 1302 return (0); 1303 } 1304 1305 int 1306 Xpoweroff_efi(void) 1307 { 1308 RS->ResetSystem(EfiResetShutdown, EFI_SUCCESS, 0, NULL); 1309 return (0); 1310 } 1311