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