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;
 | 
						|
}
 | 
						|
 |