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