第一次进入 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);
相关推荐
wdfk_prog29 分钟前
[Linux]学习笔记系列 -- [kernel]kthread
linux·笔记·学习
散峰而望3 小时前
C/C++输入输出初级(一) (算法竞赛)
c语言·开发语言·c++·算法·github
鸽子一号3 小时前
c#笔记之面向对象
笔记
偷偷的卷3 小时前
【算法笔记 11】贪心策略六
笔记·算法
河铃旅鹿4 小时前
Android开发-java版:布局
android·笔记·学习
im_AMBER5 小时前
React 18
前端·javascript·笔记·学习·react.js·前端框架
yun68539926 小时前
读书之反思系统架构设计原则_个人笔记
笔记
是苏浙6 小时前
零基础入门C语言之C语言实现数据结构之单链表经典算法
c语言·开发语言·数据结构·算法
d111111111d7 小时前
STM32中为什么会有APB1和APB2两个外设有什么区别
笔记·stm32·单片机·嵌入式硬件·学习
71-38 小时前
C语言练习题——判断水仙花数(0-100000)
c语言·笔记·学习