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