BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3108 In order to allow for the SEV-ES workarea to be used for other purposes and by other files, move the definition into the BaseMemEncryptSevLib header file, MemEncryptSevLib.h. Cc: Jordan Justen <jordan.l.justen@intel.com> Cc: Laszlo Ersek <lersek@redhat.com> Cc: Ard Biesheuvel <ard.biesheuvel@arm.com> Cc: Brijesh Singh <brijesh.singh@amd.com> Reviewed-by: Laszlo Ersek <lersek@redhat.com> Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com> Message-Id: <07d66f3384bd54da97d540e89b9f3473a6d17231.1610045305.git.thomas.lendacky@amd.com>
		
			
				
	
	
		
			1103 lines
		
	
	
		
			32 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1103 lines
		
	
	
		
			32 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
|   Main SEC phase code.  Transitions to PEI.
 | |
| 
 | |
|   Copyright (c) 2008 - 2015, Intel Corporation. All rights reserved.<BR>
 | |
|   (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
 | |
|   Copyright (c) 2020, Advanced Micro Devices, Inc. All rights reserved.<BR>
 | |
| 
 | |
|   SPDX-License-Identifier: BSD-2-Clause-Patent
 | |
| 
 | |
| **/
 | |
| 
 | |
| #include <PiPei.h>
 | |
| 
 | |
| #include <Library/PeimEntryPoint.h>
 | |
| #include <Library/BaseLib.h>
 | |
| #include <Library/DebugLib.h>
 | |
| #include <Library/BaseMemoryLib.h>
 | |
| #include <Library/PeiServicesLib.h>
 | |
| #include <Library/PcdLib.h>
 | |
| #include <Library/UefiCpuLib.h>
 | |
| #include <Library/DebugAgentLib.h>
 | |
| #include <Library/IoLib.h>
 | |
| #include <Library/PeCoffLib.h>
 | |
| #include <Library/PeCoffGetEntryPointLib.h>
 | |
| #include <Library/PeCoffExtraActionLib.h>
 | |
| #include <Library/ExtractGuidedSectionLib.h>
 | |
| #include <Library/LocalApicLib.h>
 | |
| #include <Library/CpuExceptionHandlerLib.h>
 | |
| #include <Library/MemEncryptSevLib.h>
 | |
| #include <Register/Amd/Ghcb.h>
 | |
| #include <Register/Amd/Msr.h>
 | |
| 
 | |
| #include <Ppi/TemporaryRamSupport.h>
 | |
| 
 | |
| #define SEC_IDT_ENTRY_COUNT  34
 | |
| 
 | |
| typedef struct _SEC_IDT_TABLE {
 | |
|   EFI_PEI_SERVICES          *PeiService;
 | |
|   IA32_IDT_GATE_DESCRIPTOR  IdtTable[SEC_IDT_ENTRY_COUNT];
 | |
| } SEC_IDT_TABLE;
 | |
| 
 | |
| VOID
 | |
| EFIAPI
 | |
| SecStartupPhase2 (
 | |
|   IN VOID                     *Context
 | |
|   );
 | |
| 
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| TemporaryRamMigration (
 | |
|   IN CONST EFI_PEI_SERVICES   **PeiServices,
 | |
|   IN EFI_PHYSICAL_ADDRESS     TemporaryMemoryBase,
 | |
|   IN EFI_PHYSICAL_ADDRESS     PermanentMemoryBase,
 | |
|   IN UINTN                    CopySize
 | |
|   );
 | |
| 
 | |
| //
 | |
| //
 | |
| //
 | |
| EFI_PEI_TEMPORARY_RAM_SUPPORT_PPI mTemporaryRamSupportPpi = {
 | |
|   TemporaryRamMigration
 | |
| };
 | |
| 
 | |
| EFI_PEI_PPI_DESCRIPTOR mPrivateDispatchTable[] = {
 | |
|   {
 | |
|     (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
 | |
|     &gEfiTemporaryRamSupportPpiGuid,
 | |
|     &mTemporaryRamSupportPpi
 | |
|   },
 | |
| };
 | |
| 
 | |
| //
 | |
| // Template of an IDT entry pointing to 10:FFFFFFE4h.
 | |
| //
 | |
| IA32_IDT_GATE_DESCRIPTOR  mIdtEntryTemplate = {
 | |
|   {                                      // Bits
 | |
|     0xffe4,                              // OffsetLow
 | |
|     0x10,                                // Selector
 | |
|     0x0,                                 // Reserved_0
 | |
|     IA32_IDT_GATE_TYPE_INTERRUPT_32,     // GateType
 | |
|     0xffff                               // OffsetHigh
 | |
|   }
 | |
| };
 | |
| 
 | |
| /**
 | |
|   Locates the main boot firmware volume.
 | |
| 
 | |
|   @param[in,out]  BootFv  On input, the base of the BootFv
 | |
|                           On output, the decompressed main firmware volume
 | |
| 
 | |
|   @retval EFI_SUCCESS    The main firmware volume was located and decompressed
 | |
|   @retval EFI_NOT_FOUND  The main firmware volume was not found
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| FindMainFv (
 | |
|   IN OUT  EFI_FIRMWARE_VOLUME_HEADER   **BootFv
 | |
|   )
 | |
| {
 | |
|   EFI_FIRMWARE_VOLUME_HEADER  *Fv;
 | |
|   UINTN                       Distance;
 | |
| 
 | |
|   ASSERT (((UINTN) *BootFv & EFI_PAGE_MASK) == 0);
 | |
| 
 | |
|   Fv = *BootFv;
 | |
|   Distance = (UINTN) (*BootFv)->FvLength;
 | |
|   do {
 | |
|     Fv = (EFI_FIRMWARE_VOLUME_HEADER*) ((UINT8*) Fv - EFI_PAGE_SIZE);
 | |
|     Distance += EFI_PAGE_SIZE;
 | |
|     if (Distance > SIZE_32MB) {
 | |
|       return EFI_NOT_FOUND;
 | |
|     }
 | |
| 
 | |
|     if (Fv->Signature != EFI_FVH_SIGNATURE) {
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     if ((UINTN) Fv->FvLength > Distance) {
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     *BootFv = Fv;
 | |
|     return EFI_SUCCESS;
 | |
| 
 | |
|   } while (TRUE);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Locates a section within a series of sections
 | |
|   with the specified section type.
 | |
| 
 | |
|   The Instance parameter indicates which instance of the section
 | |
|   type to return. (0 is first instance, 1 is second...)
 | |
| 
 | |
|   @param[in]   Sections        The sections to search
 | |
|   @param[in]   SizeOfSections  Total size of all sections
 | |
|   @param[in]   SectionType     The section type to locate
 | |
|   @param[in]   Instance        The section instance number
 | |
|   @param[out]  FoundSection    The FFS section if found
 | |
| 
 | |
|   @retval EFI_SUCCESS           The file and section was found
 | |
|   @retval EFI_NOT_FOUND         The file and section was not found
 | |
|   @retval EFI_VOLUME_CORRUPTED  The firmware volume was corrupted
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| FindFfsSectionInstance (
 | |
|   IN  VOID                             *Sections,
 | |
|   IN  UINTN                            SizeOfSections,
 | |
|   IN  EFI_SECTION_TYPE                 SectionType,
 | |
|   IN  UINTN                            Instance,
 | |
|   OUT EFI_COMMON_SECTION_HEADER        **FoundSection
 | |
|   )
 | |
| {
 | |
|   EFI_PHYSICAL_ADDRESS        CurrentAddress;
 | |
|   UINT32                      Size;
 | |
|   EFI_PHYSICAL_ADDRESS        EndOfSections;
 | |
|   EFI_COMMON_SECTION_HEADER   *Section;
 | |
|   EFI_PHYSICAL_ADDRESS        EndOfSection;
 | |
| 
 | |
|   //
 | |
|   // Loop through the FFS file sections within the PEI Core FFS file
 | |
|   //
 | |
|   EndOfSection = (EFI_PHYSICAL_ADDRESS)(UINTN) Sections;
 | |
|   EndOfSections = EndOfSection + SizeOfSections;
 | |
|   for (;;) {
 | |
|     if (EndOfSection == EndOfSections) {
 | |
|       break;
 | |
|     }
 | |
|     CurrentAddress = (EndOfSection + 3) & ~(3ULL);
 | |
|     if (CurrentAddress >= EndOfSections) {
 | |
|       return EFI_VOLUME_CORRUPTED;
 | |
|     }
 | |
| 
 | |
|     Section = (EFI_COMMON_SECTION_HEADER*)(UINTN) CurrentAddress;
 | |
| 
 | |
|     Size = SECTION_SIZE (Section);
 | |
|     if (Size < sizeof (*Section)) {
 | |
|       return EFI_VOLUME_CORRUPTED;
 | |
|     }
 | |
| 
 | |
|     EndOfSection = CurrentAddress + Size;
 | |
|     if (EndOfSection > EndOfSections) {
 | |
|       return EFI_VOLUME_CORRUPTED;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Look for the requested section type
 | |
|     //
 | |
|     if (Section->Type == SectionType) {
 | |
|       if (Instance == 0) {
 | |
|         *FoundSection = Section;
 | |
|         return EFI_SUCCESS;
 | |
|       } else {
 | |
|         Instance--;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return EFI_NOT_FOUND;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Locates a section within a series of sections
 | |
|   with the specified section type.
 | |
| 
 | |
|   @param[in]   Sections        The sections to search
 | |
|   @param[in]   SizeOfSections  Total size of all sections
 | |
|   @param[in]   SectionType     The section type to locate
 | |
|   @param[out]  FoundSection    The FFS section if found
 | |
| 
 | |
|   @retval EFI_SUCCESS           The file and section was found
 | |
|   @retval EFI_NOT_FOUND         The file and section was not found
 | |
|   @retval EFI_VOLUME_CORRUPTED  The firmware volume was corrupted
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| FindFfsSectionInSections (
 | |
|   IN  VOID                             *Sections,
 | |
|   IN  UINTN                            SizeOfSections,
 | |
|   IN  EFI_SECTION_TYPE                 SectionType,
 | |
|   OUT EFI_COMMON_SECTION_HEADER        **FoundSection
 | |
|   )
 | |
| {
 | |
|   return FindFfsSectionInstance (
 | |
|            Sections,
 | |
|            SizeOfSections,
 | |
|            SectionType,
 | |
|            0,
 | |
|            FoundSection
 | |
|            );
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Locates a FFS file with the specified file type and a section
 | |
|   within that file with the specified section type.
 | |
| 
 | |
|   @param[in]   Fv            The firmware volume to search
 | |
|   @param[in]   FileType      The file type to locate
 | |
|   @param[in]   SectionType   The section type to locate
 | |
|   @param[out]  FoundSection  The FFS section if found
 | |
| 
 | |
|   @retval EFI_SUCCESS           The file and section was found
 | |
|   @retval EFI_NOT_FOUND         The file and section was not found
 | |
|   @retval EFI_VOLUME_CORRUPTED  The firmware volume was corrupted
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| FindFfsFileAndSection (
 | |
|   IN  EFI_FIRMWARE_VOLUME_HEADER       *Fv,
 | |
|   IN  EFI_FV_FILETYPE                  FileType,
 | |
|   IN  EFI_SECTION_TYPE                 SectionType,
 | |
|   OUT EFI_COMMON_SECTION_HEADER        **FoundSection
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                  Status;
 | |
|   EFI_PHYSICAL_ADDRESS        CurrentAddress;
 | |
|   EFI_PHYSICAL_ADDRESS        EndOfFirmwareVolume;
 | |
|   EFI_FFS_FILE_HEADER         *File;
 | |
|   UINT32                      Size;
 | |
|   EFI_PHYSICAL_ADDRESS        EndOfFile;
 | |
| 
 | |
|   if (Fv->Signature != EFI_FVH_SIGNATURE) {
 | |
|     DEBUG ((DEBUG_ERROR, "FV at %p does not have FV header signature\n", Fv));
 | |
|     return EFI_VOLUME_CORRUPTED;
 | |
|   }
 | |
| 
 | |
|   CurrentAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) Fv;
 | |
|   EndOfFirmwareVolume = CurrentAddress + Fv->FvLength;
 | |
| 
 | |
|   //
 | |
|   // Loop through the FFS files in the Boot Firmware Volume
 | |
|   //
 | |
|   for (EndOfFile = CurrentAddress + Fv->HeaderLength; ; ) {
 | |
| 
 | |
|     CurrentAddress = (EndOfFile + 7) & ~(7ULL);
 | |
|     if (CurrentAddress > EndOfFirmwareVolume) {
 | |
|       return EFI_VOLUME_CORRUPTED;
 | |
|     }
 | |
| 
 | |
|     File = (EFI_FFS_FILE_HEADER*)(UINTN) CurrentAddress;
 | |
|     Size = FFS_FILE_SIZE (File);
 | |
|     if (Size < (sizeof (*File) + sizeof (EFI_COMMON_SECTION_HEADER))) {
 | |
|       return EFI_VOLUME_CORRUPTED;
 | |
|     }
 | |
| 
 | |
|     EndOfFile = CurrentAddress + Size;
 | |
|     if (EndOfFile > EndOfFirmwareVolume) {
 | |
|       return EFI_VOLUME_CORRUPTED;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Look for the request file type
 | |
|     //
 | |
|     if (File->Type != FileType) {
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     Status = FindFfsSectionInSections (
 | |
|                (VOID*) (File + 1),
 | |
|                (UINTN) EndOfFile - (UINTN) (File + 1),
 | |
|                SectionType,
 | |
|                FoundSection
 | |
|                );
 | |
|     if (!EFI_ERROR (Status) || (Status == EFI_VOLUME_CORRUPTED)) {
 | |
|       return Status;
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Locates the compressed main firmware volume and decompresses it.
 | |
| 
 | |
|   @param[in,out]  Fv            On input, the firmware volume to search
 | |
|                                 On output, the decompressed BOOT/PEI FV
 | |
| 
 | |
|   @retval EFI_SUCCESS           The file and section was found
 | |
|   @retval EFI_NOT_FOUND         The file and section was not found
 | |
|   @retval EFI_VOLUME_CORRUPTED  The firmware volume was corrupted
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| DecompressMemFvs (
 | |
|   IN OUT EFI_FIRMWARE_VOLUME_HEADER       **Fv
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                        Status;
 | |
|   EFI_GUID_DEFINED_SECTION          *Section;
 | |
|   UINT32                            OutputBufferSize;
 | |
|   UINT32                            ScratchBufferSize;
 | |
|   UINT16                            SectionAttribute;
 | |
|   UINT32                            AuthenticationStatus;
 | |
|   VOID                              *OutputBuffer;
 | |
|   VOID                              *ScratchBuffer;
 | |
|   EFI_COMMON_SECTION_HEADER         *FvSection;
 | |
|   EFI_FIRMWARE_VOLUME_HEADER        *PeiMemFv;
 | |
|   EFI_FIRMWARE_VOLUME_HEADER        *DxeMemFv;
 | |
|   UINT32                            FvHeaderSize;
 | |
|   UINT32                            FvSectionSize;
 | |
| 
 | |
|   FvSection = (EFI_COMMON_SECTION_HEADER*) NULL;
 | |
| 
 | |
|   Status = FindFfsFileAndSection (
 | |
|              *Fv,
 | |
|              EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE,
 | |
|              EFI_SECTION_GUID_DEFINED,
 | |
|              (EFI_COMMON_SECTION_HEADER**) &Section
 | |
|              );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     DEBUG ((DEBUG_ERROR, "Unable to find GUID defined section\n"));
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   Status = ExtractGuidedSectionGetInfo (
 | |
|              Section,
 | |
|              &OutputBufferSize,
 | |
|              &ScratchBufferSize,
 | |
|              &SectionAttribute
 | |
|              );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     DEBUG ((DEBUG_ERROR, "Unable to GetInfo for GUIDed section\n"));
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   OutputBuffer = (VOID*) ((UINT8*)(UINTN) PcdGet32 (PcdOvmfDxeMemFvBase) + SIZE_1MB);
 | |
|   ScratchBuffer = ALIGN_POINTER ((UINT8*) OutputBuffer + OutputBufferSize, SIZE_1MB);
 | |
| 
 | |
|   DEBUG ((DEBUG_VERBOSE, "%a: OutputBuffer@%p+0x%x ScratchBuffer@%p+0x%x "
 | |
|     "PcdOvmfDecompressionScratchEnd=0x%x\n", __FUNCTION__, OutputBuffer,
 | |
|     OutputBufferSize, ScratchBuffer, ScratchBufferSize,
 | |
|     PcdGet32 (PcdOvmfDecompressionScratchEnd)));
 | |
|   ASSERT ((UINTN)ScratchBuffer + ScratchBufferSize ==
 | |
|     PcdGet32 (PcdOvmfDecompressionScratchEnd));
 | |
| 
 | |
|   Status = ExtractGuidedSectionDecode (
 | |
|              Section,
 | |
|              &OutputBuffer,
 | |
|              ScratchBuffer,
 | |
|              &AuthenticationStatus
 | |
|              );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     DEBUG ((DEBUG_ERROR, "Error during GUID section decode\n"));
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   Status = FindFfsSectionInstance (
 | |
|              OutputBuffer,
 | |
|              OutputBufferSize,
 | |
|              EFI_SECTION_FIRMWARE_VOLUME_IMAGE,
 | |
|              0,
 | |
|              &FvSection
 | |
|              );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     DEBUG ((DEBUG_ERROR, "Unable to find PEI FV section\n"));
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   ASSERT (SECTION_SIZE (FvSection) ==
 | |
|           (PcdGet32 (PcdOvmfPeiMemFvSize) + sizeof (*FvSection)));
 | |
|   ASSERT (FvSection->Type == EFI_SECTION_FIRMWARE_VOLUME_IMAGE);
 | |
| 
 | |
|   PeiMemFv = (EFI_FIRMWARE_VOLUME_HEADER*)(UINTN) PcdGet32 (PcdOvmfPeiMemFvBase);
 | |
|   CopyMem (PeiMemFv, (VOID*) (FvSection + 1), PcdGet32 (PcdOvmfPeiMemFvSize));
 | |
| 
 | |
|   if (PeiMemFv->Signature != EFI_FVH_SIGNATURE) {
 | |
|     DEBUG ((DEBUG_ERROR, "Extracted FV at %p does not have FV header signature\n", PeiMemFv));
 | |
|     CpuDeadLoop ();
 | |
|     return EFI_VOLUME_CORRUPTED;
 | |
|   }
 | |
| 
 | |
|   Status = FindFfsSectionInstance (
 | |
|              OutputBuffer,
 | |
|              OutputBufferSize,
 | |
|              EFI_SECTION_FIRMWARE_VOLUME_IMAGE,
 | |
|              1,
 | |
|              &FvSection
 | |
|              );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     DEBUG ((DEBUG_ERROR, "Unable to find DXE FV section\n"));
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   ASSERT (FvSection->Type == EFI_SECTION_FIRMWARE_VOLUME_IMAGE);
 | |
| 
 | |
|   if (IS_SECTION2 (FvSection)) {
 | |
|     FvSectionSize = SECTION2_SIZE (FvSection);
 | |
|     FvHeaderSize = sizeof (EFI_COMMON_SECTION_HEADER2);
 | |
|   } else {
 | |
|     FvSectionSize = SECTION_SIZE (FvSection);
 | |
|     FvHeaderSize = sizeof (EFI_COMMON_SECTION_HEADER);
 | |
|   }
 | |
| 
 | |
|   ASSERT (FvSectionSize == (PcdGet32 (PcdOvmfDxeMemFvSize) + FvHeaderSize));
 | |
| 
 | |
|   DxeMemFv = (EFI_FIRMWARE_VOLUME_HEADER*)(UINTN) PcdGet32 (PcdOvmfDxeMemFvBase);
 | |
|   CopyMem (DxeMemFv, (VOID*) ((UINTN)FvSection + FvHeaderSize), PcdGet32 (PcdOvmfDxeMemFvSize));
 | |
| 
 | |
|   if (DxeMemFv->Signature != EFI_FVH_SIGNATURE) {
 | |
|     DEBUG ((DEBUG_ERROR, "Extracted FV at %p does not have FV header signature\n", DxeMemFv));
 | |
|     CpuDeadLoop ();
 | |
|     return EFI_VOLUME_CORRUPTED;
 | |
|   }
 | |
| 
 | |
|   *Fv = PeiMemFv;
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Locates the PEI Core entry point address
 | |
| 
 | |
|   @param[in]  Fv                 The firmware volume to search
 | |
|   @param[out] PeiCoreEntryPoint  The entry point of the PEI Core image
 | |
| 
 | |
|   @retval EFI_SUCCESS           The file and section was found
 | |
|   @retval EFI_NOT_FOUND         The file and section was not found
 | |
|   @retval EFI_VOLUME_CORRUPTED  The firmware volume was corrupted
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| FindPeiCoreImageBaseInFv (
 | |
|   IN  EFI_FIRMWARE_VOLUME_HEADER       *Fv,
 | |
|   OUT  EFI_PHYSICAL_ADDRESS             *PeiCoreImageBase
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                  Status;
 | |
|   EFI_COMMON_SECTION_HEADER   *Section;
 | |
| 
 | |
|   Status = FindFfsFileAndSection (
 | |
|              Fv,
 | |
|              EFI_FV_FILETYPE_PEI_CORE,
 | |
|              EFI_SECTION_PE32,
 | |
|              &Section
 | |
|              );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     Status = FindFfsFileAndSection (
 | |
|                Fv,
 | |
|                EFI_FV_FILETYPE_PEI_CORE,
 | |
|                EFI_SECTION_TE,
 | |
|                &Section
 | |
|                );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       DEBUG ((DEBUG_ERROR, "Unable to find PEI Core image\n"));
 | |
|       return Status;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   *PeiCoreImageBase = (EFI_PHYSICAL_ADDRESS)(UINTN)(Section + 1);
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Reads 8-bits of CMOS data.
 | |
| 
 | |
|   Reads the 8-bits of CMOS data at the location specified by Index.
 | |
|   The 8-bit read value is returned.
 | |
| 
 | |
|   @param  Index  The CMOS location to read.
 | |
| 
 | |
|   @return The value read.
 | |
| 
 | |
| **/
 | |
| STATIC
 | |
| UINT8
 | |
| CmosRead8 (
 | |
|   IN      UINTN                     Index
 | |
|   )
 | |
| {
 | |
|   IoWrite8 (0x70, (UINT8) Index);
 | |
|   return IoRead8 (0x71);
 | |
| }
 | |
| 
 | |
| 
 | |
| STATIC
 | |
| BOOLEAN
 | |
| IsS3Resume (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   return (CmosRead8 (0xF) == 0xFE);
 | |
| }
 | |
| 
 | |
| 
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| GetS3ResumePeiFv (
 | |
|   IN OUT EFI_FIRMWARE_VOLUME_HEADER       **PeiFv
 | |
|   )
 | |
| {
 | |
|   *PeiFv = (EFI_FIRMWARE_VOLUME_HEADER*)(UINTN) PcdGet32 (PcdOvmfPeiMemFvBase);
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Locates the PEI Core entry point address
 | |
| 
 | |
|   @param[in,out]  Fv                 The firmware volume to search
 | |
|   @param[out]     PeiCoreEntryPoint  The entry point of the PEI Core image
 | |
| 
 | |
|   @retval EFI_SUCCESS           The file and section was found
 | |
|   @retval EFI_NOT_FOUND         The file and section was not found
 | |
|   @retval EFI_VOLUME_CORRUPTED  The firmware volume was corrupted
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| FindPeiCoreImageBase (
 | |
|   IN OUT  EFI_FIRMWARE_VOLUME_HEADER       **BootFv,
 | |
|      OUT  EFI_PHYSICAL_ADDRESS             *PeiCoreImageBase
 | |
|   )
 | |
| {
 | |
|   BOOLEAN S3Resume;
 | |
| 
 | |
|   *PeiCoreImageBase = 0;
 | |
| 
 | |
|   S3Resume = IsS3Resume ();
 | |
|   if (S3Resume && !FeaturePcdGet (PcdSmmSmramRequire)) {
 | |
|     //
 | |
|     // A malicious runtime OS may have injected something into our previously
 | |
|     // decoded PEI FV, but we don't care about that unless SMM/SMRAM is required.
 | |
|     //
 | |
|     DEBUG ((DEBUG_VERBOSE, "SEC: S3 resume\n"));
 | |
|     GetS3ResumePeiFv (BootFv);
 | |
|   } else {
 | |
|     //
 | |
|     // We're either not resuming, or resuming "securely" -- we'll decompress
 | |
|     // both PEI FV and DXE FV from pristine flash.
 | |
|     //
 | |
|     DEBUG ((DEBUG_VERBOSE, "SEC: %a\n",
 | |
|       S3Resume ? "S3 resume (with PEI decompression)" : "Normal boot"));
 | |
|     FindMainFv (BootFv);
 | |
| 
 | |
|     DecompressMemFvs (BootFv);
 | |
|   }
 | |
| 
 | |
|   FindPeiCoreImageBaseInFv (*BootFv, PeiCoreImageBase);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Find core image base.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| FindImageBase (
 | |
|   IN  EFI_FIRMWARE_VOLUME_HEADER       *BootFirmwareVolumePtr,
 | |
|   OUT EFI_PHYSICAL_ADDRESS             *SecCoreImageBase
 | |
|   )
 | |
| {
 | |
|   EFI_PHYSICAL_ADDRESS        CurrentAddress;
 | |
|   EFI_PHYSICAL_ADDRESS        EndOfFirmwareVolume;
 | |
|   EFI_FFS_FILE_HEADER         *File;
 | |
|   UINT32                      Size;
 | |
|   EFI_PHYSICAL_ADDRESS        EndOfFile;
 | |
|   EFI_COMMON_SECTION_HEADER   *Section;
 | |
|   EFI_PHYSICAL_ADDRESS        EndOfSection;
 | |
| 
 | |
|   *SecCoreImageBase = 0;
 | |
| 
 | |
|   CurrentAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) BootFirmwareVolumePtr;
 | |
|   EndOfFirmwareVolume = CurrentAddress + BootFirmwareVolumePtr->FvLength;
 | |
| 
 | |
|   //
 | |
|   // Loop through the FFS files in the Boot Firmware Volume
 | |
|   //
 | |
|   for (EndOfFile = CurrentAddress + BootFirmwareVolumePtr->HeaderLength; ; ) {
 | |
| 
 | |
|     CurrentAddress = (EndOfFile + 7) & 0xfffffffffffffff8ULL;
 | |
|     if (CurrentAddress > EndOfFirmwareVolume) {
 | |
|       return EFI_NOT_FOUND;
 | |
|     }
 | |
| 
 | |
|     File = (EFI_FFS_FILE_HEADER*)(UINTN) CurrentAddress;
 | |
|     Size = FFS_FILE_SIZE (File);
 | |
|     if (Size < sizeof (*File)) {
 | |
|       return EFI_NOT_FOUND;
 | |
|     }
 | |
| 
 | |
|     EndOfFile = CurrentAddress + Size;
 | |
|     if (EndOfFile > EndOfFirmwareVolume) {
 | |
|       return EFI_NOT_FOUND;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Look for SEC Core
 | |
|     //
 | |
|     if (File->Type != EFI_FV_FILETYPE_SECURITY_CORE) {
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Loop through the FFS file sections within the FFS file
 | |
|     //
 | |
|     EndOfSection = (EFI_PHYSICAL_ADDRESS)(UINTN) (File + 1);
 | |
|     for (;;) {
 | |
|       CurrentAddress = (EndOfSection + 3) & 0xfffffffffffffffcULL;
 | |
|       Section = (EFI_COMMON_SECTION_HEADER*)(UINTN) CurrentAddress;
 | |
| 
 | |
|       Size = SECTION_SIZE (Section);
 | |
|       if (Size < sizeof (*Section)) {
 | |
|         return EFI_NOT_FOUND;
 | |
|       }
 | |
| 
 | |
|       EndOfSection = CurrentAddress + Size;
 | |
|       if (EndOfSection > EndOfFile) {
 | |
|         return EFI_NOT_FOUND;
 | |
|       }
 | |
| 
 | |
|       //
 | |
|       // Look for executable sections
 | |
|       //
 | |
|       if (Section->Type == EFI_SECTION_PE32 || Section->Type == EFI_SECTION_TE) {
 | |
|         if (File->Type == EFI_FV_FILETYPE_SECURITY_CORE) {
 | |
|           *SecCoreImageBase = (PHYSICAL_ADDRESS) (UINTN) (Section + 1);
 | |
|         }
 | |
|         break;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // SEC Core image found
 | |
|     //
 | |
|     if (*SecCoreImageBase != 0) {
 | |
|       return EFI_SUCCESS;
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| /*
 | |
|   Find and return Pei Core entry point.
 | |
| 
 | |
|   It also find SEC and PEI Core file debug information. It will report them if
 | |
|   remote debug is enabled.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| FindAndReportEntryPoints (
 | |
|   IN  EFI_FIRMWARE_VOLUME_HEADER       **BootFirmwareVolumePtr,
 | |
|   OUT EFI_PEI_CORE_ENTRY_POINT         *PeiCoreEntryPoint
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                       Status;
 | |
|   EFI_PHYSICAL_ADDRESS             SecCoreImageBase;
 | |
|   EFI_PHYSICAL_ADDRESS             PeiCoreImageBase;
 | |
|   PE_COFF_LOADER_IMAGE_CONTEXT     ImageContext;
 | |
| 
 | |
|   //
 | |
|   // Find SEC Core and PEI Core image base
 | |
|    //
 | |
|   Status = FindImageBase (*BootFirmwareVolumePtr, &SecCoreImageBase);
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|   FindPeiCoreImageBase (BootFirmwareVolumePtr, &PeiCoreImageBase);
 | |
| 
 | |
|   ZeroMem ((VOID *) &ImageContext, sizeof (PE_COFF_LOADER_IMAGE_CONTEXT));
 | |
|   //
 | |
|   // Report SEC Core debug information when remote debug is enabled
 | |
|   //
 | |
|   ImageContext.ImageAddress = SecCoreImageBase;
 | |
|   ImageContext.PdbPointer = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageContext.ImageAddress);
 | |
|   PeCoffLoaderRelocateImageExtraAction (&ImageContext);
 | |
| 
 | |
|   //
 | |
|   // Report PEI Core debug information when remote debug is enabled
 | |
|   //
 | |
|   ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)PeiCoreImageBase;
 | |
|   ImageContext.PdbPointer = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageContext.ImageAddress);
 | |
|   PeCoffLoaderRelocateImageExtraAction (&ImageContext);
 | |
| 
 | |
|   //
 | |
|   // Find PEI Core entry point
 | |
|   //
 | |
|   Status = PeCoffLoaderGetEntryPoint ((VOID *) (UINTN) PeiCoreImageBase, (VOID**) PeiCoreEntryPoint);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     *PeiCoreEntryPoint = 0;
 | |
|   }
 | |
| 
 | |
|   return;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Handle an SEV-ES/GHCB protocol check failure.
 | |
| 
 | |
|   Notify the hypervisor using the VMGEXIT instruction that the SEV-ES guest
 | |
|   wishes to be terminated.
 | |
| 
 | |
|   @param[in] ReasonCode  Reason code to provide to the hypervisor for the
 | |
|                          termination request.
 | |
| 
 | |
| **/
 | |
| STATIC
 | |
| VOID
 | |
| SevEsProtocolFailure (
 | |
|   IN UINT8  ReasonCode
 | |
|   )
 | |
| {
 | |
|   MSR_SEV_ES_GHCB_REGISTER  Msr;
 | |
| 
 | |
|   //
 | |
|   // Use the GHCB MSR Protocol to request termination by the hypervisor
 | |
|   //
 | |
|   Msr.GhcbPhysicalAddress = 0;
 | |
|   Msr.GhcbTerminate.Function = GHCB_INFO_TERMINATE_REQUEST;
 | |
|   Msr.GhcbTerminate.ReasonCodeSet = GHCB_TERMINATE_GHCB;
 | |
|   Msr.GhcbTerminate.ReasonCode = ReasonCode;
 | |
|   AsmWriteMsr64 (MSR_SEV_ES_GHCB, Msr.GhcbPhysicalAddress);
 | |
| 
 | |
|   AsmVmgExit ();
 | |
| 
 | |
|   ASSERT (FALSE);
 | |
|   CpuDeadLoop ();
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Validate the SEV-ES/GHCB protocol level.
 | |
| 
 | |
|   Verify that the level of SEV-ES/GHCB protocol supported by the hypervisor
 | |
|   and the guest intersect. If they don't intersect, request termination.
 | |
| 
 | |
| **/
 | |
| STATIC
 | |
| VOID
 | |
| SevEsProtocolCheck (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   MSR_SEV_ES_GHCB_REGISTER  Msr;
 | |
|   GHCB                      *Ghcb;
 | |
| 
 | |
|   //
 | |
|   // Use the GHCB MSR Protocol to obtain the GHCB SEV-ES Information for
 | |
|   // protocol checking
 | |
|   //
 | |
|   Msr.GhcbPhysicalAddress = 0;
 | |
|   Msr.GhcbInfo.Function = GHCB_INFO_SEV_INFO_GET;
 | |
|   AsmWriteMsr64 (MSR_SEV_ES_GHCB, Msr.GhcbPhysicalAddress);
 | |
| 
 | |
|   AsmVmgExit ();
 | |
| 
 | |
|   Msr.GhcbPhysicalAddress = AsmReadMsr64 (MSR_SEV_ES_GHCB);
 | |
| 
 | |
|   if (Msr.GhcbInfo.Function != GHCB_INFO_SEV_INFO) {
 | |
|     SevEsProtocolFailure (GHCB_TERMINATE_GHCB_GENERAL);
 | |
|   }
 | |
| 
 | |
|   if (Msr.GhcbProtocol.SevEsProtocolMin > Msr.GhcbProtocol.SevEsProtocolMax) {
 | |
|     SevEsProtocolFailure (GHCB_TERMINATE_GHCB_PROTOCOL);
 | |
|   }
 | |
| 
 | |
|   if ((Msr.GhcbProtocol.SevEsProtocolMin > GHCB_VERSION_MAX) ||
 | |
|       (Msr.GhcbProtocol.SevEsProtocolMax < GHCB_VERSION_MIN)) {
 | |
|     SevEsProtocolFailure (GHCB_TERMINATE_GHCB_PROTOCOL);
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // SEV-ES protocol checking succeeded, set the initial GHCB address
 | |
|   //
 | |
|   Msr.GhcbPhysicalAddress = FixedPcdGet32 (PcdOvmfSecGhcbBase);
 | |
|   AsmWriteMsr64 (MSR_SEV_ES_GHCB, Msr.GhcbPhysicalAddress);
 | |
| 
 | |
|   Ghcb = Msr.Ghcb;
 | |
|   SetMem (Ghcb, sizeof (*Ghcb), 0);
 | |
| 
 | |
|   //
 | |
|   // Set the version to the maximum that can be supported
 | |
|   //
 | |
|   Ghcb->ProtocolVersion = MIN (Msr.GhcbProtocol.SevEsProtocolMax, GHCB_VERSION_MAX);
 | |
|   Ghcb->GhcbUsage = GHCB_STANDARD_USAGE;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Determine if SEV-ES is active.
 | |
| 
 | |
|   During early booting, SEV-ES support code will set a flag to indicate that
 | |
|   SEV-ES is enabled. Return the value of this flag as an indicator that SEV-ES
 | |
|   is enabled.
 | |
| 
 | |
|   @retval TRUE   SEV-ES is enabled
 | |
|   @retval FALSE  SEV-ES is not enabled
 | |
| 
 | |
| **/
 | |
| STATIC
 | |
| BOOLEAN
 | |
| SevEsIsEnabled (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   SEC_SEV_ES_WORK_AREA  *SevEsWorkArea;
 | |
| 
 | |
|   SevEsWorkArea = (SEC_SEV_ES_WORK_AREA *) FixedPcdGet32 (PcdSevEsWorkAreaBase);
 | |
| 
 | |
|   return ((SevEsWorkArea != NULL) && (SevEsWorkArea->SevEsEnabled != 0));
 | |
| }
 | |
| 
 | |
| VOID
 | |
| EFIAPI
 | |
| SecCoreStartupWithStack (
 | |
|   IN EFI_FIRMWARE_VOLUME_HEADER       *BootFv,
 | |
|   IN VOID                             *TopOfCurrentStack
 | |
|   )
 | |
| {
 | |
|   EFI_SEC_PEI_HAND_OFF        SecCoreData;
 | |
|   SEC_IDT_TABLE               IdtTableInStack;
 | |
|   IA32_DESCRIPTOR             IdtDescriptor;
 | |
|   UINT32                      Index;
 | |
|   volatile UINT8              *Table;
 | |
| 
 | |
|   //
 | |
|   // To ensure SMM can't be compromised on S3 resume, we must force re-init of
 | |
|   // the BaseExtractGuidedSectionLib. Since this is before library contructors
 | |
|   // are called, we must use a loop rather than SetMem.
 | |
|   //
 | |
|   Table = (UINT8*)(UINTN)FixedPcdGet64 (PcdGuidedExtractHandlerTableAddress);
 | |
|   for (Index = 0;
 | |
|        Index < FixedPcdGet32 (PcdGuidedExtractHandlerTableSize);
 | |
|        ++Index) {
 | |
|     Table[Index] = 0;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Initialize IDT - Since this is before library constructors are called,
 | |
|   // we use a loop rather than CopyMem.
 | |
|   //
 | |
|   IdtTableInStack.PeiService = NULL;
 | |
|   for (Index = 0; Index < SEC_IDT_ENTRY_COUNT; Index ++) {
 | |
|     UINT8  *Src;
 | |
|     UINT8  *Dst;
 | |
|     UINTN  Byte;
 | |
| 
 | |
|     Src = (UINT8 *) &mIdtEntryTemplate;
 | |
|     Dst = (UINT8 *) &IdtTableInStack.IdtTable[Index];
 | |
|     for (Byte = 0; Byte < sizeof (mIdtEntryTemplate); Byte++) {
 | |
|       Dst[Byte] = Src[Byte];
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   IdtDescriptor.Base  = (UINTN)&IdtTableInStack.IdtTable;
 | |
|   IdtDescriptor.Limit = (UINT16)(sizeof (IdtTableInStack.IdtTable) - 1);
 | |
| 
 | |
|   if (SevEsIsEnabled ()) {
 | |
|     SevEsProtocolCheck ();
 | |
| 
 | |
|     //
 | |
|     // For SEV-ES guests, the exception handler is needed before calling
 | |
|     // ProcessLibraryConstructorList() because some of the library constructors
 | |
|     // perform some functions that result in #VC exceptions being generated.
 | |
|     //
 | |
|     // Due to this code executing before library constructors, *all* library
 | |
|     // API calls are theoretically interface contract violations. However,
 | |
|     // because this is SEC (executing in flash), those constructors cannot
 | |
|     // write variables with static storage duration anyway. Furthermore, only
 | |
|     // a small, restricted set of APIs, such as AsmWriteIdtr() and
 | |
|     // InitializeCpuExceptionHandlers(), are called, where we require that the
 | |
|     // underlying library not require constructors to have been invoked and
 | |
|     // that the library instance not trigger any #VC exceptions.
 | |
|     //
 | |
|     AsmWriteIdtr (&IdtDescriptor);
 | |
|     InitializeCpuExceptionHandlers (NULL);
 | |
|   }
 | |
| 
 | |
|   ProcessLibraryConstructorList (NULL, NULL);
 | |
| 
 | |
|   if (!SevEsIsEnabled ()) {
 | |
|     //
 | |
|     // For non SEV-ES guests, just load the IDTR.
 | |
|     //
 | |
|     AsmWriteIdtr (&IdtDescriptor);
 | |
|   } else {
 | |
|     //
 | |
|     // Under SEV-ES, the hypervisor can't modify CR0 and so can't enable
 | |
|     // caching in order to speed up the boot. Enable caching early for
 | |
|     // an SEV-ES guest.
 | |
|     //
 | |
|     AsmEnableCache ();
 | |
|   }
 | |
| 
 | |
|   DEBUG ((DEBUG_INFO,
 | |
|     "SecCoreStartupWithStack(0x%x, 0x%x)\n",
 | |
|     (UINT32)(UINTN)BootFv,
 | |
|     (UINT32)(UINTN)TopOfCurrentStack
 | |
|     ));
 | |
| 
 | |
|   //
 | |
|   // Initialize floating point operating environment
 | |
|   // to be compliant with UEFI spec.
 | |
|   //
 | |
|   InitializeFloatingPointUnits ();
 | |
| 
 | |
| #if defined (MDE_CPU_X64)
 | |
|   //
 | |
|   // ASSERT that the Page Tables were set by the reset vector code to
 | |
|   // the address we expect.
 | |
|   //
 | |
|   ASSERT (AsmReadCr3 () == (UINTN) PcdGet32 (PcdOvmfSecPageTablesBase));
 | |
| #endif
 | |
| 
 | |
|   //
 | |
|   // |-------------|       <-- TopOfCurrentStack
 | |
|   // |   Stack     | 32k
 | |
|   // |-------------|
 | |
|   // |    Heap     | 32k
 | |
|   // |-------------|       <-- SecCoreData.TemporaryRamBase
 | |
|   //
 | |
| 
 | |
|   ASSERT ((UINTN) (PcdGet32 (PcdOvmfSecPeiTempRamBase) +
 | |
|                    PcdGet32 (PcdOvmfSecPeiTempRamSize)) ==
 | |
|           (UINTN) TopOfCurrentStack);
 | |
| 
 | |
|   //
 | |
|   // Initialize SEC hand-off state
 | |
|   //
 | |
|   SecCoreData.DataSize = sizeof(EFI_SEC_PEI_HAND_OFF);
 | |
| 
 | |
|   SecCoreData.TemporaryRamSize       = (UINTN) PcdGet32 (PcdOvmfSecPeiTempRamSize);
 | |
|   SecCoreData.TemporaryRamBase       = (VOID*)((UINT8 *)TopOfCurrentStack - SecCoreData.TemporaryRamSize);
 | |
| 
 | |
|   SecCoreData.PeiTemporaryRamBase    = SecCoreData.TemporaryRamBase;
 | |
|   SecCoreData.PeiTemporaryRamSize    = SecCoreData.TemporaryRamSize >> 1;
 | |
| 
 | |
|   SecCoreData.StackBase              = (UINT8 *)SecCoreData.TemporaryRamBase + SecCoreData.PeiTemporaryRamSize;
 | |
|   SecCoreData.StackSize              = SecCoreData.TemporaryRamSize >> 1;
 | |
| 
 | |
|   SecCoreData.BootFirmwareVolumeBase = BootFv;
 | |
|   SecCoreData.BootFirmwareVolumeSize = (UINTN) BootFv->FvLength;
 | |
| 
 | |
|   //
 | |
|   // Make sure the 8259 is masked before initializing the Debug Agent and the debug timer is enabled
 | |
|   //
 | |
|   IoWrite8 (0x21, 0xff);
 | |
|   IoWrite8 (0xA1, 0xff);
 | |
| 
 | |
|   //
 | |
|   // Initialize Local APIC Timer hardware and disable Local APIC Timer
 | |
|   // interrupts before initializing the Debug Agent and the debug timer is
 | |
|   // enabled.
 | |
|   //
 | |
|   InitializeApicTimer (0, MAX_UINT32, TRUE, 5);
 | |
|   DisableApicTimerInterrupt ();
 | |
| 
 | |
|   //
 | |
|   // Initialize Debug Agent to support source level debug in SEC/PEI phases before memory ready.
 | |
|   //
 | |
|   InitializeDebugAgent (DEBUG_AGENT_INIT_PREMEM_SEC, &SecCoreData, SecStartupPhase2);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Caller provided function to be invoked at the end of InitializeDebugAgent().
 | |
| 
 | |
|   Entry point to the C language phase of SEC. After the SEC assembly
 | |
|   code has initialized some temporary memory and set up the stack,
 | |
|   the control is transferred to this function.
 | |
| 
 | |
|   @param[in] Context    The first input parameter of InitializeDebugAgent().
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| EFIAPI
 | |
| SecStartupPhase2(
 | |
|   IN VOID                     *Context
 | |
|   )
 | |
| {
 | |
|   EFI_SEC_PEI_HAND_OFF        *SecCoreData;
 | |
|   EFI_FIRMWARE_VOLUME_HEADER  *BootFv;
 | |
|   EFI_PEI_CORE_ENTRY_POINT    PeiCoreEntryPoint;
 | |
| 
 | |
|   SecCoreData = (EFI_SEC_PEI_HAND_OFF *) Context;
 | |
| 
 | |
|   //
 | |
|   // Find PEI Core entry point. It will report SEC and Pei Core debug information if remote debug
 | |
|   // is enabled.
 | |
|   //
 | |
|   BootFv = (EFI_FIRMWARE_VOLUME_HEADER *)SecCoreData->BootFirmwareVolumeBase;
 | |
|   FindAndReportEntryPoints (&BootFv, &PeiCoreEntryPoint);
 | |
|   SecCoreData->BootFirmwareVolumeBase = BootFv;
 | |
|   SecCoreData->BootFirmwareVolumeSize = (UINTN) BootFv->FvLength;
 | |
| 
 | |
|   //
 | |
|   // Transfer the control to the PEI core
 | |
|   //
 | |
|   (*PeiCoreEntryPoint) (SecCoreData, (EFI_PEI_PPI_DESCRIPTOR *)&mPrivateDispatchTable);
 | |
| 
 | |
|   //
 | |
|   // If we get here then the PEI Core returned, which is not recoverable.
 | |
|   //
 | |
|   ASSERT (FALSE);
 | |
|   CpuDeadLoop ();
 | |
| }
 | |
| 
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| TemporaryRamMigration (
 | |
|   IN CONST EFI_PEI_SERVICES   **PeiServices,
 | |
|   IN EFI_PHYSICAL_ADDRESS     TemporaryMemoryBase,
 | |
|   IN EFI_PHYSICAL_ADDRESS     PermanentMemoryBase,
 | |
|   IN UINTN                    CopySize
 | |
|   )
 | |
| {
 | |
|   IA32_DESCRIPTOR                  IdtDescriptor;
 | |
|   VOID                             *OldHeap;
 | |
|   VOID                             *NewHeap;
 | |
|   VOID                             *OldStack;
 | |
|   VOID                             *NewStack;
 | |
|   DEBUG_AGENT_CONTEXT_POSTMEM_SEC  DebugAgentContext;
 | |
|   BOOLEAN                          OldStatus;
 | |
|   BASE_LIBRARY_JUMP_BUFFER         JumpBuffer;
 | |
| 
 | |
|   DEBUG ((DEBUG_INFO,
 | |
|     "TemporaryRamMigration(0x%Lx, 0x%Lx, 0x%Lx)\n",
 | |
|     TemporaryMemoryBase,
 | |
|     PermanentMemoryBase,
 | |
|     (UINT64)CopySize
 | |
|     ));
 | |
| 
 | |
|   OldHeap = (VOID*)(UINTN)TemporaryMemoryBase;
 | |
|   NewHeap = (VOID*)((UINTN)PermanentMemoryBase + (CopySize >> 1));
 | |
| 
 | |
|   OldStack = (VOID*)((UINTN)TemporaryMemoryBase + (CopySize >> 1));
 | |
|   NewStack = (VOID*)(UINTN)PermanentMemoryBase;
 | |
| 
 | |
|   DebugAgentContext.HeapMigrateOffset = (UINTN)NewHeap - (UINTN)OldHeap;
 | |
|   DebugAgentContext.StackMigrateOffset = (UINTN)NewStack - (UINTN)OldStack;
 | |
| 
 | |
|   OldStatus = SaveAndSetDebugTimerInterrupt (FALSE);
 | |
|   InitializeDebugAgent (DEBUG_AGENT_INIT_POSTMEM_SEC, (VOID *) &DebugAgentContext, NULL);
 | |
| 
 | |
|   //
 | |
|   // Migrate Heap
 | |
|   //
 | |
|   CopyMem (NewHeap, OldHeap, CopySize >> 1);
 | |
| 
 | |
|   //
 | |
|   // Migrate Stack
 | |
|   //
 | |
|   CopyMem (NewStack, OldStack, CopySize >> 1);
 | |
| 
 | |
|   //
 | |
|   // Rebase IDT table in permanent memory
 | |
|   //
 | |
|   AsmReadIdtr (&IdtDescriptor);
 | |
|   IdtDescriptor.Base = IdtDescriptor.Base - (UINTN)OldStack + (UINTN)NewStack;
 | |
| 
 | |
|   AsmWriteIdtr (&IdtDescriptor);
 | |
| 
 | |
|   //
 | |
|   // Use SetJump()/LongJump() to switch to a new stack.
 | |
|   //
 | |
|   if (SetJump (&JumpBuffer) == 0) {
 | |
| #if defined (MDE_CPU_IA32)
 | |
|     JumpBuffer.Esp = JumpBuffer.Esp + DebugAgentContext.StackMigrateOffset;
 | |
|     JumpBuffer.Ebp = JumpBuffer.Ebp + DebugAgentContext.StackMigrateOffset;
 | |
| #endif
 | |
| #if defined (MDE_CPU_X64)
 | |
|     JumpBuffer.Rsp = JumpBuffer.Rsp + DebugAgentContext.StackMigrateOffset;
 | |
|     JumpBuffer.Rbp = JumpBuffer.Rbp + DebugAgentContext.StackMigrateOffset;
 | |
| #endif
 | |
|     LongJump (&JumpBuffer, (UINTN)-1);
 | |
|   }
 | |
| 
 | |
|   SaveAndSetDebugTimerInterrupt (OldStatus);
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 |