第一次进入 PEICORE 流程

WinDbg加载符号

复制代码
0: kd> .reload /i PEICORE=0x`820120
*** WARNING: Unable to verify timestamp for PEICORE
0: kd> lm
start    end        module name
00820120 0083b2e0   PEICORE  T (private pdb symbols)  D:\Code\edk2\Build\Ovmf3264\NOOPT_VS2022\IA32\MdeModulePkg\Core\Pei\PeiMain\DEBUG\PeiCore.pdb
fffcc094 fffe58f4   SECMAIN  T (private pdb symbols)  d:\code\edk2\build\ovmf3264\noopt_vs2022\ia32\ovmfpkg\sec\secmain\debug\SecMain.pdb

SEC -> PEI:

C 复制代码
VOID
EFIAPI
_ModuleEntryPoint (
  IN CONST  EFI_SEC_PEI_HAND_OFF    *SecCoreData,
  IN CONST  EFI_PEI_PPI_DESCRIPTOR  *PpiList
  )
{
  ProcessModuleEntryPointList (SecCoreData, PpiList, NULL);
  // Should never return
  //
  ASSERT (FALSE);
  CpuDeadLoop ();
}
C 复制代码
VOID
EFIAPI
ProcessModuleEntryPointList (
  IN CONST  EFI_SEC_PEI_HAND_OFF    *SecCoreData,
  IN CONST  EFI_PEI_PPI_DESCRIPTOR  *PpiList,
  IN VOID                           *Context
  )

{
  PeiCore (SecCoreData, PpiList, Context);
}

PeiCore:

C 复制代码
VOID
EFIAPI
PeiCore (
  IN CONST EFI_SEC_PEI_HAND_OFF    *SecCoreDataPtr,
  IN CONST EFI_PEI_PPI_DESCRIPTOR  *PpiList,
  IN VOID                          *Data
  )
{
  DEBUG((DEBUG_INFO,"\nEntryPeiCore\n\n"));
  __debugbreak();//008205e4
  PEI_CORE_INSTANCE               PrivateData;
  EFI_SEC_PEI_HAND_OFF            *SecCoreData;
  EFI_SEC_PEI_HAND_OFF            NewSecCoreData;
  EFI_STATUS                      Status;
  PEI_CORE_TEMP_POINTERS          TempPtr;
  PEI_CORE_INSTANCE               *OldCoreData;
  EFI_PEI_CPU_IO_PPI              *CpuIo;
  EFI_PEI_PCI_CFG2_PPI            *PciCfg;
  EFI_HOB_HANDOFF_INFO_TABLE      *HandoffInformationTable;
  EFI_PEI_TEMPORARY_RAM_DONE_PPI  *TemporaryRamDonePpi;
  UINTN                           Index;

  //
  // Retrieve context passed into PEI Core
  //
  OldCoreData = (PEI_CORE_INSTANCE *)Data;
  SecCoreData = (EFI_SEC_PEI_HAND_OFF *)SecCoreDataPtr;
 DEBUG((DEBUG_INFO,"SecCoreData @ %p\n",SecCoreData));
  
  //
  // Perform PEI Core phase specific actions.
  //
  if (OldCoreData == NULL) {
    //
    // If OldCoreData is NULL, means current is the first entry into the PEI Core before memory is available.
    //
    DEBUG((DEBUG_INFO,"OldData = Null\n"));
    DEBUG((DEBUG_INFO,"PrivateData @ %p, Size = %u (0x%x)\n",&PrivateData,sizeof(PEI_CORE_INSTANCE),sizeof(PEI_CORE_INSTANCE)));
    DEBUG((DEBUG_INFO,"PrivateData.ServiceTableShadow @ %p, Size = %u (0x%x)\n",&PrivateData.ServiceTableShadow,sizeof(PrivateData.ServiceTableShadow),sizeof(PrivateData.ServiceTableShadow)));
    DEBUG((DEBUG_INFO,"gPs @ %p, Size = %u (0x%x)\n",&gPs,sizeof(gPs),sizeof(gPs)));

    __debugbreak(); 
    ZeroMem (&PrivateData, sizeof (PEI_CORE_INSTANCE));
    //__debugbreak(); 
    PrivateData.Signature = PEI_CORE_HANDLE_SIGNATURE;
    CopyMem (&PrivateData.ServiceTableShadow, &gPs, sizeof (gPs));
    //__debugbreak(); 
  } else {
    //
    // Memory is available to the PEI Core.  See if the PEI Core has been shadowed to memory yet.
    //
    if (OldCoreData->ShadowedPeiCore == NULL) {
      //
      // Fixup the PeiCore's private data
      //
      OldCoreData->Ps    = &OldCoreData->ServiceTableShadow;
      OldCoreData->CpuIo = &OldCoreData->ServiceTableShadow.CpuIo;
      if (OldCoreData->HeapOffsetPositive) {
        OldCoreData->HobList.Raw = (VOID *)(OldCoreData->HobList.Raw + OldCoreData->HeapOffset);
        if (OldCoreData->UnknownFvInfo != NULL) {
          OldCoreData->UnknownFvInfo = (PEI_CORE_UNKNOW_FORMAT_FV_INFO *)((UINT8 *)OldCoreData->UnknownFvInfo + OldCoreData->HeapOffset);
        }

        if (OldCoreData->CurrentFvFileHandles != NULL) {
          OldCoreData->CurrentFvFileHandles = (EFI_PEI_FILE_HANDLE *)((UINT8 *)OldCoreData->CurrentFvFileHandles + OldCoreData->HeapOffset);
        }

        if (OldCoreData->PpiData.PpiList.PpiPtrs != NULL) {
          OldCoreData->PpiData.PpiList.PpiPtrs = (PEI_PPI_LIST_POINTERS *)((UINT8 *)OldCoreData->PpiData.PpiList.PpiPtrs + OldCoreData->HeapOffset);
        }

        if (OldCoreData->PpiData.CallbackNotifyList.NotifyPtrs != NULL) {
          OldCoreData->PpiData.CallbackNotifyList.NotifyPtrs = (PEI_PPI_LIST_POINTERS *)((UINT8 *)OldCoreData->PpiData.CallbackNotifyList.NotifyPtrs + OldCoreData->HeapOffset);
        }

        if (OldCoreData->PpiData.DispatchNotifyList.NotifyPtrs != NULL) {
          OldCoreData->PpiData.DispatchNotifyList.NotifyPtrs = (PEI_PPI_LIST_POINTERS *)((UINT8 *)OldCoreData->PpiData.DispatchNotifyList.NotifyPtrs + OldCoreData->HeapOffset);
        }

        OldCoreData->Fv = (PEI_CORE_FV_HANDLE *)((UINT8 *)OldCoreData->Fv + OldCoreData->HeapOffset);
        for (Index = 0; Index < OldCoreData->FvCount; Index++) {
          if (OldCoreData->Fv[Index].PeimState != NULL) {
            OldCoreData->Fv[Index].PeimState = (UINT8 *)OldCoreData->Fv[Index].PeimState + OldCoreData->HeapOffset;
          }

          if (OldCoreData->Fv[Index].FvFileHandles != NULL) {
            OldCoreData->Fv[Index].FvFileHandles = (EFI_PEI_FILE_HANDLE *)((UINT8 *)OldCoreData->Fv[Index].FvFileHandles + OldCoreData->HeapOffset);
          }
        }

        OldCoreData->TempFileGuid    = (EFI_GUID *)((UINT8 *)OldCoreData->TempFileGuid + OldCoreData->HeapOffset);
        OldCoreData->TempFileHandles = (EFI_PEI_FILE_HANDLE *)((UINT8 *)OldCoreData->TempFileHandles + OldCoreData->HeapOffset);
      } else {
        OldCoreData->HobList.Raw = (VOID *)(OldCoreData->HobList.Raw - OldCoreData->HeapOffset);
        if (OldCoreData->UnknownFvInfo != NULL) {
          OldCoreData->UnknownFvInfo = (PEI_CORE_UNKNOW_FORMAT_FV_INFO *)((UINT8 *)OldCoreData->UnknownFvInfo - OldCoreData->HeapOffset);
        }

        if (OldCoreData->CurrentFvFileHandles != NULL) {
          OldCoreData->CurrentFvFileHandles = (EFI_PEI_FILE_HANDLE *)((UINT8 *)OldCoreData->CurrentFvFileHandles - OldCoreData->HeapOffset);
        }

        if (OldCoreData->PpiData.PpiList.PpiPtrs != NULL) {
          OldCoreData->PpiData.PpiList.PpiPtrs = (PEI_PPI_LIST_POINTERS *)((UINT8 *)OldCoreData->PpiData.PpiList.PpiPtrs - OldCoreData->HeapOffset);
        }

        if (OldCoreData->PpiData.CallbackNotifyList.NotifyPtrs != NULL) {
          OldCoreData->PpiData.CallbackNotifyList.NotifyPtrs = (PEI_PPI_LIST_POINTERS *)((UINT8 *)OldCoreData->PpiData.CallbackNotifyList.NotifyPtrs - OldCoreData->HeapOffset);
        }

        if (OldCoreData->PpiData.DispatchNotifyList.NotifyPtrs != NULL) {
          OldCoreData->PpiData.DispatchNotifyList.NotifyPtrs = (PEI_PPI_LIST_POINTERS *)((UINT8 *)OldCoreData->PpiData.DispatchNotifyList.NotifyPtrs - OldCoreData->HeapOffset);
        }

        OldCoreData->Fv = (PEI_CORE_FV_HANDLE *)((UINT8 *)OldCoreData->Fv - OldCoreData->HeapOffset);
        for (Index = 0; Index < OldCoreData->FvCount; Index++) {
          if (OldCoreData->Fv[Index].PeimState != NULL) {
            OldCoreData->Fv[Index].PeimState = (UINT8 *)OldCoreData->Fv[Index].PeimState - OldCoreData->HeapOffset;
          }

          if (OldCoreData->Fv[Index].FvFileHandles != NULL) {
            OldCoreData->Fv[Index].FvFileHandles = (EFI_PEI_FILE_HANDLE *)((UINT8 *)OldCoreData->Fv[Index].FvFileHandles - OldCoreData->HeapOffset);
          }
        }

        OldCoreData->TempFileGuid    = (EFI_GUID *)((UINT8 *)OldCoreData->TempFileGuid - OldCoreData->HeapOffset);
        OldCoreData->TempFileHandles = (EFI_PEI_FILE_HANDLE *)((UINT8 *)OldCoreData->TempFileHandles - OldCoreData->HeapOffset);
      }

      // Force relocating the dispatch table
      OldCoreData->DelayedDispatchTable = NULL;

      //
      // Fixup for PeiService's address
      //
      SetPeiServicesTablePointer ((CONST EFI_PEI_SERVICES **)&OldCoreData->Ps);

      //
      // Initialize libraries that the PEI Core is linked against
      //
      ProcessLibraryConstructorList (NULL, (CONST EFI_PEI_SERVICES **)&OldCoreData->Ps);

      //
      // Update HandOffHob for new installed permanent memory
      //
      HandoffInformationTable = OldCoreData->HobList.HandoffInformationTable;
      if (OldCoreData->HeapOffsetPositive) {
        HandoffInformationTable->EfiEndOfHobList = HandoffInformationTable->EfiEndOfHobList + OldCoreData->HeapOffset;
      } else {
        HandoffInformationTable->EfiEndOfHobList = HandoffInformationTable->EfiEndOfHobList - OldCoreData->HeapOffset;
      }

      HandoffInformationTable->EfiMemoryTop        = OldCoreData->PhysicalMemoryBegin + OldCoreData->PhysicalMemoryLength;
      HandoffInformationTable->EfiMemoryBottom     = OldCoreData->PhysicalMemoryBegin;
      HandoffInformationTable->EfiFreeMemoryTop    = OldCoreData->FreePhysicalMemoryTop;
      HandoffInformationTable->EfiFreeMemoryBottom = HandoffInformationTable->EfiEndOfHobList + sizeof (EFI_HOB_GENERIC_HEADER);

      //
      // We need convert MemoryBaseAddress in memory allocation HOBs
      //
      ConvertMemoryAllocationHobs (OldCoreData);

      //
      // We need convert the PPI descriptor's pointer
      //
      ConvertPpiPointers (SecCoreData, OldCoreData);

      //
      // After the whole temporary memory is migrated, then we can allocate page in
      // permanent memory.
      //
      OldCoreData->PeiMemoryInstalled = TRUE;

      if (PcdGetBool (PcdMigrateTemporaryRamFirmwareVolumes)) {
        DEBUG ((DEBUG_VERBOSE, "Early Migration - PPI lists before temporary RAM evacuation:\n"));
        DumpPpiList (OldCoreData);

        //
        // Migrate installed content from Temporary RAM to Permanent RAM at this
        // stage when PEI core still runs from a cached location.
        // FVs that doesn't contain PEI_CORE should be migrated here.
        //
        EvacuateTempRam (OldCoreData, SecCoreData);

        DEBUG ((DEBUG_VERBOSE, "Early Migration - PPI lists after temporary RAM evacuation:\n"));
        DumpPpiList (OldCoreData);
      }

      //
      // Indicate that PeiCore reenter
      //
      OldCoreData->PeimDispatcherReenter = TRUE;

      if ((PcdGet64 (PcdLoadModuleAtFixAddressEnable) != 0) && (OldCoreData->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME)) {
        //
        // if Loading Module at Fixed Address is enabled, allocate the PEI code memory range usage bit map array.
        // Every bit in the array indicate the status of the corresponding memory page available or not
        //
        OldCoreData->PeiCodeMemoryRangeUsageBitMap = AllocateZeroPool (((PcdGet32 (PcdLoadFixAddressPeiCodePageNumber)>>6) + 1)*sizeof (UINT64));
      }

      //
      // Shadow PEI Core. When permanent memory is available, shadow
      // PEI Core and PEIMs to get high performance.
      //
      OldCoreData->ShadowedPeiCore = (PEICORE_FUNCTION_POINTER)(UINTN)PeiCore;
      if (PcdGetBool (PcdMigrateTemporaryRamFirmwareVolumes) ||
          ((HandoffInformationTable->BootMode == BOOT_ON_S3_RESUME) && PcdGetBool (PcdShadowPeimOnS3Boot)) ||
          ((HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME) && PcdGetBool (PcdShadowPeimOnBoot)))
      {
        OldCoreData->ShadowedPeiCore = ShadowPeiCore (OldCoreData);
      }

      //
      // PEI Core has now been shadowed to memory.  Restart PEI Core in memory.
      //
      OldCoreData->ShadowedPeiCore (SecCoreData, PpiList, OldCoreData);

      //
      // Should never reach here.
      //
      ASSERT (FALSE);
      CpuDeadLoop ();

      UNREACHABLE ();
    }

    //
    // Memory is available to the PEI Core and the PEI Core has been shadowed to memory.
    //
    CopyMem (&NewSecCoreData, SecCoreDataPtr, sizeof (NewSecCoreData));
    SecCoreData = &NewSecCoreData;

    CopyMem (&PrivateData, OldCoreData, sizeof (PrivateData));

    CpuIo  = (VOID *)PrivateData.ServiceTableShadow.CpuIo;
    PciCfg = (VOID *)PrivateData.ServiceTableShadow.PciCfg;

    CopyMem (&PrivateData.ServiceTableShadow, &gPs, sizeof (gPs));

    PrivateData.ServiceTableShadow.CpuIo  = CpuIo;
    PrivateData.ServiceTableShadow.PciCfg = PciCfg;
  }

  //
  // Cache a pointer to the PEI Services Table that is either in temporary memory or permanent memory
  //
  PrivateData.Ps = &PrivateData.ServiceTableShadow;

  //
  // Save PeiServicePointer so that it can be retrieved anywhere.
  //
  SetPeiServicesTablePointer ((CONST EFI_PEI_SERVICES **)&PrivateData.Ps);

  //
  // Initialize libraries that the PEI Core is linked against
  //
  //__debugbreak();
  ProcessLibraryConstructorList (NULL, (CONST EFI_PEI_SERVICES **)&PrivateData.Ps);

  //
  // Initialize PEI Core Services
  //
  InitializeMemoryServices (&PrivateData, SecCoreData, OldCoreData);

  //
  // Update performance measurements
  //
  if (OldCoreData == NULL) {
    PERF_EVENT ("SEC"); // Means the end of SEC phase.

    //
    // If first pass, start performance measurement.
    //
    PERF_CROSSMODULE_BEGIN ("PEI");
    PERF_INMODULE_BEGIN ("PreMem");
  } else {
    PERF_INMODULE_END ("PreMem");
    PERF_INMODULE_BEGIN ("PostMem");
  }

  //
  // Complete PEI Core Service initialization
  //
  InitializeSecurityServices (&PrivateData.Ps, OldCoreData);
  InitializeDispatcherData (&PrivateData, OldCoreData, SecCoreData);
  InitializeImageServices (&PrivateData, OldCoreData);

  //
  // Perform PEI Core Phase specific actions
  //
  if (OldCoreData == NULL) {
    //
    // Report Status Code EFI_SW_PC_INIT
    //
    REPORT_STATUS_CODE (
      EFI_PROGRESS_CODE,
      (EFI_SOFTWARE_PEI_CORE | EFI_SW_PC_INIT)
      );

    //
    // If SEC provided the PpiList, process it.
    //
    if (PpiList != NULL) {
      ProcessPpiListFromSec ((CONST EFI_PEI_SERVICES **)&PrivateData.Ps, PpiList);
    }
  } else {
    if (PcdGetBool (PcdMigrateTemporaryRamFirmwareVolumes)) {
      //
      // When PcdMigrateTemporaryRamFirmwareVolumes is TRUE, alway shadow all
      // PEIMs no matter the condition of PcdShadowPeimOnBoot and PcdShadowPeimOnS3Boot
      //
      DEBUG ((DEBUG_VERBOSE, "PPI lists before temporary RAM evacuation:\n"));
      DumpPpiList (&PrivateData);

      //
      // Migrate installed content from Temporary RAM to Permanent RAM
      // FVs containing PEI_CORE should be migrated here.
      //
      EvacuateTempRam (&PrivateData, SecCoreData);

      Status = PeiServicesInstallPpi (&mMigrateTempRamPpi);
      ASSERT_EFI_ERROR (Status);

      DEBUG ((DEBUG_VERBOSE, "PPI lists after temporary RAM evacuation:\n"));
      DumpPpiList (&PrivateData);
    }

    //
    // Try to locate Temporary RAM Done Ppi.
    //
    Status = PeiServicesLocatePpi (
               &gEfiTemporaryRamDonePpiGuid,
               0,
               NULL,
               (VOID **)&TemporaryRamDonePpi
               );
    if (!EFI_ERROR (Status)) {
      //
      // Disable the use of Temporary RAM after the transition from Temporary RAM to Permanent RAM is complete.
      //
      TemporaryRamDonePpi->TemporaryRamDone ();
    }

    //
    // Alert any listeners that there is permanent memory available
    //
    PERF_INMODULE_BEGIN ("DisMem");
    Status = PeiServicesInstallPpi (&mMemoryDiscoveredPpi);

    //
    // Process the Notify list and dispatch any notifies for the Memory Discovered PPI
    //
    ProcessDispatchNotifyList (&PrivateData);

    PERF_INMODULE_END ("DisMem");
  }

  //
  // Call PEIM dispatcher
  //
  PeiDispatcher (SecCoreData, &PrivateData);

  if (PrivateData.HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME) {
    //
    // Check if InstallPeiMemory service was called on non-S3 resume boot path.
    //
    ASSERT (PrivateData.PeiMemoryInstalled == TRUE);
  }

  //
  // Measure PEI Core execution time.
  //
  PERF_INMODULE_END ("PostMem");

  //
  // Lookup DXE IPL PPI
  //
  Status = PeiServicesLocatePpi (
             &gEfiDxeIplPpiGuid,
             0,
             NULL,
             (VOID **)&TempPtr.DxeIpl
             );
  ASSERT_EFI_ERROR (Status);

  if (EFI_ERROR (Status)) {
    //
    // Report status code to indicate DXE IPL PPI could not be found.
    //
    REPORT_STATUS_CODE (
      EFI_ERROR_CODE | EFI_ERROR_MAJOR,
      (EFI_SOFTWARE_PEI_CORE | EFI_SW_PEI_CORE_EC_DXEIPL_NOT_FOUND)
      );
    CpuDeadLoop ();
  }

  //
  // Enter DxeIpl to load Dxe core.
  //
  DEBUG ((DEBUG_INFO, "DXE IPL Entry\n"));
  Status = TempPtr.DxeIpl->Entry (
                             TempPtr.DxeIpl,
                             &PrivateData.Ps,
                             PrivateData.HobList
                             );
  //
  // Should never reach here.
  //
  ASSERT_EFI_ERROR (Status);
  CpuDeadLoop ();

  UNREACHABLE ();
}

PEI第一次进入

处理PeiServiceTable

此时OldCoreData传入的数据为NULL,进入分支

C 复制代码
if (OldCoreData == NULL) {
    //
    // If OldCoreData is NULL, means current is the first entry into the PEI Core before memory is available.
    //
    DEBUG((DEBUG_INFO,"OldData = Null\n"));
    DEBUG((DEBUG_INFO,"PrivateData @ %p, Size = %u (0x%x)\n",&PrivateData,sizeof(PEI_CORE_INSTANCE),sizeof(PEI_CORE_INSTANCE)));
    DEBUG((DEBUG_INFO,"PrivateData.ServiceTableShadow @ %p, Size = %u (0x%x)\n",&PrivateData.ServiceTableShadow,sizeof(PrivateData.ServiceTableShadow),sizeof(PrivateData.ServiceTableShadow)));
    DEBUG((DEBUG_INFO,"gPs @ %p, Size = %u (0x%x)\n",&gPs,sizeof(gPs),sizeof(gPs)));

    __debugbreak(); 
    ZeroMem (&PrivateData, sizeof (PEI_CORE_INSTANCE));
    //__debugbreak(); 
    PrivateData.Signature = PEI_CORE_HANDLE_SIGNATURE;
    CopyMem (&PrivateData.ServiceTableShadow, &gPs, sizeof (gPs));
    //__debugbreak(); 
  } else {

此分支把gPs中覆盖到PrivateData.ServiceTableShadow

gPs:


PrivateData.ServiceTableShadow:



缓存指向 PeiServiceTable的指针并保存

C 复制代码
  //
  // Cache a pointer to the PEI Services Table that is either in temporary memory or permanent memory
  //
  PrivateData.Ps = &PrivateData.ServiceTableShadow;

  //
  // Save PeiServicePointer so that it can be retrieved anywhere.
  //
  SetPeiServicesTablePointer ((CONST EFI_PEI_SERVICES **)&PrivateData.Ps);
C 复制代码
VOID
EFIAPI
SetPeiServicesTablePointer (
  IN CONST EFI_PEI_SERVICES  **PeiServicesTablePointer
  )
{
  IA32_DESCRIPTOR  Idtr;

  ASSERT (PeiServicesTablePointer != NULL);
  AsmReadIdtr (&Idtr);
  (*(UINTN *)(Idtr.Base - sizeof (UINTN))) = (UINTN)PeiServicesTablePointer;
}

初始化Pei链接库

需要重新初始化Debug串口和AcpiTimer

C 复制代码
ProcessLibraryConstructorList (NULL, (CONST EFI_PEI_SERVICES **)&PrivateData.Ps);
C 复制代码
VOID
EFIAPI
ProcessLibraryConstructorList (
  IN       EFI_PEI_FILE_HANDLE       FileHandle,
  IN CONST EFI_PEI_SERVICES          **PeiServices
  )
{
  EFI_STATUS  Status;
  Status = BaseDebugLibSerialPortConstructor ();
  ASSERT_RETURN_ERROR (Status);
  Status = AcpiTimerLibConstructor ();
  ASSERT_RETURN_ERROR (Status);
}

初始化内存服务

为后续内存服务准备数据并建立最小HOB链表

C 复制代码
  //
  // Initialize PEI Core Services
  //
  InitializeMemoryServices (&PrivateData, SecCoreData, OldCoreData);
C 复制代码
VOID
InitializeMemoryServices (
  IN PEI_CORE_INSTANCE           *PrivateData,
  IN CONST EFI_SEC_PEI_HAND_OFF  *SecCoreData,
  IN PEI_CORE_INSTANCE           *OldCoreData
  )
{
  PrivateData->SwitchStackSignal = FALSE;
  //
  // First entering PeiCore, following code will initialized some field
  // in PeiCore's private data according to hand off data from SEC core.
  //
  if (OldCoreData == NULL) {
    PrivateData->PeiMemoryInstalled = FALSE;
    PrivateData->HobList.Raw        = SecCoreData->PeiTemporaryRamBase;
    PeiCoreBuildHobHandoffInfoTable (
      BOOT_WITH_FULL_CONFIGURATION,
      (EFI_PHYSICAL_ADDRESS)(UINTN)SecCoreData->PeiTemporaryRamBase,
      (UINTN)SecCoreData->PeiTemporaryRamSize
      );
    //
    // Set Ps to point to ServiceTableShadow in Cache
    //
    PrivateData->Ps = &(PrivateData->ServiceTableShadow);
  }
  return;
}
C 复制代码
VOID
PeiCoreBuildHobHandoffInfoTable (
  IN EFI_BOOT_MODE         BootMode,
  IN EFI_PHYSICAL_ADDRESS  MemoryBegin,
  IN UINT64                MemoryLength
  )
{
  EFI_HOB_HANDOFF_INFO_TABLE  *Hob;
  EFI_HOB_GENERIC_HEADER      *HobEnd;

  Hob                   = (VOID *)(UINTN)MemoryBegin;
  HobEnd                = (EFI_HOB_GENERIC_HEADER *)(Hob+1);
  Hob->Header.HobType   = EFI_HOB_TYPE_HANDOFF;
  Hob->Header.HobLength = (UINT16)sizeof (EFI_HOB_HANDOFF_INFO_TABLE);
  Hob->Header.Reserved  = 0;

  HobEnd->HobType   = EFI_HOB_TYPE_END_OF_HOB_LIST;
  HobEnd->HobLength = (UINT16)sizeof (EFI_HOB_GENERIC_HEADER);
  HobEnd->Reserved  = 0;

  Hob->Version  = EFI_HOB_HANDOFF_TABLE_VERSION;
  Hob->BootMode = BootMode;

  Hob->EfiMemoryTop        = MemoryBegin + MemoryLength;
  Hob->EfiMemoryBottom     = MemoryBegin;
  Hob->EfiFreeMemoryTop    = MemoryBegin + MemoryLength;
  Hob->EfiFreeMemoryBottom = (EFI_PHYSICAL_ADDRESS)(UINTN)(HobEnd + 1);
  Hob->EfiEndOfHobList     = (EFI_PHYSICAL_ADDRESS)(UINTN)HobEnd;
}

PrivateData->Ps = &(PrivateData->ServiceTableShadow);看似与 PrivateData.Ps = &PrivateData.ServiceTableShadow;重复,实际是为了将全局副本里的指针预先填好,等搬到永久 RAM 后,成为全局映射

打时间戳

C 复制代码
  //
  // Update performance measurements
  //
  if (OldCoreData == NULL) {
    PERF_EVENT ("SEC"); // Means the end of SEC phase.

    //
    // If first pass, start performance measurement.
    //
    PERF_CROSSMODULE_BEGIN ("PEI");
    PERF_INMODULE_BEGIN ("PreMem");
  } else {
    PERF_INMODULE_END ("PreMem");
    PERF_INMODULE_BEGIN ("PostMem");
  }

初始化安全服务

C 复制代码
  InitializeSecurityServices (&PrivateData.Ps, OldCoreData);
C 复制代码
VOID
InitializeSecurityServices (
  IN EFI_PEI_SERVICES   **PeiServices,
  IN PEI_CORE_INSTANCE  *OldCoreData
  )
{
  if (OldCoreData == NULL) {
    PeiServicesNotifyPpi (&mNotifyList);
  }
  return;
}
C 复制代码
EFI_PEI_NOTIFY_DESCRIPTOR  mNotifyList = {
  EFI_PEI_PPI_DESCRIPTOR_NOTIFY_DISPATCH | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
  &gEfiPeiSecurity2PpiGuid,
  SecurityPpiNotifyCallback
};
C 复制代码
EFI_STATUS
EFIAPI
PeiServicesNotifyPpi (
  IN CONST EFI_PEI_NOTIFY_DESCRIPTOR  *NotifyList
  )
{
  CONST EFI_PEI_SERVICES  **PeiServices;
  PeiServices = GetPeiServicesTablePointer ();
  return (*PeiServices)->NotifyPpi (PeiServices, NotifyList);
}

获取 PeiServicesTable指针

C 复制代码
CONST EFI_PEI_SERVICES **
EFIAPI
GetPeiServicesTablePointer (
  VOID
  )
{
  CONST EFI_PEI_SERVICES  **PeiServices;
  IA32_DESCRIPTOR         Idtr;

  AsmReadIdtr (&Idtr);
  PeiServices = (CONST EFI_PEI_SERVICES **)(*(UINTN *)(Idtr.Base - sizeof (UINTN)));
  ASSERT (PeiServices != NULL);
  return PeiServices;
}

注册 Security2-PPI 上线回调(&mNotifyList)

C 复制代码
EFI_STATUS
EFIAPI
PeiNotifyPpi (
  IN CONST EFI_PEI_SERVICES           **PeiServices,
  IN CONST EFI_PEI_NOTIFY_DESCRIPTOR  *NotifyList
  )
{
  return InternalPeiNotifyPpi (PeiServices, NotifyList, FALSE);
}
C 复制代码
EFI_STATUS
InternalPeiNotifyPpi (
  IN CONST EFI_PEI_SERVICES           **PeiServices,
  IN CONST EFI_PEI_NOTIFY_DESCRIPTOR  *NotifyList,
  IN BOOLEAN                          Single
  )
{
  PEI_CORE_INSTANCE         *PrivateData;
  PEI_CALLBACK_NOTIFY_LIST  *CallbackNotifyListPointer;
  UINTN                     CallbackNotifyIndex;
  UINTN                     LastCallbackNotifyCount;
  PEI_DISPATCH_NOTIFY_LIST  *DispatchNotifyListPointer;
  UINTN                     DispatchNotifyIndex;
  UINTN                     LastDispatchNotifyCount;
  VOID                      *TempPtr;

  if (NotifyList == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);

  CallbackNotifyListPointer = &PrivateData->PpiData.CallbackNotifyList;
  CallbackNotifyIndex       = CallbackNotifyListPointer->CurrentCount;
  LastCallbackNotifyCount   = CallbackNotifyIndex;

  DispatchNotifyListPointer = &PrivateData->PpiData.DispatchNotifyList;
  DispatchNotifyIndex       = DispatchNotifyListPointer->CurrentCount;
  LastDispatchNotifyCount   = DispatchNotifyIndex;

  //
  // This is loop installs all Notify descriptors in the NotifyList.  It is
  // terminated by the EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST being set in the last
  // EFI_PEI_NOTIFY_DESCRIPTOR in the list.
  //

  for ( ; ;) {
    //
    // If some of the PPI data is invalid restore original Notify PPI database value
    //
    if ((NotifyList->Flags & EFI_PEI_PPI_DESCRIPTOR_NOTIFY_TYPES) == 0) {
      CallbackNotifyListPointer->CurrentCount = LastCallbackNotifyCount;
      DispatchNotifyListPointer->CurrentCount = LastDispatchNotifyCount;
      DEBUG ((DEBUG_ERROR, "ERROR -> NotifyPpi: %g %p\n", NotifyList->Guid, NotifyList->Notify));
      return EFI_INVALID_PARAMETER;
    }

    if ((NotifyList->Flags & EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK) != 0) {
      if (CallbackNotifyIndex >= CallbackNotifyListPointer->MaxCount) {
        //
        // Run out of room, grow the buffer.
        //
        TempPtr = AllocateZeroPool (
                    sizeof (PEI_PPI_LIST_POINTERS) * (CallbackNotifyListPointer->MaxCount + CALLBACK_NOTIFY_GROWTH_STEP)
                    );
        ASSERT (TempPtr != NULL);
        CopyMem (
          TempPtr,
          CallbackNotifyListPointer->NotifyPtrs,
          sizeof (PEI_PPI_LIST_POINTERS) * CallbackNotifyListPointer->MaxCount
          );
        CallbackNotifyListPointer->NotifyPtrs = TempPtr;
        CallbackNotifyListPointer->MaxCount   = CallbackNotifyListPointer->MaxCount + CALLBACK_NOTIFY_GROWTH_STEP;
      }

      CallbackNotifyListPointer->NotifyPtrs[CallbackNotifyIndex].Notify = (EFI_PEI_NOTIFY_DESCRIPTOR *)NotifyList;
      CallbackNotifyIndex++;
      CallbackNotifyListPointer->CurrentCount++;
    } else {
      if (DispatchNotifyIndex >= DispatchNotifyListPointer->MaxCount) {
        //
        // Run out of room, grow the buffer.
        //
        TempPtr = AllocateZeroPool (
                    sizeof (PEI_PPI_LIST_POINTERS) * (DispatchNotifyListPointer->MaxCount + DISPATCH_NOTIFY_GROWTH_STEP)
                    );
        ASSERT (TempPtr != NULL);
        CopyMem (
          TempPtr,
          DispatchNotifyListPointer->NotifyPtrs,
          sizeof (PEI_PPI_LIST_POINTERS) * DispatchNotifyListPointer->MaxCount
          );
        DispatchNotifyListPointer->NotifyPtrs = TempPtr;
        DispatchNotifyListPointer->MaxCount   = DispatchNotifyListPointer->MaxCount + DISPATCH_NOTIFY_GROWTH_STEP;
      }

      DispatchNotifyListPointer->NotifyPtrs[DispatchNotifyIndex].Notify = (EFI_PEI_NOTIFY_DESCRIPTOR *)NotifyList;
      DispatchNotifyIndex++;
      DispatchNotifyListPointer->CurrentCount++;
    }

    DEBUG ((DEBUG_INFO, "Register PPI Notify: %g\n", NotifyList->Guid));

    if (Single) {
      //
      // Only single entry in the NotifyList.
      //
      break;
    } else if ((NotifyList->Flags & EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST) ==
               EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST)
    {
      //
      // Continue until the end of the Notify List.
      //
      break;
    }

    //
    // Go to the next descriptor.
    //
    NotifyList++;
  }

  //
  // Process any callback level notifies for all previously installed PPIs.
  //
  ProcessNotify (
    PrivateData,
    EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK,
    0,
    PrivateData->PpiData.PpiList.CurrentCount,
    LastCallbackNotifyCount,
    CallbackNotifyListPointer->CurrentCount
    );

  return EFI_SUCCESS;
}

增加缓冲区

C 复制代码
VOID *
EFIAPI
AllocateZeroPool (
  IN UINTN  AllocationSize
  )
{
  VOID  *Memory;

  Memory = AllocatePool (AllocationSize);
  if (Memory != NULL) {
    Memory = ZeroMem (Memory, AllocationSize);
  }

  return Memory;
}
C 复制代码
VOID *
EFIAPI
AllocatePool (
  IN UINTN  AllocationSize
  )
{
  EFI_STATUS  Status;
  VOID        *Buffer;

  Status = PeiServicesAllocatePool (AllocationSize, &Buffer);
  if (EFI_ERROR (Status)) {
    Buffer = NULL;
  }

  return Buffer;
}
C 复制代码
EFI_STATUS
EFIAPI
PeiServicesAllocatePool (
  IN UINTN  Size,
  OUT VOID  **Buffer
  )
{
  CONST EFI_PEI_SERVICES  **PeiServices;

  PeiServices = GetPeiServicesTablePointer ();
  return (*PeiServices)->AllocatePool (PeiServices, Size, Buffer);
}

由return (*PeiServices)->AllocatePool (PeiServices, Size, Buffer);调用

C 复制代码
EFI_STATUS
EFIAPI
PeiAllocatePool (
  IN CONST EFI_PEI_SERVICES  **PeiServices,
  IN       UINTN             Size,
  OUT      VOID              **Buffer
  )
{
  EFI_STATUS           Status;
  EFI_HOB_MEMORY_POOL  *Hob;

  //
  // If some "post-memory" PEIM wishes to allocate larger pool,
  // it should use AllocatePages service instead.
  //

  //
  // Generally, the size of heap in temporary memory does not exceed 64K,
  // HobLength is multiples of 8 bytes, so the maximum size of pool is 0xFFF8 - sizeof (EFI_HOB_MEMORY_POOL)
  //
  if (Size > (0xFFF8 - sizeof (EFI_HOB_MEMORY_POOL))) {
    return EFI_OUT_OF_RESOURCES;
  }

  Status = PeiServicesCreateHob (
             EFI_HOB_TYPE_MEMORY_POOL,
             (UINT16)(sizeof (EFI_HOB_MEMORY_POOL) + Size),
             (VOID **)&Hob
             );
  if (EFI_ERROR (Status)) {
    *Buffer = NULL;
  } else {
    *Buffer = Hob + 1;
  }

  return Status;
}

创建HOB节点

C 复制代码
EFI_STATUS
EFIAPI
PeiServicesCreateHob (
  IN UINT16  Type,
  IN UINT16  Length,
  OUT VOID   **Hob
  )
{
  CONST EFI_PEI_SERVICES  **PeiServices;

  PeiServices = GetPeiServicesTablePointer ();
  return (*PeiServices)->CreateHob (PeiServices, Type, Length, Hob);
}

把通知指针整体替换到新缓冲区

C 复制代码
DispatchNotifyListPointer->NotifyPtrs = TempPtr;

处理回调级别通知(未有实际内容执行)

C 复制代码
  ProcessNotify (
    PrivateData,
    EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK,
    0,
    PrivateData->PpiData.PpiList.CurrentCount,
    LastCallbackNotifyCount,
    CallbackNotifyListPointer->CurrentCount
    );
C 复制代码
VOID
ProcessNotify (
  IN PEI_CORE_INSTANCE  *PrivateData,
  IN UINTN              NotifyType,
  IN INTN               InstallStartIndex,
  IN INTN               InstallStopIndex,
  IN INTN               NotifyStartIndex,
  IN INTN               NotifyStopIndex
  )
{
  INTN                       Index1;
  INTN                       Index2;
  EFI_GUID                   *SearchGuid;
  EFI_GUID                   *CheckGuid;
  EFI_PEI_NOTIFY_DESCRIPTOR  *NotifyDescriptor;

  for (Index1 = NotifyStartIndex; Index1 < NotifyStopIndex; Index1++) {
    if (NotifyType == EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK) {
      NotifyDescriptor = PrivateData->PpiData.CallbackNotifyList.NotifyPtrs[Index1].Notify;
    } else {
      NotifyDescriptor = PrivateData->PpiData.DispatchNotifyList.NotifyPtrs[Index1].Notify;
    }

    CheckGuid = NotifyDescriptor->Guid;

    for (Index2 = InstallStartIndex; Index2 < InstallStopIndex; Index2++) {
      SearchGuid = PrivateData->PpiData.PpiList.PpiPtrs[Index2].Ppi->Guid;
      //
      // Don't use CompareGuid function here for performance reasons.
      // Instead we compare the GUID as INT32 at a time and branch
      // on the first failed comparison.
      //
      if ((((INT32 *)SearchGuid)[0] == ((INT32 *)CheckGuid)[0]) &&
          (((INT32 *)SearchGuid)[1] == ((INT32 *)CheckGuid)[1]) &&
          (((INT32 *)SearchGuid)[2] == ((INT32 *)CheckGuid)[2]) &&
          (((INT32 *)SearchGuid)[3] == ((INT32 *)CheckGuid)[3]))
      {
        DEBUG ((
          DEBUG_INFO,
          "Notify: PPI Guid: %g, Peim notify entry point: %p\n",
          SearchGuid,
          NotifyDescriptor->Notify
          ));
        NotifyDescriptor->Notify (
                            (EFI_PEI_SERVICES **)GetPeiServicesTablePointer (),
                            NotifyDescriptor,
                            (PrivateData->PpiData.PpiList.PpiPtrs[Index2].Ppi)->Ppi
                            );
      }
    }
  }
}

初始化调度器数据

C 复制代码
 InitializeDispatcherData (&PrivateData, OldCoreData, SecCoreData);\
C 复制代码
VOID
InitializeDispatcherData (
  IN PEI_CORE_INSTANCE           *PrivateData,
  IN PEI_CORE_INSTANCE           *OldCoreData,
  IN CONST EFI_SEC_PEI_HAND_OFF  *SecCoreData
  )
{
  if (OldCoreData == NULL) {
    PrivateData->PeimDispatcherReenter = FALSE;
    PeiInitializeFv (PrivateData, SecCoreData);
  } else {
    PeiReinitializeFv (PrivateData);
  }

  return;
}

初始化 PeiCore FV列表

C 复制代码
VOID
PeiInitializeFv (
  IN  PEI_CORE_INSTANCE          *PrivateData,
  IN CONST EFI_SEC_PEI_HAND_OFF  *SecCoreData
  )
{
  EFI_STATUS                   Status;
  EFI_PEI_FIRMWARE_VOLUME_PPI  *FvPpi;
  EFI_PEI_FV_HANDLE            FvHandle;
  EFI_FIRMWARE_VOLUME_HEADER   *BfvHeader;

  //
  // Install FV_PPI for FFS2 file system.
  //
  PeiServicesInstallPpi (&mPeiFfs2FvPpiList);

  //
  // Install FV_PPI for FFS3 file system.
  //
  PeiServicesInstallPpi (&mPeiFfs3FvPpiList);

  BfvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)SecCoreData->BootFirmwareVolumeBase;

  //
  // The FV_PPI in BFV's format should be installed.
  //
  Status = PeiServicesLocatePpi (
             &BfvHeader->FileSystemGuid,
             0,
             NULL,
             (VOID **)&FvPpi
             );
  ASSERT_EFI_ERROR (Status);

  //
  // Get handle of BFV
  //
  Status = FvPpi->ProcessVolume (
                    FvPpi,
                    SecCoreData->BootFirmwareVolumeBase,
                    (UINTN)BfvHeader->FvLength,
                    &FvHandle
                    );
  ASSERT_EFI_ERROR (Status);

  PrivateData->Fv = AllocateZeroPool (sizeof (PEI_CORE_FV_HANDLE) * FV_GROWTH_STEP);
  ASSERT (PrivateData->Fv != NULL);
  PrivateData->MaxFvCount = FV_GROWTH_STEP;

  //
  // Update internal PEI_CORE_FV array.
  //
  PrivateData->Fv[PrivateData->FvCount].FvHeader             = BfvHeader;
  PrivateData->Fv[PrivateData->FvCount].FvPpi                = FvPpi;
  PrivateData->Fv[PrivateData->FvCount].FvHandle             = FvHandle;
  PrivateData->Fv[PrivateData->FvCount].AuthenticationStatus = 0;
  DEBUG ((
    DEBUG_INFO,
    "The %dth FV start address is 0x%11p, size is 0x%08x, handle is 0x%p\n",
    (UINT32)PrivateData->FvCount,
    (VOID *)BfvHeader,
    (UINT32)BfvHeader->FvLength,
    FvHandle
    ));
  PrivateData->FvCount++;

  //
  // Post a call-back for the FvInfoPPI and FvInfo2PPI services to expose
  // additional FVs to PeiCore.
  //
  Status = PeiServicesNotifyPpi (mNotifyOnFvInfoList);
  ASSERT_EFI_ERROR (Status);
}

为 FFS2 文件系统安装 FV PPI (&mPeiFfs2FvPpiList)

C 复制代码
EFI_PEI_PPI_DESCRIPTOR  mPeiFfs2FvPpiList = {
  (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
  &gEfiFirmwareFileSystem2Guid,
  &mPeiFfs2FwVol.Fv
};

获取 PeiServicesTable 指针

C 复制代码
EFI_STATUS
EFIAPI
PeiServicesInstallPpi (
  IN CONST EFI_PEI_PPI_DESCRIPTOR  *PpiList
  )
{
  CONST EFI_PEI_SERVICES  **PeiServices;

  PeiServices = GetPeiServicesTablePointer ();
  return (*PeiServices)->InstallPpi (PeiServices, PpiList);
}

安装 PPI

C 复制代码
EFI_STATUS
EFIAPI
PeiInstallPpi (
  IN CONST EFI_PEI_SERVICES        **PeiServices,
  IN CONST EFI_PEI_PPI_DESCRIPTOR  *PpiList
  )
{
  return InternalPeiInstallPpi (PeiServices, PpiList, FALSE);
}
C 复制代码
EFI_STATUS
InternalPeiInstallPpi (
  IN CONST EFI_PEI_SERVICES        **PeiServices,
  IN CONST EFI_PEI_PPI_DESCRIPTOR  *PpiList,
  IN BOOLEAN                       Single
  )
{
  PEI_CORE_INSTANCE  *PrivateData;
  PEI_PPI_LIST       *PpiListPointer;
  UINTN              Index;
  UINTN              LastCount;
  VOID               *TempPtr;

  if (PpiList == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);

  PpiListPointer = &PrivateData->PpiData.PpiList;
  Index          = PpiListPointer->CurrentCount;
  LastCount      = Index;

  //
  // This is loop installs all PPI descriptors in the PpiList.  It is terminated
  // by the EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST being set in the last
  // EFI_PEI_PPI_DESCRIPTOR in the list.
  //

  for ( ; ;) {
    //
    // Check if it is a valid PPI.
    // If not, rollback list to exclude all in this list.
    // Try to indicate which item failed.
    //
    if ((PpiList->Flags & EFI_PEI_PPI_DESCRIPTOR_PPI) == 0) {
      PpiListPointer->CurrentCount = LastCount;
      DEBUG ((DEBUG_ERROR, "ERROR -> InstallPpi: %g %p\n", PpiList->Guid, PpiList->Ppi));
      return EFI_INVALID_PARAMETER;
    }

    if (Index >= PpiListPointer->MaxCount) {
      //
      // Run out of room, grow the buffer.
      //
      TempPtr = AllocateZeroPool (
                  sizeof (PEI_PPI_LIST_POINTERS) * (PpiListPointer->MaxCount + PPI_GROWTH_STEP)
                  );
      ASSERT (TempPtr != NULL);
      CopyMem (
        TempPtr,
        PpiListPointer->PpiPtrs,
        sizeof (PEI_PPI_LIST_POINTERS) * PpiListPointer->MaxCount
        );
      PpiListPointer->PpiPtrs  = TempPtr;
      PpiListPointer->MaxCount = PpiListPointer->MaxCount + PPI_GROWTH_STEP;
    }

    DEBUG ((DEBUG_INFO, "Install PPI: %g\n", PpiList->Guid));
    PpiListPointer->PpiPtrs[Index].Ppi = (EFI_PEI_PPI_DESCRIPTOR *)PpiList;
    Index++;
    PpiListPointer->CurrentCount++;

    if (Single) {
      //
      // Only single entry in the PpiList.
      //
      break;
    } else if ((PpiList->Flags & EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST) ==
               EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST)
    {
      //
      // Continue until the end of the PPI List.
      //
      break;
    }

    //
    // Go to the next descriptor.
    //
    PpiList++;
  }

  //
  // Process any callback level notifies for newly installed PPIs.
  //
  ProcessNotify (
    PrivateData,
    EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK,
    LastCount,
    PpiListPointer->CurrentCount,
    0,
    PrivateData->PpiData.CallbackNotifyList.CurrentCount
    );

  return EFI_SUCCESS;
}

为 FFS3 文件系统安装 FV PPI (&mPeiFfs3FvPpiList)

内容与FFS2一致

设置BootFVHeader

C 复制代码
	BfvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)SecCoreData->BootFirmwareVolumeBase;

确认BFV的PPI是否被成功安装

C 复制代码
  Status = PeiServicesLocatePpi (
             &BfvHeader->FileSystemGuid,
             0,
             NULL,
             (VOID **)&FvPpi
             );
  ASSERT_EFI_ERROR (Status);
C 复制代码
EFI_STATUS
EFIAPI
PeiServicesLocatePpi (
  IN CONST EFI_GUID              *Guid,
  IN UINTN                       Instance,
  IN OUT EFI_PEI_PPI_DESCRIPTOR  **PpiDescriptor  OPTIONAL,
  IN OUT VOID                    **Ppi
  )
{
  CONST EFI_PEI_SERVICES  **PeiServices;
  PeiServices = GetPeiServicesTablePointer ();
  return (*PeiServices)->LocatePpi (PeiServices, Guid, Instance, PpiDescriptor, Ppi);
}
C 复制代码
EFI_STATUS
EFIAPI
PeiLocatePpi (
  IN CONST EFI_PEI_SERVICES      **PeiServices,
  IN CONST EFI_GUID              *Guid,
  IN UINTN                       Instance,
  IN OUT EFI_PEI_PPI_DESCRIPTOR  **PpiDescriptor,
  IN OUT VOID                    **Ppi
  )
{
  PEI_CORE_INSTANCE       *PrivateData;
  UINTN                   Index;
  EFI_GUID                *CheckGuid;
  EFI_PEI_PPI_DESCRIPTOR  *TempPtr;

  PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);

  //
  // Search the data base for the matching instance of the GUIDed PPI.
  //
  for (Index = 0; Index < PrivateData->PpiData.PpiList.CurrentCount; Index++) {
    TempPtr   = PrivateData->PpiData.PpiList.PpiPtrs[Index].Ppi;
    CheckGuid = TempPtr->Guid;

    //
    // Don't use CompareGuid function here for performance reasons.
    // Instead we compare the GUID as INT32 at a time and branch
    // on the first failed comparison.
    //
    if ((((INT32 *)Guid)[0] == ((INT32 *)CheckGuid)[0]) &&
        (((INT32 *)Guid)[1] == ((INT32 *)CheckGuid)[1]) &&
        (((INT32 *)Guid)[2] == ((INT32 *)CheckGuid)[2]) &&
        (((INT32 *)Guid)[3] == ((INT32 *)CheckGuid)[3]))
    {
      if (Instance == 0) {
        if (PpiDescriptor != NULL) {
          *PpiDescriptor = TempPtr;
        }
        if (Ppi != NULL) {
          *Ppi = TempPtr->Ppi;
        }
        return EFI_SUCCESS;
      }
      Instance--;
    }
  }
  return EFI_NOT_FOUND;
}

获取卷句柄FvHandle

C 复制代码
  //
  // Get handle of BFV
  //
  Status = FvPpi->ProcessVolume (
                    FvPpi,
                    SecCoreData->BootFirmwareVolumeBase,
                    (UINTN)BfvHeader->FvLength,
                    &FvHandle
                    );
  ASSERT_EFI_ERROR (Status);
C 复制代码
EFI_STATUS
EFIAPI
PeiFfsFvPpiProcessVolume (
  IN  CONST  EFI_PEI_FIRMWARE_VOLUME_PPI  *This,
  IN  VOID                                *Buffer,
  IN  UINTN                               BufferSize,
  OUT EFI_PEI_FV_HANDLE                   *FvHandle
  )
{
  EFI_STATUS  Status;

  ASSERT (FvHandle != NULL);

  if (Buffer == NULL) {
    return EFI_VOLUME_CORRUPTED;
  }

  //
  // The build-in EFI_PEI_FIRMWARE_VOLUME_PPI for FFS2/FFS3 support memory-mapped
  // FV image and the handle is pointed to FV image's buffer.
  //
  *FvHandle = (EFI_PEI_FV_HANDLE)Buffer;

  //
  // Do verify for given FV buffer.
  //
  Status = VerifyFv ((EFI_FIRMWARE_VOLUME_HEADER *)Buffer);
  if (EFI_ERROR (Status)) {
    DEBUG ((DEBUG_ERROR, "Fail to verify FV which address is 0x%11p", Buffer));
    return EFI_VOLUME_CORRUPTED;
  }

  return EFI_SUCCESS;
}

扩大pool更新FvCount=0的数据并计数增加

C 复制代码
  PrivateData->Fv = AllocateZeroPool (sizeof (PEI_CORE_FV_HANDLE) * FV_GROWTH_STEP);
  ASSERT (PrivateData->Fv != NULL);
  PrivateData->MaxFvCount = FV_GROWTH_STEP;
  //
  // Update internal PEI_CORE_FV array.
  //
  PrivateData->Fv[PrivateData->FvCount].FvHeader             = BfvHeader;
  PrivateData->Fv[PrivateData->FvCount].FvPpi                = FvPpi;
  PrivateData->Fv[PrivateData->FvCount].FvHandle             = FvHandle;
  PrivateData->Fv[PrivateData->FvCount].AuthenticationStatus = 0;
  DEBUG ((
    DEBUG_INFO,
    "The %dth FV start address is 0x%11p, size is 0x%08x, handle is 0x%p\n",
    (UINT32)PrivateData->FvCount,
    (VOID *)BfvHeader,
    (UINT32)BfvHeader->FvLength,
    FvHandle
    ));
  PrivateData->FvCount++;

注册 FV 信息上线回调 (mNotifyOnFvInfoList)

C 复制代码
EFI_PEI_NOTIFY_DESCRIPTOR  mNotifyOnFvInfoList[] = {
  {
    EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK,
    &gEfiPeiFirmwareVolumeInfoPpiGuid,
    FirmwareVolumeInfoPpiNotifyCallback
  },
  {
    (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
    &gEfiPeiFirmwareVolumeInfo2PpiGuid,
    FirmwareVolumeInfoPpiNotifyCallback
  }
};

与之前的List不同,是结构体数组,不需要写成&mNotifyOnFvInfoList

C 复制代码
  Status = PeiServicesNotifyPpi (mNotifyOnFvInfoList);
  ASSERT_EFI_ERROR (Status);

初始化映像服务

安装PEI文件加载PPI(&gPpiLoadFilePpiList)

C 复制代码
  InitializeImageServices (&PrivateData, OldCoreData);
C 复制代码
VOID
InitializeImageServices (
  IN  PEI_CORE_INSTANCE  *PrivateData,
  IN  PEI_CORE_INSTANCE  *OldCoreData
  )
{
  if (OldCoreData == NULL) {
    //
    // The first time we are XIP (running from FLASH). We need to remember the
    // FLASH address so we can reinstall the memory version that runs faster
    //
    PrivateData->XipLoadFile = &gPpiLoadFilePpiList;
    PeiServicesInstallPpi (PrivateData->XipLoadFile);
  } else {
    //
    // 2nd time we are running from memory so replace the XIP version with the
    // new memory version.
    //
    PeiServicesReInstallPpi (PrivateData->XipLoadFile, &gPpiLoadFilePpiList);
  }
}
C 复制代码
EFI_PEI_PPI_DESCRIPTOR  gPpiLoadFilePpiList = {
  (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
  &gEfiPeiLoadFilePpiGuid,
  &mPeiLoadImagePpi
};

报告状态码

C 复制代码
    REPORT_STATUS_CODE (
      EFI_PROGRESS_CODE,
      (EFI_SOFTWARE_PEI_CORE | EFI_SW_PC_INIT)
      );
C 复制代码
EFI_STATUS
EFIAPI
ReportStatusCode (
  IN EFI_STATUS_CODE_TYPE   Type,
  IN EFI_STATUS_CODE_VALUE  Value
  )
{
  return InternalReportStatusCode (Type, Value, 0, &gEfiCallerIdGuid, NULL);
}
C 复制代码
EFI_STATUS
InternalReportStatusCode (
  IN EFI_STATUS_CODE_TYPE   Type,
  IN EFI_STATUS_CODE_VALUE  Value,
  IN UINT32                 Instance,
  IN CONST EFI_GUID         *CallerId OPTIONAL,
  IN EFI_STATUS_CODE_DATA   *Data     OPTIONAL
  )
{
  CONST EFI_PEI_SERVICES  **PeiServices;
  EFI_STATUS              Status;

  if ((ReportProgressCodeEnabled () && (((Type) & EFI_STATUS_CODE_TYPE_MASK) == EFI_PROGRESS_CODE)) ||
      (ReportErrorCodeEnabled () && (((Type) & EFI_STATUS_CODE_TYPE_MASK) == EFI_ERROR_CODE)) ||
      (ReportDebugCodeEnabled () && (((Type) & EFI_STATUS_CODE_TYPE_MASK) == EFI_DEBUG_CODE)))
  {
    PeiServices = GetPeiServicesTablePointer ();
    Status      = (*PeiServices)->ReportStatusCode (
                                    PeiServices,
                                    Type,
                                    Value,
                                    Instance,
                                    (EFI_GUID *)CallerId,
                                    Data
                                    );
    if (Status == EFI_NOT_AVAILABLE_YET) {
      Status = OemHookStatusCodeInitialize ();
      if (!EFI_ERROR (Status)) {
        return OemHookStatusCodeReport (Type, Value, Instance, (EFI_GUID *)CallerId, Data);
      }
    }

    return Status;
  }

  return EFI_UNSUPPORTED;
}
C 复制代码
EFI_STATUS
EFIAPI
PeiReportStatusCode (
  IN CONST EFI_PEI_SERVICES      **PeiServices,
  IN EFI_STATUS_CODE_TYPE        CodeType,
  IN EFI_STATUS_CODE_VALUE       Value,
  IN UINT32                      Instance,
  IN CONST EFI_GUID              *CallerId,
  IN CONST EFI_STATUS_CODE_DATA  *Data OPTIONAL
  )
{
  EFI_STATUS                 Status;
  EFI_PEI_PROGRESS_CODE_PPI  *StatusCodePpi;

  //
  // Locate StatusCode Ppi.
  //
  Status = PeiServicesLocatePpi (
             &gEfiPeiStatusCodePpiGuid,
             0,
             NULL,
             (VOID **)&StatusCodePpi
             );

  if (!EFI_ERROR (Status)) {
    Status = StatusCodePpi->ReportStatusCode (
                              PeiServices,
                              CodeType,
                              Value,
                              Instance,
                              CallerId,
                              Data
                              );

    return Status;
  }

  return EFI_NOT_AVAILABLE_YET;
}

定位状态码PPI

C 复制代码
EFI_STATUS
EFIAPI
PeiServicesLocatePpi (
  IN CONST EFI_GUID              *Guid,
  IN UINTN                       Instance,
  IN OUT EFI_PEI_PPI_DESCRIPTOR  **PpiDescriptor  OPTIONAL,
  IN OUT VOID                    **Ppi
  )
{
  CONST EFI_PEI_SERVICES  **PeiServices;

  PeiServices = GetPeiServicesTablePointer ();
  return (*PeiServices)->LocatePpi (PeiServices, Guid, Instance, PpiDescriptor, Ppi);
}
C 复制代码
EFI_STATUS
EFIAPI
PeiLocatePpi (
  IN CONST EFI_PEI_SERVICES      **PeiServices,
  IN CONST EFI_GUID              *Guid,
  IN UINTN                       Instance,
  IN OUT EFI_PEI_PPI_DESCRIPTOR  **PpiDescriptor,
  IN OUT VOID                    **Ppi
  )
{
  PEI_CORE_INSTANCE       *PrivateData;
  UINTN                   Index;
  EFI_GUID                *CheckGuid;
  EFI_PEI_PPI_DESCRIPTOR  *TempPtr;

  PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);

  //
  // Search the data base for the matching instance of the GUIDed PPI.
  //
  for (Index = 0; Index < PrivateData->PpiData.PpiList.CurrentCount; Index++) {
    TempPtr   = PrivateData->PpiData.PpiList.PpiPtrs[Index].Ppi;
    CheckGuid = TempPtr->Guid;

    //
    // Don't use CompareGuid function here for performance reasons.
    // Instead we compare the GUID as INT32 at a time and branch
    // on the first failed comparison.
    //
    if ((((INT32 *)Guid)[0] == ((INT32 *)CheckGuid)[0]) &&
        (((INT32 *)Guid)[1] == ((INT32 *)CheckGuid)[1]) &&
        (((INT32 *)Guid)[2] == ((INT32 *)CheckGuid)[2]) &&
        (((INT32 *)Guid)[3] == ((INT32 *)CheckGuid)[3]))
    {
      if (Instance == 0) {
        if (PpiDescriptor != NULL) {
          *PpiDescriptor = TempPtr;
        }

        if (Ppi != NULL) {
          *Ppi = TempPtr->Ppi;
        }

        return EFI_SUCCESS;
      }

      Instance--;
    }
  }

  return EFI_NOT_FOUND;
}

没有定位到状态码PPI

通过 OEM Hook 状态代码库报告状态码

C 复制代码
    if (Status == EFI_NOT_AVAILABLE_YET) {
      Status = OemHookStatusCodeInitialize ();
      if (!EFI_ERROR (Status)) {
        return OemHookStatusCodeReport (Type, Value, Instance, (EFI_GUID *)CallerId, Data);
      }
    }

处理SEC提供的PpiList

C 复制代码
VOID
ProcessPpiListFromSec (
  IN CONST EFI_PEI_SERVICES        **PeiServices,
  IN CONST EFI_PEI_PPI_DESCRIPTOR  *PpiList
  )
{
  EFI_STATUS              Status;
  EFI_SEC_HOB_DATA_PPI    *SecHobDataPpi;
  EFI_HOB_GENERIC_HEADER  *SecHobList;

  for ( ; ;) {
    if ((PpiList->Flags & EFI_PEI_PPI_DESCRIPTOR_NOTIFY_TYPES) != 0) {
      //
      // It is a notification PPI.
      //
      Status = InternalPeiNotifyPpi (PeiServices, (CONST EFI_PEI_NOTIFY_DESCRIPTOR *)PpiList, TRUE);
      ASSERT_EFI_ERROR (Status);
    } else {
      //
      // It is a normal PPI.
      //
      Status = InternalPeiInstallPpi (PeiServices, PpiList, TRUE);
      ASSERT_EFI_ERROR (Status);
    }

    if ((PpiList->Flags & EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST) == EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST) {
      //
      // Continue until the end of the PPI List.
      //
      break;
    }

    PpiList++;
  }

  //
  // If the EFI_SEC_HOB_DATA_PPI is in the list of PPIs passed to the PEI entry point,
  // the PEI Foundation will call the GetHobs() member function and install all HOBs
  // returned into the HOB list. It does this after installing all PPIs passed from SEC
  // into the PPI database and before dispatching any PEIMs.
  //
  Status = PeiLocatePpi (PeiServices, &gEfiSecHobDataPpiGuid, 0, NULL, (VOID **)&SecHobDataPpi);
  if (!EFI_ERROR (Status)) {
    Status = SecHobDataPpi->GetHobs (SecHobDataPpi, &SecHobList);
    if (!EFI_ERROR (Status)) {
      Status = PeiInstallSecHobData (PeiServices, SecHobList);
      ASSERT_EFI_ERROR (Status);
    }
  }
}

判断PPI类型并注册回调或安装接口

C 复制代码
if ((PpiList->Flags & EFI_PEI_PPI_DESCRIPTOR_NOTIFY_TYPES) != 0) {
      //
      // It is a notification PPI.
      //
      Status = InternalPeiNotifyPpi (PeiServices, (CONST EFI_PEI_NOTIFY_DESCRIPTOR *)PpiList, TRUE);
      ASSERT_EFI_ERROR (Status);
    } else {
      //
      // It is a normal PPI.
      //
      Status = InternalPeiInstallPpi (PeiServices, PpiList, TRUE);
      ASSERT_EFI_ERROR (Status);
    }

定位SecHobDataPpi决定是否把数据块安装到HOB链表

C 复制代码
  Status = PeiLocatePpi (PeiServices, &gEfiSecHobDataPpiGuid, 0, NULL, (VOID **)&SecHobDataPpi);
  if (!EFI_ERROR (Status)) {
    Status = SecHobDataPpi->GetHobs (SecHobDataPpi, &SecHobList);
    if (!EFI_ERROR (Status)) {
      Status = PeiInstallSecHobData (PeiServices, SecHobList);
      ASSERT_EFI_ERROR (Status);
    }
  }

这里并没有在传递给 PEI 入口点的 PPI 列表中定位到SecHobDataPpi

调用PEIM调度器

C 复制代码
  PeiDispatcher (SecCoreData, &PrivateData);
C 复制代码
VOID
PeiDispatcher (
  IN CONST EFI_SEC_PEI_HAND_OFF  *SecCoreData,
  IN PEI_CORE_INSTANCE           *Private
  )
{
  EFI_STATUS              Status;
  UINT32                  Index1;
  UINT32                  Index2;
  CONST EFI_PEI_SERVICES  **PeiServices;
  EFI_PEI_FILE_HANDLE     PeimFileHandle;
  UINTN                   FvCount;
  UINTN                   PeimCount;
  UINT32                  AuthenticationState;
  EFI_PHYSICAL_ADDRESS    EntryPoint;
  EFI_PEIM_ENTRY_POINT2   PeimEntryPoint;
  UINTN                   SaveCurrentPeimCount;
  UINTN                   SaveCurrentFvCount;
  EFI_PEI_FILE_HANDLE     SaveCurrentFileHandle;
  EFI_FV_FILE_INFO        FvFileInfo;
  PEI_CORE_FV_HANDLE      *CoreFvHandle;
  EFI_HOB_GUID_TYPE       *GuidHob;
  UINT32                  TableSize;

  PeiServices    = (CONST EFI_PEI_SERVICES **)&Private->Ps;
  PeimEntryPoint = NULL;
  PeimFileHandle = NULL;
  EntryPoint     = 0;

  if (Private->DelayedDispatchTable == NULL) {
    GuidHob = GetFirstGuidHob (&gEfiDelayedDispatchTableGuid);
    if (GuidHob != NULL) {
      Private->DelayedDispatchTable = (DELAYED_DISPATCH_TABLE *)(GET_GUID_HOB_DATA (GuidHob));
    } else {
      TableSize                     = sizeof (DELAYED_DISPATCH_TABLE) + ((DELAYED_DISPATCH_MAX_ENTRIES - 1) * sizeof (DELAYED_DISPATCH_ENTRY));
      Private->DelayedDispatchTable = BuildGuidHob (&gEfiDelayedDispatchTableGuid, TableSize);
      if (Private->DelayedDispatchTable != NULL) {
        ZeroMem (Private->DelayedDispatchTable, TableSize);
        Status = PeiServicesInstallPpi (&mDelayedDispatchDesc);
        if (EFI_ERROR (Status)) {
          DEBUG ((DEBUG_ERROR, "%a Failed to install Delayed Dispatch PPI: %r!\n", __func__, Status));
          ASSERT_EFI_ERROR (Status);
        } else {
          Status = PeiServicesNotifyPpi (&mDelayedDispatchNotifyDesc);
          if (EFI_ERROR (Status)) {
            DEBUG ((DEBUG_ERROR, "%a Failed to notify Delayed Dispatch on End of Pei: %r!\n", __func__, Status));
            ASSERT_EFI_ERROR (Status);
          }
        }
      }
    }
  }

  if ((Private->PeiMemoryInstalled) &&
      (PcdGetBool (PcdMigrateTemporaryRamFirmwareVolumes) ||
       (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME) ||
       PcdGetBool (PcdShadowPeimOnS3Boot))
      )
  {
    //
    // Once real memory is available, shadow the RegisterForShadow modules. And meanwhile
    // update the modules' status from PEIM_STATE_REGISTER_FOR_SHADOW to PEIM_STATE_DONE.
    //
    SaveCurrentPeimCount  = Private->CurrentPeimCount;
    SaveCurrentFvCount    = Private->CurrentPeimFvCount;
    SaveCurrentFileHandle =  Private->CurrentFileHandle;

    for (Index1 = 0; Index1 < Private->FvCount; Index1++) {
      for (Index2 = 0; Index2 < Private->Fv[Index1].PeimCount; Index2++) {
        if (Private->Fv[Index1].PeimState[Index2] == PEIM_STATE_REGISTER_FOR_SHADOW) {
          PeimFileHandle              = Private->Fv[Index1].FvFileHandles[Index2];
          Private->CurrentFileHandle  = PeimFileHandle;
          Private->CurrentPeimFvCount = Index1;
          Private->CurrentPeimCount   = Index2;
          Status                      = PeiLoadImage (
                                          (CONST EFI_PEI_SERVICES **)&Private->Ps,
                                          PeimFileHandle,
                                          PEIM_STATE_REGISTER_FOR_SHADOW,
                                          &EntryPoint,
                                          &AuthenticationState
                                          );
          if (Status == EFI_SUCCESS) {
            //
            // PEIM_STATE_REGISTER_FOR_SHADOW move to PEIM_STATE_DONE
            //
            Private->Fv[Index1].PeimState[Index2]++;
            //
            // Call the PEIM entry point
            //
            PeimEntryPoint = (EFI_PEIM_ENTRY_POINT2)(UINTN)EntryPoint;

            PERF_START_IMAGE_BEGIN (PeimFileHandle);
            PeimEntryPoint (PeimFileHandle, (const EFI_PEI_SERVICES **)&Private->Ps);
            PERF_START_IMAGE_END (PeimFileHandle);
          }

          //
          // Process the Notify list and dispatch any notifies for
          // newly installed PPIs.
          //
          ProcessDispatchNotifyList (Private);
        }
      }
    }

    Private->CurrentFileHandle  = SaveCurrentFileHandle;
    Private->CurrentPeimFvCount = SaveCurrentFvCount;
    Private->CurrentPeimCount   = SaveCurrentPeimCount;
  }

  //
  // This is the main dispatch loop.  It will search known FVs for PEIMs and
  // attempt to dispatch them.  If any PEIM gets dispatched through a single
  // pass of the dispatcher, it will start over from the BFV again to see
  // if any new PEIMs dependencies got satisfied.  With a well ordered
  // FV where PEIMs are found in the order their dependencies are also
  // satisfied, this dispatcher should run only once.
  //
  do {
    //
    // In case that reenter PeiCore happens, the last pass record is still available.
    //
    if (!Private->PeimDispatcherReenter) {
      Private->PeimNeedingDispatch    = FALSE;
      Private->PeimDispatchOnThisPass = FALSE;
    } else {
      Private->PeimDispatcherReenter = FALSE;
    }

    for (FvCount = Private->CurrentPeimFvCount; FvCount < Private->FvCount; FvCount++) {
      CoreFvHandle = FindNextCoreFvHandle (Private, FvCount);
      ASSERT (CoreFvHandle != NULL);

      //
      // If the FV has corresponding EFI_PEI_FIRMWARE_VOLUME_PPI instance, then dispatch it.
      //
      if (CoreFvHandle->FvPpi == NULL) {
        continue;
      }

      Private->CurrentPeimFvCount = FvCount;

      if (Private->CurrentPeimCount == 0) {
        //
        // When going through each FV, at first, search Apriori file to
        // reorder all PEIMs to ensure the PEIMs in Apriori file to get
        // dispatch at first.
        //
        DiscoverPeimsAndOrderWithApriori (Private, CoreFvHandle);
      }

      //
      // Start to dispatch all modules within the current FV.
      //
      for (PeimCount = Private->CurrentPeimCount;
           PeimCount < Private->Fv[FvCount].PeimCount;
           PeimCount++)
      {
        Private->CurrentPeimCount = PeimCount;
        PeimFileHandle            = Private->CurrentFileHandle = Private->CurrentFvFileHandles[PeimCount];

        if (Private->Fv[FvCount].PeimState[PeimCount] == PEIM_STATE_NOT_DISPATCHED) {
          if (!DepexSatisfied (Private, PeimFileHandle, PeimCount)) {
            Private->PeimNeedingDispatch = TRUE;
          } else {
            Status = CoreFvHandle->FvPpi->GetFileInfo (CoreFvHandle->FvPpi, PeimFileHandle, &FvFileInfo);
            ASSERT_EFI_ERROR (Status);
            if (FvFileInfo.FileType == EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) {
              //
              // For FV type file, Produce new FvInfo PPI and FV HOB
              //
              Status = ProcessFvFile (Private, &Private->Fv[FvCount], PeimFileHandle);
              if (Status == EFI_SUCCESS) {
                //
                // PEIM_STATE_NOT_DISPATCHED move to PEIM_STATE_DISPATCHED
                //
                Private->Fv[FvCount].PeimState[PeimCount]++;
                Private->PeimDispatchOnThisPass = TRUE;
              } else {
                //
                // The related GuidedSectionExtraction/Decompress PPI for the
                // encapsulated FV image section may be installed in the rest
                // of this do-while loop, so need to make another pass.
                //
                Private->PeimNeedingDispatch = TRUE;
              }
            } else {
              //
              // For PEIM driver, Load its entry point
              //
              Status = PeiLoadImage (
                         PeiServices,
                         PeimFileHandle,
                         PEIM_STATE_NOT_DISPATCHED,
                         &EntryPoint,
                         &AuthenticationState
                         );
              if (Status == EFI_SUCCESS) {
                //
                // The PEIM has its dependencies satisfied, and its entry point
                // has been found, so invoke it.
                //
                PERF_START_IMAGE_BEGIN (PeimFileHandle);

                REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
                  EFI_PROGRESS_CODE,
                  (EFI_SOFTWARE_PEI_CORE | EFI_SW_PC_INIT_BEGIN),
                  (VOID *)(&PeimFileHandle),
                  sizeof (PeimFileHandle)
                  );

                Status = VerifyPeim (Private, CoreFvHandle->FvHandle, PeimFileHandle, AuthenticationState);
                if (Status != EFI_SECURITY_VIOLATION) {
                  //
                  // PEIM_STATE_NOT_DISPATCHED move to PEIM_STATE_DISPATCHED
                  //
                  Private->Fv[FvCount].PeimState[PeimCount]++;
                  //
                  // Call the PEIM entry point for PEIM driver
                  //
                  PeimEntryPoint = (EFI_PEIM_ENTRY_POINT2)(UINTN)EntryPoint;
                  PeimEntryPoint (PeimFileHandle, (const EFI_PEI_SERVICES **)PeiServices);
                  Private->PeimDispatchOnThisPass = TRUE;
                } else {
                  //
                  // The related GuidedSectionExtraction PPI for the
                  // signed PEIM image section may be installed in the rest
                  // of this do-while loop, so need to make another pass.
                  //
                  Private->PeimNeedingDispatch = TRUE;
                }

                REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
                  EFI_PROGRESS_CODE,
                  (EFI_SOFTWARE_PEI_CORE | EFI_SW_PC_INIT_END),
                  (VOID *)(&PeimFileHandle),
                  sizeof (PeimFileHandle)
                  );
                PERF_START_IMAGE_END (PeimFileHandle);
              }
            }

            PeiCheckAndSwitchStack (SecCoreData, Private);

            //
            // Process the Notify list and dispatch any notifies for
            // newly installed PPIs.
            //
            ProcessDispatchNotifyList (Private);

            //
            // Recheck SwitchStackSignal after ProcessDispatchNotifyList()
            // in case PeiInstallPeiMemory() is done in a callback with
            // EFI_PEI_PPI_DESCRIPTOR_NOTIFY_DISPATCH.
            //
            PeiCheckAndSwitchStack (SecCoreData, Private);

            if ((Private->PeiMemoryInstalled) && (Private->Fv[FvCount].PeimState[PeimCount] == PEIM_STATE_REGISTER_FOR_SHADOW) &&   \
                (PcdGetBool (PcdMigrateTemporaryRamFirmwareVolumes) ||
                 (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME) ||
                 PcdGetBool (PcdShadowPeimOnS3Boot))
                )
            {
              //
              // If memory is available we shadow images by default for performance reasons.
              // We call the entry point a 2nd time so the module knows it's shadowed.
              //
              // PERF_START (PeiServices, L"PEIM", PeimFileHandle, 0);
              if ((Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME) && !PcdGetBool (PcdShadowPeimOnBoot) &&
                  !PcdGetBool (PcdMigrateTemporaryRamFirmwareVolumes))
              {
                //
                // Load PEIM into Memory for Register for shadow PEIM.
                //
                Status = PeiLoadImage (
                           PeiServices,
                           PeimFileHandle,
                           PEIM_STATE_REGISTER_FOR_SHADOW,
                           &EntryPoint,
                           &AuthenticationState
                           );
                if (Status == EFI_SUCCESS) {
                  PeimEntryPoint = (EFI_PEIM_ENTRY_POINT2)(UINTN)EntryPoint;
                }
              }

              ASSERT (PeimEntryPoint != NULL);
              PeimEntryPoint (PeimFileHandle, (const EFI_PEI_SERVICES **)PeiServices);
              // PERF_END (PeiServices, L"PEIM", PeimFileHandle, 0);

              //
              // PEIM_STATE_REGISTER_FOR_SHADOW move to PEIM_STATE_DONE
              //
              Private->Fv[FvCount].PeimState[PeimCount]++;

              //
              // Process the Notify list and dispatch any notifies for
              // newly installed PPIs.
              //
              ProcessDispatchNotifyList (Private);
            }
          }
        }

        // Dispatch pending delalyed dispatch requests
        if (Private->DelayedDispatchTable != NULL) {
          if (DelayedDispatchDispatcher (Private->DelayedDispatchTable, NULL)) {
            ProcessDispatchNotifyList (Private);
          }
        }
      }

      //
      // Before walking through the next FV, we should set them to NULL/0 to
      // start at the beginning of the next FV.
      //
      Private->CurrentFileHandle    = NULL;
      Private->CurrentPeimCount     = 0;
      Private->CurrentFvFileHandles = NULL;
      Private->AprioriCount         = 0;
    }

    //
    // Before making another pass, we should set it to 0 to
    // go through all the FVs.
    //
    Private->CurrentPeimFvCount = 0;

    //
    // PeimNeedingDispatch being TRUE means we found a PEIM/FV that did not get
    //  dispatched. So we need to make another pass
    //
    // PeimDispatchOnThisPass being TRUE means we dispatched a PEIM/FV on this
    //  pass. If we did not dispatch a PEIM/FV there is no point in trying again
    //  as it will fail the next time too (nothing has changed).
    //
    // Also continue dispatch loop if there are outstanding delay-
    // dispatch registrations still running.
  } while ((Private->PeimNeedingDispatch && Private->PeimDispatchOnThisPass) ||
           (Private->DelayedDispatchTable->Count > 0));
}

从HOB链表里获取第一个匹配的GUID-HOB节点

C 复制代码
GuidHob = GetFirstGuidHob (&gEfiDelayedDispatchTableGuid);
C 复制代码
VOID *
EFIAPI
GetFirstGuidHob (
  IN CONST EFI_GUID  *Guid
  )
{
  VOID  *HobList;

  HobList = GetHobList ();
  return GetNextGuidHob (Guid, HobList);
}

获取HOB链表

C 复制代码
VOID *
EFIAPI
GetHobList (
  VOID
  )
{
  EFI_STATUS  Status;
  VOID        *HobList;

  Status = PeiServicesGetHobList (&HobList);
  ASSERT_EFI_ERROR (Status);
  ASSERT (HobList != NULL);

  return HobList;
}
C 复制代码
EFI_STATUS
EFIAPI
PeiServicesGetHobList (
  OUT VOID  **HobList
  )
{
  CONST EFI_PEI_SERVICES  **PeiServices;

  PeiServices = GetPeiServicesTablePointer ();
  return (*PeiServices)->GetHobList (PeiServices, HobList);
}
C 复制代码
EFI_STATUS
EFIAPI
PeiGetHobList (
  IN CONST EFI_PEI_SERVICES  **PeiServices,
  IN OUT VOID                **HobList
  )
{
  PEI_CORE_INSTANCE  *PrivateData;

  //
  // Only check this parameter in debug mode
  //

  DEBUG_CODE_BEGIN ();
  if (HobList == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  DEBUG_CODE_END ();

  PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);

  *HobList = PrivateData->HobList.Raw;

  return EFI_SUCCESS;
}

顺序遍历直到匹配(先节点type再GUID)

C 复制代码
VOID *
EFIAPI
GetNextGuidHob (
  IN CONST EFI_GUID  *Guid,
  IN CONST VOID      *HobStart
  )
{
  EFI_PEI_HOB_POINTERS  GuidHob;

  GuidHob.Raw = (UINT8 *)HobStart;
  while ((GuidHob.Raw = GetNextHob (EFI_HOB_TYPE_GUID_EXTENSION, GuidHob.Raw)) != NULL) {
    if (CompareGuid (Guid, &GuidHob.Guid->Name)) {
      break;
    }

    GuidHob.Raw = GET_NEXT_HOB (GuidHob);
  }

  return GuidHob.Raw;
}
C 复制代码
VOID *
EFIAPI
GetNextHob (
  IN UINT16      Type,
  IN CONST VOID  *HobStart
  )
{
  EFI_PEI_HOB_POINTERS  Hob;

  ASSERT (HobStart != NULL);

  Hob.Raw = (UINT8 *)HobStart;
  //
  // Parse the HOB list until end of list or matching type is found.
  //
  while (!END_OF_HOB_LIST (Hob)) {
    if (Hob.Header->HobType == Type) {
      return Hob.Raw;
    }

    Hob.Raw = GET_NEXT_HOB (Hob);
  }

  return NULL;
}

没有匹配到GUID-HOB节点

自定义GUID-HOB节点

C 复制代码
VOID *
EFIAPI
BuildGuidHob (
  IN CONST EFI_GUID  *Guid,
  IN UINTN           DataLength
  )
{
  EFI_HOB_GUID_TYPE  *Hob;

  //
  // Make sure Guid is valid
  //
  ASSERT (Guid != NULL);

  //
  // Make sure that data length is not too long.
  //
  ASSERT (DataLength <= (0xFFF8 - sizeof (EFI_HOB_GUID_TYPE)));

  Hob = InternalPeiCreateHob (EFI_HOB_TYPE_GUID_EXTENSION, (UINT16)(sizeof (EFI_HOB_GUID_TYPE) + DataLength));
  if (Hob == NULL) {
    return Hob;
  }

  CopyGuid (&Hob->Name, Guid);
  return Hob + 1;
}

创建节点

C 复制代码
VOID *
EFIAPI
InternalPeiCreateHob (
  IN UINT16  Type,
  IN UINT16  Length
  )
{
  EFI_STATUS  Status;
  VOID        *Hob;

  Status = PeiServicesCreateHob (Type, Length, &Hob);
  if (EFI_ERROR (Status)) {
    Hob = NULL;
  }

  //
  // Assume the process of HOB building is always successful.
  //
  ASSERT (Hob != NULL);
  return Hob;
}

复制GUID (16字节复制两次)

C 复制代码
GUID *
EFIAPI
CopyGuid (
  OUT GUID       *DestinationGuid,
  IN CONST GUID  *SourceGuid
  )
{
  WriteUnaligned64 (
    (UINT64 *)DestinationGuid,
    ReadUnaligned64 ((CONST UINT64 *)SourceGuid)
    );
  WriteUnaligned64 (
    (UINT64 *)DestinationGuid + 1,
    ReadUnaligned64 ((CONST UINT64 *)SourceGuid + 1)
    );
  return DestinationGuid;
}

安装延迟调度PPI(&mDelayedDispatchDesc)

PS:两次创建HOB节点

第一次创建自定义GUID-HOB 存"业务数据";第二次创建HOB 存"接口数组"

注册PEI结束时的回调 (&mDelayedDispatchNotifyDesc)

把之前因资源不足而推迟的 PEIM一次性补调度

尝试调度PEIMs

寻找FV实例

C 复制代码
PEI_CORE_FV_HANDLE *
FindNextCoreFvHandle (
  IN PEI_CORE_INSTANCE  *Private,
  IN UINTN              Instance
  )
{
  if (Instance >= Private->FvCount) {
    return NULL;
  }

  return &Private->Fv[Instance];
}

查找所有PEIMs并根据Apriori 文件排序

C 复制代码
VOID
DiscoverPeimsAndOrderWithApriori (
  IN  PEI_CORE_INSTANCE   *Private,
  IN  PEI_CORE_FV_HANDLE  *CoreFileHandle
  )
{
  EFI_STATUS                   Status;
  EFI_PEI_FILE_HANDLE          FileHandle;
  EFI_PEI_FILE_HANDLE          AprioriFileHandle;
  EFI_GUID                     *Apriori;
  UINTN                        Index;
  UINTN                        Index2;
  UINTN                        PeimIndex;
  UINTN                        PeimCount;
  EFI_GUID                     *Guid;
  EFI_PEI_FILE_HANDLE          *TempFileHandles;
  EFI_GUID                     *TempFileGuid;
  EFI_PEI_FIRMWARE_VOLUME_PPI  *FvPpi;
  EFI_FV_FILE_INFO             FileInfo;

  FvPpi = CoreFileHandle->FvPpi;

  //
  // Walk the FV and find all the PEIMs and the Apriori file.
  //
  AprioriFileHandle             = NULL;
  Private->CurrentFvFileHandles = NULL;
  Guid                          = NULL;

  //
  // If the current FV has been scanned, directly get its cached records.
  //
  if (CoreFileHandle->ScanFv) {
    Private->CurrentFvFileHandles = CoreFileHandle->FvFileHandles;
    return;
  }

  TempFileHandles = Private->TempFileHandles;
  TempFileGuid    = Private->TempFileGuid;

  //
  // Go ahead to scan this FV, get PeimCount and cache FileHandles within it to TempFileHandles.
  //
  PeimCount  = 0;
  FileHandle = NULL;
  do {
    Status = FvPpi->FindFileByType (FvPpi, PEI_CORE_INTERNAL_FFS_FILE_DISPATCH_TYPE, CoreFileHandle->FvHandle, &FileHandle);
    if (!EFI_ERROR (Status)) {
      if (PeimCount >= Private->TempPeimCount) {
        //
        // Run out of room, grow the buffer.
        //
        TempFileHandles = AllocatePool (
                            sizeof (EFI_PEI_FILE_HANDLE) * (Private->TempPeimCount + TEMP_FILE_GROWTH_STEP)
                            );
        ASSERT (TempFileHandles != NULL);
        CopyMem (
          TempFileHandles,
          Private->TempFileHandles,
          sizeof (EFI_PEI_FILE_HANDLE) * Private->TempPeimCount
          );
        Private->TempFileHandles = TempFileHandles;
        TempFileGuid             = AllocatePool (
                                     sizeof (EFI_GUID) * (Private->TempPeimCount + TEMP_FILE_GROWTH_STEP)
                                     );
        ASSERT (TempFileGuid != NULL);
        CopyMem (
          TempFileGuid,
          Private->TempFileGuid,
          sizeof (EFI_GUID) * Private->TempPeimCount
          );
        Private->TempFileGuid  = TempFileGuid;
        Private->TempPeimCount = Private->TempPeimCount + TEMP_FILE_GROWTH_STEP;
      }

      TempFileHandles[PeimCount++] = FileHandle;
    }
  } while (!EFI_ERROR (Status));

  DEBUG ((
    DEBUG_INFO,
    "%a(): Found 0x%x PEI FFS files in the %dth FV\n",
    __func__,
    PeimCount,
    Private->CurrentPeimFvCount
    ));

  if (PeimCount == 0) {
    //
    // No PEIM FFS file is found, set ScanFv flag and return.
    //
    CoreFileHandle->ScanFv = TRUE;
    return;
  }

  //
  // Record PeimCount, allocate buffer for PeimState and FvFileHandles.
  //
  CoreFileHandle->PeimCount = PeimCount;
  CoreFileHandle->PeimState = AllocateZeroPool (sizeof (UINT8) * PeimCount);
  ASSERT (CoreFileHandle->PeimState != NULL);
  CoreFileHandle->FvFileHandles = AllocateZeroPool (sizeof (EFI_PEI_FILE_HANDLE) * PeimCount);
  ASSERT (CoreFileHandle->FvFileHandles != NULL);

  //
  // Get Apriori File handle
  //
  Private->AprioriCount = 0;
  Status                = FvPpi->FindFileByName (FvPpi, &gPeiAprioriFileNameGuid, &CoreFileHandle->FvHandle, &AprioriFileHandle);
  if (!EFI_ERROR (Status) && (AprioriFileHandle != NULL)) {
    //
    // Read the Apriori file
    //
    Status = FvPpi->FindSectionByType (FvPpi, EFI_SECTION_RAW, AprioriFileHandle, (VOID **)&Apriori);
    if (!EFI_ERROR (Status)) {
      //
      // Calculate the number of PEIMs in the Apriori file
      //
      Status = FvPpi->GetFileInfo (FvPpi, AprioriFileHandle, &FileInfo);
      ASSERT_EFI_ERROR (Status);
      Private->AprioriCount = FileInfo.BufferSize;
      if (IS_SECTION2 (FileInfo.Buffer)) {
        Private->AprioriCount -= sizeof (EFI_COMMON_SECTION_HEADER2);
      } else {
        Private->AprioriCount -= sizeof (EFI_COMMON_SECTION_HEADER);
      }

      Private->AprioriCount /= sizeof (EFI_GUID);

      for (Index = 0; Index < PeimCount; Index++) {
        //
        // Make an array of file name GUIDs that matches the FileHandle array so we can convert
        // quickly from file name to file handle
        //
        Status = FvPpi->GetFileInfo (FvPpi, TempFileHandles[Index], &FileInfo);
        ASSERT_EFI_ERROR (Status);
        CopyMem (&TempFileGuid[Index], &FileInfo.FileName, sizeof (EFI_GUID));
      }

      //
      // Walk through TempFileGuid array to find out who is invalid PEIM GUID in Apriori file.
      // Add available PEIMs in Apriori file into FvFileHandles array.
      //
      Index = 0;
      for (Index2 = 0; Index2 < Private->AprioriCount; Index2++) {
        Guid = ScanGuid (TempFileGuid, PeimCount * sizeof (EFI_GUID), &Apriori[Index2]);
        if (Guid != NULL) {
          PeimIndex                              = ((UINTN)Guid - (UINTN)&TempFileGuid[0])/sizeof (EFI_GUID);
          CoreFileHandle->FvFileHandles[Index++] = TempFileHandles[PeimIndex];

          //
          // Since we have copied the file handle we can remove it from this list.
          //
          TempFileHandles[PeimIndex] = NULL;
        }
      }

      //
      // Update valid AprioriCount
      //
      Private->AprioriCount = Index;

      //
      // Add in any PEIMs not in the Apriori file
      //
      for (Index2 = 0; Index2 < PeimCount; Index2++) {
        if (TempFileHandles[Index2] != NULL) {
          CoreFileHandle->FvFileHandles[Index++] = TempFileHandles[Index2];
          TempFileHandles[Index2]                = NULL;
        }
      }

      ASSERT (Index == PeimCount);
    }
  } else {
    CopyMem (CoreFileHandle->FvFileHandles, TempFileHandles, sizeof (EFI_PEI_FILE_HANDLE) * PeimCount);
  }

  //
  // The current FV File Handles have been cached. So that we don't have to scan the FV again.
  // Instead, we can retrieve the file handles within this FV from cached records.
  //
  CoreFileHandle->ScanFv        = TRUE;
  Private->CurrentFvFileHandles = CoreFileHandle->FvFileHandles;
}
在指定的 FV 中查找符合特定类型的 PEIM 文件

为了容纳PEIM,为PEIM动态扩展两个缓冲区:Handle和GUID。

寻找Apriori文件并获取文件信息
寻找Apriori文件中的PEIMs
添加不在Apriori文件中的PEIMs

开始调度当前 FV 内的PEIMs。

C 复制代码
for (PeimCount = Private->CurrentPeimCount;
           PeimCount < Private->Fv[FvCount].PeimCount;
           PeimCount++)
      {
        Private->CurrentPeimCount = PeimCount;
        PeimFileHandle            = Private->CurrentFileHandle = Private->CurrentFvFileHandles[PeimCount];

        if (Private->Fv[FvCount].PeimState[PeimCount] == PEIM_STATE_NOT_DISPATCHED) {
          if (!DepexSatisfied (Private, PeimFileHandle, PeimCount)) {
            Private->PeimNeedingDispatch = TRUE;
          } else {
            Status = CoreFvHandle->FvPpi->GetFileInfo (CoreFvHandle->FvPpi, PeimFileHandle, &FvFileInfo);
            ASSERT_EFI_ERROR (Status);
            if (FvFileInfo.FileType == EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) {
              //
              // For FV type file, Produce new FvInfo PPI and FV HOB
              //
              Status = ProcessFvFile (Private, &Private->Fv[FvCount], PeimFileHandle);
              if (Status == EFI_SUCCESS) {
                //
                // PEIM_STATE_NOT_DISPATCHED move to PEIM_STATE_DISPATCHED
                //
                Private->Fv[FvCount].PeimState[PeimCount]++;
                Private->PeimDispatchOnThisPass = TRUE;
              } else {
                //
                // The related GuidedSectionExtraction/Decompress PPI for the
                // encapsulated FV image section may be installed in the rest
                // of this do-while loop, so need to make another pass.
                //
                Private->PeimNeedingDispatch = TRUE;
              }
            } else {
              //
              // For PEIM driver, Load its entry point
              //
              Status = PeiLoadImage (
                         PeiServices,
                         PeimFileHandle,
                         PEIM_STATE_NOT_DISPATCHED,
                         &EntryPoint,
                         &AuthenticationState
                         );
              if (Status == EFI_SUCCESS) {
                //
                // The PEIM has its dependencies satisfied, and its entry point
                // has been found, so invoke it.
                //
                PERF_START_IMAGE_BEGIN (PeimFileHandle);

                REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
                  EFI_PROGRESS_CODE,
                  (EFI_SOFTWARE_PEI_CORE | EFI_SW_PC_INIT_BEGIN),
                  (VOID *)(&PeimFileHandle),
                  sizeof (PeimFileHandle)
                  );

                Status = VerifyPeim (Private, CoreFvHandle->FvHandle, PeimFileHandle, AuthenticationState);
                if (Status != EFI_SECURITY_VIOLATION) {
                  //
                  // PEIM_STATE_NOT_DISPATCHED move to PEIM_STATE_DISPATCHED
                  //
                  Private->Fv[FvCount].PeimState[PeimCount]++;
                  //
                  // Call the PEIM entry point for PEIM driver
                  //
                  PeimEntryPoint = (EFI_PEIM_ENTRY_POINT2)(UINTN)EntryPoint;
                  PeimEntryPoint (PeimFileHandle, (const EFI_PEI_SERVICES **)PeiServices);
                  Private->PeimDispatchOnThisPass = TRUE;
                } else {
                  //
                  // The related GuidedSectionExtraction PPI for the
                  // signed PEIM image section may be installed in the rest
                  // of this do-while loop, so need to make another pass.
                  //
                  Private->PeimNeedingDispatch = TRUE;
                }

                REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
                  EFI_PROGRESS_CODE,
                  (EFI_SOFTWARE_PEI_CORE | EFI_SW_PC_INIT_END),
                  (VOID *)(&PeimFileHandle),
                  sizeof (PeimFileHandle)
                  );
                PERF_START_IMAGE_END (PeimFileHandle);
              }
            }

            PeiCheckAndSwitchStack (SecCoreData, Private);

            //
            // Process the Notify list and dispatch any notifies for
            // newly installed PPIs.
            //
            ProcessDispatchNotifyList (Private);

            //
            // Recheck SwitchStackSignal after ProcessDispatchNotifyList()
            // in case PeiInstallPeiMemory() is done in a callback with
            // EFI_PEI_PPI_DESCRIPTOR_NOTIFY_DISPATCH.
            //
            PeiCheckAndSwitchStack (SecCoreData, Private);

            if ((Private->PeiMemoryInstalled) && (Private->Fv[FvCount].PeimState[PeimCount] == PEIM_STATE_REGISTER_FOR_SHADOW) &&   \
                (PcdGetBool (PcdMigrateTemporaryRamFirmwareVolumes) ||
                 (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME) ||
                 PcdGetBool (PcdShadowPeimOnS3Boot))
                )
            {
              //
              // If memory is available we shadow images by default for performance reasons.
              // We call the entry point a 2nd time so the module knows it's shadowed.
              //
              // PERF_START (PeiServices, L"PEIM", PeimFileHandle, 0);
              if ((Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME) && !PcdGetBool (PcdShadowPeimOnBoot) &&
                  !PcdGetBool (PcdMigrateTemporaryRamFirmwareVolumes))
              {
                //
                // Load PEIM into Memory for Register for shadow PEIM.
                //
                Status = PeiLoadImage (
                           PeiServices,
                           PeimFileHandle,
                           PEIM_STATE_REGISTER_FOR_SHADOW,
                           &EntryPoint,
                           &AuthenticationState
                           );
                if (Status == EFI_SUCCESS) {
                  PeimEntryPoint = (EFI_PEIM_ENTRY_POINT2)(UINTN)EntryPoint;
                }
              }

              ASSERT (PeimEntryPoint != NULL);
              PeimEntryPoint (PeimFileHandle, (const EFI_PEI_SERVICES **)PeiServices);
              // PERF_END (PeiServices, L"PEIM", PeimFileHandle, 0);

              //
              // PEIM_STATE_REGISTER_FOR_SHADOW move to PEIM_STATE_DONE
              //
              Private->Fv[FvCount].PeimState[PeimCount]++;

              //
              // Process the Notify list and dispatch any notifies for
              // newly installed PPIs.
              //
              ProcessDispatchNotifyList (Private);
            }
          }
        }

        // Dispatch pending delalyed dispatch requests
        if (Private->DelayedDispatchTable != NULL) {
          if (DelayedDispatchDispatcher (Private->DelayedDispatchTable, NULL)) {
            ProcessDispatchNotifyList (Private);
          }
        }
      }
加载PEIM进入点
C 复制代码
EFI_STATUS
PeiLoadImage (
  IN     CONST EFI_PEI_SERVICES  **PeiServices,
  IN     EFI_PEI_FILE_HANDLE     FileHandle,
  IN     UINT8                   PeimState,
  OUT    EFI_PHYSICAL_ADDRESS    *EntryPoint,
  OUT    UINT32                  *AuthenticationState
  )
{
  EFI_STATUS             PpiStatus;
  EFI_STATUS             Status;
  UINTN                  Index;
  EFI_PEI_LOAD_FILE_PPI  *LoadFile;
  EFI_PHYSICAL_ADDRESS   ImageAddress;
  UINT64                 ImageSize;
  BOOLEAN                IsStrip;

  IsStrip = FALSE;
  //
  // If any instances of PEI_LOAD_FILE_PPI are installed, they are called.
  // one at a time, until one reports EFI_SUCCESS.
  //
  Index = 0;
  do {
    PpiStatus = PeiServicesLocatePpi (
                  &gEfiPeiLoadFilePpiGuid,
                  Index,
                  NULL,
                  (VOID **)&LoadFile
                  );
    if (!EFI_ERROR (PpiStatus)) {
      Status = LoadFile->LoadFile (
                           LoadFile,
                           FileHandle,
                           &ImageAddress,
                           &ImageSize,
                           EntryPoint,
                           AuthenticationState
                           );
      if (!EFI_ERROR (Status) || (Status == EFI_WARN_BUFFER_TOO_SMALL)) {
        //
        // The shadowed PEIM must be relocatable.
        //
        if (PeimState == PEIM_STATE_REGISTER_FOR_SHADOW) {
          IsStrip = RelocationIsStrip ((VOID *)(UINTN)ImageAddress);
          ASSERT (!IsStrip);
          if (IsStrip) {
            return EFI_UNSUPPORTED;
          }
        }

        //
        // The image to be started must have the machine type supported by PeiCore.
        //
        ASSERT (EFI_IMAGE_MACHINE_TYPE_SUPPORTED (PeCoffLoaderGetMachineType ((VOID *)(UINTN)ImageAddress)));
        if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (PeCoffLoaderGetMachineType ((VOID *)(UINTN)ImageAddress))) {
          return EFI_UNSUPPORTED;
        }

        return EFI_SUCCESS;
      }
    }

    Index++;
  } while (!EFI_ERROR (PpiStatus));

  return PpiStatus;
}
C 复制代码
EFI_STATUS
EFIAPI
PeiLoadImageLoadImageWrapper (
  IN     CONST EFI_PEI_LOAD_FILE_PPI  *This,
  IN     EFI_PEI_FILE_HANDLE          FileHandle,
  OUT    EFI_PHYSICAL_ADDRESS         *ImageAddressArg   OPTIONAL,
  OUT    UINT64                       *ImageSizeArg      OPTIONAL,
  OUT    EFI_PHYSICAL_ADDRESS         *EntryPoint,
  OUT    UINT32                       *AuthenticationState
  )
{
  return PeiLoadImageLoadImage (
           GetPeiServicesTablePointer (),
           FileHandle,
           ImageAddressArg,
           ImageSizeArg,
           EntryPoint,
           AuthenticationState
           );
}
C 复制代码
EFI_STATUS
PeiLoadImageLoadImage (
  IN     CONST EFI_PEI_SERVICES  **PeiServices,
  IN     EFI_PEI_FILE_HANDLE     FileHandle,
  OUT    EFI_PHYSICAL_ADDRESS    *ImageAddressArg   OPTIONAL,
  OUT    UINT64                  *ImageSizeArg      OPTIONAL,
  OUT    EFI_PHYSICAL_ADDRESS    *EntryPoint,
  OUT    UINT32                  *AuthenticationState
  )
{
  EFI_STATUS            Status;
  VOID                  *Pe32Data;
  EFI_PHYSICAL_ADDRESS  ImageAddress;
  UINT64                ImageSize;
  EFI_PHYSICAL_ADDRESS  ImageEntryPoint;
  UINT16                Machine;
  EFI_SECTION_TYPE      SearchType1;
  EFI_SECTION_TYPE      SearchType2;
  CHAR8                 *AsciiString;
  CHAR8                 EfiFileName[512];
  UINTN                 Index;
  UINTN                 StartIndex;

  *EntryPoint          = 0;
  ImageSize            = 0;
  *AuthenticationState = 0;

  if (FeaturePcdGet (PcdPeiCoreImageLoaderSearchTeSectionFirst)) {
    SearchType1 = EFI_SECTION_TE;
    SearchType2 = EFI_SECTION_PE32;
  } else {
    SearchType1 = EFI_SECTION_PE32;
    SearchType2 = EFI_SECTION_TE;
  }

  //
  // Try to find a first exe section (if PcdPeiCoreImageLoaderSearchTeSectionFirst
  // is true, TE will be searched first).
  //
  Status = PeiServicesFfsFindSectionData3 (
             SearchType1,
             0,
             FileHandle,
             &Pe32Data,
             AuthenticationState
             );
  //
  // If we didn't find a first exe section, try to find the second exe section.
  //
  if (EFI_ERROR (Status)) {
    Status = PeiServicesFfsFindSectionData3 (
               SearchType2,
               0,
               FileHandle,
               &Pe32Data,
               AuthenticationState
               );
    if (EFI_ERROR (Status)) {
      //
      // PEI core only carry the loader function for TE and PE32 executables
      // If this two section does not exist, just return.
      //
      return Status;
    }
  }

  DEBUG ((DEBUG_INFO, "Loading PEIM %g\n", FileHandle));

  //
  // If memory is installed, perform the shadow operations
  //
  Status = LoadAndRelocatePeCoffImage (
             FileHandle,
             Pe32Data,
             &ImageAddress,
             &ImageSize,
             &ImageEntryPoint
             );

  if (EFI_ERROR (Status)) {
    return Status;
  }

  //
  // Got the entry point from the loaded Pe32Data
  //
  Pe32Data    = (VOID *)((UINTN)ImageAddress);
  *EntryPoint = ImageEntryPoint;

  Machine = PeCoffLoaderGetMachineType (Pe32Data);

  if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Machine)) {
    if (!EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED (Machine)) {
      return EFI_UNSUPPORTED;
    }
  }

  if (ImageAddressArg != NULL) {
    *ImageAddressArg = ImageAddress;
  }

  if (ImageSizeArg != NULL) {
    *ImageSizeArg = ImageSize;
  }

  //
  // Print debug message: Loading PEIM at 0x12345678 EntryPoint=0x12345688 Driver.efi
  //
  if (Machine != EFI_IMAGE_MACHINE_IA64) {
    DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Loading PEIM at 0x%11p EntryPoint=0x%11p ", (VOID *)(UINTN)ImageAddress, (VOID *)(UINTN)*EntryPoint));
  } else {
    //
    // For IPF Image, the real entry point should be print.
    //
    DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Loading PEIM at 0x%11p EntryPoint=0x%11p ", (VOID *)(UINTN)ImageAddress, (VOID *)(UINTN)(*(UINT64 *)(UINTN)*EntryPoint)));
  }

  //
  // Print Module Name by PeImage PDB file name.
  //
  AsciiString = PeCoffLoaderGetPdbPointer (Pe32Data);

  if (AsciiString != NULL) {
    StartIndex = 0;
    for (Index = 0; AsciiString[Index] != 0; Index++) {
      if ((AsciiString[Index] == '\\') || (AsciiString[Index] == '/')) {
        StartIndex = Index + 1;
      }
    }

    //
    // Copy the PDB file name to our temporary string, and replace .pdb with .efi
    // The PDB file name is limited in the range of 0~511.
    // If the length is bigger than 511, trim the redundant characters to avoid overflow in array boundary.
    //
    for (Index = 0; Index < sizeof (EfiFileName) - 4; Index++) {
      EfiFileName[Index] = AsciiString[Index + StartIndex];
      if (EfiFileName[Index] == 0) {
        EfiFileName[Index] = '.';
      }

      if (EfiFileName[Index] == '.') {
        EfiFileName[Index + 1] = 'e';
        EfiFileName[Index + 2] = 'f';
        EfiFileName[Index + 3] = 'i';
        EfiFileName[Index + 4] = 0;
        break;
      }
    }

    if (Index == sizeof (EfiFileName) - 4) {
      EfiFileName[Index] = 0;
    }

    DEBUG ((DEBUG_INFO | DEBUG_LOAD, "%a", EfiFileName));
  }

  DEBUG ((DEBUG_INFO | DEBUG_LOAD, "\n"));

  return EFI_SUCCESS;
}
C 复制代码
EFI_STATUS
EFIAPI
PeiServicesFfsFindSectionData3 (
  IN EFI_SECTION_TYPE     SectionType,
  IN UINTN                SectionInstance,
  IN EFI_PEI_FILE_HANDLE  FileHandle,
  OUT VOID                **SectionData,
  OUT UINT32              *AuthenticationStatus
  )
{
  CONST EFI_PEI_SERVICES  **PeiServices;

  PeiServices = GetPeiServicesTablePointer ();
  return (*PeiServices)->FindSectionData3 (PeiServices, SectionType, SectionInstance, FileHandle, SectionData, AuthenticationStatus);
}
* 尝试找第一个可执行段类型(PEIM 的入口映像)
C 复制代码
EFI_STATUS
EFIAPI
PeiFfsFindSectionData3 (
  IN CONST EFI_PEI_SERVICES   **PeiServices,
  IN     EFI_SECTION_TYPE     SectionType,
  IN     UINTN                SectionInstance,
  IN     EFI_PEI_FILE_HANDLE  FileHandle,
  OUT VOID                    **SectionData,
  OUT UINT32                  *AuthenticationStatus
  )
{
  PEI_CORE_FV_HANDLE  *CoreFvHandle;

  CoreFvHandle = FileHandleToVolume (FileHandle);
  if ((CoreFvHandle == NULL) || (CoreFvHandle->FvPpi == NULL)) {
    return EFI_NOT_FOUND;
  }

  if ((CoreFvHandle->FvPpi->Signature == EFI_PEI_FIRMWARE_VOLUME_PPI_SIGNATURE) &&
      (CoreFvHandle->FvPpi->Revision == EFI_PEI_FIRMWARE_VOLUME_PPI_REVISION))
  {
    return CoreFvHandle->FvPpi->FindSectionByType2 (CoreFvHandle->FvPpi, SectionType, SectionInstance, FileHandle, SectionData, AuthenticationStatus);
  }

  //
  // The old FvPpi doesn't support to find section by section instance
  // and return authentication status, so return EFI_UNSUPPORTED.
  //
  return EFI_UNSUPPORTED;
}
C 复制代码
PEI_CORE_FV_HANDLE *
FileHandleToVolume (
  IN   EFI_PEI_FILE_HANDLE  FileHandle
  )
{
  UINTN                       Index;
  PEI_CORE_INSTANCE           *PrivateData;
  EFI_FIRMWARE_VOLUME_HEADER  *FwVolHeader;
  UINTN                       BestIndex;

  PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (GetPeiServicesTablePointer ());
  BestIndex   = PrivateData->FvCount;

  //
  // Find the best matched FV image that includes this FileHandle.
  // FV may include the child FV, and they are in the same continuous space.
  // If FileHandle is from the child FV, the updated logic can find its matched FV.
  //
  for (Index = 0; Index < PrivateData->FvCount; Index++) {
    FwVolHeader = PrivateData->Fv[Index].FvHeader;
    if (((UINT64)(UINTN)FileHandle > (UINT64)(UINTN)FwVolHeader) &&   \
        ((UINT64)(UINTN)FileHandle <= ((UINT64)(UINTN)FwVolHeader + FwVolHeader->FvLength - 1)))
    {
      if (BestIndex == PrivateData->FvCount) {
        BestIndex = Index;
      } else {
        if ((UINT64)(UINTN)PrivateData->Fv[BestIndex].FvHeader < (UINT64)(UINTN)FwVolHeader) {
          BestIndex = Index;
        }
      }
    }
  }

  if (BestIndex < PrivateData->FvCount) {
    return &PrivateData->Fv[BestIndex];
  }

  return NULL;
}
C 复制代码
EFI_STATUS
EFIAPI
PeiFfsFvPpiFindSectionByType2 (
  IN  CONST EFI_PEI_FIRMWARE_VOLUME_PPI  *This,
  IN        EFI_SECTION_TYPE             SearchType,
  IN        UINTN                        SearchInstance,
  IN        EFI_PEI_FILE_HANDLE          FileHandle,
  OUT VOID                               **SectionData,
  OUT UINT32                             *AuthenticationStatus
  )
{
  EFI_STATUS                 Status;
  EFI_FFS_FILE_HEADER        *FfsFileHeader;
  UINT32                     FileSize;
  EFI_COMMON_SECTION_HEADER  *Section;
  PEI_FW_VOL_INSTANCE        *FwVolInstance;
  PEI_CORE_FV_HANDLE         *CoreFvHandle;
  UINTN                      Instance;
  UINT32                     ExtractedAuthenticationStatus;

  if (SectionData == NULL) {
    return EFI_NOT_FOUND;
  }

  FwVolInstance = PEI_FW_VOL_INSTANCE_FROM_FV_THIS (This);

  //
  // Retrieve the FirmwareVolume which the file resides in.
  //
  CoreFvHandle = FileHandleToVolume (FileHandle);
  if (CoreFvHandle == NULL) {
    return EFI_NOT_FOUND;
  }

  FfsFileHeader = (EFI_FFS_FILE_HEADER *)(FileHandle);

  if (IS_FFS_FILE2 (FfsFileHeader)) {
    ASSERT (FFS_FILE2_SIZE (FfsFileHeader) > 0x00FFFFFF);
    if (!FwVolInstance->IsFfs3Fv) {
      DEBUG ((DEBUG_ERROR, "It is a FFS3 formatted file: %g in a non-FFS3 formatted FV.\n", &FfsFileHeader->Name));
      return EFI_NOT_FOUND;
    }

    Section  = (EFI_COMMON_SECTION_HEADER *)((UINT8 *)FfsFileHeader + sizeof (EFI_FFS_FILE_HEADER2));
    FileSize = FFS_FILE2_SIZE (FfsFileHeader) - sizeof (EFI_FFS_FILE_HEADER2);
  } else {
    Section  = (EFI_COMMON_SECTION_HEADER *)((UINT8 *)FfsFileHeader + sizeof (EFI_FFS_FILE_HEADER));
    FileSize = FFS_FILE_SIZE (FfsFileHeader) - sizeof (EFI_FFS_FILE_HEADER);
  }

  Instance                      = SearchInstance + 1;
  ExtractedAuthenticationStatus = 0;
  Status                        = ProcessSection (
                                    GetPeiServicesTablePointer (),
                                    SearchType,
                                    &Instance,
                                    Section,
                                    FileSize,
                                    SectionData,
                                    &ExtractedAuthenticationStatus,
                                    FwVolInstance->IsFfs3Fv
                                    );
  if (!EFI_ERROR (Status)) {
    //
    // Inherit the authentication status.
    //
    *AuthenticationStatus = ExtractedAuthenticationStatus | CoreFvHandle->AuthenticationStatus;
  }

  return Status;
}
* 找到第一个段头后进行处理
C 复制代码
EFI_STATUS
ProcessSection (
  IN CONST EFI_PEI_SERVICES     **PeiServices,
  IN EFI_SECTION_TYPE           SectionType,
  IN OUT UINTN                  *SectionInstance,
  IN EFI_COMMON_SECTION_HEADER  *Section,
  IN UINTN                      SectionSize,
  OUT VOID                      **OutputBuffer,
  OUT UINT32                    *AuthenticationStatus,
  IN BOOLEAN                    IsFfs3Fv
  )
{
  EFI_STATUS                             Status;
  UINT32                                 SectionLength;
  UINT32                                 ParsedLength;
  EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI  *GuidSectionPpi;
  EFI_PEI_DECOMPRESS_PPI                 *DecompressPpi;
  VOID                                   *PpiOutput;
  UINTN                                  PpiOutputSize;
  UINTN                                  Index;
  UINT32                                 Authentication;
  PEI_CORE_INSTANCE                      *PrivateData;
  EFI_GUID                               *SectionDefinitionGuid;
  BOOLEAN                                SectionCached;
  VOID                                   *TempOutputBuffer;
  UINT32                                 TempAuthenticationStatus;
  UINT16                                 GuidedSectionAttributes;

  PrivateData   = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);
  *OutputBuffer = NULL;
  ParsedLength  = 0;
  Index         = 0;
  Status        = EFI_NOT_FOUND;
  PpiOutput     = NULL;
  PpiOutputSize = 0;
  while (ParsedLength < SectionSize) {
    if (IS_SECTION2 (Section)) {
      ASSERT (SECTION2_SIZE (Section) > 0x00FFFFFF);
      if (!IsFfs3Fv) {
        DEBUG ((DEBUG_ERROR, "Found a FFS3 formatted section in a non-FFS3 formatted FV.\n"));
        SectionLength = SECTION2_SIZE (Section);
        if (SectionLength == 0) {
          break;
        }

        //
        // SectionLength is adjusted it is 4 byte aligned.
        // Go to the next section
        //
        SectionLength = GET_OCCUPIED_SIZE (SectionLength, 4);
        ASSERT (SectionLength != 0);
        ParsedLength += SectionLength;
        Section       = (EFI_COMMON_SECTION_HEADER *)((UINT8 *)Section + SectionLength);
        continue;
      }
    }

    if (Section->Type == SectionType) {
      //
      // The type matches, so check the instance count to see if it's the one we want.
      //
      (*SectionInstance)--;
      if (*SectionInstance == 0) {
        //
        // Got it!
        //
        if (IS_SECTION2 (Section)) {
          *OutputBuffer = (VOID *)((UINT8 *)Section + sizeof (EFI_COMMON_SECTION_HEADER2));
        } else {
          *OutputBuffer = (VOID *)((UINT8 *)Section + sizeof (EFI_COMMON_SECTION_HEADER));
        }

        return EFI_SUCCESS;
      } else {
        if (IS_SECTION2 (Section)) {
          SectionLength = SECTION2_SIZE (Section);
        } else {
          SectionLength = SECTION_SIZE (Section);
        }

        if (SectionLength == 0) {
          break;
        }

        //
        // SectionLength is adjusted it is 4 byte aligned.
        // Go to the next section
        //
        SectionLength = GET_OCCUPIED_SIZE (SectionLength, 4);
        ASSERT (SectionLength != 0);
        ParsedLength += SectionLength;
        Section       = (EFI_COMMON_SECTION_HEADER *)((UINT8 *)Section + SectionLength);
        continue;
      }
    } else if ((Section->Type == EFI_SECTION_GUID_DEFINED) || (Section->Type == EFI_SECTION_COMPRESSION)) {
      //
      // Check the encapsulated section is extracted into the cache data.
      //
      SectionCached = FALSE;
      for (Index = 0; Index < PrivateData->CacheSection.AllSectionCount; Index++) {
        if (Section == PrivateData->CacheSection.Section[Index]) {
          SectionCached  = TRUE;
          PpiOutput      = PrivateData->CacheSection.SectionData[Index];
          PpiOutputSize  = PrivateData->CacheSection.SectionSize[Index];
          Authentication = PrivateData->CacheSection.AuthenticationStatus[Index];
          //
          // Search section directly from the cache data.
          //
          TempAuthenticationStatus = 0;
          Status                   = ProcessSection (
                                       PeiServices,
                                       SectionType,
                                       SectionInstance,
                                       PpiOutput,
                                       PpiOutputSize,
                                       &TempOutputBuffer,
                                       &TempAuthenticationStatus,
                                       IsFfs3Fv
                                       );
          if (!EFI_ERROR (Status)) {
            *OutputBuffer         = TempOutputBuffer;
            *AuthenticationStatus = TempAuthenticationStatus | Authentication;
            return EFI_SUCCESS;
          }
        }
      }

      //
      // If SectionCached is TRUE, the section data has been cached and scanned.
      //
      if (!SectionCached) {
        Status         = EFI_NOT_FOUND;
        Authentication = 0;
        if (Section->Type == EFI_SECTION_GUID_DEFINED) {
          if (IS_SECTION2 (Section)) {
            SectionDefinitionGuid   = &((EFI_GUID_DEFINED_SECTION2 *)Section)->SectionDefinitionGuid;
            GuidedSectionAttributes = ((EFI_GUID_DEFINED_SECTION2 *)Section)->Attributes;
          } else {
            SectionDefinitionGuid   = &((EFI_GUID_DEFINED_SECTION *)Section)->SectionDefinitionGuid;
            GuidedSectionAttributes = ((EFI_GUID_DEFINED_SECTION *)Section)->Attributes;
          }

          if (VerifyGuidedSectionGuid (SectionDefinitionGuid, &GuidSectionPpi)) {
            Status = GuidSectionPpi->ExtractSection (
                                       GuidSectionPpi,
                                       Section,
                                       &PpiOutput,
                                       &PpiOutputSize,
                                       &Authentication
                                       );
          } else if ((GuidedSectionAttributes & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) == 0) {
            //
            // Figure out the proper authentication status for GUIDED section without processing required
            //
            Status = EFI_SUCCESS;
            if ((GuidedSectionAttributes & EFI_GUIDED_SECTION_AUTH_STATUS_VALID) == EFI_GUIDED_SECTION_AUTH_STATUS_VALID) {
              Authentication |= EFI_AUTH_STATUS_IMAGE_SIGNED | EFI_AUTH_STATUS_NOT_TESTED;
            }

            if (IS_SECTION2 (Section)) {
              PpiOutputSize = SECTION2_SIZE (Section) - ((EFI_GUID_DEFINED_SECTION2 *)Section)->DataOffset;
              PpiOutput     = (UINT8 *)Section + ((EFI_GUID_DEFINED_SECTION2 *)Section)->DataOffset;
            } else {
              PpiOutputSize = SECTION_SIZE (Section) - ((EFI_GUID_DEFINED_SECTION *)Section)->DataOffset;
              PpiOutput     = (UINT8 *)Section + ((EFI_GUID_DEFINED_SECTION *)Section)->DataOffset;
            }
          }
        } else if (Section->Type == EFI_SECTION_COMPRESSION) {
          Status = PeiServicesLocatePpi (&gEfiPeiDecompressPpiGuid, 0, NULL, (VOID **)&DecompressPpi);
          if (!EFI_ERROR (Status)) {
            Status = DecompressPpi->Decompress (
                                      DecompressPpi,
                                      (CONST EFI_COMPRESSION_SECTION *)Section,
                                      &PpiOutput,
                                      &PpiOutputSize
                                      );
          }
        }

        if (!EFI_ERROR (Status)) {
          if ((Authentication & EFI_AUTH_STATUS_NOT_TESTED) == 0) {
            //
            // Update cache section data.
            //
            if (PrivateData->CacheSection.AllSectionCount < CACHE_SETION_MAX_NUMBER) {
              PrivateData->CacheSection.AllSectionCount++;
            }

            PrivateData->CacheSection.Section[PrivateData->CacheSection.SectionIndex]              = Section;
            PrivateData->CacheSection.SectionData[PrivateData->CacheSection.SectionIndex]          = PpiOutput;
            PrivateData->CacheSection.SectionSize[PrivateData->CacheSection.SectionIndex]          = PpiOutputSize;
            PrivateData->CacheSection.AuthenticationStatus[PrivateData->CacheSection.SectionIndex] = Authentication;
            PrivateData->CacheSection.SectionIndex                                                 = (PrivateData->CacheSection.SectionIndex + 1)%CACHE_SETION_MAX_NUMBER;
          }

          TempAuthenticationStatus = 0;
          Status                   = ProcessSection (
                                       PeiServices,
                                       SectionType,
                                       SectionInstance,
                                       PpiOutput,
                                       PpiOutputSize,
                                       &TempOutputBuffer,
                                       &TempAuthenticationStatus,
                                       IsFfs3Fv
                                       );
          if (!EFI_ERROR (Status)) {
            *OutputBuffer         = TempOutputBuffer;
            *AuthenticationStatus = TempAuthenticationStatus | Authentication;
            return EFI_SUCCESS;
          }
        }
      }
    }

    if (IS_SECTION2 (Section)) {
      SectionLength = SECTION2_SIZE (Section);
    } else {
      SectionLength = SECTION_SIZE (Section);
    }

    if (SectionLength == 0) {
      break;
    }

    //
    // SectionLength is adjusted it is 4 byte aligned.
    // Go to the next section
    //
    SectionLength = GET_OCCUPIED_SIZE (SectionLength, 4);
    ASSERT (SectionLength != 0);
    ParsedLength += SectionLength;
    Section       = (EFI_COMMON_SECTION_HEADER *)((UINT8 *)Section + SectionLength);
  }

  return EFI_NOT_FOUND;
}

遍历该FFS所有Section发现没有想要的Section

* 尝试找第二个可执行段类型(过程与上述相同)
* 加载并重定位PE/COFF映像到内存
C 复制代码
EFI_STATUS
LoadAndRelocatePeCoffImage (
  IN  EFI_PEI_FILE_HANDLE   FileHandle,
  IN  VOID                  *Pe32Data,
  OUT EFI_PHYSICAL_ADDRESS  *ImageAddress,
  OUT UINT64                *ImageSize,
  OUT EFI_PHYSICAL_ADDRESS  *EntryPoint
  )
{
  EFI_STATUS                    Status;
  PE_COFF_LOADER_IMAGE_CONTEXT  ImageContext;
  PEI_CORE_INSTANCE             *Private;
  UINT64                        AlignImageSize;
  BOOLEAN                       IsXipImage;
  EFI_STATUS                    ReturnStatus;
  BOOLEAN                       IsS3Boot;
  BOOLEAN                       IsPeiModule;
  BOOLEAN                       IsRegisterForShadow;
  EFI_FV_FILE_INFO              FileInfo;

  Private = PEI_CORE_INSTANCE_FROM_PS_THIS (GetPeiServicesTablePointer ());

  ReturnStatus = EFI_SUCCESS;
  IsXipImage   = FALSE;
  ZeroMem (&ImageContext, sizeof (ImageContext));
  ImageContext.Handle    = Pe32Data;
  ImageContext.ImageRead = PeiImageRead;

  Status = PeCoffLoaderGetImageInfo (&ImageContext);
  if (EFI_ERROR (Status)) {
    return Status;
  }

  //
  // Initialize local IsS3Boot and IsRegisterForShadow variable
  //
  IsS3Boot = FALSE;
  if (Private->HobList.HandoffInformationTable->BootMode == BOOT_ON_S3_RESUME) {
    IsS3Boot = TRUE;
  }

  IsRegisterForShadow = FALSE;
  if (  (Private->CurrentFileHandle == FileHandle)
     && (Private->Fv[Private->CurrentPeimFvCount].PeimState[Private->CurrentPeimCount] == PEIM_STATE_REGISTER_FOR_SHADOW))
  {
    IsRegisterForShadow = TRUE;
  }

  //
  // XIP image that ImageAddress is same to Image handle.
  //
  if (ImageContext.ImageAddress == (EFI_PHYSICAL_ADDRESS)(UINTN)Pe32Data) {
    IsXipImage = TRUE;
  }

  //
  // Get file type first
  //
  Status = PeiServicesFfsGetFileInfo (FileHandle, &FileInfo);
  ASSERT_EFI_ERROR (Status);

  //
  // Check whether the file type is PEI module.
  //
  IsPeiModule = FALSE;
  if ((FileInfo.FileType == EFI_FV_FILETYPE_PEI_CORE) ||
      (FileInfo.FileType == EFI_FV_FILETYPE_PEIM) ||
      (FileInfo.FileType == EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER))
  {
    IsPeiModule = TRUE;
  }

  //
  // When Image has no reloc section, it can't be relocated into memory.
  //
  if (ImageContext.RelocationsStripped && (Private->PeiMemoryInstalled) &&
      ((!IsPeiModule) || PcdGetBool (PcdMigrateTemporaryRamFirmwareVolumes) ||
       (!IsS3Boot && (PcdGetBool (PcdShadowPeimOnBoot) || IsRegisterForShadow)) ||
       (IsS3Boot && PcdGetBool (PcdShadowPeimOnS3Boot)))
      )
  {
    DEBUG ((DEBUG_INFO|DEBUG_LOAD, "The image at 0x%08x without reloc section can't be loaded into memory\n", (UINTN)Pe32Data));
  }

  //
  // Set default base address to current image address.
  //
  ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)Pe32Data;

  //
  // Allocate Memory for the image when memory is ready, and image is relocatable.
  // On normal boot, PcdShadowPeimOnBoot decides whether load PEIM or PeiCore into memory.
  // On S3 boot, PcdShadowPeimOnS3Boot decides whether load PEIM or PeiCore into memory.
  //
  if ((!ImageContext.RelocationsStripped) && (Private->PeiMemoryInstalled) &&
      ((!IsPeiModule) || PcdGetBool (PcdMigrateTemporaryRamFirmwareVolumes) ||
       (!IsS3Boot && (PcdGetBool (PcdShadowPeimOnBoot) || IsRegisterForShadow)) ||
       (IsS3Boot && PcdGetBool (PcdShadowPeimOnS3Boot)))
      )
  {
    //
    // Allocate more buffer to avoid buffer overflow.
    //
    if (ImageContext.IsTeImage) {
      AlignImageSize = ImageContext.ImageSize + ((EFI_TE_IMAGE_HEADER *)Pe32Data)->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER);
    } else {
      AlignImageSize = ImageContext.ImageSize;
    }

    if (ImageContext.SectionAlignment > EFI_PAGE_SIZE) {
      AlignImageSize += ImageContext.SectionAlignment;
    }

    if ((PcdGet64 (PcdLoadModuleAtFixAddressEnable) != 0) && (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME)) {
      Status = GetPeCoffImageFixLoadingAssignedAddress (&ImageContext, Private);
      if (EFI_ERROR (Status)) {
        DEBUG ((DEBUG_INFO|DEBUG_LOAD, "LOADING MODULE FIXED ERROR: Failed to load module at fixed address. \n"));
        //
        // The PEIM is not assigned valid address, try to allocate page to load it.
        //
        Status = PeiServicesAllocatePages (
                   EfiBootServicesCode,
                   EFI_SIZE_TO_PAGES ((UINT32)AlignImageSize),
                   &ImageContext.ImageAddress
                   );
      }
    } else {
      Status = PeiServicesAllocatePages (
                 EfiBootServicesCode,
                 EFI_SIZE_TO_PAGES ((UINT32)AlignImageSize),
                 &ImageContext.ImageAddress
                 );
    }

    if (!EFI_ERROR (Status)) {
      //
      // Adjust the Image Address to make sure it is section alignment.
      //
      if (ImageContext.SectionAlignment > EFI_PAGE_SIZE) {
        ImageContext.ImageAddress =
          (ImageContext.ImageAddress + ImageContext.SectionAlignment - 1) &
          ~((UINTN)ImageContext.SectionAlignment - 1);
      }

      //
      // Fix alignment requirement when Load IPF TeImage into memory.
      // Skip the reserved space for the stripped PeHeader when load TeImage into memory.
      //
      if (ImageContext.IsTeImage) {
        ImageContext.ImageAddress = ImageContext.ImageAddress +
                                    ((EFI_TE_IMAGE_HEADER *)Pe32Data)->StrippedSize -
                                    sizeof (EFI_TE_IMAGE_HEADER);
      }
    } else {
      //
      // No enough memory resource.
      //
      if (IsXipImage) {
        //
        // XIP image can still be invoked.
        //
        ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)Pe32Data;
        ReturnStatus              = EFI_WARN_BUFFER_TOO_SMALL;
      } else {
        //
        // Non XIP image can't be loaded because no enough memory is allocated.
        //
        ASSERT (FALSE);
        return EFI_OUT_OF_RESOURCES;
      }
    }
  }

  //
  // Load the image to our new buffer
  //
  Status = PeCoffLoaderLoadImage (&ImageContext);
  if (EFI_ERROR (Status)) {
    if (ImageContext.ImageError == IMAGE_ERROR_INVALID_SECTION_ALIGNMENT) {
      DEBUG ((DEBUG_ERROR, "PEIM Image Address 0x%11p doesn't meet with section alignment 0x%x.\n", (VOID *)(UINTN)ImageContext.ImageAddress, ImageContext.SectionAlignment));
    }

    return Status;
  }

  //
  // Relocate the image in our new buffer
  //
  Status = PeCoffLoaderRelocateImage (&ImageContext);
  if (EFI_ERROR (Status)) {
    return Status;
  }

  //
  // Flush the instruction cache so the image data is written before we execute it
  //
  if (ImageContext.ImageAddress != (EFI_PHYSICAL_ADDRESS)(UINTN)Pe32Data) {
    InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize);
  }

  *ImageAddress = ImageContext.ImageAddress;
  *ImageSize    = ImageContext.ImageSize;
  *EntryPoint   = ImageContext.EntryPoint;

  return ReturnStatus;
}
** 获取映像信息

计算 ImageContext 结构体的以下字段:

  • PeCoffHeaderOffset
  • IsTeImage
  • ImageType
  • ImageAddress
  • ImageSize
  • DestinationAddress
  • RelocationsStripped
  • SectionAlignment
  • SizeOfHeaders
  • DllCharacteristics
  • DllCharacteristicsEx
  • DebugDirectoryEntryRva。

如果 ImageContext 为 NULL,则返回 RETURN_INVALID_PARAMETER。

如果通过 ImageContext 结构体中的 ImageRead 服务访问的 PE/COFF 映像不是受支持的 PE/COFF 映像类型,则返回 RETURN_UNSUPPORTED。

如果在计算 ImageContext 字段的过程中发生任何错误,则错误状态将返回到 ImageContext 的 ImageError 字段中。

如果映像是 TE 映像,则 SectionAlignment 设置为 0。

在调用此服务之前,ImageContext 结构体的 ImageRead 和 Handle 字段必须是有效的。

** 初始化本地 IsS3Boot 和 IsRegisterForShadow 变量
C 复制代码
  IsS3Boot = FALSE;
  if (Private->HobList.HandoffInformationTable->BootMode == BOOT_ON_S3_RESUME) {
    IsS3Boot = TRUE;
  }

  IsRegisterForShadow = FALSE;
  if (  (Private->CurrentFileHandle == FileHandle)
     && (Private->Fv[Private->CurrentPeimFvCount].PeimState[Private->CurrentPeimCount] == PEIM_STATE_REGISTER_FOR_SHADOW))
  {
    IsRegisterForShadow = TRUE;
  }

IsRegisterForShadow是Windows 内核在启动早期用来判断"当前这一组 CPU 是否需要注册为 shadow 服务处理器"的一个 内部标志位。

** 判断映像是否可以就地执行
C 复制代码
 if (ImageContext.ImageAddress == (EFI_PHYSICAL_ADDRESS)(UINTN)Pe32Data) {
    IsXipImage = TRUE;
  }
** 再次校验是否是PEIM
C 复制代码
  //
  // Get file type first
  //
  Status = PeiServicesFfsGetFileInfo (FileHandle, &FileInfo);
  ASSERT_EFI_ERROR (Status);

  //
  // Check whether the file type is PEI module.
  //
  IsPeiModule = FALSE;
  if ((FileInfo.FileType == EFI_FV_FILETYPE_PEI_CORE) ||
      (FileInfo.FileType == EFI_FV_FILETYPE_PEIM) ||
      (FileInfo.FileType == EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER))
  {
    IsPeiModule = TRUE;
  }

两步校验的目的

步骤 函数 校验级别 可能出错场景
① 快速过滤 FindFileByType 仅看 FFS 头 1 字节 Type 链接脚本写错、平台移植时 GUID 复用
② 最终确认 FfsGetFileInfo 再读一次头字段 ① 的过滤结果与头字段不一致
** 确保不能重定位的映像不会被重定位到内存
C 复制代码
  if (ImageContext.RelocationsStripped && (Private->PeiMemoryInstalled) &&
      ((!IsPeiModule) || PcdGetBool (PcdMigrateTemporaryRamFirmwareVolumes) ||
       (!IsS3Boot && (PcdGetBool (PcdShadowPeimOnBoot) || IsRegisterForShadow)) ||
       (IsS3Boot && PcdGetBool (PcdShadowPeimOnS3Boot)))
      )
  {
    DEBUG ((DEBUG_INFO|DEBUG_LOAD, "The image at 0x%08x without reloc section can't be loaded into memory\n", (UINTN)Pe32Data));
  }
** 将默认基址设置为当前映像地址
C 复制代码
  ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)Pe32Data;
** 当内存准备好且可重定位的时候为映像分配内存
C 复制代码
  if ((!ImageContext.RelocationsStripped) && (Private->PeiMemoryInstalled) &&
      ((!IsPeiModule) || PcdGetBool (PcdMigrateTemporaryRamFirmwareVolumes) ||
       (!IsS3Boot && (PcdGetBool (PcdShadowPeimOnBoot) || IsRegisterForShadow)) ||
       (IsS3Boot && PcdGetBool (PcdShadowPeimOnS3Boot)))
      )
  {
    //
    // Allocate more buffer to avoid buffer overflow.
    //
    if (ImageContext.IsTeImage) {
      AlignImageSize = ImageContext.ImageSize + ((EFI_TE_IMAGE_HEADER *)Pe32Data)->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER);
    } else {
      AlignImageSize = ImageContext.ImageSize;
    }

    if (ImageContext.SectionAlignment > EFI_PAGE_SIZE) {
      AlignImageSize += ImageContext.SectionAlignment;
    }

    if ((PcdGet64 (PcdLoadModuleAtFixAddressEnable) != 0) && (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME)) {
      Status = GetPeCoffImageFixLoadingAssignedAddress (&ImageContext, Private);
      if (EFI_ERROR (Status)) {
        DEBUG ((DEBUG_INFO|DEBUG_LOAD, "LOADING MODULE FIXED ERROR: Failed to load module at fixed address. \n"));
        //
        // The PEIM is not assigned valid address, try to allocate page to load it.
        //
        Status = PeiServicesAllocatePages (
                   EfiBootServicesCode,
                   EFI_SIZE_TO_PAGES ((UINT32)AlignImageSize),
                   &ImageContext.ImageAddress
                   );
      }
    } else {
      Status = PeiServicesAllocatePages (
                 EfiBootServicesCode,
                 EFI_SIZE_TO_PAGES ((UINT32)AlignImageSize),
                 &ImageContext.ImageAddress
                 );
    }

    if (!EFI_ERROR (Status)) {
      //
      // Adjust the Image Address to make sure it is section alignment.
      //
      if (ImageContext.SectionAlignment > EFI_PAGE_SIZE) {
        ImageContext.ImageAddress =
          (ImageContext.ImageAddress + ImageContext.SectionAlignment - 1) &
          ~((UINTN)ImageContext.SectionAlignment - 1);
      }

      //
      // Fix alignment requirement when Load IPF TeImage into memory.
      // Skip the reserved space for the stripped PeHeader when load TeImage into memory.
      //
      if (ImageContext.IsTeImage) {
        ImageContext.ImageAddress = ImageContext.ImageAddress +
                                    ((EFI_TE_IMAGE_HEADER *)Pe32Data)->StrippedSize -
                                    sizeof (EFI_TE_IMAGE_HEADER);
      }
    } else {
      //
      // No enough memory resource.
      //
      if (IsXipImage) {
        //
        // XIP image can still be invoked.
        //
        ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)Pe32Data;
        ReturnStatus              = EFI_WARN_BUFFER_TOO_SMALL;
      } else {
        //
        // Non XIP image can't be loaded because no enough memory is allocated.
        //
        ASSERT (FALSE);
        return EFI_OUT_OF_RESOURCES;
      }
    }
  }
** 加载映像到内存
C 复制代码
RETURN_STATUS
EFIAPI
PeCoffLoaderLoadImage (
  IN OUT PE_COFF_LOADER_IMAGE_CONTEXT  *ImageContext
  )
{
  RETURN_STATUS                        Status;
  EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION  Hdr;
  PE_COFF_LOADER_IMAGE_CONTEXT         CheckContext;
  EFI_IMAGE_SECTION_HEADER             *FirstSection;
  EFI_IMAGE_SECTION_HEADER             *Section;
  UINTN                                NumberOfSections;
  UINTN                                Index;
  CHAR8                                *Base;
  CHAR8                                *End;
  EFI_IMAGE_DATA_DIRECTORY             *DirectoryEntry;
  EFI_IMAGE_DEBUG_DIRECTORY_ENTRY      *DebugEntry;
  UINTN                                Size;
  UINT32                               TempDebugEntryRva;
  UINT32                               NumberOfRvaAndSizes;
  EFI_IMAGE_RESOURCE_DIRECTORY         *ResourceDirectory;
  EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY   *ResourceDirectoryEntry;
  EFI_IMAGE_RESOURCE_DIRECTORY_STRING  *ResourceDirectoryString;
  EFI_IMAGE_RESOURCE_DATA_ENTRY        *ResourceDataEntry;
  CHAR16                               *String;
  UINT32                               Offset;
  UINT32                               TeStrippedOffset;

  ASSERT (ImageContext != NULL);

  //
  // Assume success
  //
  ImageContext->ImageError = IMAGE_ERROR_SUCCESS;

  //
  // Copy the provided context information into our local version, get what we
  // can from the original image, and then use that to make sure everything
  // is legit.
  //
  CopyMem (&CheckContext, ImageContext, sizeof (PE_COFF_LOADER_IMAGE_CONTEXT));

  Status = PeCoffLoaderGetImageInfo (&CheckContext);
  if (RETURN_ERROR (Status)) {
    return Status;
  }

  //
  // Make sure there is enough allocated space for the image being loaded
  //
  if (ImageContext->ImageSize < CheckContext.ImageSize) {
    ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_SIZE;
    return RETURN_BUFFER_TOO_SMALL;
  }

  if (ImageContext->ImageAddress == 0) {
    //
    // Image cannot be loaded into 0 address.
    //
    ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_ADDRESS;
    return RETURN_INVALID_PARAMETER;
  }

  //
  // If there's no relocations, then make sure it's not a runtime driver,
  // and that it's being loaded at the linked address.
  //
  if (CheckContext.RelocationsStripped) {
    //
    // If the image does not contain relocations and it is a runtime driver
    // then return an error.
    //
    if (CheckContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) {
      ImageContext->ImageError = IMAGE_ERROR_INVALID_SUBSYSTEM;
      return RETURN_LOAD_ERROR;
    }

    //
    // If the image does not contain relocations, and the requested load address
    // is not the linked address, then return an error.
    //
    if (CheckContext.ImageAddress != ImageContext->ImageAddress) {
      ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_ADDRESS;
      return RETURN_INVALID_PARAMETER;
    }
  }

  //
  // Make sure the allocated space has the proper section alignment
  //
  if (!(ImageContext->IsTeImage)) {
    if ((ImageContext->ImageAddress & (CheckContext.SectionAlignment - 1)) != 0) {
      ImageContext->ImageError = IMAGE_ERROR_INVALID_SECTION_ALIGNMENT;
      return RETURN_INVALID_PARAMETER;
    }
  }

  //
  // Read the entire PE/COFF or TE header into memory
  //
  if (!(ImageContext->IsTeImage)) {
    Status = ImageContext->ImageRead (
                             ImageContext->Handle,
                             0,
                             &ImageContext->SizeOfHeaders,
                             (VOID *)(UINTN)ImageContext->ImageAddress
                             );

    Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN)ImageContext->ImageAddress + ImageContext->PeCoffHeaderOffset);

    FirstSection = (EFI_IMAGE_SECTION_HEADER *)(
                                                (UINTN)ImageContext->ImageAddress +
                                                ImageContext->PeCoffHeaderOffset +
                                                sizeof (UINT32) +
                                                sizeof (EFI_IMAGE_FILE_HEADER) +
                                                Hdr.Pe32->FileHeader.SizeOfOptionalHeader
                                                );
    NumberOfSections = (UINTN)(Hdr.Pe32->FileHeader.NumberOfSections);
    TeStrippedOffset = 0;
  } else {
    Status = ImageContext->ImageRead (
                             ImageContext->Handle,
                             0,
                             &ImageContext->SizeOfHeaders,
                             (void *)(UINTN)ImageContext->ImageAddress
                             );

    Hdr.Te       = (EFI_TE_IMAGE_HEADER *)(UINTN)(ImageContext->ImageAddress);
    FirstSection = (EFI_IMAGE_SECTION_HEADER *)(
                                                (UINTN)ImageContext->ImageAddress +
                                                sizeof (EFI_TE_IMAGE_HEADER)
                                                );
    NumberOfSections = (UINTN)(Hdr.Te->NumberOfSections);
    TeStrippedOffset = (UINT32)Hdr.Te->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER);
  }

  if (RETURN_ERROR (Status)) {
    ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
    return RETURN_LOAD_ERROR;
  }

  //
  // Load each section of the image
  //
  Section = FirstSection;
  for (Index = 0; Index < NumberOfSections; Index++) {
    //
    // Read the section
    //
    Size = (UINTN)Section->Misc.VirtualSize;
    if ((Size == 0) || (Size > Section->SizeOfRawData)) {
      Size = (UINTN)Section->SizeOfRawData;
    }

    //
    // Compute sections address
    //
    Base = PeCoffLoaderImageAddress (ImageContext, Section->VirtualAddress, TeStrippedOffset);
    End  = PeCoffLoaderImageAddress (ImageContext, Section->VirtualAddress + Section->Misc.VirtualSize - 1, TeStrippedOffset);

    //
    // If the size of the section is non-zero and the base address or end address resolved to 0, then fail.
    //
    if ((Size > 0) && ((Base == NULL) || (End == NULL))) {
      ImageContext->ImageError = IMAGE_ERROR_SECTION_NOT_LOADED;
      return RETURN_LOAD_ERROR;
    }

    if ((Section->SizeOfRawData > 0) && (Base != NULL)) {
      Status = ImageContext->ImageRead (
                               ImageContext->Handle,
                               Section->PointerToRawData - TeStrippedOffset,
                               &Size,
                               Base
                               );
      if (RETURN_ERROR (Status)) {
        ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
        return Status;
      }
    }

    //
    // If raw size is less then virtual size, zero fill the remaining
    //

    if ((Size < Section->Misc.VirtualSize) && (Base != NULL)) {
      ZeroMem (Base + Size, Section->Misc.VirtualSize - Size);
    }

    //
    // Next Section
    //
    Section += 1;
  }

  //
  // Get image's entry point
  //
  if (!(ImageContext->IsTeImage)) {
    //
    // Sizes of AddressOfEntryPoint are different so we need to do this safely
    //
    if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
      //
      // Use PE32 offset
      //
      ImageContext->EntryPoint = (PHYSICAL_ADDRESS)(UINTN)PeCoffLoaderImageAddress (
                                                            ImageContext,
                                                            (UINTN)Hdr.Pe32->OptionalHeader.AddressOfEntryPoint,
                                                            0
                                                            );
    } else {
      //
      // Use PE32+ offset
      //
      ImageContext->EntryPoint = (PHYSICAL_ADDRESS)(UINTN)PeCoffLoaderImageAddress (
                                                            ImageContext,
                                                            (UINTN)Hdr.Pe32Plus->OptionalHeader.AddressOfEntryPoint,
                                                            0
                                                            );
    }
  } else {
    ImageContext->EntryPoint = (PHYSICAL_ADDRESS)(UINTN)PeCoffLoaderImageAddress (
                                                          ImageContext,
                                                          (UINTN)Hdr.Te->AddressOfEntryPoint,
                                                          TeStrippedOffset
                                                          );
  }

  //
  // Determine the size of the fixup data
  //
  // Per the PE/COFF spec, you can't assume that a given data directory
  // is present in the image. You have to check the NumberOfRvaAndSizes in
  // the optional header to verify a desired directory entry is there.
  //
  if (!(ImageContext->IsTeImage)) {
    if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
      //
      // Use PE32 offset
      //
      NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;
      DirectoryEntry      = (EFI_IMAGE_DATA_DIRECTORY *)&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
    } else {
      //
      // Use PE32+ offset
      //
      NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;
      DirectoryEntry      = (EFI_IMAGE_DATA_DIRECTORY *)&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
    }

    //
    // Must use UINT64 here, because there might a case that 32bit loader to load 64bit image.
    //
    if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {
      ImageContext->FixupDataSize = DirectoryEntry->Size / sizeof (UINT16) * sizeof (UINT64);
    } else {
      ImageContext->FixupDataSize = 0;
    }
  } else {
    DirectoryEntry              = &Hdr.Te->DataDirectory[0];
    ImageContext->FixupDataSize = DirectoryEntry->Size / sizeof (UINT16) * sizeof (UINT64);
  }

  //
  // Consumer must allocate a buffer for the relocation fixup log.
  // Only used for runtime drivers.
  //
  ImageContext->FixupData = NULL;

  //
  // Load the Codeview information if present
  //
  if (ImageContext->DebugDirectoryEntryRva != 0) {
    DebugEntry = PeCoffLoaderImageAddress (
                   ImageContext,
                   ImageContext->DebugDirectoryEntryRva,
                   TeStrippedOffset
                   );
    if (DebugEntry == NULL) {
      ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
      return RETURN_LOAD_ERROR;
    }

    TempDebugEntryRva = DebugEntry->RVA;
    if ((DebugEntry->RVA == 0) && (DebugEntry->FileOffset != 0)) {
      Section--;
      if ((UINTN)Section->SizeOfRawData < Section->Misc.VirtualSize) {
        TempDebugEntryRva = Section->VirtualAddress + Section->Misc.VirtualSize;
      } else {
        TempDebugEntryRva = Section->VirtualAddress + Section->SizeOfRawData;
      }
    }

    if (TempDebugEntryRva != 0) {
      ImageContext->CodeView = PeCoffLoaderImageAddress (ImageContext, TempDebugEntryRva, TeStrippedOffset);
      if (ImageContext->CodeView == NULL) {
        ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
        return RETURN_LOAD_ERROR;
      }

      if (DebugEntry->RVA == 0) {
        Size   = DebugEntry->SizeOfData;
        Status = ImageContext->ImageRead (
                                 ImageContext->Handle,
                                 DebugEntry->FileOffset - TeStrippedOffset,
                                 &Size,
                                 ImageContext->CodeView
                                 );
        //
        // Should we apply fix up to this field according to the size difference between PE and TE?
        // Because now we maintain TE header fields unfixed, this field will also remain as they are
        // in original PE image.
        //

        if (RETURN_ERROR (Status)) {
          ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
          return RETURN_LOAD_ERROR;
        }

        DebugEntry->RVA = TempDebugEntryRva;
      }

      switch (*(UINT32 *)ImageContext->CodeView) {
        case CODEVIEW_SIGNATURE_NB10:
          if (DebugEntry->SizeOfData < sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY)) {
            ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
            return RETURN_UNSUPPORTED;
          }

          ImageContext->PdbPointer = (CHAR8 *)ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY);
          break;

        case CODEVIEW_SIGNATURE_RSDS:
          if (DebugEntry->SizeOfData < sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY)) {
            ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
            return RETURN_UNSUPPORTED;
          }

          ImageContext->PdbPointer = (CHAR8 *)ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY);
          break;

        case CODEVIEW_SIGNATURE_MTOC:
          if (DebugEntry->SizeOfData < sizeof (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY)) {
            ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
            return RETURN_UNSUPPORTED;
          }

          ImageContext->PdbPointer = (CHAR8 *)ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY);
          break;

        default:
          break;
      }
    }
  }

  //
  // Get Image's HII resource section
  //
  ImageContext->HiiResourceData = 0;
  if (!(ImageContext->IsTeImage)) {
    if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
      //
      // Use PE32 offset
      //
      NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;
      DirectoryEntry      = (EFI_IMAGE_DATA_DIRECTORY *)&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE];
    } else {
      //
      // Use PE32+ offset
      //
      NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;
      DirectoryEntry      = (EFI_IMAGE_DATA_DIRECTORY *)&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE];
    }

    if ((NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE) && (DirectoryEntry->Size != 0)) {
      Base = PeCoffLoaderImageAddress (ImageContext, DirectoryEntry->VirtualAddress, 0);
      if (Base != NULL) {
        ResourceDirectory = (EFI_IMAGE_RESOURCE_DIRECTORY *)Base;
        Offset            = sizeof (EFI_IMAGE_RESOURCE_DIRECTORY) + sizeof (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY) *
                            (ResourceDirectory->NumberOfNamedEntries + ResourceDirectory->NumberOfIdEntries);
        if (Offset > DirectoryEntry->Size) {
          ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
          return RETURN_UNSUPPORTED;
        }

        ResourceDirectoryEntry = (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *)(ResourceDirectory + 1);

        for (Index = 0; Index < ResourceDirectory->NumberOfNamedEntries; Index++) {
          if (ResourceDirectoryEntry->u1.s.NameIsString) {
            //
            // Check the ResourceDirectoryEntry->u1.s.NameOffset before use it.
            //
            if (ResourceDirectoryEntry->u1.s.NameOffset >= DirectoryEntry->Size) {
              ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
              return RETURN_UNSUPPORTED;
            }

            ResourceDirectoryString = (EFI_IMAGE_RESOURCE_DIRECTORY_STRING *)(Base + ResourceDirectoryEntry->u1.s.NameOffset);
            String                  = &ResourceDirectoryString->String[0];

            if ((ResourceDirectoryString->Length == 3) &&
                (String[0] == L'H') &&
                (String[1] == L'I') &&
                (String[2] == L'I'))
            {
              //
              // Resource Type "HII" found
              //
              if (ResourceDirectoryEntry->u2.s.DataIsDirectory) {
                //
                // Move to next level - resource Name
                //
                if (ResourceDirectoryEntry->u2.s.OffsetToDirectory >= DirectoryEntry->Size) {
                  ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
                  return RETURN_UNSUPPORTED;
                }

                ResourceDirectory = (EFI_IMAGE_RESOURCE_DIRECTORY *)(Base + ResourceDirectoryEntry->u2.s.OffsetToDirectory);
                Offset            = ResourceDirectoryEntry->u2.s.OffsetToDirectory + sizeof (EFI_IMAGE_RESOURCE_DIRECTORY) +
                                    sizeof (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY) * (ResourceDirectory->NumberOfNamedEntries + ResourceDirectory->NumberOfIdEntries);
                if (Offset > DirectoryEntry->Size) {
                  ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
                  return RETURN_UNSUPPORTED;
                }

                ResourceDirectoryEntry = (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *)(ResourceDirectory + 1);

                if (ResourceDirectoryEntry->u2.s.DataIsDirectory) {
                  //
                  // Move to next level - resource Language
                  //
                  if (ResourceDirectoryEntry->u2.s.OffsetToDirectory >= DirectoryEntry->Size) {
                    ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
                    return RETURN_UNSUPPORTED;
                  }

                  ResourceDirectory = (EFI_IMAGE_RESOURCE_DIRECTORY *)(Base + ResourceDirectoryEntry->u2.s.OffsetToDirectory);
                  Offset            = ResourceDirectoryEntry->u2.s.OffsetToDirectory + sizeof (EFI_IMAGE_RESOURCE_DIRECTORY) +
                                      sizeof (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY) * (ResourceDirectory->NumberOfNamedEntries + ResourceDirectory->NumberOfIdEntries);
                  if (Offset > DirectoryEntry->Size) {
                    ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
                    return RETURN_UNSUPPORTED;
                  }

                  ResourceDirectoryEntry = (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *)(ResourceDirectory + 1);
                }
              }

              //
              // Now it ought to be resource Data
              //
              if (!ResourceDirectoryEntry->u2.s.DataIsDirectory) {
                if (ResourceDirectoryEntry->u2.OffsetToData >= DirectoryEntry->Size) {
                  ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
                  return RETURN_UNSUPPORTED;
                }

                ResourceDataEntry             = (EFI_IMAGE_RESOURCE_DATA_ENTRY *)(Base + ResourceDirectoryEntry->u2.OffsetToData);
                ImageContext->HiiResourceData = (PHYSICAL_ADDRESS)(UINTN)PeCoffLoaderImageAddress (ImageContext, ResourceDataEntry->OffsetToData, 0);
                break;
              }
            }
          }

          ResourceDirectoryEntry++;
        }
      }
    }
  }

  return Status;
}
** 应用重定位修正
C 复制代码
RETURN_STATUS
EFIAPI
PeCoffLoaderRelocateImage (
  IN OUT PE_COFF_LOADER_IMAGE_CONTEXT  *ImageContext
  )
{
  RETURN_STATUS                        Status;
  EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION  Hdr;
  EFI_IMAGE_DATA_DIRECTORY             *RelocDir;
  UINT64                               Adjust;
  EFI_IMAGE_BASE_RELOCATION            *RelocBaseOrg;
  EFI_IMAGE_BASE_RELOCATION            *RelocBase;
  EFI_IMAGE_BASE_RELOCATION            *RelocBaseEnd;
  UINT16                               *Reloc;
  UINT16                               *RelocEnd;
  CHAR8                                *Fixup;
  CHAR8                                *FixupBase;
  UINT16                               *Fixup16;
  UINT32                               *Fixup32;
  UINT64                               *Fixup64;
  CHAR8                                *FixupData;
  PHYSICAL_ADDRESS                     BaseAddress;
  UINT32                               NumberOfRvaAndSizes;
  UINT32                               TeStrippedOffset;
  UINT32                               EndAddress;

  ASSERT (ImageContext != NULL);

  //
  // Assume success
  //
  ImageContext->ImageError = IMAGE_ERROR_SUCCESS;

  //
  // If there are no relocation entries, then we are done
  //
  if (ImageContext->RelocationsStripped) {
    // Applies additional environment specific actions to relocate fixups
    // to a PE/COFF image if needed
    PeCoffLoaderRelocateImageExtraAction (ImageContext);
    return RETURN_SUCCESS;
  }

  //
  // If the destination address is not 0, use that rather than the
  // image address as the relocation target.
  //
  if (ImageContext->DestinationAddress != 0) {
    BaseAddress = ImageContext->DestinationAddress;
  } else {
    BaseAddress = ImageContext->ImageAddress;
  }

  if (!(ImageContext->IsTeImage)) {
    Hdr.Pe32         = (EFI_IMAGE_NT_HEADERS32 *)((UINTN)ImageContext->ImageAddress + ImageContext->PeCoffHeaderOffset);
    TeStrippedOffset = 0;

    if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
      //
      // Use PE32 offset
      //
      Adjust = (UINT64)BaseAddress - Hdr.Pe32->OptionalHeader.ImageBase;
      if (Adjust != 0) {
        Hdr.Pe32->OptionalHeader.ImageBase = (UINT32)BaseAddress;
      }

      NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;
      RelocDir            = &Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
    } else {
      //
      // Use PE32+ offset
      //
      Adjust = (UINT64)BaseAddress - Hdr.Pe32Plus->OptionalHeader.ImageBase;
      if (Adjust != 0) {
        Hdr.Pe32Plus->OptionalHeader.ImageBase = (UINT64)BaseAddress;
      }

      NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;
      RelocDir            = &Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
    }

    //
    // Find the relocation block
    // Per the PE/COFF spec, you can't assume that a given data directory
    // is present in the image. You have to check the NumberOfRvaAndSizes in
    // the optional header to verify a desired directory entry is there.
    //
    if ((NumberOfRvaAndSizes < EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC)) {
      RelocDir = NULL;
    }
  } else {
    Hdr.Te           = (EFI_TE_IMAGE_HEADER *)(UINTN)(ImageContext->ImageAddress);
    TeStrippedOffset = (UINT32)Hdr.Te->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER);
    Adjust           = (UINT64)(BaseAddress - (Hdr.Te->ImageBase + TeStrippedOffset));
    if (Adjust != 0) {
      Hdr.Te->ImageBase = (UINT64)(BaseAddress - TeStrippedOffset);
    }

    //
    // Find the relocation block
    //
    RelocDir = &Hdr.Te->DataDirectory[0];
  }

  RelocBase    = NULL;
  RelocBaseEnd = NULL;
  if ((RelocDir != NULL) && (RelocDir->Size > 0)) {
    Status = SafeUint32Add (RelocDir->VirtualAddress, (RelocDir->Size - 1), &EndAddress);
    if (!RETURN_ERROR (Status)) {
      RelocBase    = (EFI_IMAGE_BASE_RELOCATION *)PeCoffLoaderImageAddress (ImageContext, RelocDir->VirtualAddress, TeStrippedOffset);
      RelocBaseEnd = (EFI_IMAGE_BASE_RELOCATION *)PeCoffLoaderImageAddress (
                                                    ImageContext,
                                                    EndAddress,
                                                    TeStrippedOffset
                                                    );
    }

    if ((RelocBase == NULL) || (RelocBaseEnd == NULL) || ((UINTN)RelocBaseEnd < (UINTN)RelocBase)) {
      ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
      DEBUG ((DEBUG_ERROR, "Relocation block is not valid\n"));
      return RETURN_LOAD_ERROR;
    }
  }

  RelocBaseOrg = RelocBase;

  //
  // If Adjust is not zero, then apply fix ups to the image
  //
  if (Adjust != 0) {
    //
    // Run the relocation information and apply the fixups
    //
    FixupData = ImageContext->FixupData;
    while ((UINTN)RelocBase < (UINTN)RelocBaseEnd) {
      Reloc = (UINT16 *)((CHAR8 *)RelocBase + sizeof (EFI_IMAGE_BASE_RELOCATION));
      //
      // Add check for RelocBase->SizeOfBlock field.
      //
      if (RelocBase->SizeOfBlock == 0) {
        ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
        return RETURN_LOAD_ERROR;
      }

      if ((UINTN)RelocBase > MAX_ADDRESS - RelocBase->SizeOfBlock) {
        ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
        return RETURN_LOAD_ERROR;
      }

      RelocEnd = (UINT16 *)((CHAR8 *)RelocBase + RelocBase->SizeOfBlock);
      if ((UINTN)RelocEnd > (UINTN)RelocBaseOrg + RelocDir->Size) {
        ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
        return RETURN_LOAD_ERROR;
      }

      FixupBase = PeCoffLoaderImageAddress (ImageContext, RelocBase->VirtualAddress, TeStrippedOffset);
      if (FixupBase == NULL) {
        ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
        return RETURN_LOAD_ERROR;
      }

      //
      // Run this relocation record
      //
      while ((UINTN)Reloc < (UINTN)RelocEnd) {
        Fixup = PeCoffLoaderImageAddress (ImageContext, RelocBase->VirtualAddress + (*Reloc & 0xFFF), TeStrippedOffset);
        if (Fixup == NULL) {
          ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
          return RETURN_LOAD_ERROR;
        }

        switch ((*Reloc) >> 12) {
          case EFI_IMAGE_REL_BASED_ABSOLUTE:
            break;

          case EFI_IMAGE_REL_BASED_HIGH:
            Fixup16  = (UINT16 *)Fixup;
            *Fixup16 = (UINT16)(*Fixup16 + ((UINT16)((UINT32)Adjust >> 16)));
            if (FixupData != NULL) {
              *(UINT16 *)FixupData = *Fixup16;
              FixupData            = FixupData + sizeof (UINT16);
            }

            break;

          case EFI_IMAGE_REL_BASED_LOW:
            Fixup16  = (UINT16 *)Fixup;
            *Fixup16 = (UINT16)(*Fixup16 + (UINT16)Adjust);
            if (FixupData != NULL) {
              *(UINT16 *)FixupData = *Fixup16;
              FixupData            = FixupData + sizeof (UINT16);
            }

            break;

          case EFI_IMAGE_REL_BASED_HIGHLOW:
            Fixup32  = (UINT32 *)Fixup;
            *Fixup32 = *Fixup32 + (UINT32)Adjust;
            if (FixupData != NULL) {
              FixupData            = ALIGN_POINTER (FixupData, sizeof (UINT32));
              *(UINT32 *)FixupData = *Fixup32;
              FixupData            = FixupData + sizeof (UINT32);
            }

            break;

          case EFI_IMAGE_REL_BASED_DIR64:
            Fixup64  = (UINT64 *)Fixup;
            *Fixup64 = *Fixup64 + (UINT64)Adjust;
            if (FixupData != NULL) {
              FixupData              = ALIGN_POINTER (FixupData, sizeof (UINT64));
              *(UINT64 *)(FixupData) = *Fixup64;
              FixupData              = FixupData + sizeof (UINT64);
            }

            break;

          default:
            //
            // The common code does not handle some of the stranger IPF relocations
            // PeCoffLoaderRelocateImageEx () adds support for these complex fixups
            // on IPF and is a No-Op on other architectures.
            //
            Status = PeCoffLoaderRelocateImageEx (Reloc, Fixup, &FixupData, Adjust);
            if (RETURN_ERROR (Status)) {
              ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
              return Status;
            }
        }

        //
        // Next relocation record
        //
        Reloc += 1;
      }

      //
      // Next reloc block
      //
      RelocBase = (EFI_IMAGE_BASE_RELOCATION *)RelocEnd;
    }

    ASSERT ((UINTN)FixupData <= (UINTN)ImageContext->FixupData + ImageContext->FixupDataSize);

    //
    // Adjust the EntryPoint to match the linked-to address
    //
    if (ImageContext->DestinationAddress != 0) {
      ImageContext->EntryPoint -= (UINT64)ImageContext->ImageAddress;
      ImageContext->EntryPoint += (UINT64)ImageContext->DestinationAddress;
    }
  }

  // Applies additional environment specific actions to relocate fixups
  // to a PE/COFF image if needed
  PeCoffLoaderRelocateImageExtraAction (ImageContext);

  return RETURN_SUCCESS;
}
* 获取进入点
C 复制代码
  Pe32Data    = (VOID *)((UINTN)ImageAddress);
  *EntryPoint = ImageEntryPoint;
调用PEIM安全验证服务
C 复制代码
EFI_STATUS
VerifyPeim (
  IN PEI_CORE_INSTANCE    *PrivateData,
  IN EFI_PEI_FV_HANDLE    VolumeHandle,
  IN EFI_PEI_FILE_HANDLE  FileHandle,
  IN UINT32               AuthenticationStatus
  )
{
  EFI_STATUS  Status;
  BOOLEAN     DeferExecution;

  Status = EFI_NOT_FOUND;
  if (PrivateData->PrivateSecurityPpi == NULL) {
    //
    // Check AuthenticationStatus first.
    //
    if ((AuthenticationStatus & EFI_AUTH_STATUS_IMAGE_SIGNED) != 0) {
      if ((AuthenticationStatus & (EFI_AUTH_STATUS_TEST_FAILED | EFI_AUTH_STATUS_NOT_TESTED)) != 0) {
        Status = EFI_SECURITY_VIOLATION;
      }
    }
  } else {
    //
    // Check to see if the image is OK
    //
    Status = PrivateData->PrivateSecurityPpi->AuthenticationState (
                                                (CONST EFI_PEI_SERVICES **)&PrivateData->Ps,
                                                PrivateData->PrivateSecurityPpi,
                                                AuthenticationStatus,
                                                VolumeHandle,
                                                FileHandle,
                                                &DeferExecution
                                                );
    if (DeferExecution) {
      Status = EFI_SECURITY_VIOLATION;
    }
  }

  return Status;
}
变更PEIM调度状态
C 复制代码
Private->Fv[FvCount].PeimState[PeimCount]++;
尝试调用PEIM进入点
C 复制代码
  PeimEntryPoint = (EFI_PEIM_ENTRY_POINT2)(UINTN)EntryPoint;
  PeimEntryPoint (PeimFileHandle, (const EFI_PEI_SERVICES **)PeiServices);
  Private->PeimDispatchOnThisPass = TRUE;
windbg 复制代码
0: kd> .reload /i PCDPEIM=0x`83b5a0
C 复制代码
EFI_STATUS
EFIAPI
_ModuleEntryPoint (
  IN EFI_PEI_FILE_HANDLE     FileHandle,
  IN CONST EFI_PEI_SERVICES  **PeiServices
  )
{
  if (_gPeimRevision != 0) {
    //
    // Make sure that the PEI spec revision of the platform is >= PEI spec revision of the driver
    //
    ASSERT ((*PeiServices)->Hdr.Revision >= _gPeimRevision);
  }

  //
  // Call constructor for all libraries
  //
  ProcessLibraryConstructorList (FileHandle, PeiServices);

  //
  // Call the driver entry point
  //
  return ProcessModuleEntryPointList (FileHandle, PeiServices);
}
* 为所有库调用构造函数
C 复制代码
VOID
EFIAPI
ProcessLibraryConstructorList (
  IN       EFI_PEI_FILE_HANDLE       FileHandle,
  IN CONST EFI_PEI_SERVICES          **PeiServices
  )
{
  EFI_STATUS  Status;

  Status = BaseDebugLibSerialPortConstructor ();
  ASSERT_RETURN_ERROR (Status);

}
C 复制代码
RETURN_STATUS
EFIAPI
BaseDebugLibSerialPortConstructor (
  VOID
  )
{
  return SerialPortInitialize ();
}
* 调用PEIM进入点
C 复制代码
EFI_STATUS
EFIAPI
ProcessModuleEntryPointList (
  IN       EFI_PEI_FILE_HANDLE  FileHandle,
  IN CONST EFI_PEI_SERVICES     **PeiServices
  )

{
  return PcdPeimInit (FileHandle, PeiServices);
}
** PCD PEIM 模块的主入口函数

PCD PEIM模块主入口函数介绍:

https://blog.csdn.net/degen_/article/details/153330562

C 复制代码
EFI_STATUS
EFIAPI
PcdPeimInit (
  IN       EFI_PEI_FILE_HANDLE  FileHandle,
  IN CONST EFI_PEI_SERVICES     **PeiServices
  )
{
  EFI_STATUS  Status;

  Status = PeiServicesRegisterForShadow (FileHandle);
  if (Status == EFI_ALREADY_STARTED) {
    //
    // This is now starting in memory, the second time starting.
    //
    EFI_PEI_PPI_DESCRIPTOR  *OldPpiList;
    EFI_PEI_PPI_DESCRIPTOR  *OldPpiList2;
    VOID                    *Ppi;
    VOID                    *Ppi2;

    OldPpiList = NULL;
    Status     = PeiServicesLocatePpi (
                   &gPcdPpiGuid,
                   0,
                   &OldPpiList,
                   &Ppi
                   );
    ASSERT_EFI_ERROR (Status);

    if (OldPpiList != NULL) {
      Status = PeiServicesReInstallPpi (OldPpiList, &mPpiList[0]);
      ASSERT_EFI_ERROR (Status);
    }

    OldPpiList2 = NULL;
    Status      = PeiServicesLocatePpi (
                    &gGetPcdInfoPpiGuid,
                    0,
                    &OldPpiList2,
                    &Ppi2
                    );
    ASSERT_EFI_ERROR (Status);

    if (OldPpiList2 != NULL) {
      Status = PeiServicesReInstallPpi (OldPpiList2, &mPpiList2[0]);
      ASSERT_EFI_ERROR (Status);
    }

    OldPpiList = NULL;
    Status     = PeiServicesLocatePpi (
                   &gEfiPeiPcdPpiGuid,
                   0,
                   &OldPpiList,
                   &Ppi
                   );
    ASSERT_EFI_ERROR (Status);

    if (OldPpiList != NULL) {
      Status = PeiServicesReInstallPpi (OldPpiList, &mPpiList[1]);
      ASSERT_EFI_ERROR (Status);
    }

    OldPpiList2 = NULL;
    Status      = PeiServicesLocatePpi (
                    &gEfiGetPcdInfoPpiGuid,
                    0,
                    &OldPpiList2,
                    &Ppi2
                    );
    ASSERT_EFI_ERROR (Status);

    if (OldPpiList2 != NULL) {
      Status = PeiServicesReInstallPpi (OldPpiList2, &mPpiList2[1]);
      ASSERT_EFI_ERROR (Status);
    }

    return Status;
  }

  BuildPcdDatabase (FileHandle);

  //
  // Install PCD_PPI and EFI_PEI_PCD_PPI.
  //
  Status = PeiServicesInstallPpi (&mPpiList[0]);
  ASSERT_EFI_ERROR (Status);

  //
  // Install GET_PCD_INFO_PPI and EFI_GET_PCD_INFO_PPI.
  //
  Status = PeiServicesInstallPpi (&mPpiList2[0]);
  ASSERT_EFI_ERROR (Status);

  Status = PeiServicesNotifyPpi (&mEndOfPeiSignalPpiNotifyList[0]);
  ASSERT_EFI_ERROR (Status);

  Status = PeiRegisterCallBackOnSet (
             &gEfiMdeModulePkgTokenSpaceGuid,
             PcdToken (PcdSetNvStoreDefaultId),
             PcdSetNvStoreDefaultIdCallBack
             );
  ASSERT_EFI_ERROR (Status);

  return Status;
}
报告PEIM 已初始化完毕
C 复制代码
                REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
                  EFI_PROGRESS_CODE,
                  (EFI_SOFTWARE_PEI_CORE | EFI_SW_PC_INIT_END),
                  (VOID *)(&PeimFileHandle),
                  sizeof (PeimFileHandle)
                  );
C 复制代码
BOOLEAN
EFIAPI
ReportProgressCodeEnabled (
  VOID
  )
{
  return (BOOLEAN)((PcdGet8 (PcdReportStatusCodePropertyMask) & REPORT_STATUS_CODE_PROPERTY_PROGRESS_CODE_ENABLED) != 0);
}
C 复制代码
EFI_STATUS
EFIAPI
ReportStatusCodeWithExtendedData (
  IN EFI_STATUS_CODE_TYPE   Type,
  IN EFI_STATUS_CODE_VALUE  Value,
  IN CONST VOID             *ExtendedData,
  IN UINTN                  ExtendedDataSize
  )
{
  ASSERT (ExtendedData     != NULL);
  ASSERT (ExtendedDataSize != 0);
  return ReportStatusCodeEx (
           Type,
           Value,
           0,
           NULL,
           NULL,
           ExtendedData,
           ExtendedDataSize
           );
}
检测性能测量值是否可以被记录
C 复制代码
PERF_START_IMAGE_END (PeimFileHandle);
C 复制代码
BOOLEAN
EFIAPI
LogPerformanceMeasurementEnabled (
  IN  CONST UINTN  Type
  )
{
  //
  // When Performance measurement is enabled and the type is not filtered, the performance can be logged.
  //
  if (PerformanceMeasurementEnabled () && ((PcdGet8 (PcdPerformanceLibraryPropertyMask) & Type) == 0)) {
    return TRUE;
  }

  return FALSE;
}
根据SwitchStackSignal切换栈

轮到 MemoryInit PEIM 时才把 SwitchStackSignal 置 TRUE

C 复制代码
            PeiCheckAndSwitchStack (SecCoreData, Private);
C 复制代码
VOID
PeiCheckAndSwitchStack (
  IN CONST EFI_SEC_PEI_HAND_OFF  *SecCoreData,
  IN PEI_CORE_INSTANCE           *Private
  )
{
  VOID                               *LoadFixPeiCodeBegin;
  EFI_STATUS                         Status;
  CONST EFI_PEI_SERVICES             **PeiServices;
  UINT64                             NewStackSize;
  EFI_PHYSICAL_ADDRESS               TopOfOldStack;
  EFI_PHYSICAL_ADDRESS               TopOfNewStack;
  UINTN                              StackOffset;
  BOOLEAN                            StackOffsetPositive;
  EFI_PHYSICAL_ADDRESS               TemporaryRamBase;
  UINTN                              TemporaryRamSize;
  UINTN                              TemporaryStackSize;
  VOID                               *TemporaryStackBase;
  UINTN                              PeiTemporaryRamSize;
  VOID                               *PeiTemporaryRamBase;
  EFI_PEI_TEMPORARY_RAM_SUPPORT_PPI  *TemporaryRamSupportPpi;
  EFI_PHYSICAL_ADDRESS               BaseOfNewHeap;
  EFI_PHYSICAL_ADDRESS               HoleMemBase;
  UINTN                              HoleMemSize;
  UINTN                              HeapTemporaryRamSize;
  EFI_PHYSICAL_ADDRESS               TempBase1;
  UINTN                              TempSize1;
  EFI_PHYSICAL_ADDRESS               TempBase2;
  UINTN                              TempSize2;
  UINTN                              Index;

  PeiServices = (CONST EFI_PEI_SERVICES **)&Private->Ps;

  if (Private->SwitchStackSignal) {
    //
    // Before switch stack from temporary memory to permanent memory, calculate the heap and stack
    // usage in temporary memory for debugging.
    //
    DEBUG_CODE_BEGIN ();
    UINT32                *StackPointer;
    EFI_PEI_HOB_POINTERS  Hob;

    for (  StackPointer = (UINT32 *)SecCoreData->StackBase;
           (StackPointer < (UINT32 *)((UINTN)SecCoreData->StackBase + SecCoreData->StackSize)) \
        && (*StackPointer == PcdGet32 (PcdInitValueInTempStack));
           StackPointer++)
    {
    }

    DEBUG ((DEBUG_INFO, "Temp Stack : BaseAddress=0x%p Length=0x%X\n", SecCoreData->StackBase, (UINT32)SecCoreData->StackSize));
    DEBUG ((DEBUG_INFO, "Temp Heap  : BaseAddress=0x%p Length=0x%X\n", SecCoreData->PeiTemporaryRamBase, (UINT32)SecCoreData->PeiTemporaryRamSize));
    DEBUG ((DEBUG_INFO, "Total temporary memory:    %d bytes.\n", (UINT32)SecCoreData->TemporaryRamSize));
    DEBUG ((
      DEBUG_INFO,
      "  temporary memory stack ever used:       %d bytes.\n",
      (UINT32)(SecCoreData->StackSize - ((UINTN)StackPointer - (UINTN)SecCoreData->StackBase))
      ));
    DEBUG ((
      DEBUG_INFO,
      "  temporary memory heap used for HobList: %d bytes.\n",
      (UINT32)((UINTN)Private->HobList.HandoffInformationTable->EfiFreeMemoryBottom - (UINTN)Private->HobList.Raw)
      ));
    DEBUG ((
      DEBUG_INFO,
      "  temporary memory heap occupied by memory pages: %d bytes.\n",
      (UINT32)(UINTN)(Private->HobList.HandoffInformationTable->EfiMemoryTop - Private->HobList.HandoffInformationTable->EfiFreeMemoryTop)
      ));
    for (Hob.Raw = Private->HobList.Raw; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {
      if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_MEMORY_ALLOCATION) {
        DEBUG ((
          DEBUG_INFO,
          "Memory Allocation 0x%08x 0x%0lx - 0x%0lx\n", \
          Hob.MemoryAllocation->AllocDescriptor.MemoryType,               \
          Hob.MemoryAllocation->AllocDescriptor.MemoryBaseAddress,        \
          Hob.MemoryAllocation->AllocDescriptor.MemoryBaseAddress + Hob.MemoryAllocation->AllocDescriptor.MemoryLength - 1
          ));
      }
    }

    DEBUG_CODE_END ();

    if ((PcdGet64 (PcdLoadModuleAtFixAddressEnable) != 0) && (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME)) {
      //
      // Loading Module at Fixed Address is enabled
      //
      PeiLoadFixAddressHook (Private);

      //
      // If Loading Module at Fixed Address is enabled, Allocating memory range for Pei code range.
      //
      LoadFixPeiCodeBegin = AllocatePages ((UINTN)PcdGet32 (PcdLoadFixAddressPeiCodePageNumber));
      DEBUG ((DEBUG_INFO, "LOADING MODULE FIXED INFO: PeiCodeBegin = 0x%lX, PeiCodeTop= 0x%lX\n", (UINT64)(UINTN)LoadFixPeiCodeBegin, (UINT64)((UINTN)LoadFixPeiCodeBegin + PcdGet32 (PcdLoadFixAddressPeiCodePageNumber) * EFI_PAGE_SIZE)));
    }

    //
    // Reserve the size of new stack at bottom of physical memory
    //
    // The size of new stack in permanent memory must be the same size
    // or larger than the size of old stack in temporary memory.
    // But if new stack is smaller than the size of old stack, we also reserve
    // the size of old stack at bottom of permanent memory.
    //
    NewStackSize = RShiftU64 (Private->PhysicalMemoryLength, 1);
    NewStackSize = ALIGN_VALUE (NewStackSize, EFI_PAGE_SIZE);
    NewStackSize = MIN (PcdGet32 (PcdPeiCoreMaxPeiStackSize), NewStackSize);
    DEBUG ((DEBUG_INFO, "Old Stack size %d, New stack size %d\n", (UINT32)SecCoreData->StackSize, (UINT32)NewStackSize));
    ASSERT (NewStackSize >= SecCoreData->StackSize);

    //
    // Calculate stack offset and heap offset between temporary memory and new permanent
    // memory separately.
    //
    TopOfOldStack = (UINTN)SecCoreData->StackBase + SecCoreData->StackSize;
    TopOfNewStack = Private->PhysicalMemoryBegin + NewStackSize;
    if (TopOfNewStack >= TopOfOldStack) {
      StackOffsetPositive = TRUE;
      StackOffset         = (UINTN)(TopOfNewStack - TopOfOldStack);
    } else {
      StackOffsetPositive = FALSE;
      StackOffset         = (UINTN)(TopOfOldStack - TopOfNewStack);
    }

    Private->StackOffsetPositive = StackOffsetPositive;
    Private->StackOffset         = StackOffset;

    //
    // Build Stack HOB that describes the permanent memory stack
    //
    DEBUG ((DEBUG_INFO, "Stack Hob: BaseAddress=0x%lX Length=0x%lX\n", TopOfNewStack - NewStackSize, NewStackSize));
    BuildStackHob (TopOfNewStack - NewStackSize, NewStackSize);

    //
    // Cache information from SecCoreData into locals before SecCoreData is converted to a permanent memory address
    //
    TemporaryRamBase    = (EFI_PHYSICAL_ADDRESS)(UINTN)SecCoreData->TemporaryRamBase;
    TemporaryRamSize    = SecCoreData->TemporaryRamSize;
    TemporaryStackSize  = SecCoreData->StackSize;
    TemporaryStackBase  = SecCoreData->StackBase;
    PeiTemporaryRamSize = SecCoreData->PeiTemporaryRamSize;
    PeiTemporaryRamBase = SecCoreData->PeiTemporaryRamBase;

    //
    // TemporaryRamSupportPpi is produced by platform's SEC
    //
    Status = PeiServicesLocatePpi (
               &gEfiTemporaryRamSupportPpiGuid,
               0,
               NULL,
               (VOID **)&TemporaryRamSupportPpi
               );
    if (!EFI_ERROR (Status)) {
      //
      // Heap Offset
      //
      BaseOfNewHeap = TopOfNewStack;
      if (BaseOfNewHeap >= (UINTN)SecCoreData->PeiTemporaryRamBase) {
        Private->HeapOffsetPositive = TRUE;
        Private->HeapOffset         = (UINTN)(BaseOfNewHeap - (UINTN)SecCoreData->PeiTemporaryRamBase);
      } else {
        Private->HeapOffsetPositive = FALSE;
        Private->HeapOffset         = (UINTN)((UINTN)SecCoreData->PeiTemporaryRamBase - BaseOfNewHeap);
      }

      DEBUG ((DEBUG_INFO, "Heap Offset = 0x%lX Stack Offset = 0x%lX\n", (UINT64)Private->HeapOffset, (UINT64)Private->StackOffset));

      //
      // Calculate new HandOffTable and PrivateData address in permanent memory's stack
      //
      if (StackOffsetPositive) {
        SecCoreData = (CONST EFI_SEC_PEI_HAND_OFF *)((UINTN)(VOID *)SecCoreData + StackOffset);
        Private     = (PEI_CORE_INSTANCE *)((UINTN)(VOID *)Private + StackOffset);
      } else {
        SecCoreData = (CONST EFI_SEC_PEI_HAND_OFF *)((UINTN)(VOID *)SecCoreData - StackOffset);
        Private     = (PEI_CORE_INSTANCE *)((UINTN)(VOID *)Private - StackOffset);
      }

      //
      // Temporary Ram Support PPI is provided by platform, it will copy
      // temporary memory to permanent memory and do stack switching.
      // After invoking Temporary Ram Support PPI, the following code's
      // stack is in permanent memory.
      //
      TemporaryRamSupportPpi->TemporaryRamMigration (
                                PeiServices,
                                TemporaryRamBase,
                                (EFI_PHYSICAL_ADDRESS)(UINTN)(TopOfNewStack - TemporaryStackSize),
                                TemporaryRamSize
                                );

      //
      // Migrate memory pages allocated in pre-memory phase.
      // It could not be called before calling TemporaryRamSupportPpi->TemporaryRamMigration()
      // as the migrated memory pages may be overridden by TemporaryRamSupportPpi->TemporaryRamMigration().
      //
      MigrateMemoryPages (Private, TRUE);

      //
      // Entry PEI Phase 2
      //
      PeiCore (SecCoreData, NULL, Private);
    } else {
      //
      // Migrate memory pages allocated in pre-memory phase.
      //
      MigrateMemoryPages (Private, FALSE);

      //
      // Migrate the PEI Services Table pointer from temporary RAM to permanent RAM.
      //
      MigratePeiServicesTablePointer ();

      //
      // Heap Offset
      //
      BaseOfNewHeap = TopOfNewStack;
      HoleMemBase   = TopOfNewStack;
      HoleMemSize   = TemporaryRamSize - PeiTemporaryRamSize - TemporaryStackSize;
      if (HoleMemSize != 0) {
        //
        // Make sure HOB List start address is 8 byte alignment.
        //
        BaseOfNewHeap = ALIGN_VALUE (BaseOfNewHeap + HoleMemSize, 8);
      }

      if (BaseOfNewHeap >= (UINTN)SecCoreData->PeiTemporaryRamBase) {
        Private->HeapOffsetPositive = TRUE;
        Private->HeapOffset         = (UINTN)(BaseOfNewHeap - (UINTN)SecCoreData->PeiTemporaryRamBase);
      } else {
        Private->HeapOffsetPositive = FALSE;
        Private->HeapOffset         = (UINTN)((UINTN)SecCoreData->PeiTemporaryRamBase - BaseOfNewHeap);
      }

      DEBUG ((DEBUG_INFO, "Heap Offset = 0x%lX Stack Offset = 0x%lX\n", (UINT64)Private->HeapOffset, (UINT64)Private->StackOffset));

      //
      // Migrate Heap
      //
      HeapTemporaryRamSize = (UINTN)(Private->HobList.HandoffInformationTable->EfiFreeMemoryBottom - Private->HobList.HandoffInformationTable->EfiMemoryBottom);
      ASSERT (BaseOfNewHeap + HeapTemporaryRamSize <= Private->FreePhysicalMemoryTop);
      CopyMem ((UINT8 *)(UINTN)BaseOfNewHeap, PeiTemporaryRamBase, HeapTemporaryRamSize);

      //
      // Migrate Stack
      //
      CopyMem ((UINT8 *)(UINTN)(TopOfNewStack - TemporaryStackSize), TemporaryStackBase, TemporaryStackSize);

      //
      // Copy Hole Range Data
      //
      if (HoleMemSize != 0) {
        //
        // Prepare Hole
        //
        if (PeiTemporaryRamBase < TemporaryStackBase) {
          TempBase1 = (EFI_PHYSICAL_ADDRESS)(UINTN)PeiTemporaryRamBase;
          TempSize1 = PeiTemporaryRamSize;
          TempBase2 = (EFI_PHYSICAL_ADDRESS)(UINTN)TemporaryStackBase;
          TempSize2 = TemporaryStackSize;
        } else {
          TempBase1 = (EFI_PHYSICAL_ADDRESS)(UINTN)TemporaryStackBase;
          TempSize1 = TemporaryStackSize;
          TempBase2 = (EFI_PHYSICAL_ADDRESS)(UINTN)PeiTemporaryRamBase;
          TempSize2 = PeiTemporaryRamSize;
        }

        if (TemporaryRamBase < TempBase1) {
          Private->HoleData[0].Base = TemporaryRamBase;
          Private->HoleData[0].Size = (UINTN)(TempBase1 - TemporaryRamBase);
        }

        if (TempBase1 + TempSize1 < TempBase2) {
          Private->HoleData[1].Base = TempBase1 + TempSize1;
          Private->HoleData[1].Size = (UINTN)(TempBase2 - TempBase1 - TempSize1);
        }

        if (TempBase2 + TempSize2 < TemporaryRamBase + TemporaryRamSize) {
          Private->HoleData[2].Base = TempBase2 + TempSize2;
          Private->HoleData[2].Size = (UINTN)(TemporaryRamBase + TemporaryRamSize - TempBase2 - TempSize2);
        }

        //
        // Copy Hole Range data.
        //
        for (Index = 0; Index < HOLE_MAX_NUMBER; Index++) {
          if (Private->HoleData[Index].Size > 0) {
            if (HoleMemBase > Private->HoleData[Index].Base) {
              Private->HoleData[Index].OffsetPositive = TRUE;
              Private->HoleData[Index].Offset         = (UINTN)(HoleMemBase - Private->HoleData[Index].Base);
            } else {
              Private->HoleData[Index].OffsetPositive = FALSE;
              Private->HoleData[Index].Offset         = (UINTN)(Private->HoleData[Index].Base - HoleMemBase);
            }

            CopyMem ((VOID *)(UINTN)HoleMemBase, (VOID *)(UINTN)Private->HoleData[Index].Base, Private->HoleData[Index].Size);
            HoleMemBase = HoleMemBase + Private->HoleData[Index].Size;
          }
        }
      }

      //
      // Switch new stack
      //
      SwitchStack (
        (SWITCH_STACK_ENTRY_POINT)(UINTN)PeiCoreEntry,
        (VOID *)SecCoreData,
        (VOID *)Private,
        (VOID *)(UINTN)TopOfNewStack
        );
    }

    //
    // Code should not come here
    //
    ASSERT (FALSE);
  }
}
在调度级别处理通知列表

分别处理新增的Notify和PPI

C 复制代码
VOID
ProcessDispatchNotifyList (
  IN PEI_CORE_INSTANCE  *PrivateData
  )
{
  UINTN  TempValue;

  while (TRUE) {
    //
    // Check if the PEIM that was just dispatched resulted in any
    // Notifies getting installed.  If so, go process any dispatch
    // level Notifies that match the previously installed PPIs.
    // Use "while" instead of "if" since ProcessNotify can modify
    // DispatchNotifyList.CurrentCount (with NotifyPpi) so we have
    // to iterate until the same.
    //
    while (PrivateData->PpiData.DispatchNotifyList.LastDispatchedCount != PrivateData->PpiData.DispatchNotifyList.CurrentCount) {
      TempValue = PrivateData->PpiData.DispatchNotifyList.CurrentCount;
      ProcessNotify (
        PrivateData,
        EFI_PEI_PPI_DESCRIPTOR_NOTIFY_DISPATCH,
        0,
        PrivateData->PpiData.PpiList.LastDispatchedCount,
        PrivateData->PpiData.DispatchNotifyList.LastDispatchedCount,
        PrivateData->PpiData.DispatchNotifyList.CurrentCount
        );
      PrivateData->PpiData.DispatchNotifyList.LastDispatchedCount = TempValue;
    }

    //
    // Check if the PEIM that was just dispatched resulted in any
    // PPIs getting installed.  If so, go process any dispatch
    // level Notifies that match the installed PPIs.
    // Use "while" instead of "if" since ProcessNotify can modify
    // PpiList.CurrentCount (with InstallPpi) so we have to iterate
    // until the same.
    //
    while (PrivateData->PpiData.PpiList.LastDispatchedCount != PrivateData->PpiData.PpiList.CurrentCount) {
      TempValue = PrivateData->PpiData.PpiList.CurrentCount;
      ProcessNotify (
        PrivateData,
        EFI_PEI_PPI_DESCRIPTOR_NOTIFY_DISPATCH,
        PrivateData->PpiData.PpiList.LastDispatchedCount,
        PrivateData->PpiData.PpiList.CurrentCount,
        0,
        PrivateData->PpiData.DispatchNotifyList.LastDispatchedCount
        );
      PrivateData->PpiData.PpiList.LastDispatchedCount = TempValue;
    }

    if (PrivateData->PpiData.DispatchNotifyList.LastDispatchedCount == PrivateData->PpiData.DispatchNotifyList.CurrentCount) {
      break;
    }
  }

  return;
}
再次检测是否切换栈
C 复制代码
            PeiCheckAndSwitchStack (SecCoreData, Private);
永久内存到位后,把代码和数据迁移到内存
C 复制代码
            if ((Private->PeiMemoryInstalled) && (Private->Fv[FvCount].PeimState[PeimCount] == PEIM_STATE_REGISTER_FOR_SHADOW) &&   \
                (PcdGetBool (PcdMigrateTemporaryRamFirmwareVolumes) ||
                 (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME) ||
                 PcdGetBool (PcdShadowPeimOnS3Boot))
                )
            {
              //
              // If memory is available we shadow images by default for performance reasons.
              // We call the entry point a 2nd time so the module knows it's shadowed.
              //
              // PERF_START (PeiServices, L"PEIM", PeimFileHandle, 0);
              if ((Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME) && !PcdGetBool (PcdShadowPeimOnBoot) &&
                  !PcdGetBool (PcdMigrateTemporaryRamFirmwareVolumes))
              {
                //
                // Load PEIM into Memory for Register for shadow PEIM.
                //
                Status = PeiLoadImage (
                           PeiServices,
                           PeimFileHandle,
                           PEIM_STATE_REGISTER_FOR_SHADOW,
                           &EntryPoint,
                           &AuthenticationState
                           );
                if (Status == EFI_SUCCESS) {
                  PeimEntryPoint = (EFI_PEIM_ENTRY_POINT2)(UINTN)EntryPoint;
                }
              }

              ASSERT (PeimEntryPoint != NULL);
              PeimEntryPoint (PeimFileHandle, (const EFI_PEI_SERVICES **)PeiServices);
              // PERF_END (PeiServices, L"PEIM", PeimFileHandle, 0);

              //
              // PEIM_STATE_REGISTER_FOR_SHADOW move to PEIM_STATE_DONE
              //
              Private->Fv[FvCount].PeimState[PeimCount]++;

              //
              // Process the Notify list and dispatch any notifies for
              // newly installed PPIs.
              //
              ProcessDispatchNotifyList (Private);
            }
          }
        }
调度挂起的延迟调度请求
C 复制代码
        if (Private->DelayedDispatchTable != NULL) {
          if (DelayedDispatchDispatcher (Private->DelayedDispatchTable, NULL)) {
            ProcessDispatchNotifyList (Private);
          }
        }
      }

至此一个PEIM调度完成

依次调度其他PEIM

0083b620 00843240 PCDPEIM (已调度)

008432a0 00846fc0 REPORTSTATUSCODEROUTERPEI

008470a0 0084b4a0 STATUSCODEHANDLERPEI

0084b5a0 00869440 PLATFORMPEI

* REPORTSTATUSCODEROUTERPEI
C 复制代码
EFI_STATUS
EFIAPI
ProcessModuleEntryPointList (
  IN       EFI_PEI_FILE_HANDLE  FileHandle,
  IN CONST EFI_PEI_SERVICES     **PeiServices
  )

{
  return GenericStatusCodePeiEntry (FileHandle, PeiServices);
}
C 复制代码
EFI_STATUS
EFIAPI
GenericStatusCodePeiEntry (
  IN       EFI_PEI_FILE_HANDLE  FileHandle,
  IN CONST EFI_PEI_SERVICES     **PeiServices
  )
{
  EFI_STATUS                 Status;
  EFI_PEI_PPI_DESCRIPTOR     *OldDescriptor;
  EFI_PEI_PROGRESS_CODE_PPI  *OldStatusCodePpi;

  CreateRscHandlerCallbackPacket ();

  //
  // Install Report Status Code Handler PPI
  //
  Status = PeiServicesInstallPpi (mRscHandlerPpiList);
  ASSERT_EFI_ERROR (Status);

  //
  // Install Status Code PPI. PI spec specifies that there can be only one instance
  // of this PPI in system. So first check if other instance already exists.
  // If no other instance exists, then just install the PPI.
  // If other instance already exists, then reinstall it.
  //
  Status = PeiServicesLocatePpi (
             &gEfiPeiStatusCodePpiGuid,
             0,
             &OldDescriptor,
             (VOID **)&OldStatusCodePpi
             );
  if (!EFI_ERROR (Status)) {
    Status = PeiServicesReInstallPpi (OldDescriptor, mStatusCodePpiList);
  } else {
    Status = PeiServicesInstallPpi (mStatusCodePpiList);
  }

  ASSERT_EFI_ERROR (Status);

  return EFI_SUCCESS;
}
* STATUSCODEHANDLERPEI
C 复制代码
EFI_STATUS
EFIAPI
ProcessModuleEntryPointList (
  IN       EFI_PEI_FILE_HANDLE  FileHandle,
  IN CONST EFI_PEI_SERVICES     **PeiServices
  )

{
  return StatusCodeHandlerPeiEntry (FileHandle, PeiServices);
}
C 复制代码
EFI_STATUS
EFIAPI
StatusCodeHandlerPeiEntry (
  IN       EFI_PEI_FILE_HANDLE  FileHandle,
  IN CONST EFI_PEI_SERVICES     **PeiServices
  )
{
  EFI_STATUS               Status;
  EFI_PEI_RSC_HANDLER_PPI  *RscHandlerPpi;

  Status = PeiServicesLocatePpi (
             &gEfiPeiRscHandlerPpiGuid,
             0,
             NULL,
             (VOID **)&RscHandlerPpi
             );
  ASSERT_EFI_ERROR (Status);

  //
  // Dispatch initialization request to sub-statuscode-devices.
  // If enable UseSerial, then initialize serial port.
  // if enable UseMemory, then initialize memory status code worker.
  //
  if (PcdGetBool (PcdStatusCodeUseSerial)) {
    Status = SerialPortInitialize ();
    ASSERT_EFI_ERROR (Status);
    Status = RscHandlerPpi->Register (SerialStatusCodeReportWorker);
    ASSERT_EFI_ERROR (Status);
  }

  if (PcdGetBool (PcdStatusCodeUseMemory)) {
    Status = MemoryStatusCodeInitializeWorker ();
    ASSERT_EFI_ERROR (Status);
    Status = RscHandlerPpi->Register (MemoryStatusCodeReportWorker);
    ASSERT_EFI_ERROR (Status);
  }

  return EFI_SUCCESS;
}
* PLATFORMPEI
C 复制代码
EFI_STATUS
EFIAPI
ProcessModuleEntryPointList (
  IN       EFI_PEI_FILE_HANDLE  FileHandle,
  IN CONST EFI_PEI_SERVICES     **PeiServices
  )

{
  return InitializePlatform (FileHandle, PeiServices);
}
C 复制代码
EFI_STATUS
EFIAPI
InitializePlatform (
  IN       EFI_PEI_FILE_HANDLE  FileHandle,
  IN CONST EFI_PEI_SERVICES     **PeiServices
  )
{
  EFI_HOB_PLATFORM_INFO  *PlatformInfoHob;
  EFI_STATUS             Status;

  DEBUG ((DEBUG_INFO, "Platform PEIM Loaded\n"));
  PlatformInfoHob = BuildPlatformInfoHob ();

  if (TdIsEnabled ()) {
    TdxHelperBuildGuidHobForTdxMeasurement ();
  }

  if (RETURN_ERROR (QemuFwCfgInitCache (PlatformInfoHob))) {
    DEBUG ((DEBUG_ERROR, "QemuFwCfgInitCache failed !\n"));
  }

  PlatformInfoHob->SmmSmramRequire     = FeaturePcdGet (PcdSmmSmramRequire);
  PlatformInfoHob->SevEsIsEnabled      = MemEncryptSevEsIsEnabled ();
  PlatformInfoHob->PcdPciMmio64Size    = PcdGet64 (PcdPciMmio64Size);
  PlatformInfoHob->DefaultMaxCpuNumber = PcdGet32 (PcdCpuMaxLogicalProcessorNumber);

  PlatformDebugDumpCmos ();

  if (QemuFwCfgS3Enabled ()) {
    DEBUG ((DEBUG_INFO, "S3 support was detected on QEMU\n"));
    PlatformInfoHob->S3Supported = TRUE;
    Status                       = PcdSetBoolS (PcdAcpiS3Enable, TRUE);
    ASSERT_EFI_ERROR (Status);
  }

  BootModeInitialization (PlatformInfoHob);

  //
  // Query Host Bridge DID
  //
  PlatformInfoHob->HostBridgeDevId = PciRead16 (OVMF_HOSTBRIDGE_DID);
  AddressWidthInitialization (PlatformInfoHob);

  MaxCpuCountInitialization (PlatformInfoHob);

  if (PlatformInfoHob->SmmSmramRequire) {
    Q35BoardVerification (PlatformInfoHob);
    Q35TsegMbytesInitialization (PlatformInfoHob);
    Q35SmramAtDefaultSmbaseInitialization (PlatformInfoHob);
  }

  PublishPeiMemory (PlatformInfoHob);

  PlatformQemuUc32BaseInitialization (PlatformInfoHob);

  InitializeRamRegions (PlatformInfoHob);

  if (PlatformInfoHob->BootMode != BOOT_ON_S3_RESUME) {
    PeiFvInitialization (PlatformInfoHob);
    MemTypeInfoInitialization (PlatformInfoHob);
    MemMapInitialization (PlatformInfoHob);
    NoexecDxeInitialization (PlatformInfoHob);
  }

  InstallClearCacheCallback ();
  AmdSevInitialize (PlatformInfoHob);
  if (PlatformInfoHob->HostBridgeDevId == 0xffff) {
    MiscInitializationForMicrovm (PlatformInfoHob);
  } else {
    MiscInitialization (PlatformInfoHob);
    PlatformIdInitialization (PeiServices);
  }

  IntelTdxInitialize ();
  InstallFeatureControlCallback (PlatformInfoHob);
  if (PlatformInfoHob->SmmSmramRequire) {
    RelocateSmBase ();
  }

  //
  // Performed after CoCo (SEV/TDX) initialization to allow the memory
  // used to be validated before being used.
  //
  if (PlatformInfoHob->BootMode != BOOT_ON_S3_RESUME) {
    if (!PlatformInfoHob->SmmSmramRequire) {
      ReserveEmuVariableNvStore ();
    }
  }

  return EFI_SUCCESS;
}
PLATFORMPEI模块结束后进行切换栈

从临时内存到永久内存

* 打印临时内存信息
C 复制代码
    DEBUG_CODE_BEGIN ();
    UINT32                *StackPointer;
    EFI_PEI_HOB_POINTERS  Hob;

    for (  StackPointer = (UINT32 *)SecCoreData->StackBase;
           (StackPointer < (UINT32 *)((UINTN)SecCoreData->StackBase + SecCoreData->StackSize)) \
        && (*StackPointer == PcdGet32 (PcdInitValueInTempStack));
           StackPointer++)
    {
    }

    DEBUG ((DEBUG_INFO, "Temp Stack : BaseAddress=0x%p Length=0x%X\n", SecCoreData->StackBase, (UINT32)SecCoreData->StackSize));
    DEBUG ((DEBUG_INFO, "Temp Heap  : BaseAddress=0x%p Length=0x%X\n", SecCoreData->PeiTemporaryRamBase, (UINT32)SecCoreData->PeiTemporaryRamSize));
    DEBUG ((DEBUG_INFO, "Total temporary memory:    %d bytes.\n", (UINT32)SecCoreData->TemporaryRamSize));
    DEBUG ((
      DEBUG_INFO,
      "  temporary memory stack ever used:       %d bytes.\n",
      (UINT32)(SecCoreData->StackSize - ((UINTN)StackPointer - (UINTN)SecCoreData->StackBase))
      ));
    DEBUG ((
      DEBUG_INFO,
      "  temporary memory heap used for HobList: %d bytes.\n",
      (UINT32)((UINTN)Private->HobList.HandoffInformationTable->EfiFreeMemoryBottom - (UINTN)Private->HobList.Raw)
      ));
    DEBUG ((
      DEBUG_INFO,
      "  temporary memory heap occupied by memory pages: %d bytes.\n",
      (UINT32)(UINTN)(Private->HobList.HandoffInformationTable->EfiMemoryTop - Private->HobList.HandoffInformationTable->EfiFreeMemoryTop)
      ));
    for (Hob.Raw = Private->HobList.Raw; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {
      if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_MEMORY_ALLOCATION) {
        DEBUG ((
          DEBUG_INFO,
          "Memory Allocation 0x%08x 0x%0lx - 0x%0lx\n", \
          Hob.MemoryAllocation->AllocDescriptor.MemoryType,               \
          Hob.MemoryAllocation->AllocDescriptor.MemoryBaseAddress,        \
          Hob.MemoryAllocation->AllocDescriptor.MemoryBaseAddress + Hob.MemoryAllocation->AllocDescriptor.MemoryLength - 1
          ));
      }
    }

    DEBUG_CODE_END ();
复制代码
Temp Stack : BaseAddress=0x818000 Length=0x8000
Temp Heap  : BaseAddress=0x810000 Length=0x8000
Total temporary memory:    65536 bytes.
temporary memory stack ever used:       32768 bytes.
temporary memory heap used for HobList: 7224 bytes.
temporary memory heap occupied by memory pages: 0 bytes.
Memory Allocation 0x00000000 0x7000000 - 0x7FFFFFF
Memory Allocation 0x00000000 0x30000 - 0x4FFFF
Memory Allocation 0x00000004 0x820000 - 0x8EFFFF
Memory Allocation 0x00000004 0x900000 - 0x177FFFF
Memory Allocation 0x00000000 0xE0000000 - 0xEFFFFFFF
* 预留新栈的大小
C 复制代码
    NewStackSize = RShiftU64 (Private->PhysicalMemoryLength, 1);
    NewStackSize = ALIGN_VALUE (NewStackSize, EFI_PAGE_SIZE);
    NewStackSize = MIN (PcdGet32 (PcdPeiCoreMaxPeiStackSize), NewStackSize);
    DEBUG ((DEBUG_INFO, "Old Stack size %d, New stack size %d\n", (UINT32)SecCoreData->StackSize, (UINT32)NewStackSize));
    ASSERT (NewStackSize >= SecCoreData->StackSize);
复制代码
Old Stack size 32768, New stack size 131072
* 计算新栈和旧栈之间的偏移量
C 复制代码
    //
    // Calculate stack offset and heap offset between temporary memory and new permanent
    // memory separately.
    //
    TopOfOldStack = (UINTN)SecCoreData->StackBase + SecCoreData->StackSize;
    TopOfNewStack = Private->PhysicalMemoryBegin + NewStackSize;
    if (TopOfNewStack >= TopOfOldStack) {
      StackOffsetPositive = TRUE;
      StackOffset         = (UINTN)(TopOfNewStack - TopOfOldStack);
    } else {
      StackOffsetPositive = FALSE;
      StackOffset         = (UINTN)(TopOfOldStack - TopOfNewStack);
    }

    Private->StackOffsetPositive = StackOffsetPositive;
    Private->StackOffset         = StackOffset;
* 建立栈HOB
C 复制代码
    DEBUG ((DEBUG_INFO, "Stack Hob: BaseAddress=0x%lX Length=0x%lX\n", TopOfNewStack - NewStackSize, NewStackSize));
    BuildStackHob (TopOfNewStack - NewStackSize, NewStackSize);
复制代码
Stack Hob: BaseAddress=0x2BF4000 Length=0x20000
* 记录 SecCoreData 中的缓存信息
C 复制代码
    TemporaryRamBase    = (EFI_PHYSICAL_ADDRESS)(UINTN)SecCoreData->TemporaryRamBase;
    TemporaryRamSize    = SecCoreData->TemporaryRamSize;
    TemporaryStackSize  = SecCoreData->StackSize;
    TemporaryStackBase  = SecCoreData->StackBase;
    PeiTemporaryRamSize = SecCoreData->PeiTemporaryRamSize;
    PeiTemporaryRamBase = SecCoreData->PeiTemporaryRamBase;
* 定位并获取 TemporaryRamSupportPpi 接口
C 复制代码
    Status = PeiServicesLocatePpi (
               &gEfiTemporaryRamSupportPpiGuid,
               0,
               NULL,
               (VOID **)&TemporaryRamSupportPpi
               );
* 计算新堆和旧堆之间的偏移量
C 复制代码
      BaseOfNewHeap = TopOfNewStack;
      if (BaseOfNewHeap >= (UINTN)SecCoreData->PeiTemporaryRamBase) {
        Private->HeapOffsetPositive = TRUE;
        Private->HeapOffset         = (UINTN)(BaseOfNewHeap - (UINTN)SecCoreData->PeiTemporaryRamBase);
      } else {
        Private->HeapOffsetPositive = FALSE;
        Private->HeapOffset         = (UINTN)((UINTN)SecCoreData->PeiTemporaryRamBase - BaseOfNewHeap);
      }

      DEBUG ((DEBUG_INFO, "Heap Offset = 0x%lX Stack Offset = 0x%lX\n", (UINT64)Private->HeapOffset, (UINT64)Private->StackOffset));
* 计算永久内存栈的HandOffTable和PrivateData地址
C 复制代码
      if (StackOffsetPositive) {
        SecCoreData = (CONST EFI_SEC_PEI_HAND_OFF *)((UINTN)(VOID *)SecCoreData + StackOffset);
        Private     = (PEI_CORE_INSTANCE *)((UINTN)(VOID *)Private + StackOffset);
      } else {
        SecCoreData = (CONST EFI_SEC_PEI_HAND_OFF *)((UINTN)(VOID *)SecCoreData - StackOffset);
        Private     = (PEI_CORE_INSTANCE *)((UINTN)(VOID *)Private - StackOffset);
      }
* 从临时内存迁移到永久内存
C 复制代码
      TemporaryRamSupportPpi->TemporaryRamMigration (
                                PeiServices,
                                TemporaryRamBase,
                                (EFI_PHYSICAL_ADDRESS)(UINTN)(TopOfNewStack - TemporaryStackSize),
                                TemporaryRamSize
                                );
C 复制代码
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;
}
* 迁移内存页
C 复制代码
VOID
MigrateMemoryPages (
  IN PEI_CORE_INSTANCE  *Private,
  IN BOOLEAN            TemporaryRamMigrated
  )
{
  EFI_PHYSICAL_ADDRESS  NewMemPagesBase;
  EFI_PHYSICAL_ADDRESS  MemPagesBase;

  Private->MemoryPages.Size = (UINTN)(Private->HobList.HandoffInformationTable->EfiMemoryTop -
                                      Private->HobList.HandoffInformationTable->EfiFreeMemoryTop);
  if (Private->MemoryPages.Size == 0) {
    //
    // No any memory page allocated in pre-memory phase.
    //
    return;
  }

  Private->MemoryPages.Base = Private->HobList.HandoffInformationTable->EfiFreeMemoryTop;

  ASSERT (Private->MemoryPages.Size <= Private->FreePhysicalMemoryTop);
  NewMemPagesBase  = Private->FreePhysicalMemoryTop - Private->MemoryPages.Size;
  NewMemPagesBase &= ~(UINT64)EFI_PAGE_MASK;
  ASSERT (NewMemPagesBase >= Private->PhysicalMemoryBegin);
  //
  // Copy memory pages at temporary heap top to permanent heap top.
  //
  if (TemporaryRamMigrated) {
    //
    // Memory pages at temporary heap top has been migrated to permanent heap,
    // Here still needs to copy them from permanent heap to permanent heap top.
    //
    MemPagesBase = Private->MemoryPages.Base;
    if (Private->HeapOffsetPositive) {
      MemPagesBase += Private->HeapOffset;
    } else {
      MemPagesBase -= Private->HeapOffset;
    }

    CopyMem ((VOID *)(UINTN)NewMemPagesBase, (VOID *)(UINTN)MemPagesBase, Private->MemoryPages.Size);
  } else {
    CopyMem ((VOID *)(UINTN)NewMemPagesBase, (VOID *)(UINTN)Private->MemoryPages.Base, Private->MemoryPages.Size);
  }

  if (NewMemPagesBase >= Private->MemoryPages.Base) {
    Private->MemoryPages.OffsetPositive = TRUE;
    Private->MemoryPages.Offset         = (UINTN)(NewMemPagesBase - Private->MemoryPages.Base);
  } else {
    Private->MemoryPages.OffsetPositive = FALSE;
    Private->MemoryPages.Offset         = (UINTN)(Private->MemoryPages.Base - NewMemPagesBase);
  }

  DEBUG ((DEBUG_INFO, "Pages Offset = 0x%lX\n", (UINT64)Private->MemoryPages.Offset));

  Private->FreePhysicalMemoryTop = NewMemPagesBase;
}
* 第二次进入
C 复制代码
      PeiCore (SecCoreData, NULL, Private);
相关推荐
YJlio5 小时前
Process Monitor 学习笔记(5.24):工具栏参考与高效快捷键指南
笔记·学习·php
我是大咖5 小时前
C语言-贪吃蛇项目开发工具篇---ncursee库安装
c语言·开发语言
czy87874756 小时前
用C语言实现单例模式
c语言·单例模式
摇滚侠6 小时前
Spring Boot 3零基础教程,WEB 开发 Thymeleaf 核心语法 笔记39
spring boot·笔记·后端·thymeleaf
张人玉6 小时前
WPF 常用样式属性及示例笔记
笔记·wpf
czy87874756 小时前
用C语言实现适配器模式
c语言·适配器模式
报错小能手7 小时前
linux学习笔记(49)Redis详解(1)
linux·笔记·学习
QT 小鲜肉7 小时前
【个人成长笔记】在本地Windows系统中如何正确使用adb pull命令,把Linux系统中的文件或文件夹复制到本地中(亲测有效)
linux·windows·笔记·学习·adb
La Pulga7 小时前
【STM32】RTC实时时钟
c语言·stm32·单片机·嵌入式硬件·mcu·实时音视频