Home | History | Annotate | Download | only in Sec
      1 /**@file
      2 
      3 Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
      4 This program and the accompanying materials
      5 are licensed and made available under the terms and conditions of the BSD License
      6 which accompanies this distribution.  The full text of the license may be found at
      7 http://opensource.org/licenses/bsd-license.php
      8 
      9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     11 
     12 Module Name:
     13 
     14   SecMain.c
     15 
     16 Abstract:
     17   WinNt emulator of SEC phase. It's really a Win32 application, but this is
     18   Ok since all the other modules for NT32 are NOT Win32 applications.
     19 
     20   This program gets NT32 PCD setting and figures out what the memory layout
     21   will be, how may FD's will be loaded and also what the boot mode is.
     22 
     23   The SEC registers a set of services with the SEC core. gPrivateDispatchTable
     24   is a list of PPI's produced by the SEC that are availble for usage in PEI.
     25 
     26   This code produces 128 K of temporary memory for the PEI stack by directly
     27   allocate memory space with ReadWrite and Execute attribute.
     28 
     29 **/
     30 
     31 #include "SecMain.h"
     32 
     33 #ifndef SE_TIME_ZONE_NAME
     34 #define SE_TIME_ZONE_NAME                 TEXT("SeTimeZonePrivilege")
     35 #endif
     36 
     37 NT_PEI_LOAD_FILE_PPI                      mSecNtLoadFilePpi     = { SecWinNtPeiLoadFile };
     38 
     39 PEI_NT_AUTOSCAN_PPI                       mSecNtAutoScanPpi     = { SecWinNtPeiAutoScan };
     40 
     41 PEI_NT_THUNK_PPI                          mSecWinNtThunkPpi     = { SecWinNtWinNtThunkAddress };
     42 
     43 EFI_PEI_PROGRESS_CODE_PPI                 mSecStatusCodePpi     = { SecPeiReportStatusCode };
     44 
     45 NT_FWH_PPI                                mSecFwhInformationPpi = { SecWinNtFdAddress };
     46 
     47 EFI_PEI_TEMPORARY_RAM_SUPPORT_PPI         mSecTemporaryRamSupportPpi = {SecTemporaryRamSupport};
     48 
     49 EFI_PEI_PPI_DESCRIPTOR  gPrivateDispatchTable[] = {
     50   {
     51     EFI_PEI_PPI_DESCRIPTOR_PPI,
     52     &gNtPeiLoadFilePpiGuid,
     53     &mSecNtLoadFilePpi
     54   },
     55   {
     56     EFI_PEI_PPI_DESCRIPTOR_PPI,
     57     &gPeiNtAutoScanPpiGuid,
     58     &mSecNtAutoScanPpi
     59   },
     60   {
     61     EFI_PEI_PPI_DESCRIPTOR_PPI,
     62     &gPeiNtThunkPpiGuid,
     63     &mSecWinNtThunkPpi
     64   },
     65   {
     66     EFI_PEI_PPI_DESCRIPTOR_PPI,
     67     &gEfiPeiStatusCodePpiGuid,
     68     &mSecStatusCodePpi
     69   },
     70   {
     71     EFI_PEI_PPI_DESCRIPTOR_PPI,
     72     &gEfiTemporaryRamSupportPpiGuid,
     73     &mSecTemporaryRamSupportPpi
     74   },
     75   {
     76     EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
     77     &gNtFwhPpiGuid,
     78     &mSecFwhInformationPpi
     79   }
     80 };
     81 
     82 
     83 //
     84 // Default information about where the FD is located.
     85 //  This array gets filled in with information from PcdWinNtFirmwareVolume
     86 //  The number of array elements is allocated base on parsing
     87 //  PcdWinNtFirmwareVolume and the memory is never freed.
     88 //
     89 UINTN                                     gFdInfoCount = 0;
     90 NT_FD_INFO                                *gFdInfo;
     91 
     92 //
     93 // Array that supports seperate memory rantes.
     94 //  The memory ranges are set by PcdWinNtMemorySizeForSecMain.
     95 //  The number of array elements is allocated base on parsing
     96 //  PcdWinNtMemorySizeForSecMain value and the memory is never freed.
     97 //
     98 UINTN                                     gSystemMemoryCount = 0;
     99 NT_SYSTEM_MEMORY                          *gSystemMemory;
    100 
    101 VOID
    102 EFIAPI
    103 SecSwitchStack (
    104   UINT32   TemporaryMemoryBase,
    105   UINT32   PermenentMemoryBase
    106   );
    107 EFI_STATUS
    108 SecNt32PeCoffRelocateImage (
    109   IN OUT PE_COFF_LOADER_IMAGE_CONTEXT         *ImageContext
    110   );
    111 
    112 VOID
    113 EFIAPI
    114 PeiSwitchStacks (
    115   IN      SWITCH_STACK_ENTRY_POINT  EntryPoint,
    116   IN      VOID                      *Context1,  OPTIONAL
    117   IN      VOID                      *Context2,  OPTIONAL
    118   IN      VOID                      *Context3,  OPTIONAL
    119   IN      VOID                      *NewStack
    120   );
    121 
    122 VOID
    123 SecPrint (
    124   CHAR8  *Format,
    125   ...
    126   )
    127 {
    128   va_list  Marker;
    129   UINTN    CharCount;
    130   CHAR8    Buffer[EFI_STATUS_CODE_DATA_MAX_SIZE];
    131 
    132   va_start (Marker, Format);
    133 
    134   _vsnprintf (Buffer, sizeof (Buffer), Format, Marker);
    135 
    136   va_end (Marker);
    137 
    138   CharCount = strlen (Buffer);
    139   WriteFile (
    140     GetStdHandle (STD_OUTPUT_HANDLE),
    141     Buffer,
    142     (DWORD)CharCount,
    143     (LPDWORD)&CharCount,
    144     NULL
    145     );
    146 }
    147 
    148 INTN
    149 EFIAPI
    150 main (
    151   IN  INTN  Argc,
    152   IN  CHAR8 **Argv,
    153   IN  CHAR8 **Envp
    154   )
    155 /*++
    156 
    157 Routine Description:
    158   Main entry point to SEC for WinNt. This is a Windows program
    159 
    160 Arguments:
    161   Argc - Number of command line arguments
    162   Argv - Array of command line argument strings
    163   Envp - Array of environmemt variable strings
    164 
    165 Returns:
    166   0 - Normal exit
    167   1 - Abnormal exit
    168 
    169 --*/
    170 {
    171   EFI_STATUS            Status;
    172   HANDLE                Token;
    173   TOKEN_PRIVILEGES      TokenPrivileges;
    174   EFI_PHYSICAL_ADDRESS  InitialStackMemory;
    175   UINT64                InitialStackMemorySize;
    176   UINTN                 Index;
    177   UINTN                 Index1;
    178   UINTN                 Index2;
    179   CHAR16                *FileName;
    180   CHAR16                *FileNamePtr;
    181   BOOLEAN               Done;
    182   VOID                  *PeiCoreFile;
    183   CHAR16                *MemorySizeStr;
    184   CHAR16                *FirmwareVolumesStr;
    185   UINTN                 *StackPointer;
    186   UINT32                ProcessAffinityMask;
    187   UINT32                SystemAffinityMask;
    188   INT32                 LowBit;
    189 
    190 
    191   //
    192   // Enable the privilege so that RTC driver can successfully run SetTime()
    193   //
    194   OpenProcessToken (GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY, &Token);
    195   if (LookupPrivilegeValue(NULL, SE_TIME_ZONE_NAME, &TokenPrivileges.Privileges[0].Luid)) {
    196     TokenPrivileges.PrivilegeCount = 1;
    197     TokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
    198     AdjustTokenPrivileges(Token, FALSE, &TokenPrivileges, 0, (PTOKEN_PRIVILEGES) NULL, 0);
    199   }
    200 
    201   MemorySizeStr      = (CHAR16 *) PcdGetPtr (PcdWinNtMemorySizeForSecMain);
    202   FirmwareVolumesStr = (CHAR16 *) PcdGetPtr (PcdWinNtFirmwareVolume);
    203 
    204   SecPrint ("\nEDK II SEC Main NT Emulation Environment from www.TianoCore.org\n");
    205 
    206   //
    207   // Determine the first thread available to this process.
    208   //
    209   if (GetProcessAffinityMask (GetCurrentProcess (), &ProcessAffinityMask, &SystemAffinityMask)) {
    210     LowBit = (INT32)LowBitSet32 (ProcessAffinityMask);
    211     if (LowBit != -1) {
    212       //
    213       // Force the system to bind the process to a single thread to work
    214       // around odd semaphore type crashes.
    215       //
    216       SetProcessAffinityMask (GetCurrentProcess (), (INTN)(BIT0 << LowBit));
    217     }
    218   }
    219 
    220   //
    221   // Make some Windows calls to Set the process to the highest priority in the
    222   //  idle class. We need this to have good performance.
    223   //
    224   SetPriorityClass (GetCurrentProcess (), IDLE_PRIORITY_CLASS);
    225   SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_HIGHEST);
    226 
    227   //
    228   // Allocate space for gSystemMemory Array
    229   //
    230   gSystemMemoryCount  = CountSeperatorsInString (MemorySizeStr, '!') + 1;
    231   gSystemMemory       = calloc (gSystemMemoryCount, sizeof (NT_SYSTEM_MEMORY));
    232   if (gSystemMemory == NULL) {
    233     SecPrint ("ERROR : Can not allocate memory for %S.  Exiting.\n", MemorySizeStr);
    234     exit (1);
    235   }
    236   //
    237   // Allocate space for gSystemMemory Array
    238   //
    239   gFdInfoCount  = CountSeperatorsInString (FirmwareVolumesStr, '!') + 1;
    240   gFdInfo       = calloc (gFdInfoCount, sizeof (NT_FD_INFO));
    241   if (gFdInfo == NULL) {
    242     SecPrint ("ERROR : Can not allocate memory for %S.  Exiting.\n", FirmwareVolumesStr);
    243     exit (1);
    244   }
    245   //
    246   // Setup Boot Mode. If BootModeStr == "" then BootMode = 0 (BOOT_WITH_FULL_CONFIGURATION)
    247   //
    248   SecPrint ("  BootMode 0x%02x\n", PcdGet32 (PcdWinNtBootMode));
    249 
    250   //
    251   //  Allocate 128K memory to emulate temp memory for PEI.
    252   //  on a real platform this would be SRAM, or using the cache as RAM.
    253   //  Set InitialStackMemory to zero so WinNtOpenFile will allocate a new mapping
    254   //
    255   InitialStackMemorySize  = STACK_SIZE;
    256   InitialStackMemory = (EFI_PHYSICAL_ADDRESS) (UINTN) VirtualAlloc (NULL, (SIZE_T) (InitialStackMemorySize), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    257   if (InitialStackMemory == 0) {
    258     SecPrint ("ERROR : Can not allocate enough space for SecStack\n");
    259     exit (1);
    260   }
    261 
    262   for (StackPointer = (UINTN*) (UINTN) InitialStackMemory;
    263        StackPointer < (UINTN*) ((UINTN)InitialStackMemory + (SIZE_T) InitialStackMemorySize);
    264        StackPointer ++) {
    265     *StackPointer = 0x5AA55AA5;
    266   }
    267 
    268   SecPrint ("  SEC passing in %d bytes of temp RAM to PEI\n", InitialStackMemorySize);
    269 
    270   //
    271   // Open All the firmware volumes and remember the info in the gFdInfo global
    272   //
    273   FileNamePtr = (CHAR16 *)malloc (StrLen ((CHAR16 *)FirmwareVolumesStr) * sizeof(CHAR16));
    274   if (FileNamePtr == NULL) {
    275     SecPrint ("ERROR : Can not allocate memory for firmware volume string\n");
    276     exit (1);
    277   }
    278 
    279   StrCpy (FileNamePtr, (CHAR16*)FirmwareVolumesStr);
    280 
    281   for (Done = FALSE, Index = 0, PeiCoreFile = NULL; !Done; Index++) {
    282     FileName = FileNamePtr;
    283     for (Index1 = 0; (FileNamePtr[Index1] != '!') && (FileNamePtr[Index1] != 0); Index1++)
    284       ;
    285     if (FileNamePtr[Index1] == 0) {
    286       Done = TRUE;
    287     } else {
    288       FileNamePtr[Index1]  = '\0';
    289       FileNamePtr = FileNamePtr + Index1 + 1;
    290     }
    291 
    292     //
    293     // Open the FD and remmeber where it got mapped into our processes address space
    294     //
    295     Status = WinNtOpenFile (
    296               FileName,
    297               0,
    298               OPEN_EXISTING,
    299               &gFdInfo[Index].Address,
    300               &gFdInfo[Index].Size
    301               );
    302     if (EFI_ERROR (Status)) {
    303       SecPrint ("ERROR : Can not open Firmware Device File %S (0x%X).  Exiting.\n", FileName, Status);
    304       exit (1);
    305     }
    306 
    307     SecPrint ("  FD loaded from");
    308     //
    309     // printf can't print filenames directly as the \ gets interperted as an
    310     //  escape character.
    311     //
    312     for (Index2 = 0; FileName[Index2] != '\0'; Index2++) {
    313       SecPrint ("%c", FileName[Index2]);
    314     }
    315 
    316     if (PeiCoreFile == NULL) {
    317       //
    318       // Assume the beginning of the FD is an FV and look for the PEI Core.
    319       // Load the first one we find.
    320       //
    321       Status = SecFfsFindPeiCore ((EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) gFdInfo[Index].Address, &PeiCoreFile);
    322       if (!EFI_ERROR (Status)) {
    323         SecPrint (" contains SEC Core");
    324       }
    325     }
    326 
    327     SecPrint ("\n");
    328   }
    329   //
    330   // Calculate memory regions and store the information in the gSystemMemory
    331   //  global for later use. The autosizing code will use this data to
    332   //  map this memory into the SEC process memory space.
    333   //
    334   for (Index = 0, Done = FALSE; !Done; Index++) {
    335     //
    336     // Save the size of the memory and make a Unicode filename SystemMemory00, ...
    337     //
    338     gSystemMemory[Index].Size = _wtoi (MemorySizeStr) * 0x100000;
    339 
    340     //
    341     // Find the next region
    342     //
    343     for (Index1 = 0; MemorySizeStr[Index1] != '!' && MemorySizeStr[Index1] != 0; Index1++)
    344       ;
    345     if (MemorySizeStr[Index1] == 0) {
    346       Done = TRUE;
    347     }
    348 
    349     MemorySizeStr = MemorySizeStr + Index1 + 1;
    350   }
    351 
    352   SecPrint ("\n");
    353 
    354   //
    355   // Hand off to PEI Core
    356   //
    357   SecLoadFromCore ((UINTN) InitialStackMemory, (UINTN) InitialStackMemorySize, (UINTN) gFdInfo[0].Address, PeiCoreFile);
    358 
    359   //
    360   // If we get here, then the PEI Core returned. This is an error as PEI should
    361   //  always hand off to DXE.
    362   //
    363   SecPrint ("ERROR : PEI Core returned\n");
    364   exit (1);
    365 }
    366 
    367 EFI_STATUS
    368 WinNtOpenFile (
    369   IN  CHAR16                    *FileName,
    370   IN  UINT32                    MapSize,
    371   IN  DWORD                     CreationDisposition,
    372   IN OUT  EFI_PHYSICAL_ADDRESS  *BaseAddress,
    373   OUT UINT64                    *Length
    374   )
    375 /*++
    376 
    377 Routine Description:
    378   Opens and memory maps a file using WinNt services. If BaseAddress is non zero
    379   the process will try and allocate the memory starting at BaseAddress.
    380 
    381 Arguments:
    382   FileName            - The name of the file to open and map
    383   MapSize             - The amount of the file to map in bytes
    384   CreationDisposition - The flags to pass to CreateFile().  Use to create new files for
    385                         memory emulation, and exiting files for firmware volume emulation
    386   BaseAddress         - The base address of the mapped file in the user address space.
    387                          If passed in as NULL the a new memory region is used.
    388                          If passed in as non NULL the request memory region is used for
    389                           the mapping of the file into the process space.
    390   Length              - The size of the mapped region in bytes
    391 
    392 Returns:
    393   EFI_SUCCESS      - The file was opened and mapped.
    394   EFI_NOT_FOUND    - FileName was not found in the current directory
    395   EFI_DEVICE_ERROR - An error occured attempting to map the opened file
    396 
    397 --*/
    398 {
    399   HANDLE  NtFileHandle;
    400   HANDLE  NtMapHandle;
    401   VOID    *VirtualAddress;
    402   UINTN   FileSize;
    403 
    404   //
    405   // Use Win API to open/create a file
    406   //
    407   NtFileHandle = CreateFile (
    408                   FileName,
    409                   GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE,
    410                   FILE_SHARE_READ,
    411                   NULL,
    412                   CreationDisposition,
    413                   FILE_ATTRIBUTE_NORMAL,
    414                   NULL
    415                   );
    416   if (NtFileHandle == INVALID_HANDLE_VALUE) {
    417     return EFI_NOT_FOUND;
    418   }
    419   //
    420   // Map the open file into a memory range
    421   //
    422   NtMapHandle = CreateFileMapping (
    423                   NtFileHandle,
    424                   NULL,
    425                   PAGE_EXECUTE_READWRITE,
    426                   0,
    427                   MapSize,
    428                   NULL
    429                   );
    430   if (NtMapHandle == NULL) {
    431     return EFI_DEVICE_ERROR;
    432   }
    433   //
    434   // Get the virtual address (address in the emulator) of the mapped file
    435   //
    436   VirtualAddress = MapViewOfFileEx (
    437                     NtMapHandle,
    438                     FILE_MAP_EXECUTE | FILE_MAP_ALL_ACCESS,
    439                     0,
    440                     0,
    441                     MapSize,
    442                     (LPVOID) (UINTN) *BaseAddress
    443                     );
    444   if (VirtualAddress == NULL) {
    445     return EFI_DEVICE_ERROR;
    446   }
    447 
    448   if (MapSize == 0) {
    449     //
    450     // Seek to the end of the file to figure out the true file size.
    451     //
    452     FileSize = SetFilePointer (
    453                 NtFileHandle,
    454                 0,
    455                 NULL,
    456                 FILE_END
    457                 );
    458     if (FileSize == -1) {
    459       return EFI_DEVICE_ERROR;
    460     }
    461 
    462     *Length = (UINT64) FileSize;
    463   } else {
    464     *Length = (UINT64) MapSize;
    465   }
    466 
    467   *BaseAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) VirtualAddress;
    468 
    469   return EFI_SUCCESS;
    470 }
    471 
    472 
    473 #define BYTES_PER_RECORD  512
    474 
    475 EFI_STATUS
    476 EFIAPI
    477 SecPeiReportStatusCode (
    478   IN CONST EFI_PEI_SERVICES           **PeiServices,
    479   IN EFI_STATUS_CODE_TYPE       CodeType,
    480   IN EFI_STATUS_CODE_VALUE      Value,
    481   IN UINT32                     Instance,
    482   IN CONST EFI_GUID                   *CallerId,
    483   IN CONST EFI_STATUS_CODE_DATA       *Data OPTIONAL
    484   )
    485 /*++
    486 
    487 Routine Description:
    488 
    489   This routine produces the ReportStatusCode PEI service. It's passed
    490   up to the PEI Core via a PPI. T
    491 
    492   This code currently uses the NT clib printf. This does not work the same way
    493   as the EFI Print (), as %t, %g, %s as Unicode are not supported.
    494 
    495 Arguments:
    496   (see EFI_PEI_REPORT_STATUS_CODE)
    497 
    498 Returns:
    499   EFI_SUCCESS - Always return success
    500 
    501 --*/
    502 // TODO:    PeiServices - add argument and description to function comment
    503 // TODO:    CodeType - add argument and description to function comment
    504 // TODO:    Value - add argument and description to function comment
    505 // TODO:    Instance - add argument and description to function comment
    506 // TODO:    CallerId - add argument and description to function comment
    507 // TODO:    Data - add argument and description to function comment
    508 {
    509   CHAR8           *Format;
    510   BASE_LIST       Marker;
    511   CHAR8           PrintBuffer[BYTES_PER_RECORD * 2];
    512   CHAR8           *Filename;
    513   CHAR8           *Description;
    514   UINT32          LineNumber;
    515   UINT32          ErrorLevel;
    516 
    517 
    518   if (Data == NULL) {
    519   } else if (ReportStatusCodeExtractAssertInfo (CodeType, Value, Data, &Filename, &Description, &LineNumber)) {
    520     //
    521     // Processes ASSERT ()
    522     //
    523     SecPrint ("ASSERT %s(%d): %s\n", Filename, (int)LineNumber, Description);
    524 
    525   } else if (ReportStatusCodeExtractDebugInfo (Data, &ErrorLevel, &Marker, &Format)) {
    526     //
    527     // Process DEBUG () macro
    528     //
    529     AsciiBSPrint (PrintBuffer, BYTES_PER_RECORD, Format, Marker);
    530     SecPrint (PrintBuffer);
    531   }
    532 
    533   return EFI_SUCCESS;
    534 }
    535 
    536 #if defined (MDE_CPU_IA32)
    537 /**
    538   Transfers control to a function starting with a new stack.
    539 
    540   Transfers control to the function specified by EntryPoint using the new stack
    541   specified by NewStack and passing in the parameters specified by Context1 and
    542   Context2. Context1 and Context2 are optional and may be NULL. The function
    543   EntryPoint must never return.
    544 
    545   If EntryPoint is NULL, then ASSERT().
    546   If NewStack is NULL, then ASSERT().
    547 
    548   @param  EntryPoint  A pointer to function to call with the new stack.
    549   @param  Context1    A pointer to the context to pass into the EntryPoint
    550                       function.
    551   @param  Context2    A pointer to the context to pass into the EntryPoint
    552                       function.
    553   @param  NewStack    A pointer to the new stack to use for the EntryPoint
    554                       function.
    555   @param  NewBsp      A pointer to the new BSP for the EntryPoint on IPF. It's
    556                       Reserved on other architectures.
    557 
    558 **/
    559 VOID
    560 EFIAPI
    561 PeiSwitchStacks (
    562   IN      SWITCH_STACK_ENTRY_POINT  EntryPoint,
    563   IN      VOID                      *Context1,  OPTIONAL
    564   IN      VOID                      *Context2,  OPTIONAL
    565   IN      VOID                      *Context3,  OPTIONAL
    566   IN      VOID                      *NewStack
    567   )
    568 {
    569   BASE_LIBRARY_JUMP_BUFFER  JumpBuffer;
    570 
    571   ASSERT (EntryPoint != NULL);
    572   ASSERT (NewStack != NULL);
    573 
    574   //
    575   // Stack should be aligned with CPU_STACK_ALIGNMENT
    576   //
    577   ASSERT (((UINTN)NewStack & (CPU_STACK_ALIGNMENT - 1)) == 0);
    578 
    579   JumpBuffer.Eip = (UINTN)EntryPoint;
    580   JumpBuffer.Esp = (UINTN)NewStack - sizeof (VOID*);
    581   JumpBuffer.Esp -= sizeof (Context1) + sizeof (Context2) + sizeof(Context3);
    582   ((VOID**)JumpBuffer.Esp)[1] = Context1;
    583   ((VOID**)JumpBuffer.Esp)[2] = Context2;
    584   ((VOID**)JumpBuffer.Esp)[3] = Context3;
    585 
    586   LongJump (&JumpBuffer, (UINTN)-1);
    587 
    588 
    589   //
    590   // InternalSwitchStack () will never return
    591   //
    592   ASSERT (FALSE);
    593 }
    594 #endif
    595 
    596 VOID
    597 SecLoadFromCore (
    598   IN  UINTN   LargestRegion,
    599   IN  UINTN   LargestRegionSize,
    600   IN  UINTN   BootFirmwareVolumeBase,
    601   IN  VOID    *PeiCorePe32File
    602   )
    603 /*++
    604 
    605 Routine Description:
    606   This is the service to load the PEI Core from the Firmware Volume
    607 
    608 Arguments:
    609   LargestRegion           - Memory to use for PEI.
    610   LargestRegionSize       - Size of Memory to use for PEI
    611   BootFirmwareVolumeBase  - Start of the Boot FV
    612   PeiCorePe32File         - PEI Core PE32
    613 
    614 Returns:
    615   Success means control is transfered and thus we should never return
    616 
    617 --*/
    618 {
    619   EFI_STATUS                  Status;
    620   VOID                        *TopOfStack;
    621   UINT64                      PeiCoreSize;
    622   EFI_PHYSICAL_ADDRESS        PeiCoreEntryPoint;
    623   EFI_PHYSICAL_ADDRESS        PeiImageAddress;
    624   EFI_SEC_PEI_HAND_OFF        *SecCoreData;
    625   UINTN                       PeiStackSize;
    626 
    627   //
    628   // Compute Top Of Memory for Stack and PEI Core Allocations
    629   //
    630   PeiStackSize = (UINTN)RShiftU64((UINT64)STACK_SIZE,1);
    631 
    632   //
    633   // |-----------| <---- TemporaryRamBase + TemporaryRamSize
    634   // |   Heap    |
    635   // |           |
    636   // |-----------| <---- StackBase / PeiTemporaryMemoryBase
    637   // |           |
    638   // |  Stack    |
    639   // |-----------| <---- TemporaryRamBase
    640   //
    641   TopOfStack  = (VOID *)(LargestRegion + PeiStackSize);
    642 
    643   //
    644   // Reservet space for storing PeiCore's parament in stack.
    645   //
    646   TopOfStack  = (VOID *)((UINTN)TopOfStack - sizeof (EFI_SEC_PEI_HAND_OFF) - CPU_STACK_ALIGNMENT);
    647   TopOfStack  = ALIGN_POINTER (TopOfStack, CPU_STACK_ALIGNMENT);
    648 
    649   //
    650   // Bind this information into the SEC hand-off state
    651   //
    652   SecCoreData                        = (EFI_SEC_PEI_HAND_OFF*)(UINTN) TopOfStack;
    653   SecCoreData->DataSize               = sizeof(EFI_SEC_PEI_HAND_OFF);
    654   SecCoreData->BootFirmwareVolumeBase = (VOID*)BootFirmwareVolumeBase;
    655   SecCoreData->BootFirmwareVolumeSize = PcdGet32(PcdWinNtFirmwareFdSize);
    656   SecCoreData->TemporaryRamBase       = (VOID*)(UINTN)LargestRegion;
    657   SecCoreData->TemporaryRamSize       = STACK_SIZE;
    658   SecCoreData->StackBase              = SecCoreData->TemporaryRamBase;
    659   SecCoreData->StackSize              = PeiStackSize;
    660   SecCoreData->PeiTemporaryRamBase    = (VOID*) ((UINTN) SecCoreData->TemporaryRamBase + PeiStackSize);
    661   SecCoreData->PeiTemporaryRamSize    = STACK_SIZE - PeiStackSize;
    662 
    663   //
    664   // Load the PEI Core from a Firmware Volume
    665   //
    666   Status = SecWinNtPeiLoadFile (
    667             PeiCorePe32File,
    668             &PeiImageAddress,
    669             &PeiCoreSize,
    670             &PeiCoreEntryPoint
    671             );
    672   if (EFI_ERROR (Status)) {
    673     return ;
    674   }
    675 
    676   //
    677   // Transfer control to the PEI Core
    678   //
    679   PeiSwitchStacks (
    680     (SWITCH_STACK_ENTRY_POINT) (UINTN) PeiCoreEntryPoint,
    681     SecCoreData,
    682     (VOID *) (UINTN) ((EFI_PEI_PPI_DESCRIPTOR *) &gPrivateDispatchTable),
    683     NULL,
    684     TopOfStack
    685     );
    686   //
    687   // If we get here, then the PEI Core returned.  This is an error
    688   //
    689   return ;
    690 }
    691 
    692 EFI_STATUS
    693 EFIAPI
    694 SecWinNtPeiAutoScan (
    695   IN  UINTN                 Index,
    696   OUT EFI_PHYSICAL_ADDRESS  *MemoryBase,
    697   OUT UINT64                *MemorySize
    698   )
    699 /*++
    700 
    701 Routine Description:
    702   This service is called from Index == 0 until it returns EFI_UNSUPPORTED.
    703   It allows discontiguous memory regions to be supported by the emulator.
    704   It uses gSystemMemory[] and gSystemMemoryCount that were created by
    705   parsing PcdWinNtMemorySizeForSecMain value.
    706   The size comes from the Pcd value and the address comes from the memory space
    707   with ReadWrite and Execute attributes allocated by VirtualAlloc() API.
    708 
    709 Arguments:
    710   Index      - Which memory region to use
    711   MemoryBase - Return Base address of memory region
    712   MemorySize - Return size in bytes of the memory region
    713 
    714 Returns:
    715   EFI_SUCCESS - If memory region was mapped
    716   EFI_UNSUPPORTED - If Index is not supported
    717 
    718 --*/
    719 {
    720   if (Index >= gSystemMemoryCount) {
    721     return EFI_UNSUPPORTED;
    722   }
    723 
    724   //
    725   // Allocate enough memory space for emulator
    726   //
    727   gSystemMemory[Index].Memory = (EFI_PHYSICAL_ADDRESS) (UINTN) VirtualAlloc (NULL, (SIZE_T) (gSystemMemory[Index].Size), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    728   if (gSystemMemory[Index].Memory == 0) {
    729     return EFI_OUT_OF_RESOURCES;
    730   }
    731 
    732   *MemoryBase = gSystemMemory[Index].Memory;
    733   *MemorySize = gSystemMemory[Index].Size;
    734 
    735   return EFI_SUCCESS;
    736 }
    737 
    738 VOID *
    739 EFIAPI
    740 SecWinNtWinNtThunkAddress (
    741   VOID
    742   )
    743 /*++
    744 
    745 Routine Description:
    746   Since the SEC is the only Windows program in stack it must export
    747   an interface to do Win API calls. That's what the WinNtThunk address
    748   is for. gWinNt is initailized in WinNtThunk.c.
    749 
    750 Arguments:
    751   InterfaceSize - sizeof (EFI_WIN_NT_THUNK_PROTOCOL);
    752   InterfaceBase - Address of the gWinNt global
    753 
    754 Returns:
    755   EFI_SUCCESS - Data returned
    756 
    757 --*/
    758 {
    759   return gWinNt;
    760 }
    761 
    762 
    763 EFI_STATUS
    764 EFIAPI
    765 SecWinNtPeiLoadFile (
    766   IN  VOID                    *Pe32Data,
    767   IN  EFI_PHYSICAL_ADDRESS    *ImageAddress,
    768   IN  UINT64                  *ImageSize,
    769   IN  EFI_PHYSICAL_ADDRESS    *EntryPoint
    770   )
    771 /*++
    772 
    773 Routine Description:
    774   Loads and relocates a PE/COFF image into memory.
    775 
    776 Arguments:
    777   Pe32Data         - The base address of the PE/COFF file that is to be loaded and relocated
    778   ImageAddress     - The base address of the relocated PE/COFF image
    779   ImageSize        - The size of the relocated PE/COFF image
    780   EntryPoint       - The entry point of the relocated PE/COFF image
    781 
    782 Returns:
    783   EFI_SUCCESS   - The file was loaded and relocated
    784   EFI_OUT_OF_RESOURCES - There was not enough memory to load and relocate the PE/COFF file
    785 
    786 --*/
    787 {
    788   EFI_STATUS                            Status;
    789   PE_COFF_LOADER_IMAGE_CONTEXT          ImageContext;
    790 
    791   ZeroMem (&ImageContext, sizeof (ImageContext));
    792   ImageContext.Handle     = Pe32Data;
    793 
    794   ImageContext.ImageRead  = (PE_COFF_LOADER_READ_FILE) SecImageRead;
    795 
    796   Status                  = PeCoffLoaderGetImageInfo (&ImageContext);
    797   if (EFI_ERROR (Status)) {
    798     return Status;
    799   }
    800   //
    801   // Allocate space in NT (not emulator) memory with ReadWrite and Execute attribue.
    802   // Extra space is for alignment
    803   //
    804   ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) VirtualAlloc (NULL, (SIZE_T) (ImageContext.ImageSize + (ImageContext.SectionAlignment * 2)), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    805   if (ImageContext.ImageAddress == 0) {
    806     return EFI_OUT_OF_RESOURCES;
    807   }
    808   //
    809   // Align buffer on section boundry
    810   //
    811   ImageContext.ImageAddress += ImageContext.SectionAlignment - 1;
    812   ImageContext.ImageAddress &= ~(ImageContext.SectionAlignment - 1);
    813 
    814   Status = PeCoffLoaderLoadImage (&ImageContext);
    815   if (EFI_ERROR (Status)) {
    816     return Status;
    817   }
    818 
    819   Status = SecNt32PeCoffRelocateImage (&ImageContext);
    820   if (EFI_ERROR (Status)) {
    821     return Status;
    822   }
    823 
    824   //
    825   // BugBug: Flush Instruction Cache Here when CPU Lib is ready
    826   //
    827 
    828   *ImageAddress = ImageContext.ImageAddress;
    829   *ImageSize    = ImageContext.ImageSize;
    830   *EntryPoint   = ImageContext.EntryPoint;
    831 
    832   return EFI_SUCCESS;
    833 }
    834 
    835 EFI_STATUS
    836 EFIAPI
    837 SecWinNtFdAddress (
    838   IN     UINTN                 Index,
    839   IN OUT EFI_PHYSICAL_ADDRESS  *FdBase,
    840   IN OUT UINT64                *FdSize
    841   )
    842 /*++
    843 
    844 Routine Description:
    845   Return the FD Size and base address. Since the FD is loaded from a
    846   file into Windows memory only the SEC will know it's address.
    847 
    848 Arguments:
    849   Index  - Which FD, starts at zero.
    850   FdSize - Size of the FD in bytes
    851   FdBase - Start address of the FD. Assume it points to an FV Header
    852 
    853 Returns:
    854   EFI_SUCCESS     - Return the Base address and size of the FV
    855   EFI_UNSUPPORTED - Index does nto map to an FD in the system
    856 
    857 --*/
    858 {
    859   if (Index >= gFdInfoCount) {
    860     return EFI_UNSUPPORTED;
    861   }
    862 
    863   *FdBase = gFdInfo[Index].Address;
    864   *FdSize = gFdInfo[Index].Size;
    865 
    866   if (*FdBase == 0 && *FdSize == 0) {
    867     return EFI_UNSUPPORTED;
    868   }
    869 
    870   return EFI_SUCCESS;
    871 }
    872 
    873 EFI_STATUS
    874 EFIAPI
    875 SecImageRead (
    876   IN     VOID    *FileHandle,
    877   IN     UINTN   FileOffset,
    878   IN OUT UINTN   *ReadSize,
    879   OUT    VOID    *Buffer
    880   )
    881 /*++
    882 
    883 Routine Description:
    884   Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file
    885 
    886 Arguments:
    887   FileHandle - The handle to the PE/COFF file
    888   FileOffset - The offset, in bytes, into the file to read
    889   ReadSize   - The number of bytes to read from the file starting at FileOffset
    890   Buffer     - A pointer to the buffer to read the data into.
    891 
    892 Returns:
    893   EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset
    894 
    895 --*/
    896 {
    897   CHAR8 *Destination8;
    898   CHAR8 *Source8;
    899   UINTN Length;
    900 
    901   Destination8  = Buffer;
    902   Source8       = (CHAR8 *) ((UINTN) FileHandle + FileOffset);
    903   Length        = *ReadSize;
    904   while (Length--) {
    905     *(Destination8++) = *(Source8++);
    906   }
    907 
    908   return EFI_SUCCESS;
    909 }
    910 
    911 CHAR16 *
    912 AsciiToUnicode (
    913   IN  CHAR8   *Ascii,
    914   IN  UINTN   *StrLen OPTIONAL
    915   )
    916 /*++
    917 
    918 Routine Description:
    919   Convert the passed in Ascii string to Unicode.
    920   Optionally return the length of the strings.
    921 
    922 Arguments:
    923   Ascii   - Ascii string to convert
    924   StrLen  - Length of string
    925 
    926 Returns:
    927   Pointer to malloc'ed Unicode version of Ascii
    928 
    929 --*/
    930 {
    931   UINTN   Index;
    932   CHAR16  *Unicode;
    933 
    934   //
    935   // Allocate a buffer for unicode string
    936   //
    937   for (Index = 0; Ascii[Index] != '\0'; Index++)
    938     ;
    939   Unicode = malloc ((Index + 1) * sizeof (CHAR16));
    940   if (Unicode == NULL) {
    941     return NULL;
    942   }
    943 
    944   for (Index = 0; Ascii[Index] != '\0'; Index++) {
    945     Unicode[Index] = (CHAR16) Ascii[Index];
    946   }
    947 
    948   Unicode[Index] = '\0';
    949 
    950   if (StrLen != NULL) {
    951     *StrLen = Index;
    952   }
    953 
    954   return Unicode;
    955 }
    956 
    957 UINTN
    958 CountSeperatorsInString (
    959   IN  CONST CHAR16   *String,
    960   IN  CHAR16         Seperator
    961   )
    962 /*++
    963 
    964 Routine Description:
    965   Count the number of seperators in String
    966 
    967 Arguments:
    968   String    - String to process
    969   Seperator - Item to count
    970 
    971 Returns:
    972   Number of Seperator in String
    973 
    974 --*/
    975 {
    976   UINTN Count;
    977 
    978   for (Count = 0; *String != '\0'; String++) {
    979     if (*String == Seperator) {
    980       Count++;
    981     }
    982   }
    983 
    984   return Count;
    985 }
    986 
    987 
    988 EFI_STATUS
    989 SecNt32PeCoffRelocateImage (
    990   IN OUT PE_COFF_LOADER_IMAGE_CONTEXT         *ImageContext
    991   )
    992 {
    993   EFI_STATUS        Status;
    994   VOID              *DllEntryPoint;
    995   CHAR16            *DllFileName;
    996   HMODULE           Library;
    997   UINTN             Index;
    998 
    999 
   1000   Status = PeCoffLoaderRelocateImage (ImageContext);
   1001   if (EFI_ERROR (Status)) {
   1002     //
   1003     // We could not relocated the image in memory properly
   1004     //
   1005     return Status;
   1006   }
   1007 
   1008   //
   1009   // If we load our own PE COFF images the Windows debugger can not source
   1010   //  level debug our code. If a valid PDB pointer exists usw it to load
   1011   //  the *.dll file as a library using Windows* APIs. This allows
   1012   //  source level debug. The image is still loaded and reloaced
   1013   //  in the Framework memory space like on a real system (by the code above),
   1014   //  but the entry point points into the DLL loaded by the code bellow.
   1015   //
   1016 
   1017   DllEntryPoint = NULL;
   1018 
   1019   //
   1020   // Load the DLL if it's not an EBC image.
   1021   //
   1022   if ((ImageContext->PdbPointer != NULL) &&
   1023       (ImageContext->Machine != EFI_IMAGE_MACHINE_EBC)) {
   1024     //
   1025     // Convert filename from ASCII to Unicode
   1026     //
   1027     DllFileName = AsciiToUnicode (ImageContext->PdbPointer, &Index);
   1028 
   1029     //
   1030     // Check that we have a valid filename
   1031     //
   1032     if (Index < 5 || DllFileName[Index - 4] != '.') {
   1033       free (DllFileName);
   1034 
   1035       //
   1036       // Never return an error if PeCoffLoaderRelocateImage() succeeded.
   1037       // The image will run, but we just can't source level debug. If we
   1038       // return an error the image will not run.
   1039       //
   1040       return EFI_SUCCESS;
   1041     }
   1042     //
   1043     // Replace .PDB with .DLL on the filename
   1044     //
   1045     DllFileName[Index - 3]  = 'D';
   1046     DllFileName[Index - 2]  = 'L';
   1047     DllFileName[Index - 1]  = 'L';
   1048 
   1049     //
   1050     // Load the .DLL file into the user process's address space for source
   1051     // level debug
   1052     //
   1053     Library = LoadLibraryEx (DllFileName, NULL, DONT_RESOLVE_DLL_REFERENCES);
   1054     if (Library != NULL) {
   1055       //
   1056       // InitializeDriver is the entry point we put in all our EFI DLL's. The
   1057       // DONT_RESOLVE_DLL_REFERENCES argument to LoadLIbraryEx() supresses the
   1058       // normal DLL entry point of DllMain, and prevents other modules that are
   1059       // referenced in side the DllFileName from being loaded. There is no error
   1060       // checking as the we can point to the PE32 image loaded by Tiano. This
   1061       // step is only needed for source level debuging
   1062       //
   1063       DllEntryPoint = (VOID *) (UINTN) GetProcAddress (Library, "InitializeDriver");
   1064 
   1065     }
   1066 
   1067     if ((Library != NULL) && (DllEntryPoint != NULL)) {
   1068       ImageContext->EntryPoint  = (EFI_PHYSICAL_ADDRESS) (UINTN) DllEntryPoint;
   1069       SecPrint ("LoadLibraryEx (%S,\n               NULL, DONT_RESOLVE_DLL_REFERENCES)\n", DllFileName);
   1070     } else {
   1071       SecPrint ("WARNING: No source level debug %S. \n", DllFileName);
   1072     }
   1073 
   1074     free (DllFileName);
   1075   }
   1076 
   1077   //
   1078   // Never return an error if PeCoffLoaderRelocateImage() succeeded.
   1079   // The image will run, but we just can't source level debug. If we
   1080   // return an error the image will not run.
   1081   //
   1082   return EFI_SUCCESS;
   1083 }
   1084 
   1085 
   1086 
   1087 
   1088 VOID
   1089 _ModuleEntryPoint (
   1090   VOID
   1091   )
   1092 {
   1093 }
   1094 
   1095 EFI_STATUS
   1096 EFIAPI
   1097 SecTemporaryRamSupport (
   1098   IN CONST EFI_PEI_SERVICES   **PeiServices,
   1099   IN EFI_PHYSICAL_ADDRESS     TemporaryMemoryBase,
   1100   IN EFI_PHYSICAL_ADDRESS     PermanentMemoryBase,
   1101   IN UINTN                    CopySize
   1102   )
   1103 {
   1104   //
   1105   // Migrate the whole temporary memory to permenent memory.
   1106   //
   1107   CopyMem (
   1108     (VOID*)(UINTN)PermanentMemoryBase,
   1109     (VOID*)(UINTN)TemporaryMemoryBase,
   1110     CopySize
   1111     );
   1112 
   1113   //
   1114   // SecSwitchStack function must be invoked after the memory migration
   1115   // immediatly, also we need fixup the stack change caused by new call into
   1116   // permenent memory.
   1117   //
   1118   SecSwitchStack (
   1119     (UINT32) TemporaryMemoryBase,
   1120     (UINT32) PermanentMemoryBase
   1121     );
   1122 
   1123   //
   1124   // We need *not* fix the return address because currently,
   1125   // The PeiCore is excuted in flash.
   1126   //
   1127 
   1128   //
   1129   // Simulate to invalid temporary memory, terminate temporary memory
   1130   //
   1131   //ZeroMem ((VOID*)(UINTN)TemporaryMemoryBase, CopySize);
   1132 
   1133   return EFI_SUCCESS;
   1134 }
   1135 
   1136