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