1 /*++ @file 2 3 Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR> 4 Portions copyright (c) 2008 - 2011, Apple Inc. All rights reserved.<BR> 5 This program and the accompanying materials 6 are licensed and made available under the terms and conditions of the BSD License 7 which accompanies this distribution. The full text of the license may be found at 8 http://opensource.org/licenses/bsd-license.php 9 10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 12 13 **/ 14 15 #include "Host.h" 16 17 #ifdef __APPLE__ 18 #define MAP_ANONYMOUS MAP_ANON 19 #endif 20 21 22 // 23 // Globals 24 // 25 26 EMU_THUNK_PPI mSecEmuThunkPpi = { 27 GasketSecUnixPeiAutoScan, 28 GasketSecUnixFdAddress, 29 GasketSecEmuThunkAddress 30 }; 31 32 char *gGdbWorkingFileName = NULL; 33 unsigned int mScriptSymbolChangesCount = 0; 34 35 36 // 37 // Default information about where the FD is located. 38 // This array gets filled in with information from EFI_FIRMWARE_VOLUMES 39 // EFI_FIRMWARE_VOLUMES is a host environment variable set by system.cmd. 40 // The number of array elements is allocated base on parsing 41 // EFI_FIRMWARE_VOLUMES and the memory is never freed. 42 // 43 UINTN gFdInfoCount = 0; 44 EMU_FD_INFO *gFdInfo; 45 46 // 47 // Array that supports seperate memory rantes. 48 // The memory ranges are set in system.cmd via the EFI_MEMORY_SIZE variable. 49 // The number of array elements is allocated base on parsing 50 // EFI_MEMORY_SIZE and the memory is never freed. 51 // 52 UINTN gSystemMemoryCount = 0; 53 EMU_SYSTEM_MEMORY *gSystemMemory; 54 55 56 57 UINTN mImageContextModHandleArraySize = 0; 58 IMAGE_CONTEXT_TO_MOD_HANDLE *mImageContextModHandleArray = NULL; 59 60 EFI_PEI_PPI_DESCRIPTOR *gPpiList; 61 62 63 int gInXcode = 0; 64 65 66 /*++ 67 Breakpoint target for Xcode project. Set in the Xcode XML 68 69 Xcode breakpoint will 'source Host.gdb' 70 gGdbWorkingFileName is set to Host.gdb 71 72 **/ 73 VOID 74 SecGdbConfigBreak ( 75 VOID 76 ) 77 { 78 } 79 80 81 82 /*++ 83 84 Routine Description: 85 Main entry point to SEC for Unix. This is a unix program 86 87 Arguments: 88 Argc - Number of command line arguments 89 Argv - Array of command line argument strings 90 Envp - Array of environment variable strings 91 92 Returns: 93 0 - Normal exit 94 1 - Abnormal exit 95 96 **/ 97 int 98 main ( 99 IN int Argc, 100 IN char **Argv, 101 IN char **Envp 102 ) 103 { 104 EFI_STATUS Status; 105 EFI_PHYSICAL_ADDRESS InitialStackMemory; 106 UINT64 InitialStackMemorySize; 107 UINTN Index; 108 UINTN Index1; 109 UINTN Index2; 110 UINTN PeiIndex; 111 CHAR8 *FileName; 112 BOOLEAN Done; 113 EFI_PEI_FILE_HANDLE FileHandle; 114 VOID *SecFile; 115 CHAR16 *MemorySizeStr; 116 CHAR16 *FirmwareVolumesStr; 117 UINTN *StackPointer; 118 FILE *GdbTempFile; 119 120 // 121 // Xcode does not support sourcing gdb scripts directly, so the Xcode XML 122 // has a break point script to source the GdbRun script. 123 // 124 SecGdbConfigBreak (); 125 126 // 127 // If dlopen doesn't work, then we build a gdb script to allow the 128 // symbols to be loaded. 129 // 130 Index = strlen (*Argv); 131 gGdbWorkingFileName = AllocatePool (Index + strlen(".gdb") + 1); 132 strcpy (gGdbWorkingFileName, *Argv); 133 strcat (gGdbWorkingFileName, ".gdb"); 134 135 // 136 // Empty out the gdb symbols script file. 137 // 138 GdbTempFile = fopen (gGdbWorkingFileName, "w"); 139 if (GdbTempFile != NULL) { 140 fclose (GdbTempFile); 141 } 142 143 printf ("\nEDK II UNIX Host Emulation Environment from http://www.tianocore.org/edk2/\n"); 144 145 setbuf (stdout, 0); 146 setbuf (stderr, 0); 147 148 MemorySizeStr = (CHAR16 *) PcdGetPtr (PcdEmuMemorySize); 149 FirmwareVolumesStr = (CHAR16 *) PcdGetPtr (PcdEmuFirmwareVolume); 150 151 // 152 // PPIs pased into PEI_CORE 153 // 154 AddThunkPpi (EFI_PEI_PPI_DESCRIPTOR_PPI, &gEmuThunkPpiGuid, &mSecEmuThunkPpi); 155 156 SecInitThunkProtocol (); 157 158 // 159 // Emulator Bus Driver Thunks 160 // 161 AddThunkProtocol (&gX11ThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuGop), TRUE); 162 AddThunkProtocol (&gPosixFileSystemThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuFileSystem), TRUE); 163 AddThunkProtocol (&gBlockIoThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuVirtualDisk), TRUE); 164 AddThunkProtocol (&gSnpThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuNetworkInterface), TRUE); 165 166 // 167 // Emulator other Thunks 168 // 169 AddThunkProtocol (&gPthreadThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuApCount), FALSE); 170 171 // EmuSecLibConstructor (); 172 173 gPpiList = GetThunkPpiList (); 174 175 // 176 // Allocate space for gSystemMemory Array 177 // 178 gSystemMemoryCount = CountSeparatorsInString (MemorySizeStr, '!') + 1; 179 gSystemMemory = AllocateZeroPool (gSystemMemoryCount * sizeof (EMU_SYSTEM_MEMORY)); 180 if (gSystemMemory == NULL) { 181 printf ("ERROR : Can not allocate memory for system. Exiting.\n"); 182 exit (1); 183 } 184 // 185 // Allocate space for gSystemMemory Array 186 // 187 gFdInfoCount = CountSeparatorsInString (FirmwareVolumesStr, '!') + 1; 188 gFdInfo = AllocateZeroPool (gFdInfoCount * sizeof (EMU_FD_INFO)); 189 if (gFdInfo == NULL) { 190 printf ("ERROR : Can not allocate memory for fd info. Exiting.\n"); 191 exit (1); 192 } 193 194 printf (" BootMode 0x%02x\n", (unsigned int)PcdGet32 (PcdEmuBootMode)); 195 196 // 197 // Open up a 128K file to emulate temp memory for SEC. 198 // on a real platform this would be SRAM, or using the cache as RAM. 199 // Set InitialStackMemory to zero so UnixOpenFile will allocate a new mapping 200 // 201 InitialStackMemorySize = STACK_SIZE; 202 InitialStackMemory = (UINTN)MapMemory ( 203 0, (UINT32) InitialStackMemorySize, 204 PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE 205 ); 206 if (InitialStackMemory == 0) { 207 printf ("ERROR : Can not open SecStack Exiting\n"); 208 exit (1); 209 } 210 211 printf (" OS Emulator passing in %u KB of temp RAM at 0x%08lx to SEC\n", 212 (unsigned int)(InitialStackMemorySize / 1024), 213 (unsigned long)InitialStackMemory 214 ); 215 216 for (StackPointer = (UINTN*) (UINTN) InitialStackMemory; 217 StackPointer < (UINTN*)(UINTN)((UINTN) InitialStackMemory + (UINT64) InitialStackMemorySize); 218 StackPointer ++) { 219 *StackPointer = 0x5AA55AA5; 220 } 221 222 // 223 // Open All the firmware volumes and remember the info in the gFdInfo global 224 // 225 FileName = (CHAR8 *) AllocatePool (StrLen (FirmwareVolumesStr) + 1); 226 if (FileName == NULL) { 227 printf ("ERROR : Can not allocate memory for firmware volume string\n"); 228 exit (1); 229 } 230 231 Index2 = 0; 232 for (Done = FALSE, Index = 0, PeiIndex = 0, SecFile = NULL; 233 FirmwareVolumesStr[Index2] != 0; 234 Index++) { 235 for (Index1 = 0; (FirmwareVolumesStr[Index2] != '!') && (FirmwareVolumesStr[Index2] != 0); Index2++) { 236 FileName[Index1++] = FirmwareVolumesStr[Index2]; 237 } 238 if (FirmwareVolumesStr[Index2] == '!') { 239 Index2++; 240 } 241 FileName[Index1] = '\0'; 242 243 if (Index == 0) { 244 // Map FV Recovery Read Only and other areas Read/Write 245 Status = MapFd0 ( 246 FileName, 247 &gFdInfo[0].Address, 248 &gFdInfo[0].Size 249 ); 250 } else { 251 // 252 // Open the FD and remember where it got mapped into our processes address space 253 // Maps Read Only 254 // 255 Status = MapFile ( 256 FileName, 257 &gFdInfo[Index].Address, 258 &gFdInfo[Index].Size 259 ); 260 } 261 if (EFI_ERROR (Status)) { 262 printf ("ERROR : Can not open Firmware Device File %s (%x). Exiting.\n", FileName, (unsigned int)Status); 263 exit (1); 264 } 265 266 printf (" FD loaded from %s at 0x%08lx",FileName, (unsigned long)gFdInfo[Index].Address); 267 268 if (SecFile == NULL) { 269 // 270 // Assume the beginning of the FD is an FV and look for the SEC Core. 271 // Load the first one we find. 272 // 273 FileHandle = NULL; 274 Status = PeiServicesFfsFindNextFile ( 275 EFI_FV_FILETYPE_SECURITY_CORE, 276 (EFI_PEI_FV_HANDLE)(UINTN)gFdInfo[Index].Address, 277 &FileHandle 278 ); 279 if (!EFI_ERROR (Status)) { 280 Status = PeiServicesFfsFindSectionData (EFI_SECTION_PE32, FileHandle, &SecFile); 281 if (!EFI_ERROR (Status)) { 282 PeiIndex = Index; 283 printf (" contains SEC Core"); 284 } 285 } 286 } 287 288 printf ("\n"); 289 } 290 291 if (SecFile == NULL) { 292 printf ("ERROR : SEC not found!\n"); 293 exit (1); 294 } 295 296 // 297 // Calculate memory regions and store the information in the gSystemMemory 298 // global for later use. The autosizing code will use this data to 299 // map this memory into the SEC process memory space. 300 // 301 Index1 = 0; 302 Index = 0; 303 while (1) { 304 UINTN val = 0; 305 // 306 // Save the size of the memory. 307 // 308 while (MemorySizeStr[Index1] >= '0' && MemorySizeStr[Index1] <= '9') { 309 val = val * 10 + MemorySizeStr[Index1] - '0'; 310 Index1++; 311 } 312 gSystemMemory[Index++].Size = val * 0x100000; 313 if (MemorySizeStr[Index1] == 0) { 314 break; 315 } 316 Index1++; 317 } 318 319 printf ("\n"); 320 321 // 322 // Hand off to SEC 323 // 324 SecLoadFromCore ((UINTN) InitialStackMemory, (UINTN) InitialStackMemorySize, (UINTN) gFdInfo[0].Address, SecFile); 325 326 // 327 // If we get here, then the SEC Core returned. This is an error as SEC should 328 // always hand off to PEI Core and then on to DXE Core. 329 // 330 printf ("ERROR : SEC returned\n"); 331 exit (1); 332 } 333 334 335 EFI_PHYSICAL_ADDRESS * 336 MapMemory ( 337 IN INTN fd, 338 IN UINT64 length, 339 IN INTN prot, 340 IN INTN flags 341 ) 342 { 343 STATIC UINTN base = 0x40000000; 344 CONST UINTN align = (1 << 24); 345 VOID *res = NULL; 346 BOOLEAN isAligned = 0; 347 348 // 349 // Try to get an aligned block somewhere in the address space of this 350 // process. 351 // 352 while((!isAligned) && (base != 0)) { 353 res = mmap ((void *)base, length, prot, flags, fd, 0); 354 if (res == MAP_FAILED) { 355 return NULL; 356 } 357 if ((((UINTN)res) & ~(align-1)) == (UINTN)res) { 358 isAligned=1; 359 } else { 360 munmap(res, length); 361 base += align; 362 } 363 } 364 return res; 365 } 366 367 368 /*++ 369 370 Routine Description: 371 Opens and memory maps a file using Unix services. If BaseAddress is non zero 372 the process will try and allocate the memory starting at BaseAddress. 373 374 Arguments: 375 FileName - The name of the file to open and map 376 MapSize - The amount of the file to map in bytes 377 CreationDisposition - The flags to pass to CreateFile(). Use to create new files for 378 memory emulation, and exiting files for firmware volume emulation 379 BaseAddress - The base address of the mapped file in the user address space. 380 If passed in as NULL the a new memory region is used. 381 If passed in as non NULL the request memory region is used for 382 the mapping of the file into the process space. 383 Length - The size of the mapped region in bytes 384 385 Returns: 386 EFI_SUCCESS - The file was opened and mapped. 387 EFI_NOT_FOUND - FileName was not found in the current directory 388 EFI_DEVICE_ERROR - An error occured attempting to map the opened file 389 390 **/ 391 EFI_STATUS 392 MapFile ( 393 IN CHAR8 *FileName, 394 IN OUT EFI_PHYSICAL_ADDRESS *BaseAddress, 395 OUT UINT64 *Length 396 ) 397 { 398 int fd; 399 VOID *res; 400 UINTN FileSize; 401 402 fd = open (FileName, O_RDWR); 403 if (fd < 0) { 404 return EFI_NOT_FOUND; 405 } 406 FileSize = lseek (fd, 0, SEEK_END); 407 408 409 res = MapMemory (fd, FileSize, PROT_READ | PROT_EXEC, MAP_PRIVATE); 410 411 close (fd); 412 413 if (res == NULL) { 414 perror ("MapFile() Failed"); 415 return EFI_DEVICE_ERROR; 416 } 417 418 *Length = (UINT64) FileSize; 419 *BaseAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) res; 420 421 return EFI_SUCCESS; 422 } 423 424 EFI_STATUS 425 MapFd0 ( 426 IN CHAR8 *FileName, 427 IN OUT EFI_PHYSICAL_ADDRESS *BaseAddress, 428 OUT UINT64 *Length 429 ) 430 { 431 int fd; 432 void *res, *res2, *res3; 433 UINTN FileSize; 434 UINTN FvSize; 435 void *EmuMagicPage; 436 437 fd = open (FileName, O_RDWR); 438 if (fd < 0) { 439 return EFI_NOT_FOUND; 440 } 441 FileSize = lseek (fd, 0, SEEK_END); 442 443 FvSize = FixedPcdGet64 (PcdEmuFlashFvRecoverySize); 444 445 // Assume start of FD is Recovery FV, and make it write protected 446 res = mmap ( 447 (void *)(UINTN)FixedPcdGet64 (PcdEmuFlashFvRecoveryBase), 448 FvSize, 449 PROT_READ | PROT_EXEC, 450 MAP_PRIVATE, 451 fd, 452 0 453 ); 454 if (res == MAP_FAILED) { 455 perror ("MapFd0() Failed res ="); 456 close (fd); 457 return EFI_DEVICE_ERROR; 458 } else if (res != (void *)(UINTN)FixedPcdGet64 (PcdEmuFlashFvRecoveryBase)) { 459 // We could not load at the build address, so we need to allow writes 460 munmap (res, FvSize); 461 res = mmap ( 462 (void *)(UINTN)FixedPcdGet64 (PcdEmuFlashFvRecoveryBase), 463 FvSize, 464 PROT_READ | PROT_WRITE | PROT_EXEC, 465 MAP_PRIVATE, 466 fd, 467 0 468 ); 469 if (res == MAP_FAILED) { 470 perror ("MapFd0() Failed res ="); 471 close (fd); 472 return EFI_DEVICE_ERROR; 473 } 474 } 475 476 // Map the rest of the FD as read/write 477 res2 = mmap ( 478 (void *)(UINTN)(FixedPcdGet64 (PcdEmuFlashFvRecoveryBase) + FvSize), 479 FileSize - FvSize, 480 PROT_READ | PROT_WRITE | PROT_EXEC, 481 MAP_SHARED, 482 fd, 483 FvSize 484 ); 485 close (fd); 486 if (res2 == MAP_FAILED) { 487 perror ("MapFd0() Failed res2 ="); 488 return EFI_DEVICE_ERROR; 489 } 490 491 // 492 // If enabled use the magic page to communicate between modules 493 // This replaces the PI PeiServicesTable pointer mechanism that 494 // deos not work in the emulator. It also allows the removal of 495 // writable globals from SEC, PEI_CORE (libraries), PEIMs 496 // 497 EmuMagicPage = (void *)(UINTN)FixedPcdGet64 (PcdPeiServicesTablePage); 498 if (EmuMagicPage != NULL) { 499 res3 = mmap ( 500 (void *)EmuMagicPage, 501 4096, 502 PROT_READ | PROT_WRITE, 503 MAP_PRIVATE | MAP_ANONYMOUS, 504 0, 505 0 506 ); 507 if (res3 != EmuMagicPage) { 508 printf ("MapFd0(): Could not allocate PeiServicesTablePage @ %lx\n", (long unsigned int)EmuMagicPage); 509 return EFI_DEVICE_ERROR; 510 } 511 } 512 513 *Length = (UINT64) FileSize; 514 *BaseAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) res; 515 516 return EFI_SUCCESS; 517 } 518 519 520 /*++ 521 522 Routine Description: 523 This is the service to load the SEC Core from the Firmware Volume 524 525 Arguments: 526 LargestRegion - Memory to use for SEC. 527 LargestRegionSize - Size of Memory to use for PEI 528 BootFirmwareVolumeBase - Start of the Boot FV 529 PeiCorePe32File - SEC PE32 530 531 Returns: 532 Success means control is transfered and thus we should never return 533 534 **/ 535 VOID 536 SecLoadFromCore ( 537 IN UINTN LargestRegion, 538 IN UINTN LargestRegionSize, 539 IN UINTN BootFirmwareVolumeBase, 540 IN VOID *PeiCorePe32File 541 ) 542 { 543 EFI_STATUS Status; 544 EFI_PHYSICAL_ADDRESS TopOfMemory; 545 VOID *TopOfStack; 546 EFI_PHYSICAL_ADDRESS PeiCoreEntryPoint; 547 EFI_SEC_PEI_HAND_OFF *SecCoreData; 548 UINTN PeiStackSize; 549 550 // 551 // Compute Top Of Memory for Stack and PEI Core Allocations 552 // 553 TopOfMemory = LargestRegion + LargestRegionSize; 554 PeiStackSize = (UINTN)RShiftU64((UINT64)STACK_SIZE,1); 555 556 // 557 // |-----------| <---- TemporaryRamBase + TemporaryRamSize 558 // | Heap | 559 // | | 560 // |-----------| <---- StackBase / PeiTemporaryMemoryBase 561 // | | 562 // | Stack | 563 // |-----------| <---- TemporaryRamBase 564 // 565 TopOfStack = (VOID *)(LargestRegion + PeiStackSize); 566 TopOfMemory = LargestRegion + PeiStackSize; 567 568 // 569 // Reservet space for storing PeiCore's parament in stack. 570 // 571 TopOfStack = (VOID *)((UINTN)TopOfStack - sizeof (EFI_SEC_PEI_HAND_OFF) - CPU_STACK_ALIGNMENT); 572 TopOfStack = ALIGN_POINTER (TopOfStack, CPU_STACK_ALIGNMENT); 573 574 575 // 576 // Bind this information into the SEC hand-off state 577 // 578 SecCoreData = (EFI_SEC_PEI_HAND_OFF*)(UINTN) TopOfStack; 579 SecCoreData->DataSize = sizeof(EFI_SEC_PEI_HAND_OFF); 580 SecCoreData->BootFirmwareVolumeBase = (VOID*)BootFirmwareVolumeBase; 581 SecCoreData->BootFirmwareVolumeSize = PcdGet32 (PcdEmuFirmwareFdSize); 582 SecCoreData->TemporaryRamBase = (VOID*)(UINTN)LargestRegion; 583 SecCoreData->TemporaryRamSize = STACK_SIZE; 584 SecCoreData->StackBase = SecCoreData->TemporaryRamBase; 585 SecCoreData->StackSize = PeiStackSize; 586 SecCoreData->PeiTemporaryRamBase = (VOID*) ((UINTN) SecCoreData->TemporaryRamBase + PeiStackSize); 587 SecCoreData->PeiTemporaryRamSize = STACK_SIZE - PeiStackSize; 588 589 // 590 // Find the SEC Core Entry Point 591 // 592 Status = SecPeCoffGetEntryPoint (PeiCorePe32File, (VOID **)&PeiCoreEntryPoint); 593 if (EFI_ERROR (Status)) { 594 return ; 595 } 596 597 // 598 // Transfer control to the SEC Core 599 // 600 PeiSwitchStacks ( 601 (SWITCH_STACK_ENTRY_POINT) (UINTN) PeiCoreEntryPoint, 602 SecCoreData, 603 (VOID *)gPpiList, 604 TopOfStack 605 ); 606 // 607 // If we get here, then the SEC Core returned. This is an error 608 // 609 return ; 610 } 611 612 613 /*++ 614 615 Routine Description: 616 This service is called from Index == 0 until it returns EFI_UNSUPPORTED. 617 It allows discontinuous memory regions to be supported by the emulator. 618 It uses gSystemMemory[] and gSystemMemoryCount that were created by 619 parsing the host environment variable EFI_MEMORY_SIZE. 620 The size comes from the varaible and the address comes from the call to 621 UnixOpenFile. 622 623 Arguments: 624 Index - Which memory region to use 625 MemoryBase - Return Base address of memory region 626 MemorySize - Return size in bytes of the memory region 627 628 Returns: 629 EFI_SUCCESS - If memory region was mapped 630 EFI_UNSUPPORTED - If Index is not supported 631 632 **/ 633 EFI_STATUS 634 SecUnixPeiAutoScan ( 635 IN UINTN Index, 636 OUT EFI_PHYSICAL_ADDRESS *MemoryBase, 637 OUT UINT64 *MemorySize 638 ) 639 { 640 void *res; 641 642 if (Index >= gSystemMemoryCount) { 643 return EFI_UNSUPPORTED; 644 } 645 646 *MemoryBase = 0; 647 res = MapMemory ( 648 0, gSystemMemory[Index].Size, 649 PROT_READ | PROT_WRITE | PROT_EXEC, 650 MAP_PRIVATE | MAP_ANONYMOUS 651 ); 652 if (res == MAP_FAILED) { 653 return EFI_DEVICE_ERROR; 654 } 655 *MemorySize = gSystemMemory[Index].Size; 656 *MemoryBase = (UINTN)res; 657 gSystemMemory[Index].Memory = *MemoryBase; 658 659 return EFI_SUCCESS; 660 } 661 662 663 /*++ 664 665 Routine Description: 666 Check to see if an address range is in the EFI GCD memory map. 667 668 This is all of GCD for system memory passed to DXE Core. FV 669 mapping and other device mapped into system memory are not 670 inlcuded in the check. 671 672 Arguments: 673 Index - Which memory region to use 674 MemoryBase - Return Base address of memory region 675 MemorySize - Return size in bytes of the memory region 676 677 Returns: 678 TRUE - Address is in the EFI GCD memory map 679 FALSE - Address is NOT in memory map 680 681 **/ 682 BOOLEAN 683 EfiSystemMemoryRange ( 684 IN VOID *MemoryAddress 685 ) 686 { 687 UINTN Index; 688 EFI_PHYSICAL_ADDRESS MemoryBase; 689 690 MemoryBase = (EFI_PHYSICAL_ADDRESS)(UINTN)MemoryAddress; 691 for (Index = 0; Index < gSystemMemoryCount; Index++) { 692 if ((MemoryBase >= gSystemMemory[Index].Memory) && 693 (MemoryBase < (gSystemMemory[Index].Memory + gSystemMemory[Index].Size)) ) { 694 return TRUE; 695 } 696 } 697 698 return FALSE; 699 } 700 701 702 /*++ 703 704 Routine Description: 705 Since the SEC is the only Unix program in stack it must export 706 an interface to do POSIX calls. gUnix is initialized in UnixThunk.c. 707 708 Arguments: 709 InterfaceSize - sizeof (EFI_WIN_NT_THUNK_PROTOCOL); 710 InterfaceBase - Address of the gUnix global 711 712 Returns: 713 EFI_SUCCESS - Data returned 714 715 **/ 716 VOID * 717 SecEmuThunkAddress ( 718 VOID 719 ) 720 { 721 return &gEmuThunkProtocol; 722 } 723 724 725 726 RETURN_STATUS 727 EFIAPI 728 SecPeCoffGetEntryPoint ( 729 IN VOID *Pe32Data, 730 IN OUT VOID **EntryPoint 731 ) 732 { 733 EFI_STATUS Status; 734 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; 735 736 ZeroMem (&ImageContext, sizeof (ImageContext)); 737 ImageContext.Handle = Pe32Data; 738 ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) SecImageRead; 739 740 Status = PeCoffLoaderGetImageInfo (&ImageContext); 741 if (EFI_ERROR (Status)) { 742 return Status; 743 } 744 745 if (ImageContext.ImageAddress != (UINTN)Pe32Data) { 746 // 747 // Relocate image to match the address where it resides 748 // 749 ImageContext.ImageAddress = (UINTN)Pe32Data; 750 Status = PeCoffLoaderLoadImage (&ImageContext); 751 if (EFI_ERROR (Status)) { 752 return Status; 753 } 754 755 Status = PeCoffLoaderRelocateImage (&ImageContext); 756 if (EFI_ERROR (Status)) { 757 return Status; 758 } 759 } else { 760 // 761 // Or just return image entry point 762 // 763 ImageContext.PdbPointer = PeCoffLoaderGetPdbPointer (Pe32Data); 764 Status = PeCoffLoaderGetEntryPoint (Pe32Data, EntryPoint); 765 if (EFI_ERROR (Status)) { 766 return Status; 767 } 768 ImageContext.EntryPoint = (UINTN)*EntryPoint; 769 } 770 771 // On Unix a dlopen is done that will change the entry point 772 SecPeCoffRelocateImageExtraAction (&ImageContext); 773 *EntryPoint = (VOID *)(UINTN)ImageContext.EntryPoint; 774 775 return Status; 776 } 777 778 779 780 /*++ 781 782 Routine Description: 783 Return the FD Size and base address. Since the FD is loaded from a 784 file into host memory only the SEC will know it's address. 785 786 Arguments: 787 Index - Which FD, starts at zero. 788 FdSize - Size of the FD in bytes 789 FdBase - Start address of the FD. Assume it points to an FV Header 790 FixUp - Difference between actual FD address and build address 791 792 Returns: 793 EFI_SUCCESS - Return the Base address and size of the FV 794 EFI_UNSUPPORTED - Index does nto map to an FD in the system 795 796 **/ 797 EFI_STATUS 798 SecUnixFdAddress ( 799 IN UINTN Index, 800 IN OUT EFI_PHYSICAL_ADDRESS *FdBase, 801 IN OUT UINT64 *FdSize, 802 IN OUT EFI_PHYSICAL_ADDRESS *FixUp 803 ) 804 { 805 if (Index >= gFdInfoCount) { 806 return EFI_UNSUPPORTED; 807 } 808 809 *FdBase = gFdInfo[Index].Address; 810 *FdSize = gFdInfo[Index].Size; 811 *FixUp = 0; 812 813 if (*FdBase == 0 && *FdSize == 0) { 814 return EFI_UNSUPPORTED; 815 } 816 817 if (Index == 0) { 818 // 819 // FD 0 has XIP code and well known PCD values 820 // If the memory buffer could not be allocated at the FD build address 821 // the Fixup is the difference. 822 // 823 *FixUp = *FdBase - PcdGet64 (PcdEmuFdBaseAddress); 824 } 825 826 return EFI_SUCCESS; 827 } 828 829 830 /*++ 831 832 Routine Description: 833 Count the number of separators in String 834 835 Arguments: 836 String - String to process 837 Separator - Item to count 838 839 Returns: 840 Number of Separator in String 841 842 **/ 843 UINTN 844 CountSeparatorsInString ( 845 IN const CHAR16 *String, 846 IN CHAR16 Separator 847 ) 848 { 849 UINTN Count; 850 851 for (Count = 0; *String != '\0'; String++) { 852 if (*String == Separator) { 853 Count++; 854 } 855 } 856 857 return Count; 858 } 859 860 861 EFI_STATUS 862 EFIAPI 863 SecImageRead ( 864 IN VOID *FileHandle, 865 IN UINTN FileOffset, 866 IN OUT UINTN *ReadSize, 867 OUT VOID *Buffer 868 ) 869 /*++ 870 871 Routine Description: 872 Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file 873 874 Arguments: 875 FileHandle - The handle to the PE/COFF file 876 FileOffset - The offset, in bytes, into the file to read 877 ReadSize - The number of bytes to read from the file starting at FileOffset 878 Buffer - A pointer to the buffer to read the data into. 879 880 Returns: 881 EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset 882 883 **/ 884 { 885 CHAR8 *Destination8; 886 CHAR8 *Source8; 887 UINTN Length; 888 889 Destination8 = Buffer; 890 Source8 = (CHAR8 *) ((UINTN) FileHandle + FileOffset); 891 Length = *ReadSize; 892 while (Length--) { 893 *(Destination8++) = *(Source8++); 894 } 895 896 return EFI_SUCCESS; 897 } 898 899 900 /*++ 901 902 Routine Description: 903 Store the ModHandle in an array indexed by the Pdb File name. 904 The ModHandle is needed to unload the image. 905 906 Arguments: 907 ImageContext - Input data returned from PE Laoder Library. Used to find the 908 .PDB file name of the PE Image. 909 ModHandle - Returned from LoadLibraryEx() and stored for call to 910 FreeLibrary(). 911 912 Returns: 913 EFI_SUCCESS - ModHandle was stored. 914 915 **/ 916 EFI_STATUS 917 AddHandle ( 918 IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext, 919 IN VOID *ModHandle 920 ) 921 { 922 UINTN Index; 923 IMAGE_CONTEXT_TO_MOD_HANDLE *Array; 924 UINTN PreviousSize; 925 926 927 Array = mImageContextModHandleArray; 928 for (Index = 0; Index < mImageContextModHandleArraySize; Index++, Array++) { 929 if (Array->ImageContext == NULL) { 930 // 931 // Make a copy of the stirng and store the ModHandle 932 // 933 Array->ImageContext = ImageContext; 934 Array->ModHandle = ModHandle; 935 return EFI_SUCCESS; 936 } 937 } 938 939 // 940 // No free space in mImageContextModHandleArray so grow it by 941 // IMAGE_CONTEXT_TO_MOD_HANDLE entires. realloc will 942 // copy the old values to the new locaiton. But it does 943 // not zero the new memory area. 944 // 945 PreviousSize = mImageContextModHandleArraySize * sizeof (IMAGE_CONTEXT_TO_MOD_HANDLE); 946 mImageContextModHandleArraySize += MAX_IMAGE_CONTEXT_TO_MOD_HANDLE_ARRAY_SIZE; 947 948 mImageContextModHandleArray = ReallocatePool ( 949 (mImageContextModHandleArraySize - 1) * sizeof (IMAGE_CONTEXT_TO_MOD_HANDLE), 950 mImageContextModHandleArraySize * sizeof (IMAGE_CONTEXT_TO_MOD_HANDLE), 951 mImageContextModHandleArray 952 ); 953 if (mImageContextModHandleArray == NULL) { 954 ASSERT (FALSE); 955 return EFI_OUT_OF_RESOURCES; 956 } 957 958 memset (mImageContextModHandleArray + PreviousSize, 0, MAX_IMAGE_CONTEXT_TO_MOD_HANDLE_ARRAY_SIZE * sizeof (IMAGE_CONTEXT_TO_MOD_HANDLE)); 959 960 return AddHandle (ImageContext, ModHandle); 961 } 962 963 964 /*++ 965 966 Routine Description: 967 Return the ModHandle and delete the entry in the array. 968 969 Arguments: 970 ImageContext - Input data returned from PE Laoder Library. Used to find the 971 .PDB file name of the PE Image. 972 973 Returns: 974 ModHandle - ModHandle assoicated with ImageContext is returned 975 NULL - No ModHandle associated with ImageContext 976 977 **/ 978 VOID * 979 RemoveHandle ( 980 IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext 981 ) 982 { 983 UINTN Index; 984 IMAGE_CONTEXT_TO_MOD_HANDLE *Array; 985 986 if (ImageContext->PdbPointer == NULL) { 987 // 988 // If no PDB pointer there is no ModHandle so return NULL 989 // 990 return NULL; 991 } 992 993 Array = mImageContextModHandleArray; 994 for (Index = 0; Index < mImageContextModHandleArraySize; Index++, Array++) { 995 if (Array->ImageContext == ImageContext) { 996 // 997 // If you find a match return it and delete the entry 998 // 999 Array->ImageContext = NULL; 1000 return Array->ModHandle; 1001 } 1002 } 1003 1004 return NULL; 1005 } 1006 1007 1008 1009 BOOLEAN 1010 IsPdbFile ( 1011 IN CHAR8 *PdbFileName 1012 ) 1013 { 1014 UINTN Len; 1015 1016 if (PdbFileName == NULL) { 1017 return FALSE; 1018 } 1019 1020 Len = strlen (PdbFileName); 1021 if ((Len < 5)|| (PdbFileName[Len - 4] != '.')) { 1022 return FALSE; 1023 } 1024 1025 if ((PdbFileName[Len - 3] == 'P' || PdbFileName[Len - 3] == 'p') && 1026 (PdbFileName[Len - 2] == 'D' || PdbFileName[Len - 2] == 'd') && 1027 (PdbFileName[Len - 1] == 'B' || PdbFileName[Len - 1] == 'b')) { 1028 return TRUE; 1029 } 1030 1031 return FALSE; 1032 } 1033 1034 1035 #define MAX_SPRINT_BUFFER_SIZE 0x200 1036 1037 void 1038 PrintLoadAddress ( 1039 IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext 1040 ) 1041 { 1042 if (ImageContext->PdbPointer == NULL) { 1043 fprintf (stderr, 1044 "0x%08lx Loading NO DEBUG with entry point 0x%08lx\n", 1045 (unsigned long)(ImageContext->ImageAddress), 1046 (unsigned long)ImageContext->EntryPoint 1047 ); 1048 } else { 1049 fprintf (stderr, 1050 "0x%08lx Loading %s with entry point 0x%08lx\n", 1051 (unsigned long)(ImageContext->ImageAddress + ImageContext->SizeOfHeaders), 1052 ImageContext->PdbPointer, 1053 (unsigned long)ImageContext->EntryPoint 1054 ); 1055 } 1056 // Keep output synced up 1057 fflush (stderr); 1058 } 1059 1060 1061 /** 1062 Loads the image using dlopen so symbols will be automatically 1063 loaded by gdb. 1064 1065 @param ImageContext The PE/COFF image context 1066 1067 @retval TRUE - The image was successfully loaded 1068 @retval FALSE - The image was successfully loaded 1069 1070 **/ 1071 BOOLEAN 1072 DlLoadImage ( 1073 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext 1074 ) 1075 { 1076 1077 #ifdef __APPLE__ 1078 1079 return FALSE; 1080 1081 #else 1082 1083 void *Handle = NULL; 1084 void *Entry = NULL; 1085 1086 if (ImageContext->PdbPointer == NULL) { 1087 return FALSE; 1088 } 1089 1090 if (!IsPdbFile (ImageContext->PdbPointer)) { 1091 return FALSE; 1092 } 1093 1094 fprintf ( 1095 stderr, 1096 "Loading %s 0x%08lx - entry point 0x%08lx\n", 1097 ImageContext->PdbPointer, 1098 (unsigned long)ImageContext->ImageAddress, 1099 (unsigned long)ImageContext->EntryPoint 1100 ); 1101 1102 Handle = dlopen (ImageContext->PdbPointer, RTLD_NOW); 1103 if (Handle != NULL) { 1104 Entry = dlsym (Handle, "_ModuleEntryPoint"); 1105 AddHandle (ImageContext, Handle); 1106 } else { 1107 printf("%s\n", dlerror()); 1108 } 1109 1110 if (Entry != NULL) { 1111 ImageContext->EntryPoint = (UINTN)Entry; 1112 printf ("Change %s Entrypoint to :0x%08lx\n", ImageContext->PdbPointer, (unsigned long)Entry); 1113 return TRUE; 1114 } else { 1115 return FALSE; 1116 } 1117 1118 #endif 1119 } 1120 1121 1122 VOID 1123 SecGdbScriptBreak ( 1124 char *FileName, 1125 int FileNameLength, 1126 long unsigned int LoadAddress, 1127 int AddSymbolFlag 1128 ) 1129 { 1130 return; 1131 } 1132 1133 1134 /** 1135 Adds the image to a gdb script so it's symbols can be loaded. 1136 The AddFirmwareSymbolFile helper macro is used. 1137 1138 @param ImageContext The PE/COFF image context 1139 1140 **/ 1141 VOID 1142 GdbScriptAddImage ( 1143 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext 1144 ) 1145 { 1146 1147 PrintLoadAddress (ImageContext); 1148 1149 if (ImageContext->PdbPointer != NULL && !IsPdbFile (ImageContext->PdbPointer)) { 1150 FILE *GdbTempFile; 1151 if (FeaturePcdGet (PcdEmulatorLazyLoadSymbols)) { 1152 GdbTempFile = fopen (gGdbWorkingFileName, "a"); 1153 if (GdbTempFile != NULL) { 1154 long unsigned int SymbolsAddr = (long unsigned int)(ImageContext->ImageAddress + ImageContext->SizeOfHeaders); 1155 mScriptSymbolChangesCount++; 1156 fprintf ( 1157 GdbTempFile, 1158 "AddFirmwareSymbolFile 0x%x %s 0x%08lx\n", 1159 mScriptSymbolChangesCount, 1160 ImageContext->PdbPointer, 1161 SymbolsAddr 1162 ); 1163 fclose (GdbTempFile); 1164 // This is for the lldb breakpoint only 1165 SecGdbScriptBreak (ImageContext->PdbPointer, strlen (ImageContext->PdbPointer) + 1, (long unsigned int)(ImageContext->ImageAddress + ImageContext->SizeOfHeaders), 1); 1166 } else { 1167 ASSERT (FALSE); 1168 } 1169 } else { 1170 GdbTempFile = fopen (gGdbWorkingFileName, "w"); 1171 if (GdbTempFile != NULL) { 1172 fprintf ( 1173 GdbTempFile, 1174 "add-symbol-file %s 0x%08lx\n", 1175 ImageContext->PdbPointer, 1176 (long unsigned int)(ImageContext->ImageAddress + ImageContext->SizeOfHeaders) 1177 ); 1178 fclose (GdbTempFile); 1179 1180 // 1181 // Target for gdb breakpoint in a script that uses gGdbWorkingFileName to set a breakpoint. 1182 // Hey what can you say scripting in gdb is not that great.... 1183 // Also used for the lldb breakpoint script. The lldb breakpoint script does 1184 // not use the file, it uses the arguments. 1185 // 1186 SecGdbScriptBreak (ImageContext->PdbPointer, strlen (ImageContext->PdbPointer) + 1, (long unsigned int)(ImageContext->ImageAddress + ImageContext->SizeOfHeaders), 1); 1187 } else { 1188 ASSERT (FALSE); 1189 } 1190 } 1191 } 1192 } 1193 1194 1195 VOID 1196 EFIAPI 1197 SecPeCoffRelocateImageExtraAction ( 1198 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext 1199 ) 1200 { 1201 if (!DlLoadImage (ImageContext)) { 1202 GdbScriptAddImage (ImageContext); 1203 } 1204 } 1205 1206 1207 /** 1208 Adds the image to a gdb script so it's symbols can be unloaded. 1209 The RemoveFirmwareSymbolFile helper macro is used. 1210 1211 @param ImageContext The PE/COFF image context 1212 1213 **/ 1214 VOID 1215 GdbScriptRemoveImage ( 1216 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext 1217 ) 1218 { 1219 FILE *GdbTempFile; 1220 1221 // 1222 // Need to skip .PDB files created from VC++ 1223 // 1224 if (IsPdbFile (ImageContext->PdbPointer)) { 1225 return; 1226 } 1227 1228 if (FeaturePcdGet (PcdEmulatorLazyLoadSymbols)) { 1229 // 1230 // Write the file we need for the gdb script 1231 // 1232 GdbTempFile = fopen (gGdbWorkingFileName, "a"); 1233 if (GdbTempFile != NULL) { 1234 mScriptSymbolChangesCount++; 1235 fprintf ( 1236 GdbTempFile, 1237 "RemoveFirmwareSymbolFile 0x%x %s\n", 1238 mScriptSymbolChangesCount, 1239 ImageContext->PdbPointer 1240 ); 1241 fclose (GdbTempFile); 1242 SecGdbScriptBreak (ImageContext->PdbPointer, strlen (ImageContext->PdbPointer) + 1, 0, 0); 1243 } else { 1244 ASSERT (FALSE); 1245 } 1246 } else { 1247 GdbTempFile = fopen (gGdbWorkingFileName, "w"); 1248 if (GdbTempFile != NULL) { 1249 fprintf (GdbTempFile, "remove-symbol-file %s\n", ImageContext->PdbPointer); 1250 fclose (GdbTempFile); 1251 1252 // 1253 // Target for gdb breakpoint in a script that uses gGdbWorkingFileName to set a breakpoint. 1254 // Hey what can you say scripting in gdb is not that great.... 1255 // 1256 SecGdbScriptBreak (ImageContext->PdbPointer, strlen (ImageContext->PdbPointer) + 1, 0, 0); 1257 } else { 1258 ASSERT (FALSE); 1259 } 1260 } 1261 } 1262 1263 1264 VOID 1265 EFIAPI 1266 SecPeCoffUnloadImageExtraAction ( 1267 IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext 1268 ) 1269 { 1270 VOID *Handle; 1271 1272 // 1273 // Check to see if the image symbols were loaded with gdb script, or dlopen 1274 // 1275 Handle = RemoveHandle (ImageContext); 1276 if (Handle != NULL) { 1277 #ifndef __APPLE__ 1278 dlclose (Handle); 1279 #endif 1280 return; 1281 } 1282 1283 GdbScriptRemoveImage (ImageContext); 1284 } 1285 1286 1287