1 /* $OpenBSD: efiboot.c,v 1.38 2021/06/07 00:04:20 krw Exp $ */ 2 3 /* 4 * Copyright (c) 2015 YASUOKA Masahiko <yasuoka@yasuoka.net> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/param.h> 20 #include <sys/queue.h> 21 #include <dev/cons.h> 22 #include <dev/isa/isareg.h> 23 #include <dev/ic/comreg.h> 24 #include <sys/disklabel.h> 25 #include <cmd.h> 26 #include <stand/boot/bootarg.h> 27 #include <machine/pio.h> 28 29 #include "libsa.h" 30 #include "disk.h" 31 32 #include <efi.h> 33 #include <efiapi.h> 34 #include <efiprot.h> 35 #include <eficonsctl.h> 36 37 #include "efidev.h" 38 #include "efiboot.h" 39 #include "run_i386.h" 40 41 #define KERN_LOADSPACE_SIZE (64 * 1024 * 1024) 42 43 EFI_SYSTEM_TABLE *ST; 44 EFI_BOOT_SERVICES *BS; 45 EFI_RUNTIME_SERVICES *RS; 46 EFI_HANDLE IH; 47 EFI_DEVICE_PATH *efi_bootdp = NULL; 48 EFI_PHYSICAL_ADDRESS heap; 49 EFI_LOADED_IMAGE *loadedImage; 50 UINTN heapsiz = 1 * 1024 * 1024; 51 UINTN mmap_key; 52 static EFI_GUID imgp_guid = LOADED_IMAGE_PROTOCOL; 53 static EFI_GUID blkio_guid = BLOCK_IO_PROTOCOL; 54 static EFI_GUID devp_guid = DEVICE_PATH_PROTOCOL; 55 u_long efi_loadaddr; 56 57 int efi_device_path_depth(EFI_DEVICE_PATH *dp, int); 58 int efi_device_path_ncmp(EFI_DEVICE_PATH *, EFI_DEVICE_PATH *, int); 59 static void efi_heap_init(void); 60 static int efi_memprobe_internal(void); 61 static void efi_video_init(void); 62 static void efi_video_reset(void); 63 static EFI_STATUS 64 efi_gop_setmode(int mode); 65 EFI_STATUS efi_main(EFI_HANDLE, EFI_SYSTEM_TABLE *); 66 67 void (*run_i386)(u_long, u_long, int, int, int, int, int, int, int, int) 68 __attribute__((noreturn)); 69 70 extern int bios_bootdev; 71 72 EFI_STATUS 73 efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab) 74 { 75 extern char *progname; 76 EFI_LOADED_IMAGE *imgp; 77 EFI_DEVICE_PATH *dp0 = NULL, *dp; 78 EFI_STATUS status; 79 EFI_PHYSICAL_ADDRESS stack; 80 81 ST = systab; 82 BS = ST->BootServices; 83 RS = ST->RuntimeServices; 84 IH = image; 85 86 /* disable reset by watchdog after 5 minutes */ 87 BS->SetWatchdogTimer(0, 0, 0, NULL); 88 89 efi_video_init(); 90 efi_heap_init(); 91 92 status = BS->HandleProtocol(image, &imgp_guid, (void **)&imgp); 93 if (status == EFI_SUCCESS) 94 status = BS->HandleProtocol(imgp->DeviceHandle, &devp_guid, 95 (void **)&dp0); 96 if (status == EFI_SUCCESS) { 97 for (dp = dp0; !IsDevicePathEnd(dp); 98 dp = NextDevicePathNode(dp)) { 99 if (DevicePathType(dp) == MEDIA_DEVICE_PATH && 100 (DevicePathSubType(dp) == MEDIA_HARDDRIVE_DP || 101 DevicePathSubType(dp) == MEDIA_CDROM_DP)) { 102 bios_bootdev = 103 (DevicePathSubType(dp) == MEDIA_CDROM_DP) 104 ? 0x1e0 : 0x80; 105 efi_bootdp = dp0; 106 break; 107 } else if (DevicePathType(dp) == MESSAGING_DEVICE_PATH&& 108 DevicePathSubType(dp) == MSG_MAC_ADDR_DP) { 109 bios_bootdev = 0x0; 110 efi_bootdp = dp0; 111 break; 112 } 113 } 114 } 115 116 #ifdef __amd64__ 117 /* allocate run_i386_start() on heap */ 118 if ((run_i386 = alloc(run_i386_size)) == NULL) 119 panic("alloc() failed"); 120 memcpy(run_i386, run_i386_start, run_i386_size); 121 #endif 122 123 /* can't use sa_cleanup since printf is used after sa_cleanup() */ 124 /* sa_cleanup = efi_cleanup; */ 125 126 #ifdef __amd64__ 127 progname = "BOOTX64"; 128 #else 129 progname = "BOOTIA32"; 130 #endif 131 132 /* 133 * Move the stack before calling boot(). UEFI on some machines 134 * locate the stack on our kernel load address. 135 */ 136 stack = heap + heapsiz; 137 #if defined(__amd64__) 138 asm("movq %0, %%rsp;" 139 "mov %1, %%edi;" 140 "call boot;" 141 :: "r"(stack - 32), "r"(bios_bootdev)); 142 #else 143 asm("movl %0, %%esp;" 144 "movl %1, (%%esp);" 145 "call boot;" 146 :: "r"(stack - 32), "r"(bios_bootdev)); 147 #endif 148 /* must not reach here */ 149 return (EFI_SUCCESS); 150 } 151 152 void 153 efi_cleanup(void) 154 { 155 int retry; 156 EFI_STATUS status; 157 158 /* retry once in case of failure */ 159 for (retry = 1; retry >= 0; retry--) { 160 efi_memprobe_internal(); /* sync the current map */ 161 status = BS->ExitBootServices(IH, mmap_key); 162 if (status == EFI_SUCCESS) 163 break; 164 if (retry == 0) 165 panic("ExitBootServices failed (%d)", status); 166 } 167 } 168 169 /*********************************************************************** 170 * Disk 171 ***********************************************************************/ 172 struct disklist_lh efi_disklist; 173 174 void 175 efi_diskprobe(void) 176 { 177 int i, bootdev = 0, depth = -1; 178 UINTN sz; 179 EFI_STATUS status; 180 EFI_HANDLE *handles = NULL; 181 EFI_BLOCK_IO *blkio; 182 EFI_BLOCK_IO_MEDIA *media; 183 struct diskinfo *di; 184 EFI_DEVICE_PATH *dp; 185 186 TAILQ_INIT(&efi_disklist); 187 188 sz = 0; 189 status = BS->LocateHandle(ByProtocol, &blkio_guid, 0, &sz, 0); 190 if (status == EFI_BUFFER_TOO_SMALL) { 191 handles = alloc(sz); 192 status = BS->LocateHandle(ByProtocol, &blkio_guid, 193 0, &sz, handles); 194 } 195 if (handles == NULL || EFI_ERROR(status)) 196 panic("BS->LocateHandle() returns %d", status); 197 198 if (efi_bootdp != NULL) 199 depth = efi_device_path_depth(efi_bootdp, MEDIA_DEVICE_PATH); 200 201 /* 202 * U-Boot incorrectly represents devices with a single 203 * MEDIA_DEVICE_PATH component. In that case include that 204 * component into the matching, otherwise we'll blindly select 205 * the first device. 206 */ 207 if (depth == 0) 208 depth = 1; 209 210 for (i = 0; i < sz / sizeof(EFI_HANDLE); i++) { 211 status = BS->HandleProtocol(handles[i], &blkio_guid, 212 (void **)&blkio); 213 if (EFI_ERROR(status)) 214 panic("BS->HandleProtocol() returns %d", status); 215 216 media = blkio->Media; 217 if (media->LogicalPartition || !media->MediaPresent) 218 continue; 219 di = alloc(sizeof(struct diskinfo)); 220 efid_init(di, blkio); 221 222 if (efi_bootdp == NULL || depth == -1 || bootdev != 0) 223 goto next; 224 status = BS->HandleProtocol(handles[i], &devp_guid, 225 (void **)&dp); 226 if (EFI_ERROR(status)) 227 goto next; 228 if (efi_device_path_ncmp(efi_bootdp, dp, depth) == 0) { 229 TAILQ_INSERT_HEAD(&efi_disklist, di, list); 230 bootdev = 1; 231 continue; 232 } 233 next: 234 TAILQ_INSERT_TAIL(&efi_disklist, di, list); 235 } 236 237 free(handles, sz); 238 } 239 240 /* 241 * Determine the number of nodes up to, but not including, the first 242 * node of the specified type. 243 */ 244 int 245 efi_device_path_depth(EFI_DEVICE_PATH *dp, int dptype) 246 { 247 int i; 248 249 for (i = 0; !IsDevicePathEnd(dp); dp = NextDevicePathNode(dp), i++) { 250 if (DevicePathType(dp) == dptype) 251 return (i); 252 } 253 254 return (i); 255 } 256 257 int 258 efi_device_path_ncmp(EFI_DEVICE_PATH *dpa, EFI_DEVICE_PATH *dpb, int deptn) 259 { 260 int i, cmp; 261 262 for (i = 0; i < deptn; i++) { 263 if (IsDevicePathEnd(dpa) || IsDevicePathEnd(dpb)) 264 return ((IsDevicePathEnd(dpa) && IsDevicePathEnd(dpb)) 265 ? 0 : (IsDevicePathEnd(dpa))? -1 : 1); 266 cmp = DevicePathNodeLength(dpa) - DevicePathNodeLength(dpb); 267 if (cmp) 268 return (cmp); 269 cmp = memcmp(dpa, dpb, DevicePathNodeLength(dpa)); 270 if (cmp) 271 return (cmp); 272 dpa = NextDevicePathNode(dpa); 273 dpb = NextDevicePathNode(dpb); 274 } 275 276 return (0); 277 } 278 279 /*********************************************************************** 280 * Memory 281 ***********************************************************************/ 282 bios_memmap_t bios_memmap[128]; 283 bios_efiinfo_t bios_efiinfo; 284 285 static void 286 efi_heap_init(void) 287 { 288 EFI_STATUS status; 289 290 heap = HEAP_LIMIT; 291 status = BS->AllocatePages(AllocateMaxAddress, EfiLoaderData, 292 EFI_SIZE_TO_PAGES(heapsiz), &heap); 293 if (status != EFI_SUCCESS) 294 panic("BS->AllocatePages()"); 295 } 296 297 void 298 efi_memprobe(void) 299 { 300 u_int n = 0; 301 bios_memmap_t *bm; 302 EFI_STATUS status; 303 EFI_PHYSICAL_ADDRESS 304 addr = 0x10000000ULL; /* Below 256MB */ 305 int error; 306 307 status = BS->AllocatePages(AllocateMaxAddress, EfiLoaderData, 308 EFI_SIZE_TO_PAGES(KERN_LOADSPACE_SIZE), &addr); 309 if (status != EFI_SUCCESS) 310 panic("BS->AllocatePages()"); 311 efi_loadaddr = addr; 312 313 printf(" mem["); 314 error = efi_memprobe_internal(); 315 for (bm = bios_memmap; bm->type != BIOS_MAP_END; bm++) { 316 if (bm->type == BIOS_MAP_FREE && bm->size > 12 * 1024) { 317 if (n++ != 0) 318 printf(" "); 319 if (bm->size > 1024 * 1024) 320 printf("%uM", bm->size / 1024 / 1024); 321 else 322 printf("%uK", bm->size / 1024); 323 } 324 } 325 if (error == E2BIG) 326 printf(" overflow"); 327 printf("]"); 328 } 329 330 static int 331 efi_memprobe_internal(void) 332 { 333 EFI_STATUS status; 334 UINTN mapkey, mmsiz, siz; 335 UINT32 mmver; 336 EFI_MEMORY_DESCRIPTOR *mm0, *mm; 337 int i, n; 338 bios_memmap_t *bm, bm0; 339 int error = 0; 340 341 cnvmem = extmem = 0; 342 bios_memmap[0].type = BIOS_MAP_END; 343 344 if (bios_efiinfo.mmap_start != 0) 345 free((void *)bios_efiinfo.mmap_start, bios_efiinfo.mmap_size); 346 347 siz = 0; 348 status = BS->GetMemoryMap(&siz, NULL, &mapkey, &mmsiz, &mmver); 349 if (status != EFI_BUFFER_TOO_SMALL) 350 panic("cannot get the size of memory map"); 351 mm0 = alloc(siz); 352 status = BS->GetMemoryMap(&siz, mm0, &mapkey, &mmsiz, &mmver); 353 if (status != EFI_SUCCESS) 354 panic("cannot get the memory map"); 355 n = siz / mmsiz; 356 mmap_key = mapkey; 357 358 for (i = 0, mm = mm0; i < n; i++, mm = NextMemoryDescriptor(mm, mmsiz)){ 359 bm0.type = BIOS_MAP_END; 360 bm0.addr = mm->PhysicalStart; 361 bm0.size = mm->NumberOfPages * EFI_PAGE_SIZE; 362 if (mm->Type == EfiReservedMemoryType || 363 mm->Type == EfiUnusableMemory || 364 mm->Type == EfiRuntimeServicesCode || 365 mm->Type == EfiRuntimeServicesData) 366 bm0.type = BIOS_MAP_RES; 367 else if (mm->Type == EfiLoaderCode || 368 mm->Type == EfiLoaderData || 369 mm->Type == EfiBootServicesCode || 370 mm->Type == EfiBootServicesData || 371 mm->Type == EfiConventionalMemory) 372 bm0.type = BIOS_MAP_FREE; 373 else if (mm->Type == EfiACPIReclaimMemory) 374 bm0.type = BIOS_MAP_ACPI; 375 else if (mm->Type == EfiACPIMemoryNVS) 376 bm0.type = BIOS_MAP_NVS; 377 else 378 /* 379 * XXX Is there anything to do for EfiMemoryMappedIO 380 * XXX EfiMemoryMappedIOPortSpace EfiPalCode? 381 */ 382 bm0.type = BIOS_MAP_RES; 383 384 for (bm = bios_memmap; bm->type != BIOS_MAP_END; bm++) { 385 if (bm->type != bm0.type) 386 continue; 387 if (bm->addr <= bm0.addr && 388 bm0.addr <= bm->addr + bm->size) { 389 bm->size = bm0.addr + bm0.size - bm->addr; 390 break; 391 } else if (bm0.addr <= bm->addr && 392 bm->addr <= bm0.addr + bm0.size) { 393 bm->size = bm->addr + bm->size - bm0.addr; 394 bm->addr = bm0.addr; 395 break; 396 } 397 } 398 if (bm->type == BIOS_MAP_END) { 399 if (bm == &bios_memmap[nitems(bios_memmap) - 1]) { 400 error = E2BIG; 401 break; 402 } 403 *bm = bm0; 404 (++bm)->type = BIOS_MAP_END; 405 } 406 } 407 for (bm = bios_memmap; bm->type != BIOS_MAP_END; bm++) { 408 if (bm->addr < IOM_BEGIN) /* Below memory hole */ 409 cnvmem = 410 max(cnvmem, (bm->addr + bm->size) / 1024); 411 if (bm->addr >= IOM_END /* Above the memory hole */ && 412 bm->addr / 1024 == extmem + 1024) 413 extmem += bm->size / 1024; 414 } 415 416 bios_efiinfo.mmap_desc_ver = mmver; 417 bios_efiinfo.mmap_desc_size = mmsiz; 418 bios_efiinfo.mmap_size = siz; 419 bios_efiinfo.mmap_start = (uintptr_t)mm0; 420 421 return error; 422 } 423 424 /*********************************************************************** 425 * Console 426 ***********************************************************************/ 427 static SIMPLE_TEXT_OUTPUT_INTERFACE *conout = NULL; 428 static SIMPLE_INPUT_INTERFACE *conin; 429 static EFI_GUID con_guid 430 = EFI_CONSOLE_CONTROL_PROTOCOL_GUID; 431 static EFI_GUID gop_guid 432 = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID; 433 static EFI_GUID serio_guid 434 = SERIAL_IO_PROTOCOL; 435 struct efi_video { 436 int cols; 437 int rows; 438 } efi_video[32]; 439 440 static void 441 efi_video_init(void) 442 { 443 EFI_CONSOLE_CONTROL_PROTOCOL *conctrl = NULL; 444 int i, mode80x25, mode100x31; 445 UINTN cols, rows; 446 EFI_STATUS status; 447 448 conout = ST->ConOut; 449 status = BS->LocateProtocol(&con_guid, NULL, (void **)&conctrl); 450 if (status == EFI_SUCCESS) 451 conctrl->SetMode(conctrl, EfiConsoleControlScreenText); 452 mode80x25 = -1; 453 mode100x31 = -1; 454 for (i = 0; i < conout->Mode->MaxMode; i++) { 455 status = conout->QueryMode(conout, i, &cols, &rows); 456 if (EFI_ERROR(status)) 457 continue; 458 if (mode80x25 < 0 && cols == 80 && rows == 25) 459 mode80x25 = i; 460 if (mode100x31 < 0 && cols == 100 && rows == 31) 461 mode100x31 = i; 462 if (i < nitems(efi_video)) { 463 efi_video[i].cols = cols; 464 efi_video[i].rows = rows; 465 } 466 } 467 if (mode100x31 >= 0) 468 conout->SetMode(conout, mode100x31); 469 else if (mode80x25 >= 0) 470 conout->SetMode(conout, mode80x25); 471 conin = ST->ConIn; 472 efi_video_reset(); 473 } 474 475 static void 476 efi_video_reset(void) 477 { 478 conout->EnableCursor(conout, TRUE); 479 conout->SetAttribute(conout, EFI_TEXT_ATTR(EFI_LIGHTGRAY, EFI_BLACK)); 480 conout->ClearScreen(conout); 481 } 482 483 void 484 efi_cons_probe(struct consdev *cn) 485 { 486 cn->cn_pri = CN_MIDPRI; 487 cn->cn_dev = makedev(12, 0); 488 printf(" pc%d", minor(cn->cn_dev)); 489 } 490 491 void 492 efi_cons_init(struct consdev *cp) 493 { 494 } 495 496 int 497 efi_cons_getc(dev_t dev) 498 { 499 EFI_INPUT_KEY key; 500 EFI_STATUS status; 501 UINTN dummy; 502 static int lastchar = 0; 503 504 if (lastchar) { 505 int r = lastchar; 506 if ((dev & 0x80) == 0) 507 lastchar = 0; 508 return (r); 509 } 510 511 status = conin->ReadKeyStroke(conin, &key); 512 while (status == EFI_NOT_READY || key.UnicodeChar == 0) { 513 if (dev & 0x80) 514 return (0); 515 BS->WaitForEvent(1, &conin->WaitForKey, &dummy); 516 status = conin->ReadKeyStroke(conin, &key); 517 } 518 519 if (dev & 0x80) 520 lastchar = key.UnicodeChar; 521 522 return (key.UnicodeChar); 523 } 524 525 void 526 efi_cons_putc(dev_t dev, int c) 527 { 528 CHAR16 buf[2]; 529 530 if (c == '\n') 531 efi_cons_putc(dev, '\r'); 532 533 buf[0] = c; 534 buf[1] = 0; 535 536 conout->OutputString(conout, buf); 537 } 538 539 int 540 efi_cons_getshifts(dev_t dev) 541 { 542 /* XXX */ 543 return (0); 544 } 545 546 int com_addr = -1; 547 int com_speed = -1; 548 549 static SERIAL_IO_INTERFACE *serios[4]; 550 const int comports[4] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 }; 551 552 /* call with sp == 0 to query the current speed */ 553 int 554 pio_comspeed(dev_t dev, int sp) 555 { 556 int port = (com_addr == -1) ? comports[minor(dev)] : com_addr; 557 int i, newsp; 558 int err; 559 560 if (sp <= 0) 561 return com_speed; 562 /* valid baud rate? */ 563 if (115200 < sp || sp < 75) 564 return -1; 565 566 /* 567 * Accepted speeds: 568 * 75 150 300 600 1200 2400 4800 9600 19200 38400 76800 and 569 * 14400 28800 57600 115200 570 */ 571 for (i = sp; i != 75 && i != 14400; i >>= 1) 572 if (i & 1) 573 return -1; 574 575 /* ripped screaming from dev/ic/com.c */ 576 #define divrnd(n, q) (((n)*2/(q)+1)/2) /* divide and round off */ 577 newsp = divrnd((COM_FREQ / 16), sp); 578 if (newsp <= 0) 579 return -1; 580 err = divrnd((COM_FREQ / 16) * 1000, sp * newsp) - 1000; 581 if (err < 0) 582 err = -err; 583 if (err > COM_TOLERANCE) 584 return -1; 585 #undef divrnd 586 587 if (com_speed != -1 && cn_tab && cn_tab->cn_dev == dev && 588 com_speed != sp) { 589 printf("com%d: changing speed to %d baud in 5 seconds, " 590 "change your terminal to match!\n\a", 591 minor(dev), sp); 592 sleep(5); 593 } 594 595 outb(port + com_cfcr, LCR_DLAB); 596 outb(port + com_dlbl, newsp); 597 outb(port + com_dlbh, newsp>>8); 598 outb(port + com_cfcr, LCR_8BITS); 599 if (com_speed != -1) 600 printf("\ncom%d: %d baud\n", minor(dev), sp); 601 602 newsp = com_speed; 603 com_speed = sp; 604 return newsp; 605 } 606 607 int 608 pio_com_getc(dev_t dev) 609 { 610 int port = (com_addr == -1) ? comports[minor(dev & 0x7f)] : com_addr; 611 612 if (dev & 0x80) 613 return (inb(port + com_lsr) & LSR_RXRDY); 614 615 while ((inb(port + com_lsr) & LSR_RXRDY) == 0) 616 ; 617 618 return (inb(port + com_data) & 0xff); 619 } 620 621 void 622 pio_com_putc(dev_t dev, int c) 623 { 624 int port = (com_addr == -1) ? comports[minor(dev)] : com_addr; 625 626 while ((inb(port + com_lsr) & LSR_TXRDY) == 0) 627 ; 628 629 outb(port + com_data, c); 630 } 631 632 void 633 efi_com_probe(struct consdev *cn) 634 { 635 EFI_HANDLE *handles = NULL; 636 SERIAL_IO_INTERFACE *serio; 637 EFI_STATUS status; 638 EFI_DEVICE_PATH *dp, *dp0; 639 EFI_DEV_PATH_PTR dpp; 640 UINTN sz; 641 int i, uid = -1; 642 643 cn->cn_pri = CN_LOWPRI; 644 cn->cn_dev = makedev(8, 0); 645 646 sz = 0; 647 status = BS->LocateHandle(ByProtocol, &serio_guid, 0, &sz, 0); 648 if (status == EFI_BUFFER_TOO_SMALL) { 649 handles = alloc(sz); 650 status = BS->LocateHandle(ByProtocol, &serio_guid, 651 0, &sz, handles); 652 } 653 if (handles == NULL || EFI_ERROR(status)) { 654 free(handles, sz); 655 return; 656 } 657 658 for (i = 0; i < sz / sizeof(EFI_HANDLE); i++) { 659 /* 660 * Identify port number of the handle. This assumes ACPI 661 * UID 0-3 map to legacy COM[1-4] and they use the legacy 662 * port address. 663 */ 664 status = BS->HandleProtocol(handles[i], &devp_guid, 665 (void **)&dp0); 666 if (EFI_ERROR(status)) 667 continue; 668 uid = -1; 669 for (dp = dp0; !IsDevicePathEnd(dp); 670 dp = NextDevicePathNode(dp)) { 671 dpp = (EFI_DEV_PATH_PTR)dp; 672 if (DevicePathType(dp) == ACPI_DEVICE_PATH && 673 DevicePathSubType(dp) == ACPI_DP) 674 if (dpp.Acpi->HID == EFI_PNP_ID(0x0501)) { 675 uid = dpp.Acpi->UID; 676 break; 677 } 678 } 679 if (uid < 0 || nitems(serios) <= uid) 680 continue; 681 682 /* Prepare SERIAL_IO_INTERFACE */ 683 status = BS->HandleProtocol(handles[i], &serio_guid, 684 (void **)&serio); 685 if (EFI_ERROR(status)) 686 continue; 687 serios[uid] = serio; 688 } 689 free(handles, sz); 690 691 for (i = 0; i < nitems(serios); i++) { 692 if (serios[i] != NULL) 693 printf(" com%d", i); 694 } 695 } 696 697 int 698 efi_valid_com(dev_t dev) 699 { 700 return (minor(dev) < nitems(serios) && serios[minor(dev)] != NULL); 701 } 702 703 int 704 comspeed(dev_t dev, int sp) 705 { 706 EFI_STATUS status; 707 SERIAL_IO_INTERFACE *serio = serios[minor(dev)]; 708 int newsp; 709 710 if (sp <= 0) 711 return com_speed; 712 713 if (!efi_valid_com(dev)) 714 return pio_comspeed(dev, sp); 715 716 if (serio->Mode->BaudRate != sp) { 717 status = serio->SetAttributes(serio, sp, 718 serio->Mode->ReceiveFifoDepth, 719 serio->Mode->Timeout, serio->Mode->Parity, 720 serio->Mode->DataBits, serio->Mode->StopBits); 721 if (EFI_ERROR(status)) { 722 printf("com%d: SetAttribute() failed with status=%d\n", 723 minor(dev), status); 724 return (-1); 725 } 726 if (com_speed != -1) 727 printf("\ncom%d: %d baud\n", minor(dev), sp); 728 } 729 730 /* same as comspeed() in libsa/bioscons.c */ 731 newsp = com_speed; 732 com_speed = sp; 733 734 return (newsp); 735 } 736 737 void 738 efi_com_init(struct consdev *cn) 739 { 740 if (!efi_valid_com(cn->cn_dev)) 741 /* This actually happens if the machine has another serial. */ 742 return; 743 744 if (com_speed == -1) 745 comspeed(cn->cn_dev, 9600); /* default speed is 9600 baud */ 746 } 747 748 int 749 efi_com_getc(dev_t dev) 750 { 751 EFI_STATUS status; 752 SERIAL_IO_INTERFACE *serio; 753 UINTN sz; 754 u_char buf; 755 static u_char lastchar = 0; 756 757 if (!efi_valid_com(dev & 0x7f)) 758 return pio_com_getc(dev); 759 serio = serios[minor(dev & 0x7f)]; 760 761 if (lastchar != 0) { 762 int r = lastchar; 763 if ((dev & 0x80) == 0) 764 lastchar = 0; 765 return (r); 766 } 767 768 for (;;) { 769 sz = 1; 770 status = serio->Read(serio, &sz, &buf); 771 if (status == EFI_SUCCESS && sz > 0) 772 break; 773 if (status != EFI_TIMEOUT && EFI_ERROR(status)) 774 panic("Error reading from serial status=%d", status); 775 if (dev & 0x80) 776 return (0); 777 } 778 779 if (dev & 0x80) 780 lastchar = buf; 781 782 return (buf); 783 } 784 785 void 786 efi_com_putc(dev_t dev, int c) 787 { 788 SERIAL_IO_INTERFACE *serio; 789 UINTN sz = 1; 790 u_char buf; 791 792 if (!efi_valid_com(dev)) { 793 pio_com_putc(dev, c); 794 return; 795 } 796 serio = serios[minor(dev)]; 797 buf = c; 798 serio->Write(serio, &sz, &buf); 799 } 800 801 /*********************************************************************** 802 * Miscellaneous 803 ***********************************************************************/ 804 /* 805 * ACPI GUID is confusing in UEFI spec. 806 * {EFI_,}_ACPI_20_TABLE_GUID or EFI_ACPI_TABLE_GUID means 807 * ACPI 2.0 or above. 808 */ 809 static EFI_GUID acpi_guid = ACPI_20_TABLE_GUID; 810 static EFI_GUID smbios_guid = SMBIOS_TABLE_GUID; 811 static EFI_GRAPHICS_OUTPUT *gop; 812 static int gopmode = -1; 813 814 #define efi_guidcmp(_a, _b) memcmp((_a), (_b), sizeof(EFI_GUID)) 815 816 static EFI_STATUS 817 efi_gop_setmode(int mode) 818 { 819 EFI_STATUS status; 820 821 status = gop->SetMode(gop, mode); 822 if (EFI_ERROR(status) || gop->Mode->Mode != mode) 823 printf("GOP SetMode() failed (%d)\n", status); 824 825 return (status); 826 } 827 828 void 829 efi_makebootargs(void) 830 { 831 int i; 832 EFI_STATUS status; 833 EFI_GRAPHICS_OUTPUT_MODE_INFORMATION 834 *gopi; 835 bios_efiinfo_t *ei = &bios_efiinfo; 836 int curmode; 837 UINTN sz, gopsiz, bestsiz = 0; 838 839 /* 840 * ACPI, BIOS configuration table 841 */ 842 for (i = 0; i < ST->NumberOfTableEntries; i++) { 843 if (efi_guidcmp(&acpi_guid, 844 &ST->ConfigurationTable[i].VendorGuid) == 0) 845 ei->config_acpi = (uintptr_t) 846 ST->ConfigurationTable[i].VendorTable; 847 else if (efi_guidcmp(&smbios_guid, 848 &ST->ConfigurationTable[i].VendorGuid) == 0) 849 ei->config_smbios = (uintptr_t) 850 ST->ConfigurationTable[i].VendorTable; 851 } 852 853 /* 854 * Frame buffer 855 */ 856 status = BS->LocateProtocol(&gop_guid, NULL, (void **)&gop); 857 if (!EFI_ERROR(status)) { 858 if (gopmode < 0) { 859 for (i = 0; i < gop->Mode->MaxMode; i++) { 860 status = gop->QueryMode(gop, i, &sz, &gopi); 861 if (EFI_ERROR(status)) 862 continue; 863 gopsiz = gopi->HorizontalResolution * 864 gopi->VerticalResolution; 865 if (gopsiz > bestsiz) { 866 gopmode = i; 867 bestsiz = gopsiz; 868 } 869 } 870 } 871 if (gopmode >= 0 && gopmode != gop->Mode->Mode) { 872 curmode = gop->Mode->Mode; 873 if (efi_gop_setmode(gopmode) != EFI_SUCCESS) 874 (void)efi_gop_setmode(curmode); 875 } 876 877 gopi = gop->Mode->Info; 878 switch (gopi->PixelFormat) { 879 case PixelBlueGreenRedReserved8BitPerColor: 880 ei->fb_red_mask = 0x00ff0000; 881 ei->fb_green_mask = 0x0000ff00; 882 ei->fb_blue_mask = 0x000000ff; 883 ei->fb_reserved_mask = 0xff000000; 884 break; 885 case PixelRedGreenBlueReserved8BitPerColor: 886 ei->fb_red_mask = 0x000000ff; 887 ei->fb_green_mask = 0x0000ff00; 888 ei->fb_blue_mask = 0x00ff0000; 889 ei->fb_reserved_mask = 0xff000000; 890 break; 891 case PixelBitMask: 892 ei->fb_red_mask = gopi->PixelInformation.RedMask; 893 ei->fb_green_mask = gopi->PixelInformation.GreenMask; 894 ei->fb_blue_mask = gopi->PixelInformation.BlueMask; 895 ei->fb_reserved_mask = 896 gopi->PixelInformation.ReservedMask; 897 break; 898 default: 899 break; 900 } 901 ei->fb_addr = gop->Mode->FrameBufferBase; 902 ei->fb_size = gop->Mode->FrameBufferSize; 903 ei->fb_height = gopi->VerticalResolution; 904 ei->fb_width = gopi->HorizontalResolution; 905 ei->fb_pixpsl = gopi->PixelsPerScanLine; 906 } 907 908 /* 909 * EFI system table 910 */ 911 ei->system_table = (uintptr_t)ST; 912 913 #ifdef __amd64__ 914 ei->flags |= BEI_64BIT; 915 #endif 916 917 addbootarg(BOOTARG_EFIINFO, sizeof(bios_efiinfo), &bios_efiinfo); 918 } 919 920 void 921 _rtt(void) 922 { 923 #ifdef EFI_DEBUG 924 printf("Hit any key to reboot\n"); 925 efi_cons_getc(0); 926 #endif 927 RS->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL); 928 for (;;) 929 continue; 930 } 931 932 time_t 933 getsecs(void) 934 { 935 EFI_TIME t; 936 time_t r = 0; 937 int y = 0; 938 const int daytab[][14] = { 939 { 0, -1, 30, 58, 89, 119, 150, 180, 211, 242, 272, 303, 333, 364 }, 940 { 0, -1, 30, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }, 941 }; 942 #define isleap(_y) (((_y) % 4) == 0 && (((_y) % 100) != 0 || ((_y) % 400) == 0)) 943 944 ST->RuntimeServices->GetTime(&t, NULL); 945 946 /* Calc days from UNIX epoch */ 947 r = (t.Year - 1970) * 365; 948 for (y = 1970; y < t.Year; y++) { 949 if (isleap(y)) 950 r++; 951 } 952 r += daytab[isleap(t.Year)? 1 : 0][t.Month] + t.Day; 953 954 /* Calc secs */ 955 r *= 60 * 60 * 24; 956 r += ((t.Hour * 60) + t.Minute) * 60 + t.Second; 957 if (-24 * 60 < t.TimeZone && t.TimeZone < 24 * 60) 958 r += t.TimeZone * 60; 959 960 return (r); 961 } 962 963 u_int 964 sleep(u_int i) 965 { 966 time_t t; 967 968 /* 969 * Loop for the requested number of seconds, polling, 970 * so that it may handle interrupts. 971 */ 972 for (t = getsecs() + i; getsecs() < t; cnischar()) 973 ; 974 975 return 0; 976 } 977 978 /*********************************************************************** 979 * Commands 980 ***********************************************************************/ 981 int 982 Xexit_efi(void) 983 { 984 BS->Exit(IH, 0, 0, NULL); 985 for (;;) 986 continue; 987 return (0); 988 } 989 990 int 991 Xvideo_efi(void) 992 { 993 int i, mode = -1; 994 995 if (cmd.argc >= 2) { 996 mode = strtol(cmd.argv[1], NULL, 10); 997 if (0 <= mode && mode < nitems(efi_video) && 998 efi_video[mode].cols > 0) { 999 conout->SetMode(conout, mode); 1000 efi_video_reset(); 1001 } 1002 } else { 1003 for (i = 0; i < nitems(efi_video) && 1004 i < conout->Mode->MaxMode; i++) { 1005 if (efi_video[i].cols > 0) 1006 printf("Mode %d: %d x %d\n", i, 1007 efi_video[i].cols, 1008 efi_video[i].rows); 1009 } 1010 printf("\n"); 1011 } 1012 printf("Current Mode = %d\n", conout->Mode->Mode); 1013 1014 return (0); 1015 } 1016 1017 int 1018 Xpoweroff_efi(void) 1019 { 1020 RS->ResetSystem(EfiResetShutdown, EFI_SUCCESS, 0, NULL); 1021 return (0); 1022 } 1023 1024 int 1025 Xgop_efi(void) 1026 { 1027 EFI_STATUS status; 1028 int i, mode = -1; 1029 UINTN sz; 1030 EFI_GRAPHICS_OUTPUT_MODE_INFORMATION 1031 *gopi; 1032 1033 status = BS->LocateProtocol(&gop_guid, NULL, (void **)&gop); 1034 if (EFI_ERROR(status)) 1035 return (0); 1036 1037 if (cmd.argc >= 2) { 1038 mode = strtol(cmd.argv[1], NULL, 10); 1039 if (0 <= mode && mode < gop->Mode->MaxMode) { 1040 status = gop->QueryMode(gop, mode, &sz, &gopi); 1041 if (!EFI_ERROR(status)) { 1042 if (efi_gop_setmode(mode) == EFI_SUCCESS) 1043 gopmode = mode; 1044 } 1045 } 1046 } else { 1047 for (i = 0; i < gop->Mode->MaxMode; i++) { 1048 status = gop->QueryMode(gop, i, &sz, &gopi); 1049 if (EFI_ERROR(status)) 1050 continue; 1051 printf("Mode %d: %d x %d (stride = %d)\n", i, 1052 gopi->HorizontalResolution, 1053 gopi->VerticalResolution, 1054 gopi->PixelsPerScanLine); 1055 } 1056 printf("\n"); 1057 } 1058 printf("Current Mode = %d\n", gop->Mode->Mode); 1059 1060 return (0); 1061 } 1062