dxeload.c

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

C
1,324
字号
  IN EFI_PEI_FV_FILE_LOADER_PPI                 *This,
  IN  EFI_FFS_FILE_HEADER                       *FfsHeader,
  OUT EFI_PHYSICAL_ADDRESS                      *ImageAddress,
  OUT UINT64                                    *ImageSize,
  OUT EFI_PHYSICAL_ADDRESS                      *EntryPoint
  )
/*++

Routine Description:

  Given a pointer to an FFS file containing a PE32 image, get the
  information on the PE32 image, and then "load" it so that it
  can be executed.

Arguments:

  This  - pointer to our file loader protocol
  FfsHeader - pointer to the FFS file header of the FFS file that
              contains the PE32 image we want to load
  ImageAddress  - returned address where the PE32 image is loaded
  ImageSize     - returned size of the loaded PE32 image
  EntryPoint    - entry point to the loaded PE32 image

Returns:
 
  EFI_SUCCESS  - The FFS file was successfully loaded.
  EFI_ERROR    - Unable to load the FFS file.

--*/
{
  EFI_PEI_PE_COFF_LOADER_PROTOCOL           *PeiEfiPeiPeCoffLoader;
  EFI_PEI_FLUSH_INSTRUCTION_CACHE_PROTOCOL  *PeiEfiPeiFlushInstructionCache;
  EFI_STATUS                                Status;
  VOID                                      *Pe32Data;

  Pe32Data = NULL;
  InstallEfiPeiFlushInstructionCache (&PeiEfiPeiFlushInstructionCache);
  InstallEfiPeiPeCoffLoader (gPeiServices, &PeiEfiPeiPeCoffLoader, NULL);
  //
  // Preprocess the FFS file to get a pointer to the PE32 information
  // in the enclosed PE32 image.
  //
  Status = PeiProcessFile (
            gPeiServices,
            EFI_SECTION_PE32,
            &FfsHeader,
            &Pe32Data
            );

  if (EFI_ERROR (Status)) {
    return Status;
  }
  //
  // Load the PE image from the FFS file
  //
  Status = PeiLoadFile (
            gPeiServices,
            PeiEfiPeiPeCoffLoader,
            PeiEfiPeiFlushInstructionCache,
            Pe32Data,
            ImageAddress,
            ImageSize,
            EntryPoint
            );

  return Status;
}

EFI_STATUS
PeiProcessFile (
  IN     EFI_PEI_SERVICES       **PeiServices,
  IN     UINT16                 SectionType,
  IN OUT EFI_FFS_FILE_HEADER    **FfsFileHeaderPoint,
  OUT    VOID                   **Pe32Data
  )
/*++

Routine Description:
  
Arguments:

  PeiServices        - General purpose services available to every PEIM.

  SectionType        - The type of section in the FFS file to process.

  FfsFileHeaderPoint - Pointer to pointer to the FFS file to process, looking for the
                       specified SectionType and return pointer to FFS file that PE32 image is found

  Pe32Data           - returned pointer to the start of the PE32 image found
                       in the FFS file.

Returns:

  EFI_SUCCESS       - found the PE32 section in the FFS file

--*/
{
  EFI_STATUS                      Status;
  VOID                            *SectionData;
  EFI_TIANO_DECOMPRESS_PROTOCOL   *DecompressProtocol;
  EFI_PHYSICAL_ADDRESS            OldTopOfMemory;
  UINT8                           *DstBuffer;
  UINT8                           *ScratchBuffer;
  UINT32                          DstBufferSize;
  UINTN                           ScratchBufferSize;
  EFI_COMMON_SECTION_HEADER       *CmpSection;
  UINTN                           CmpSectionLength;
  UINTN                           OccupiedCmpSectionLength;
  VOID                            *CmpFileData;
  UINTN                           CmpFileSize;
  EFI_COMMON_SECTION_HEADER       *Section;
  UINTN                           SectionLength;
  UINTN                           OccupiedSectionLength;
  UINT64                          FileSize;
  EFI_GUID_DEFINED_SECTION        *GuidedSectionHeader;
  UINT32                          AuthenticationStatus;
  EFI_PEI_SECTION_EXTRACTION_PPI  *SectionExtract;
  UINT32                          BufferSize;
  UINT8                           *Buffer;
  PEI_SECURITY_PPI                *Security;
  BOOLEAN                         StartCrisisRecovery;
  EFI_GUID                        TempGuid;
  EFI_FIRMWARE_VOLUME_HEADER      *FvHeader;
  EFI_COMPRESSION_SECTION         *CompressionSection;
  EFI_FFS_FILE_HEADER             *FfsFileHeader;
  
  FfsFileHeader = *FfsFileHeaderPoint;

  Status = (*PeiServices)->FfsFindSectionData (
                            PeiServices,
                            EFI_SECTION_COMPRESSION,
                            FfsFileHeader,
                            &SectionData
                            );

  //
  // Upon finding a DXE Core file, see if there is first a compression section
  //
  if (!EFI_ERROR (Status)) {
    //
    // Yes, there is a compression section, so extract the contents
    // Decompress the image here
    //
    Section = (EFI_COMMON_SECTION_HEADER *) (UINTN) (VOID *) ((UINT8 *) (FfsFileHeader) + (UINTN) sizeof (EFI_FFS_FILE_HEADER));

    do {
      SectionLength         = *(UINT32 *) (Section->Size) & 0x00ffffff;
      OccupiedSectionLength = GetOccupiedSize (SectionLength, 4);

      //
      // Was the DXE Core file encapsulated in a GUID'd section?
      //
      if (Section->Type == EFI_SECTION_GUID_DEFINED) {
        //
        // Locate the GUID'd Section Extractor
        //
        GuidedSectionHeader = (VOID *) (Section + 1);

        //
        // This following code constitutes the addition of the security model
        // to the DXE IPL.
        //
        //
        // Set a default authenticatino state
        //
        AuthenticationStatus = 0;

        Status = (*PeiServices)->LocatePpi (
                                  PeiServices,
                                  &gPeiSectionExtractionPpiGuid,
                                  0,
                                  NULL,
                                  &SectionExtract
                                  );

        if (EFI_ERROR (Status)) {
          return Status;
        }
        //
        // Verify Authentication State
        //
        (*PeiServices)->CopyMem (&TempGuid, Section + 1, sizeof (EFI_GUID));

        Status = SectionExtract->PeiGetSection (
                                  PeiServices,
                                  SectionExtract,
                                  (EFI_SECTION_TYPE *) &SectionType,
                                  &TempGuid,
                                  0,
                                  (VOID **) &Buffer,
                                  &BufferSize,
                                  &AuthenticationStatus
                                  );

        if (EFI_ERROR (Status)) {
          return Status;
        }
        //
        // If not ask the Security PPI, if exists, for disposition
        //
        //
        Status = (*PeiServices)->LocatePpi (
                                  PeiServices,
                                  &gPeiSecurityPpiGuid,
                                  0,
                                  NULL,
                                  &Security
                                  );
        if (EFI_ERROR (Status)) {
          return Status;
        }

        Status = Security->AuthenticationState (
                            PeiServices,
                            (struct _PEI_SECURITY_PPI *) Security,
                            AuthenticationStatus,
                            FfsFileHeader,
                            &StartCrisisRecovery
                            );

        if (EFI_ERROR (Status)) {
          return Status;
        }
        //
        // If there is a security violation, report to caller and have
        // the upper-level logic possible engender a crisis recovery
        //
        if (StartCrisisRecovery) {
          return EFI_SECURITY_VIOLATION;
        }
      }

      if (Section->Type == EFI_SECTION_PE32) {
        //
        // This is what we want
        //
        *Pe32Data = (VOID *) (Section + 1);
        return EFI_SUCCESS;
      } else if (Section->Type == EFI_SECTION_COMPRESSION) {
        //
        // This is a compression set, expand it
        //
        CompressionSection  = (EFI_COMPRESSION_SECTION *) Section;
        DecompressProtocol  = NULL;

        switch (CompressionSection->CompressionType) {
        case EFI_STANDARD_COMPRESSION:
          Status = InstallTianoDecompress (&DecompressProtocol);
          break;

        case EFI_CUSTOMIZED_COMPRESSION:
          //
          // Load user customized compression protocol.
          //
          Status = InstallCustomizedDecompress ((EFI_CUSTOMIZED_DECOMPRESS_PROTOCOL **) &DecompressProtocol);
          break;

        case EFI_NOT_COMPRESSED:
          //
          // Need to support not compressed file
          //
          Status = EFI_UNSUPPORTED;
          break;

        default:
          Status = EFI_UNSUPPORTED;
        }
        //
        // Unsupport compression type
        //
        if (EFI_ERROR (Status)) {
          ASSERT_PEI_ERROR (PeiServices, Status);
          return EFI_NOT_FOUND;
        }

        Status = (*PeiServices)->AllocatePages (
                                  PeiServices,
                                  EfiBootServicesData,
                                  1,  // EFI_PAGE_SIZE,
                                  &OldTopOfMemory
                                  );

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

        DstBufferSize     = 0;
        ScratchBufferSize = 0;
        DstBuffer         = (UINT8 *) (UINTN) (OldTopOfMemory);
        ScratchBuffer     = (UINT8 *) (UINTN) (OldTopOfMemory);
        Status = DecompressProtocol->GetInfo (
                                      DecompressProtocol,
                                      (UINT8 *) ((EFI_COMPRESSION_SECTION *) Section + 1),
                                      (UINT32) SectionLength - sizeof (EFI_COMPRESSION_SECTION),
                                      (UINT32 *) &DstBufferSize,
                                      (UINT32 *) &ScratchBufferSize
                                      );

        if (EFI_SUCCESS == Status) {
          //
          // This is a compression set, expand it
          //
          Status = (*PeiServices)->AllocatePages (
                                    PeiServices,
                                    EfiBootServicesData,
                                    EFI_SIZE_TO_PAGES (ScratchBufferSize),
                                    &OldTopOfMemory
                                    );

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

          ScratchBuffer = (UINT8 *) (UINTN) (OldTopOfMemory);

          //
          // Allocate destination buffer
          //
          Status = (*PeiServices)->AllocatePages (
                                    PeiServices,
                                    EfiBootServicesData,
                                    EFI_SIZE_TO_PAGES (DstBufferSize),
                                    &OldTopOfMemory
                                    );

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

          DstBuffer = (UINT8 *) (UINTN) (OldTopOfMemory);

          //
          // Call decompress function
          //
          Status = DecompressProtocol->Decompress (
                                        DecompressProtocol,
                                        (CHAR8 *) ((EFI_COMPRESSION_SECTION *) Section + 1),
                                        (UINT32) SectionLength - sizeof (EFI_COMPRESSION_SECTION),
                                        DstBuffer,
                                        (UINT32) DstBufferSize,
                                        ScratchBuffer,
                                        (UINT32) ScratchBufferSize
                                        );
        }

        if (EFI_ERROR (Status)) {
          //
          // Decompress failed
          //
          return EFI_NOT_FOUND;
        }

        CmpSection = (EFI_COMMON_SECTION_HEADER *) DstBuffer;
        if (CmpSection->Type == EFI_SECTION_RAW) {
          //
          // Skip the section header and
          // adjust the pointer alignment to 16
          //
          FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (DstBuffer + 16);

          if (FvHeader->Signature == EFI_FVH_SIGNATURE) {
            FfsFileHeader = NULL;
            Status        = PeiBuildHobFv (PeiServices, (EFI_PHYSICAL_ADDRESS) (UINTN) FvHeader, FvHeader->FvLength);
            Status = (*PeiServices)->FfsFindNextFile (
                                      PeiServices,
                                      EFI_FV_FILETYPE_DXE_CORE,
                                      FvHeader,
                                      &FfsFileHeader
                                      );

            if (EFI_ERROR (Status)) {
              return EFI_NOT_FOUND;
            }
            
            //
            // Write the pointer to the FFS file processed to FfsFileHeaderPoint.
            //
            *FfsFileHeaderPoint = FfsFileHeader;
            
            return PeiProcessFile (PeiServices, SectionType, FfsFileHeaderPoint, Pe32Data);
          }
        }
        //
        // Decompress successfully.
        // Loop the decompressed data searching for expected section.
        //
        CmpFileData = (VOID *) DstBuffer;
        CmpFileSize = DstBufferSize;
        do {
          CmpSectionLength = *(UINT32 *) (CmpSection->Size) & 0x00ffffff;
          if (CmpSection->Type == EFI_SECTION_PE32) {
            //
            // This is what we want
            //
            *Pe32Data = (VOID *) (CmpSection + 1);
            return EFI_SUCCESS;
          }

          OccupiedCmpSectionLength  = GetOccupiedSize (CmpSectionLength, 4);
          CmpSection                = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) CmpSection + OccupiedCmpSectionLength);
        } while (CmpSection->Type != 0 && (UINTN) ((UINT8 *) CmpSection - (UINT8 *) CmpFileData) < CmpFileSize);
      }

      Section   = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) Section + OccupiedSectionLength);
      FileSize  = FfsFileHeader->Size[0] & 0xFF;
      FileSize += (FfsFileHeader->Size[1] << 8) & 0xFF00;
      FileSize += (FfsFileHeader->Size[2] << 16) & 0xFF0000;
      FileSize &= 0x00FFFFFF;
    } while (Section->Type != 0 && (UINTN) ((UINT8 *) Section - (UINT8 *) FfsFileHeader) < FileSize);

    //
    // End of the decompression activity
    //
  } else {

    Status = (*PeiServices)->FfsFindSectionData (
                              PeiServices,
                              EFI_SECTION_PE32,
                              FfsFileHeader,
                              &SectionData
                              );

    if (EFI_ERROR (Status)) {
      Status = (*PeiServices)->FfsFindSectionData (
                                PeiServices,
                                EFI_SECTION_TE,
                                FfsFileHeader,
                                &SectionData
                                );
      if (EFI_ERROR (Status)) {
        return Status;
      }
    }
  }

  *Pe32Data = SectionData;

  return EFI_SUCCESS;
}

⌨️ 快捷键说明

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