Home | History | Annotate | Download | only in Sec
      1 /** @file
      2   Main SEC phase code.  Transitions to PEI.
      3 
      4   Copyright (c) 2008 - 2015, Intel Corporation. All rights reserved.<BR>
      5   (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
      6 
      7   This program and the accompanying materials
      8   are licensed and made available under the terms and conditions of the BSD License
      9   which accompanies this distribution.  The full text of the license may be found at
     10   http://opensource.org/licenses/bsd-license.php
     11 
     12   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     13   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     14 
     15 **/
     16 
     17 #include <PiPei.h>
     18 
     19 #include <Library/PeimEntryPoint.h>
     20 #include <Library/BaseLib.h>
     21 #include <Library/DebugLib.h>
     22 #include <Library/BaseMemoryLib.h>
     23 #include <Library/PeiServicesLib.h>
     24 #include <Library/PcdLib.h>
     25 #include <Library/UefiCpuLib.h>
     26 #include <Library/DebugAgentLib.h>
     27 #include <Library/IoLib.h>
     28 #include <Library/PeCoffLib.h>
     29 #include <Library/PeCoffGetEntryPointLib.h>
     30 #include <Library/PeCoffExtraActionLib.h>
     31 #include <Library/ExtractGuidedSectionLib.h>
     32 #include <Library/LocalApicLib.h>
     33 
     34 #include <Ppi/TemporaryRamSupport.h>
     35 
     36 #define SEC_IDT_ENTRY_COUNT  34
     37 
     38 typedef struct _SEC_IDT_TABLE {
     39   EFI_PEI_SERVICES          *PeiService;
     40   IA32_IDT_GATE_DESCRIPTOR  IdtTable[SEC_IDT_ENTRY_COUNT];
     41 } SEC_IDT_TABLE;
     42 
     43 VOID
     44 EFIAPI
     45 SecStartupPhase2 (
     46   IN VOID                     *Context
     47   );
     48 
     49 EFI_STATUS
     50 EFIAPI
     51 TemporaryRamMigration (
     52   IN CONST EFI_PEI_SERVICES   **PeiServices,
     53   IN EFI_PHYSICAL_ADDRESS     TemporaryMemoryBase,
     54   IN EFI_PHYSICAL_ADDRESS     PermanentMemoryBase,
     55   IN UINTN                    CopySize
     56   );
     57 
     58 //
     59 //
     60 //
     61 EFI_PEI_TEMPORARY_RAM_SUPPORT_PPI mTemporaryRamSupportPpi = {
     62   TemporaryRamMigration
     63 };
     64 
     65 EFI_PEI_PPI_DESCRIPTOR mPrivateDispatchTable[] = {
     66   {
     67     (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
     68     &gEfiTemporaryRamSupportPpiGuid,
     69     &mTemporaryRamSupportPpi
     70   },
     71 };
     72 
     73 //
     74 // Template of an IDT entry pointing to 10:FFFFFFE4h.
     75 //
     76 IA32_IDT_GATE_DESCRIPTOR  mIdtEntryTemplate = {
     77   {                                      // Bits
     78     0xffe4,                              // OffsetLow
     79     0x10,                                // Selector
     80     0x0,                                 // Reserved_0
     81     IA32_IDT_GATE_TYPE_INTERRUPT_32,     // GateType
     82     0xffff                               // OffsetHigh
     83   }
     84 };
     85 
     86 /**
     87   Locates the main boot firmware volume.
     88 
     89   @param[in,out]  BootFv  On input, the base of the BootFv
     90                           On output, the decompressed main firmware volume
     91 
     92   @retval EFI_SUCCESS    The main firmware volume was located and decompressed
     93   @retval EFI_NOT_FOUND  The main firmware volume was not found
     94 
     95 **/
     96 EFI_STATUS
     97 FindMainFv (
     98   IN OUT  EFI_FIRMWARE_VOLUME_HEADER   **BootFv
     99   )
    100 {
    101   EFI_FIRMWARE_VOLUME_HEADER  *Fv;
    102   UINTN                       Distance;
    103 
    104   ASSERT (((UINTN) *BootFv & EFI_PAGE_MASK) == 0);
    105 
    106   Fv = *BootFv;
    107   Distance = (UINTN) (*BootFv)->FvLength;
    108   do {
    109     Fv = (EFI_FIRMWARE_VOLUME_HEADER*) ((UINT8*) Fv - EFI_PAGE_SIZE);
    110     Distance += EFI_PAGE_SIZE;
    111     if (Distance > SIZE_32MB) {
    112       return EFI_NOT_FOUND;
    113     }
    114 
    115     if (Fv->Signature != EFI_FVH_SIGNATURE) {
    116       continue;
    117     }
    118 
    119     if ((UINTN) Fv->FvLength > Distance) {
    120       continue;
    121     }
    122 
    123     *BootFv = Fv;
    124     return EFI_SUCCESS;
    125 
    126   } while (TRUE);
    127 }
    128 
    129 /**
    130   Locates a section within a series of sections
    131   with the specified section type.
    132 
    133   The Instance parameter indicates which instance of the section
    134   type to return. (0 is first instance, 1 is second...)
    135 
    136   @param[in]   Sections        The sections to search
    137   @param[in]   SizeOfSections  Total size of all sections
    138   @param[in]   SectionType     The section type to locate
    139   @param[in]   Instance        The section instance number
    140   @param[out]  FoundSection    The FFS section if found
    141 
    142   @retval EFI_SUCCESS           The file and section was found
    143   @retval EFI_NOT_FOUND         The file and section was not found
    144   @retval EFI_VOLUME_CORRUPTED  The firmware volume was corrupted
    145 
    146 **/
    147 EFI_STATUS
    148 FindFfsSectionInstance (
    149   IN  VOID                             *Sections,
    150   IN  UINTN                            SizeOfSections,
    151   IN  EFI_SECTION_TYPE                 SectionType,
    152   IN  UINTN                            Instance,
    153   OUT EFI_COMMON_SECTION_HEADER        **FoundSection
    154   )
    155 {
    156   EFI_PHYSICAL_ADDRESS        CurrentAddress;
    157   UINT32                      Size;
    158   EFI_PHYSICAL_ADDRESS        EndOfSections;
    159   EFI_COMMON_SECTION_HEADER   *Section;
    160   EFI_PHYSICAL_ADDRESS        EndOfSection;
    161 
    162   //
    163   // Loop through the FFS file sections within the PEI Core FFS file
    164   //
    165   EndOfSection = (EFI_PHYSICAL_ADDRESS)(UINTN) Sections;
    166   EndOfSections = EndOfSection + SizeOfSections;
    167   for (;;) {
    168     if (EndOfSection == EndOfSections) {
    169       break;
    170     }
    171     CurrentAddress = (EndOfSection + 3) & ~(3ULL);
    172     if (CurrentAddress >= EndOfSections) {
    173       return EFI_VOLUME_CORRUPTED;
    174     }
    175 
    176     Section = (EFI_COMMON_SECTION_HEADER*)(UINTN) CurrentAddress;
    177 
    178     Size = SECTION_SIZE (Section);
    179     if (Size < sizeof (*Section)) {
    180       return EFI_VOLUME_CORRUPTED;
    181     }
    182 
    183     EndOfSection = CurrentAddress + Size;
    184     if (EndOfSection > EndOfSections) {
    185       return EFI_VOLUME_CORRUPTED;
    186     }
    187 
    188     //
    189     // Look for the requested section type
    190     //
    191     if (Section->Type == SectionType) {
    192       if (Instance == 0) {
    193         *FoundSection = Section;
    194         return EFI_SUCCESS;
    195       } else {
    196         Instance--;
    197       }
    198     }
    199   }
    200 
    201   return EFI_NOT_FOUND;
    202 }
    203 
    204 /**
    205   Locates a section within a series of sections
    206   with the specified section type.
    207 
    208   @param[in]   Sections        The sections to search
    209   @param[in]   SizeOfSections  Total size of all sections
    210   @param[in]   SectionType     The section type to locate
    211   @param[out]  FoundSection    The FFS section if found
    212 
    213   @retval EFI_SUCCESS           The file and section was found
    214   @retval EFI_NOT_FOUND         The file and section was not found
    215   @retval EFI_VOLUME_CORRUPTED  The firmware volume was corrupted
    216 
    217 **/
    218 EFI_STATUS
    219 FindFfsSectionInSections (
    220   IN  VOID                             *Sections,
    221   IN  UINTN                            SizeOfSections,
    222   IN  EFI_SECTION_TYPE                 SectionType,
    223   OUT EFI_COMMON_SECTION_HEADER        **FoundSection
    224   )
    225 {
    226   return FindFfsSectionInstance (
    227            Sections,
    228            SizeOfSections,
    229            SectionType,
    230            0,
    231            FoundSection
    232            );
    233 }
    234 
    235 /**
    236   Locates a FFS file with the specified file type and a section
    237   within that file with the specified section type.
    238 
    239   @param[in]   Fv            The firmware volume to search
    240   @param[in]   FileType      The file type to locate
    241   @param[in]   SectionType   The section type to locate
    242   @param[out]  FoundSection  The FFS section if found
    243 
    244   @retval EFI_SUCCESS           The file and section was found
    245   @retval EFI_NOT_FOUND         The file and section was not found
    246   @retval EFI_VOLUME_CORRUPTED  The firmware volume was corrupted
    247 
    248 **/
    249 EFI_STATUS
    250 FindFfsFileAndSection (
    251   IN  EFI_FIRMWARE_VOLUME_HEADER       *Fv,
    252   IN  EFI_FV_FILETYPE                  FileType,
    253   IN  EFI_SECTION_TYPE                 SectionType,
    254   OUT EFI_COMMON_SECTION_HEADER        **FoundSection
    255   )
    256 {
    257   EFI_STATUS                  Status;
    258   EFI_PHYSICAL_ADDRESS        CurrentAddress;
    259   EFI_PHYSICAL_ADDRESS        EndOfFirmwareVolume;
    260   EFI_FFS_FILE_HEADER         *File;
    261   UINT32                      Size;
    262   EFI_PHYSICAL_ADDRESS        EndOfFile;
    263 
    264   if (Fv->Signature != EFI_FVH_SIGNATURE) {
    265     DEBUG ((EFI_D_ERROR, "FV at %p does not have FV header signature\n", Fv));
    266     return EFI_VOLUME_CORRUPTED;
    267   }
    268 
    269   CurrentAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) Fv;
    270   EndOfFirmwareVolume = CurrentAddress + Fv->FvLength;
    271 
    272   //
    273   // Loop through the FFS files in the Boot Firmware Volume
    274   //
    275   for (EndOfFile = CurrentAddress + Fv->HeaderLength; ; ) {
    276 
    277     CurrentAddress = (EndOfFile + 7) & ~(7ULL);
    278     if (CurrentAddress > EndOfFirmwareVolume) {
    279       return EFI_VOLUME_CORRUPTED;
    280     }
    281 
    282     File = (EFI_FFS_FILE_HEADER*)(UINTN) CurrentAddress;
    283     Size = *(UINT32*) File->Size & 0xffffff;
    284     if (Size < (sizeof (*File) + sizeof (EFI_COMMON_SECTION_HEADER))) {
    285       return EFI_VOLUME_CORRUPTED;
    286     }
    287 
    288     EndOfFile = CurrentAddress + Size;
    289     if (EndOfFile > EndOfFirmwareVolume) {
    290       return EFI_VOLUME_CORRUPTED;
    291     }
    292 
    293     //
    294     // Look for the request file type
    295     //
    296     if (File->Type != FileType) {
    297       continue;
    298     }
    299 
    300     Status = FindFfsSectionInSections (
    301                (VOID*) (File + 1),
    302                (UINTN) EndOfFile - (UINTN) (File + 1),
    303                SectionType,
    304                FoundSection
    305                );
    306     if (!EFI_ERROR (Status) || (Status == EFI_VOLUME_CORRUPTED)) {
    307       return Status;
    308     }
    309   }
    310 }
    311 
    312 /**
    313   Locates the compressed main firmware volume and decompresses it.
    314 
    315   @param[in,out]  Fv            On input, the firmware volume to search
    316                                 On output, the decompressed BOOT/PEI FV
    317 
    318   @retval EFI_SUCCESS           The file and section was found
    319   @retval EFI_NOT_FOUND         The file and section was not found
    320   @retval EFI_VOLUME_CORRUPTED  The firmware volume was corrupted
    321 
    322 **/
    323 EFI_STATUS
    324 DecompressMemFvs (
    325   IN OUT EFI_FIRMWARE_VOLUME_HEADER       **Fv
    326   )
    327 {
    328   EFI_STATUS                        Status;
    329   EFI_GUID_DEFINED_SECTION          *Section;
    330   UINT32                            OutputBufferSize;
    331   UINT32                            ScratchBufferSize;
    332   UINT16                            SectionAttribute;
    333   UINT32                            AuthenticationStatus;
    334   VOID                              *OutputBuffer;
    335   VOID                              *ScratchBuffer;
    336   EFI_COMMON_SECTION_HEADER         *FvSection;
    337   EFI_FIRMWARE_VOLUME_HEADER        *PeiMemFv;
    338   EFI_FIRMWARE_VOLUME_HEADER        *DxeMemFv;
    339   UINT32                            FvHeaderSize;
    340   UINT32                            FvSectionSize;
    341 
    342   FvSection = (EFI_COMMON_SECTION_HEADER*) NULL;
    343 
    344   Status = FindFfsFileAndSection (
    345              *Fv,
    346              EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE,
    347              EFI_SECTION_GUID_DEFINED,
    348              (EFI_COMMON_SECTION_HEADER**) &Section
    349              );
    350   if (EFI_ERROR (Status)) {
    351     DEBUG ((EFI_D_ERROR, "Unable to find GUID defined section\n"));
    352     return Status;
    353   }
    354 
    355   Status = ExtractGuidedSectionGetInfo (
    356              Section,
    357              &OutputBufferSize,
    358              &ScratchBufferSize,
    359              &SectionAttribute
    360              );
    361   if (EFI_ERROR (Status)) {
    362     DEBUG ((EFI_D_ERROR, "Unable to GetInfo for GUIDed section\n"));
    363     return Status;
    364   }
    365 
    366   OutputBuffer = (VOID*) ((UINT8*)(UINTN) PcdGet32 (PcdOvmfDxeMemFvBase) + SIZE_1MB);
    367   ScratchBuffer = ALIGN_POINTER ((UINT8*) OutputBuffer + OutputBufferSize, SIZE_1MB);
    368 
    369   DEBUG ((EFI_D_VERBOSE, "%a: OutputBuffer@%p+0x%x ScratchBuffer@%p+0x%x "
    370     "PcdOvmfDecompressionScratchEnd=0x%x\n", __FUNCTION__, OutputBuffer,
    371     OutputBufferSize, ScratchBuffer, ScratchBufferSize,
    372     PcdGet32 (PcdOvmfDecompressionScratchEnd)));
    373   ASSERT ((UINTN)ScratchBuffer + ScratchBufferSize ==
    374     PcdGet32 (PcdOvmfDecompressionScratchEnd));
    375 
    376   Status = ExtractGuidedSectionDecode (
    377              Section,
    378              &OutputBuffer,
    379              ScratchBuffer,
    380              &AuthenticationStatus
    381              );
    382   if (EFI_ERROR (Status)) {
    383     DEBUG ((EFI_D_ERROR, "Error during GUID section decode\n"));
    384     return Status;
    385   }
    386 
    387   Status = FindFfsSectionInstance (
    388              OutputBuffer,
    389              OutputBufferSize,
    390              EFI_SECTION_FIRMWARE_VOLUME_IMAGE,
    391              0,
    392              &FvSection
    393              );
    394   if (EFI_ERROR (Status)) {
    395     DEBUG ((EFI_D_ERROR, "Unable to find PEI FV section\n"));
    396     return Status;
    397   }
    398 
    399   ASSERT (SECTION_SIZE (FvSection) ==
    400           (PcdGet32 (PcdOvmfPeiMemFvSize) + sizeof (*FvSection)));
    401   ASSERT (FvSection->Type == EFI_SECTION_FIRMWARE_VOLUME_IMAGE);
    402 
    403   PeiMemFv = (EFI_FIRMWARE_VOLUME_HEADER*)(UINTN) PcdGet32 (PcdOvmfPeiMemFvBase);
    404   CopyMem (PeiMemFv, (VOID*) (FvSection + 1), PcdGet32 (PcdOvmfPeiMemFvSize));
    405 
    406   if (PeiMemFv->Signature != EFI_FVH_SIGNATURE) {
    407     DEBUG ((EFI_D_ERROR, "Extracted FV at %p does not have FV header signature\n", PeiMemFv));
    408     CpuDeadLoop ();
    409     return EFI_VOLUME_CORRUPTED;
    410   }
    411 
    412   Status = FindFfsSectionInstance (
    413              OutputBuffer,
    414              OutputBufferSize,
    415              EFI_SECTION_FIRMWARE_VOLUME_IMAGE,
    416              1,
    417              &FvSection
    418              );
    419   if (EFI_ERROR (Status)) {
    420     DEBUG ((EFI_D_ERROR, "Unable to find DXE FV section\n"));
    421     return Status;
    422   }
    423 
    424   ASSERT (FvSection->Type == EFI_SECTION_FIRMWARE_VOLUME_IMAGE);
    425 
    426   if (IS_SECTION2 (FvSection)) {
    427     FvSectionSize = SECTION2_SIZE (FvSection);
    428     FvHeaderSize = sizeof (EFI_COMMON_SECTION_HEADER2);
    429   } else {
    430     FvSectionSize = SECTION_SIZE (FvSection);
    431     FvHeaderSize = sizeof (EFI_COMMON_SECTION_HEADER);
    432   }
    433 
    434   ASSERT (FvSectionSize == (PcdGet32 (PcdOvmfDxeMemFvSize) + FvHeaderSize));
    435 
    436   DxeMemFv = (EFI_FIRMWARE_VOLUME_HEADER*)(UINTN) PcdGet32 (PcdOvmfDxeMemFvBase);
    437   CopyMem (DxeMemFv, (VOID*) ((UINTN)FvSection + FvHeaderSize), PcdGet32 (PcdOvmfDxeMemFvSize));
    438 
    439   if (DxeMemFv->Signature != EFI_FVH_SIGNATURE) {
    440     DEBUG ((EFI_D_ERROR, "Extracted FV at %p does not have FV header signature\n", DxeMemFv));
    441     CpuDeadLoop ();
    442     return EFI_VOLUME_CORRUPTED;
    443   }
    444 
    445   *Fv = PeiMemFv;
    446   return EFI_SUCCESS;
    447 }
    448 
    449 /**
    450   Locates the PEI Core entry point address
    451 
    452   @param[in]  Fv                 The firmware volume to search
    453   @param[out] PeiCoreEntryPoint  The entry point of the PEI Core image
    454 
    455   @retval EFI_SUCCESS           The file and section was found
    456   @retval EFI_NOT_FOUND         The file and section was not found
    457   @retval EFI_VOLUME_CORRUPTED  The firmware volume was corrupted
    458 
    459 **/
    460 EFI_STATUS
    461 FindPeiCoreImageBaseInFv (
    462   IN  EFI_FIRMWARE_VOLUME_HEADER       *Fv,
    463   OUT  EFI_PHYSICAL_ADDRESS             *PeiCoreImageBase
    464   )
    465 {
    466   EFI_STATUS                  Status;
    467   EFI_COMMON_SECTION_HEADER   *Section;
    468 
    469   Status = FindFfsFileAndSection (
    470              Fv,
    471              EFI_FV_FILETYPE_PEI_CORE,
    472              EFI_SECTION_PE32,
    473              &Section
    474              );
    475   if (EFI_ERROR (Status)) {
    476     Status = FindFfsFileAndSection (
    477                Fv,
    478                EFI_FV_FILETYPE_PEI_CORE,
    479                EFI_SECTION_TE,
    480                &Section
    481                );
    482     if (EFI_ERROR (Status)) {
    483       DEBUG ((EFI_D_ERROR, "Unable to find PEI Core image\n"));
    484       return Status;
    485     }
    486   }
    487 
    488   *PeiCoreImageBase = (EFI_PHYSICAL_ADDRESS)(UINTN)(Section + 1);
    489   return EFI_SUCCESS;
    490 }
    491 
    492 
    493 /**
    494   Reads 8-bits of CMOS data.
    495 
    496   Reads the 8-bits of CMOS data at the location specified by Index.
    497   The 8-bit read value is returned.
    498 
    499   @param  Index  The CMOS location to read.
    500 
    501   @return The value read.
    502 
    503 **/
    504 STATIC
    505 UINT8
    506 CmosRead8 (
    507   IN      UINTN                     Index
    508   )
    509 {
    510   IoWrite8 (0x70, (UINT8) Index);
    511   return IoRead8 (0x71);
    512 }
    513 
    514 
    515 STATIC
    516 BOOLEAN
    517 IsS3Resume (
    518   VOID
    519   )
    520 {
    521   return (CmosRead8 (0xF) == 0xFE);
    522 }
    523 
    524 
    525 STATIC
    526 EFI_STATUS
    527 GetS3ResumePeiFv (
    528   IN OUT EFI_FIRMWARE_VOLUME_HEADER       **PeiFv
    529   )
    530 {
    531   *PeiFv = (EFI_FIRMWARE_VOLUME_HEADER*)(UINTN) PcdGet32 (PcdOvmfPeiMemFvBase);
    532   return EFI_SUCCESS;
    533 }
    534 
    535 
    536 /**
    537   Locates the PEI Core entry point address
    538 
    539   @param[in,out]  Fv                 The firmware volume to search
    540   @param[out]     PeiCoreEntryPoint  The entry point of the PEI Core image
    541 
    542   @retval EFI_SUCCESS           The file and section was found
    543   @retval EFI_NOT_FOUND         The file and section was not found
    544   @retval EFI_VOLUME_CORRUPTED  The firmware volume was corrupted
    545 
    546 **/
    547 VOID
    548 FindPeiCoreImageBase (
    549   IN OUT  EFI_FIRMWARE_VOLUME_HEADER       **BootFv,
    550      OUT  EFI_PHYSICAL_ADDRESS             *PeiCoreImageBase
    551   )
    552 {
    553   BOOLEAN S3Resume;
    554 
    555   *PeiCoreImageBase = 0;
    556 
    557   S3Resume = IsS3Resume ();
    558   if (S3Resume && !FeaturePcdGet (PcdSmmSmramRequire)) {
    559     //
    560     // A malicious runtime OS may have injected something into our previously
    561     // decoded PEI FV, but we don't care about that unless SMM/SMRAM is required.
    562     //
    563     DEBUG ((EFI_D_VERBOSE, "SEC: S3 resume\n"));
    564     GetS3ResumePeiFv (BootFv);
    565   } else {
    566     //
    567     // We're either not resuming, or resuming "securely" -- we'll decompress
    568     // both PEI FV and DXE FV from pristine flash.
    569     //
    570     DEBUG ((EFI_D_VERBOSE, "SEC: %a\n",
    571       S3Resume ? "S3 resume (with PEI decompression)" : "Normal boot"));
    572     FindMainFv (BootFv);
    573 
    574     DecompressMemFvs (BootFv);
    575   }
    576 
    577   FindPeiCoreImageBaseInFv (*BootFv, PeiCoreImageBase);
    578 }
    579 
    580 /**
    581   Find core image base.
    582 
    583 **/
    584 EFI_STATUS
    585 FindImageBase (
    586   IN  EFI_FIRMWARE_VOLUME_HEADER       *BootFirmwareVolumePtr,
    587   OUT EFI_PHYSICAL_ADDRESS             *SecCoreImageBase
    588   )
    589 {
    590   EFI_PHYSICAL_ADDRESS        CurrentAddress;
    591   EFI_PHYSICAL_ADDRESS        EndOfFirmwareVolume;
    592   EFI_FFS_FILE_HEADER         *File;
    593   UINT32                      Size;
    594   EFI_PHYSICAL_ADDRESS        EndOfFile;
    595   EFI_COMMON_SECTION_HEADER   *Section;
    596   EFI_PHYSICAL_ADDRESS        EndOfSection;
    597 
    598   *SecCoreImageBase = 0;
    599 
    600   CurrentAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) BootFirmwareVolumePtr;
    601   EndOfFirmwareVolume = CurrentAddress + BootFirmwareVolumePtr->FvLength;
    602 
    603   //
    604   // Loop through the FFS files in the Boot Firmware Volume
    605   //
    606   for (EndOfFile = CurrentAddress + BootFirmwareVolumePtr->HeaderLength; ; ) {
    607 
    608     CurrentAddress = (EndOfFile + 7) & 0xfffffffffffffff8ULL;
    609     if (CurrentAddress > EndOfFirmwareVolume) {
    610       return EFI_NOT_FOUND;
    611     }
    612 
    613     File = (EFI_FFS_FILE_HEADER*)(UINTN) CurrentAddress;
    614     Size = *(UINT32*) File->Size & 0xffffff;
    615     if (Size < sizeof (*File)) {
    616       return EFI_NOT_FOUND;
    617     }
    618 
    619     EndOfFile = CurrentAddress + Size;
    620     if (EndOfFile > EndOfFirmwareVolume) {
    621       return EFI_NOT_FOUND;
    622     }
    623 
    624     //
    625     // Look for SEC Core
    626     //
    627     if (File->Type != EFI_FV_FILETYPE_SECURITY_CORE) {
    628       continue;
    629     }
    630 
    631     //
    632     // Loop through the FFS file sections within the FFS file
    633     //
    634     EndOfSection = (EFI_PHYSICAL_ADDRESS)(UINTN) (File + 1);
    635     for (;;) {
    636       CurrentAddress = (EndOfSection + 3) & 0xfffffffffffffffcULL;
    637       Section = (EFI_COMMON_SECTION_HEADER*)(UINTN) CurrentAddress;
    638 
    639       Size = *(UINT32*) Section->Size & 0xffffff;
    640       if (Size < sizeof (*Section)) {
    641         return EFI_NOT_FOUND;
    642       }
    643 
    644       EndOfSection = CurrentAddress + Size;
    645       if (EndOfSection > EndOfFile) {
    646         return EFI_NOT_FOUND;
    647       }
    648 
    649       //
    650       // Look for executable sections
    651       //
    652       if (Section->Type == EFI_SECTION_PE32 || Section->Type == EFI_SECTION_TE) {
    653         if (File->Type == EFI_FV_FILETYPE_SECURITY_CORE) {
    654           *SecCoreImageBase = (PHYSICAL_ADDRESS) (UINTN) (Section + 1);
    655         }
    656         break;
    657       }
    658     }
    659 
    660     //
    661     // SEC Core image found
    662     //
    663     if (*SecCoreImageBase != 0) {
    664       return EFI_SUCCESS;
    665     }
    666   }
    667 }
    668 
    669 /*
    670   Find and return Pei Core entry point.
    671 
    672   It also find SEC and PEI Core file debug information. It will report them if
    673   remote debug is enabled.
    674 
    675 **/
    676 VOID
    677 FindAndReportEntryPoints (
    678   IN  EFI_FIRMWARE_VOLUME_HEADER       **BootFirmwareVolumePtr,
    679   OUT EFI_PEI_CORE_ENTRY_POINT         *PeiCoreEntryPoint
    680   )
    681 {
    682   EFI_STATUS                       Status;
    683   EFI_PHYSICAL_ADDRESS             SecCoreImageBase;
    684   EFI_PHYSICAL_ADDRESS             PeiCoreImageBase;
    685   PE_COFF_LOADER_IMAGE_CONTEXT     ImageContext;
    686 
    687   //
    688   // Find SEC Core and PEI Core image base
    689    //
    690   Status = FindImageBase (*BootFirmwareVolumePtr, &SecCoreImageBase);
    691   ASSERT_EFI_ERROR (Status);
    692 
    693   FindPeiCoreImageBase (BootFirmwareVolumePtr, &PeiCoreImageBase);
    694 
    695   ZeroMem ((VOID *) &ImageContext, sizeof (PE_COFF_LOADER_IMAGE_CONTEXT));
    696   //
    697   // Report SEC Core debug information when remote debug is enabled
    698   //
    699   ImageContext.ImageAddress = SecCoreImageBase;
    700   ImageContext.PdbPointer = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageContext.ImageAddress);
    701   PeCoffLoaderRelocateImageExtraAction (&ImageContext);
    702 
    703   //
    704   // Report PEI Core debug information when remote debug is enabled
    705   //
    706   ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)PeiCoreImageBase;
    707   ImageContext.PdbPointer = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageContext.ImageAddress);
    708   PeCoffLoaderRelocateImageExtraAction (&ImageContext);
    709 
    710   //
    711   // Find PEI Core entry point
    712   //
    713   Status = PeCoffLoaderGetEntryPoint ((VOID *) (UINTN) PeiCoreImageBase, (VOID**) PeiCoreEntryPoint);
    714   if (EFI_ERROR (Status)) {
    715     *PeiCoreEntryPoint = 0;
    716   }
    717 
    718   return;
    719 }
    720 
    721 VOID
    722 EFIAPI
    723 SecCoreStartupWithStack (
    724   IN EFI_FIRMWARE_VOLUME_HEADER       *BootFv,
    725   IN VOID                             *TopOfCurrentStack
    726   )
    727 {
    728   EFI_SEC_PEI_HAND_OFF        SecCoreData;
    729   SEC_IDT_TABLE               IdtTableInStack;
    730   IA32_DESCRIPTOR             IdtDescriptor;
    731   UINT32                      Index;
    732   volatile UINT8              *Table;
    733 
    734   //
    735   // To ensure SMM can't be compromised on S3 resume, we must force re-init of
    736   // the BaseExtractGuidedSectionLib. Since this is before library contructors
    737   // are called, we must use a loop rather than SetMem.
    738   //
    739   Table = (UINT8*)(UINTN)FixedPcdGet64 (PcdGuidedExtractHandlerTableAddress);
    740   for (Index = 0;
    741        Index < FixedPcdGet32 (PcdGuidedExtractHandlerTableSize);
    742        ++Index) {
    743     Table[Index] = 0;
    744   }
    745 
    746   ProcessLibraryConstructorList (NULL, NULL);
    747 
    748   DEBUG ((EFI_D_INFO,
    749     "SecCoreStartupWithStack(0x%x, 0x%x)\n",
    750     (UINT32)(UINTN)BootFv,
    751     (UINT32)(UINTN)TopOfCurrentStack
    752     ));
    753 
    754   //
    755   // Initialize floating point operating environment
    756   // to be compliant with UEFI spec.
    757   //
    758   InitializeFloatingPointUnits ();
    759 
    760   //
    761   // Initialize IDT
    762   //
    763   IdtTableInStack.PeiService = NULL;
    764   for (Index = 0; Index < SEC_IDT_ENTRY_COUNT; Index ++) {
    765     CopyMem (&IdtTableInStack.IdtTable[Index], &mIdtEntryTemplate, sizeof (mIdtEntryTemplate));
    766   }
    767 
    768   IdtDescriptor.Base  = (UINTN)&IdtTableInStack.IdtTable;
    769   IdtDescriptor.Limit = (UINT16)(sizeof (IdtTableInStack.IdtTable) - 1);
    770 
    771   AsmWriteIdtr (&IdtDescriptor);
    772 
    773 #if defined (MDE_CPU_X64)
    774   //
    775   // ASSERT that the Page Tables were set by the reset vector code to
    776   // the address we expect.
    777   //
    778   ASSERT (AsmReadCr3 () == (UINTN) PcdGet32 (PcdOvmfSecPageTablesBase));
    779 #endif
    780 
    781   //
    782   // |-------------|       <-- TopOfCurrentStack
    783   // |   Stack     | 32k
    784   // |-------------|
    785   // |    Heap     | 32k
    786   // |-------------|       <-- SecCoreData.TemporaryRamBase
    787   //
    788 
    789   ASSERT ((UINTN) (PcdGet32 (PcdOvmfSecPeiTempRamBase) +
    790                    PcdGet32 (PcdOvmfSecPeiTempRamSize)) ==
    791           (UINTN) TopOfCurrentStack);
    792 
    793   //
    794   // Initialize SEC hand-off state
    795   //
    796   SecCoreData.DataSize = sizeof(EFI_SEC_PEI_HAND_OFF);
    797 
    798   SecCoreData.TemporaryRamSize       = (UINTN) PcdGet32 (PcdOvmfSecPeiTempRamSize);
    799   SecCoreData.TemporaryRamBase       = (VOID*)((UINT8 *)TopOfCurrentStack - SecCoreData.TemporaryRamSize);
    800 
    801   SecCoreData.PeiTemporaryRamBase    = SecCoreData.TemporaryRamBase;
    802   SecCoreData.PeiTemporaryRamSize    = SecCoreData.TemporaryRamSize >> 1;
    803 
    804   SecCoreData.StackBase              = (UINT8 *)SecCoreData.TemporaryRamBase + SecCoreData.PeiTemporaryRamSize;
    805   SecCoreData.StackSize              = SecCoreData.TemporaryRamSize >> 1;
    806 
    807   SecCoreData.BootFirmwareVolumeBase = BootFv;
    808   SecCoreData.BootFirmwareVolumeSize = (UINTN) BootFv->FvLength;
    809 
    810   //
    811   // Make sure the 8259 is masked before initializing the Debug Agent and the debug timer is enabled
    812   //
    813   IoWrite8 (0x21, 0xff);
    814   IoWrite8 (0xA1, 0xff);
    815 
    816   //
    817   // Initialize Local APIC Timer hardware and disable Local APIC Timer
    818   // interrupts before initializing the Debug Agent and the debug timer is
    819   // enabled.
    820   //
    821   InitializeApicTimer (0, MAX_UINT32, TRUE, 5);
    822   DisableApicTimerInterrupt ();
    823 
    824   //
    825   // Initialize Debug Agent to support source level debug in SEC/PEI phases before memory ready.
    826   //
    827   InitializeDebugAgent (DEBUG_AGENT_INIT_PREMEM_SEC, &SecCoreData, SecStartupPhase2);
    828 }
    829 
    830 /**
    831   Caller provided function to be invoked at the end of InitializeDebugAgent().
    832 
    833   Entry point to the C language phase of SEC. After the SEC assembly
    834   code has initialized some temporary memory and set up the stack,
    835   the control is transferred to this function.
    836 
    837   @param[in] Context    The first input parameter of InitializeDebugAgent().
    838 
    839 **/
    840 VOID
    841 EFIAPI
    842 SecStartupPhase2(
    843   IN VOID                     *Context
    844   )
    845 {
    846   EFI_SEC_PEI_HAND_OFF        *SecCoreData;
    847   EFI_FIRMWARE_VOLUME_HEADER  *BootFv;
    848   EFI_PEI_CORE_ENTRY_POINT    PeiCoreEntryPoint;
    849 
    850   SecCoreData = (EFI_SEC_PEI_HAND_OFF *) Context;
    851 
    852   //
    853   // Find PEI Core entry point. It will report SEC and Pei Core debug information if remote debug
    854   // is enabled.
    855   //
    856   BootFv = (EFI_FIRMWARE_VOLUME_HEADER *)SecCoreData->BootFirmwareVolumeBase;
    857   FindAndReportEntryPoints (&BootFv, &PeiCoreEntryPoint);
    858   SecCoreData->BootFirmwareVolumeBase = BootFv;
    859   SecCoreData->BootFirmwareVolumeSize = (UINTN) BootFv->FvLength;
    860 
    861   //
    862   // Transfer the control to the PEI core
    863   //
    864   (*PeiCoreEntryPoint) (SecCoreData, (EFI_PEI_PPI_DESCRIPTOR *)&mPrivateDispatchTable);
    865 
    866   //
    867   // If we get here then the PEI Core returned, which is not recoverable.
    868   //
    869   ASSERT (FALSE);
    870   CpuDeadLoop ();
    871 }
    872 
    873 EFI_STATUS
    874 EFIAPI
    875 TemporaryRamMigration (
    876   IN CONST EFI_PEI_SERVICES   **PeiServices,
    877   IN EFI_PHYSICAL_ADDRESS     TemporaryMemoryBase,
    878   IN EFI_PHYSICAL_ADDRESS     PermanentMemoryBase,
    879   IN UINTN                    CopySize
    880   )
    881 {
    882   IA32_DESCRIPTOR                  IdtDescriptor;
    883   VOID                             *OldHeap;
    884   VOID                             *NewHeap;
    885   VOID                             *OldStack;
    886   VOID                             *NewStack;
    887   DEBUG_AGENT_CONTEXT_POSTMEM_SEC  DebugAgentContext;
    888   BOOLEAN                          OldStatus;
    889   BASE_LIBRARY_JUMP_BUFFER         JumpBuffer;
    890 
    891   DEBUG ((EFI_D_INFO,
    892     "TemporaryRamMigration(0x%Lx, 0x%Lx, 0x%Lx)\n",
    893     TemporaryMemoryBase,
    894     PermanentMemoryBase,
    895     (UINT64)CopySize
    896     ));
    897 
    898   OldHeap = (VOID*)(UINTN)TemporaryMemoryBase;
    899   NewHeap = (VOID*)((UINTN)PermanentMemoryBase + (CopySize >> 1));
    900 
    901   OldStack = (VOID*)((UINTN)TemporaryMemoryBase + (CopySize >> 1));
    902   NewStack = (VOID*)(UINTN)PermanentMemoryBase;
    903 
    904   DebugAgentContext.HeapMigrateOffset = (UINTN)NewHeap - (UINTN)OldHeap;
    905   DebugAgentContext.StackMigrateOffset = (UINTN)NewStack - (UINTN)OldStack;
    906 
    907   OldStatus = SaveAndSetDebugTimerInterrupt (FALSE);
    908   InitializeDebugAgent (DEBUG_AGENT_INIT_POSTMEM_SEC, (VOID *) &DebugAgentContext, NULL);
    909 
    910   //
    911   // Migrate Heap
    912   //
    913   CopyMem (NewHeap, OldHeap, CopySize >> 1);
    914 
    915   //
    916   // Migrate Stack
    917   //
    918   CopyMem (NewStack, OldStack, CopySize >> 1);
    919 
    920   //
    921   // Rebase IDT table in permanent memory
    922   //
    923   AsmReadIdtr (&IdtDescriptor);
    924   IdtDescriptor.Base = IdtDescriptor.Base - (UINTN)OldStack + (UINTN)NewStack;
    925 
    926   AsmWriteIdtr (&IdtDescriptor);
    927 
    928   //
    929   // Use SetJump()/LongJump() to switch to a new stack.
    930   //
    931   if (SetJump (&JumpBuffer) == 0) {
    932 #if defined (MDE_CPU_IA32)
    933     JumpBuffer.Esp = JumpBuffer.Esp + DebugAgentContext.StackMigrateOffset;
    934 #endif
    935 #if defined (MDE_CPU_X64)
    936     JumpBuffer.Rsp = JumpBuffer.Rsp + DebugAgentContext.StackMigrateOffset;
    937 #endif
    938     LongJump (&JumpBuffer, (UINTN)-1);
    939   }
    940 
    941   SaveAndSetDebugTimerInterrupt (OldStatus);
    942 
    943   return EFI_SUCCESS;
    944 }
    945 
    946