dxeload.c

来自「EFI BIOS是Intel提出的下一代的BIOS标准。这里上传的Edk源代码是」· C语言 代码 · 共 1,324 行 · 第 1/3 页

C
1,324
字号
  //
  // Add HOB for the Flush Instruction Cache Protocol
  //
  Interface = (VOID *) PeiEfiPeiFlushInstructionCache;

  Status = PeiBuildHobGuidData (
            PeiServices,
            &mPeiEfiPeiFlushInstructionCacheGuid,
            &Interface,
            sizeof (VOID *)
            );

  ASSERT_PEI_ERROR (PeiServices, Status);

  //
  // Add HOB for the PE/COFF Loader Protocol
  //
  Interface = (VOID *) PeiEfiPeiPeCoffLoader;

  Status = PeiBuildHobGuidData (
            PeiServices,
            &mPeiEfiPeiPeCoffLoaderGuid,
            &Interface,
            sizeof (VOID *)
            );

  ASSERT_PEI_ERROR (PeiServices, Status);

  //
  // Add HOB for the Transfer Control Protocol
  //
  Interface = (VOID *) PeiEfiPeiTransferControl;

  Status = PeiBuildHobGuidData (
            PeiServices,
            &mPeiEfiPeiTransferControlGuid,
            &Interface,
            sizeof (VOID *)
            );

  ASSERT_PEI_ERROR (PeiServices, Status);

  //
  // See if we are in crisis recovery
  //
  Status = (*PeiServices)->GetBootMode (PeiServices, &BootMode);

  if (!EFI_ERROR (Status) && (BootMode == BOOT_IN_RECOVERY_MODE)) {

    Status = (*PeiServices)->LocatePpi (
                              PeiServices,
                              &gPeiRecoveryModulePpiGuid,
                              0,
                              NULL,
                              &PeiRecovery
                              );

    ASSERT_PEI_ERROR (PeiServices, Status);
    Status = PeiRecovery->LoadRecoveryCapsule (PeiServices, PeiRecovery);
    ASSERT_PEI_ERROR (PeiServices, Status);

    //
    // Now should have a HOB with the DXE core w/ the old HOB destroyed
    //
  }
  
  //
  // Find the EFI_FV_FILETYPE_RAW type compressed Firmware Volume file in FTW spare block
  // The file found will be processed by PeiProcessFile: It will first be decompressed to
  // a normal FV, then a corresponding FV type hob will be built which is provided for DXE
  // core to find and dispatch drivers in this FV. Because PeiProcessFile typically checks
  // for EFI_FV_FILETYPE_DXE_CORE type file, in this condition we need not check returned 
  // status
  //
  Status = PeiFindFile (
            PeiServices,
            EFI_FV_FILETYPE_RAW,
            EFI_SECTION_PE32,
            &FirmwareFileName,
            &Pe32Data
            );
                             
  //
  // Find the DXE Core in a Firmware Volume
  //
  Status = PeiFindFile (
            PeiServices,
            EFI_FV_FILETYPE_DXE_CORE,
            EFI_SECTION_PE32,
            &DxeCoreFileName,
            &Pe32Data
            );

  ASSERT_PEI_ERROR (PeiServices, Status);

  //
  // Load the DXE Core from a Firmware Volume
  //
  Status = PeiLoadFile (
            PeiServices,
            PeiEfiPeiPeCoffLoader,
            PeiEfiPeiFlushInstructionCache,
            Pe32Data,
            &DxeCoreAddress,
            &DxeCoreSize,
            &DxeCoreEntryPoint
            );

  ASSERT_PEI_ERROR (PeiServices, Status);

  //
  // Transfer control to the DXE Core
  // The handoff state is simply a pointer to the HOB list
  //
  PEI_PERF_END (PeiServices, L"DxeIpl", NULL, 0);

  Status = (*PeiServices)->InstallPpi (PeiServices, &mPpiSignal);

  ASSERT_PEI_ERROR (PeiServices, Status);

  //
  // Add HOB for the DXE Core
  //
  Status = PeiBuildHobModule (
            PeiServices,
            &DxeCoreFileName,
            DxeCoreAddress,
            DxeCoreSize,
            DxeCoreEntryPoint
            );

  ASSERT_PEI_ERROR (PeiServices, Status);

  //
  // Report Status Code EFI_SW_PEI_PC_HANDOFF_TO_NEXT
  //
  PEI_REPORT_STATUS_CODE (
    PeiServices,
    EFI_PROGRESS_CODE,
    EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_CORE_PC_HANDOFF_TO_NEXT,
    0,
    NULL,
    NULL
    );

  PEI_DEBUG ((PeiServices, EFI_D_INFO, "DXE Core Entry\n"));
  SwitchStacks (
    (VOID *) (UINTN) DxeCoreEntryPoint,
    (UINTN) (HobList.Raw),
    (VOID *) (UINTN) TopOfStack,
    (VOID *) (UINTN) BspStore
    );

  //
  // If we get here, then the DXE Core returned.  This is an error
  //
  ASSERT_PEI_ERROR (PeiServices, Status);

  return EFI_OUT_OF_RESOURCES;
}

EFI_STATUS
PeiFindFile (
  IN  EFI_PEI_SERVICES       **PeiServices,
  IN  UINT8                  Type,
  IN  UINT16                 SectionType,
  OUT EFI_GUID               *FileName,
  OUT VOID                   **Pe32Data
  )
/*++

Routine Description:

  Finds a PE/COFF of a specific Type and SectionType in the Firmware Volumes
  described in the HOB list. Able to search in a compression set in a FFS file.
  But only one level of compression is supported, that is, not able to search
  in a compression set that is within another compression set.

Arguments:

  PeiServices - General purpose services available to every PEIM.
  Type        - The Type of file to retrieve
  SectionType - The type of section to retrieve from a file
  FileName    - The name of the file found in the Firmware Volume
  Pe32Data    - Pointer to the beginning of the PE/COFF file found in the Firmware Volume

Returns:

  EFI_SUCCESS   - The file was found, and the name is returned in FileName, and a pointer to
                  the PE/COFF image is returned in Pe32Data
  EFI_NOT_FOUND - The file was not found in the Firmware Volumes present in the HOB List

--*/
{
  EFI_FIRMWARE_VOLUME_HEADER  *FwVolHeader;
  EFI_FFS_FILE_HEADER         *FfsFileHeader;
  VOID                        *SectionData;
  EFI_STATUS                  Status;
  BOOLEAN                     Found;
  EFI_PEI_HOB_POINTERS        Hob;

  Status = (*PeiServices)->GetHobList (PeiServices, &Hob.Raw);

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

  Found         = FALSE;

  Status        = EFI_SUCCESS;

  FwVolHeader   = NULL;
  FfsFileHeader = NULL;
  SectionData   = NULL;

  //
  // Foreach Firmware Volume, look for a specified type
  // of file and break out when one is found
  //
  Hob.Raw = GetHob (EFI_HOB_TYPE_FV, Hob.Raw);
  if (Hob.Header->HobType != EFI_HOB_TYPE_FV) {
    return EFI_NOT_FOUND;
  }

  while (!END_OF_HOB_LIST (Hob)) {

    FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) (Hob.FirmwareVolume->BaseAddress);

    Status = (*PeiServices)->FfsFindNextFile (
                              PeiServices,
                              Type,
                              FwVolHeader,
                              &FfsFileHeader
                              );

    if (EFI_ERROR (Status)) {
      Hob.Raw = GET_NEXT_HOB (Hob);
      Hob.Raw = GetHob (EFI_HOB_TYPE_FV, Hob.Raw);
      if (Hob.Header->HobType != EFI_HOB_TYPE_FV) {
        break;
      }

      continue;
    } else {

      Status = PeiProcessFile (
                PeiServices,
                SectionType,
                &FfsFileHeader,
                Pe32Data
                );
      //
      // Copy the File GUID from the FFS file that Pe32Data is found
      //
      (*PeiServices)->CopyMem (
                        FileName,
                        &FfsFileHeader->Name,
                        sizeof (EFI_GUID)
                        );
      return Status;
    }
  }

  return EFI_NOT_FOUND;
}

EFI_STATUS
PeiLoadFile (
  IN  EFI_PEI_SERVICES                          **PeiServices,
  IN  EFI_PEI_PE_COFF_LOADER_PROTOCOL           *PeiEfiPeiPeCoffLoader,
  IN  EFI_PEI_FLUSH_INSTRUCTION_CACHE_PROTOCOL  *PeiEfiPeiFlushInstructionCache,
  IN  VOID                                      *Pe32Data,
  OUT EFI_PHYSICAL_ADDRESS                      *ImageAddress,
  OUT UINT64                                    *ImageSize,
  OUT EFI_PHYSICAL_ADDRESS                      *EntryPoint
  )
/*++

Routine Description:

  Loads and relocates a PE/COFF image into memory.

Arguments:

  PeiService         - General purpose services available to every PEIM.
  PeiEfiPeiPeCoffLoader - Pointer to a PE COFF loader protocol
  PeiEfiPeiFlushInstructionCache  - Pointer to a flush-instruction-cache protocol so
                                    we can flush the cache after loading
  Pe32Data         - The base address of the PE/COFF file that is to be loaded and relocated
  ImageAddress     - The base address of the relocated PE/COFF image
  ImageSize        - The size of the relocated PE/COFF image
  EntryPoint       - The entry point of the relocated PE/COFF image

Returns:

  EFI_SUCCESS   - The file was loaded and relocated
  EFI_OUT_OF_RESOURCES - There was not enough memory to load and relocate the PE/COFF file

--*/
{
  EFI_STATUS                            Status;
  EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT  ImageContext;
  EFI_PHYSICAL_ADDRESS                  MemoryBuffer;

  (*PeiServices)->SetMem (
                    &ImageContext,
                    sizeof (ImageContext),
                    0
                    );
  ImageContext.Handle = Pe32Data;
  Status              = GetImageReadFunction (PeiServices, &ImageContext);

  ASSERT_PEI_ERROR (PeiServices, Status);

  Status = PeiEfiPeiPeCoffLoader->GetImageInfo (PeiEfiPeiPeCoffLoader, &ImageContext);
  if (EFI_ERROR (Status)) {
    return Status;
  }
  //
  // Allocate Memory for the image
  //
  Status = (*PeiServices)->AllocatePages (
                            PeiServices,
                            EfiBootServicesData,
                            EFI_SIZE_TO_PAGES ((UINT32) ImageContext.ImageSize),
                            &MemoryBuffer
                            );

  ASSERT_PEI_ERROR (PeiServices, Status);

  ImageContext.ImageAddress = MemoryBuffer;
  //
  // Load the image to our new buffer
  //
  Status = PeiEfiPeiPeCoffLoader->LoadImage (PeiEfiPeiPeCoffLoader, &ImageContext);
  if (EFI_ERROR (Status)) {
    return Status;
  }
  //
  // Relocate the image in our new buffer
  //
  Status = PeiEfiPeiPeCoffLoader->RelocateImage (PeiEfiPeiPeCoffLoader, &ImageContext);
  if (EFI_ERROR (Status)) {
    return Status;
  }
  //
  // Flush the instruction cache so the image data is written before we execute it
  //
  Status = PeiEfiPeiFlushInstructionCache->Flush (
                                            PeiEfiPeiFlushInstructionCache,
                                            ImageContext.ImageAddress,
                                            ImageContext.ImageSize
                                            );

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

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

  return EFI_SUCCESS;
}

EFI_STATUS
ShadowDxeIpl (
  IN EFI_PEI_SERVICES                          **PeiServices,
  IN EFI_FFS_FILE_HEADER                       *DxeIpl,
  IN EFI_PEI_PE_COFF_LOADER_PROTOCOL           *PeiEfiPeiPeCoffLoader,
  IN EFI_PEI_FLUSH_INSTRUCTION_CACHE_PROTOCOL  *PeiEfiPeiFlushInstructionCache
  )
/*++

Routine Description:

  Shadow the DXE IPL to a different memory location. This occurs after permanent
  memory has been discovered.

Arguments:

  PeiService        - General purpose services available to every PEIM.
  DxeIpl            - Pointer to the FFS file header of the DXE IPL driver
  PeiEfiPeiPeCoffLoader - Pointer to a PE COFF loader protocol
  PeiEfiPeiFlushInstructionCache  - Pointer to a flush-instruction-cache protocol so
                                    we can flush the cache after shadowing the image

Returns:

  EFI_SUCCESS   - DXE IPL was successfully shadowed to a different memory location.
  EFI_ ERROR    - The shadow was unsuccessful.
  
--*/
{
  UINTN                     SectionLength;
  UINTN                     OccupiedSectionLength;
  EFI_PHYSICAL_ADDRESS      DxeIplAddress;
  UINT64                    DxeIplSize;
  EFI_PHYSICAL_ADDRESS      DxeIplEntryPoint;
  EFI_STATUS                Status;
  EFI_COMMON_SECTION_HEADER *Section;

  Section = (EFI_COMMON_SECTION_HEADER *) (DxeIpl + 1);

  while ((Section->Type != EFI_SECTION_PE32) && (Section->Type != EFI_SECTION_TE)) {
    SectionLength         = *(UINT32 *) (Section->Size) & 0x00ffffff;
    OccupiedSectionLength = GetOccupiedSize (SectionLength, 4);
    Section               = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) Section + OccupiedSectionLength);
  }
  
  //
  // Relocate DxeIpl into memory by using loadfile service
  //
  Status = PeiLoadFile (
            PeiServices,
            PeiEfiPeiPeCoffLoader,
            PeiEfiPeiFlushInstructionCache,
            (VOID *) (Section + 1),
            &DxeIplAddress,
            &DxeIplSize,
            &DxeIplEntryPoint
            );

  if (Status == EFI_SUCCESS) {
    //
    // Install PeiInMemory to indicate the Dxeipl is shadowed
    //
    Status = (*PeiServices)->InstallPpi (PeiServices, &mPpiPeiInMemory);

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

    Status = ((DXE_IPL_ENTRYPOINT) (UINTN) DxeIplEntryPoint) (DxeIpl, PeiServices);
  }

  return Status;
}

EFI_STATUS
EFIAPI
DxeIplLoadFile (

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?