Пример #1
0
/**
  Loads an EFI image into SMRAM.

  @param  DriverEntry             EFI_SMM_DRIVER_ENTRY instance

  @return EFI_STATUS

**/
EFI_STATUS
EFIAPI
SmmLoadImage (
  IN OUT EFI_SMM_DRIVER_ENTRY  *DriverEntry
  )
{
  UINT32                         AuthenticationStatus;
  UINTN                          FilePathSize;
  VOID                           *Buffer;
  UINTN                          Size;
  UINTN                          PageCount;
  EFI_GUID                       *NameGuid;
  EFI_STATUS                     Status;
  EFI_STATUS                     SecurityStatus;
  EFI_HANDLE                     DeviceHandle;
  EFI_PHYSICAL_ADDRESS           DstBuffer;
  EFI_DEVICE_PATH_PROTOCOL       *FilePath;
  EFI_DEVICE_PATH_PROTOCOL       *OriginalFilePath;
  EFI_DEVICE_PATH_PROTOCOL       *HandleFilePath;
  EFI_FIRMWARE_VOLUME2_PROTOCOL  *Fv;
  PE_COFF_LOADER_IMAGE_CONTEXT   ImageContext;
   
  Buffer               = NULL;
  Size                 = 0;
  Fv                   = DriverEntry->Fv;
  NameGuid             = &DriverEntry->FileName;
  FilePath             = DriverEntry->FvFileDevicePath;

  OriginalFilePath     = FilePath;
  HandleFilePath       = FilePath;
  DeviceHandle         = NULL;
  SecurityStatus       = EFI_SUCCESS;
  Status               = EFI_SUCCESS;
  AuthenticationStatus = 0;

  //
  // Try to get the image device handle by checking the match protocol.
  //
  Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &HandleFilePath, &DeviceHandle);
  if (EFI_ERROR(Status)) {
    return Status;
  }

  //
  // If the Security Architectural Protocol has not been located yet, then attempt to locate it
  //
  if (mSecurity == NULL) {
    gBS->LocateProtocol (&gEfiSecurityArchProtocolGuid, NULL, (VOID**)&mSecurity);
  }

  //
  // Verify the Authentication Status through the Security Architectural Protocol
  //
  if ((mSecurity != NULL) && (OriginalFilePath != NULL)) {
    SecurityStatus = mSecurity->FileAuthenticationState (
                                  mSecurity,
                                  AuthenticationStatus,
                                  OriginalFilePath
                                  );
    if (EFI_ERROR (SecurityStatus) && SecurityStatus != EFI_SECURITY_VIOLATION) {
      Status = SecurityStatus;
      return Status;
    }
  }
  
  //
  // Pull out just the file portion of the DevicePath for the LoadedImage FilePath
  //
  FilePath = OriginalFilePath;
  Status = gBS->HandleProtocol (DeviceHandle, &gEfiDevicePathProtocolGuid, (VOID **)&HandleFilePath);
  if (!EFI_ERROR (Status)) {
    FilePathSize = GetDevicePathSize (HandleFilePath) - sizeof(EFI_DEVICE_PATH_PROTOCOL);
    FilePath = (EFI_DEVICE_PATH_PROTOCOL *) (((UINT8 *)FilePath) + FilePathSize );
  }

  //
  // Try reading PE32 section firstly
  //
  Status = Fv->ReadSection (
                 Fv,
                 NameGuid,
                 EFI_SECTION_PE32,
                 0,
                 &Buffer,
                 &Size,
                 &AuthenticationStatus
                 );

  if (EFI_ERROR (Status)) {
    //
    // Try reading TE section secondly
    //
    Buffer = NULL;
    Size   = 0;
    Status = Fv->ReadSection (
                  Fv,
                  NameGuid,
                  EFI_SECTION_TE,
                  0,
                  &Buffer,
                  &Size,
                  &AuthenticationStatus
                  );
  }
  
  if (EFI_ERROR (Status)) {
    if (Buffer != NULL) {
      Status = gBS->FreePool (Buffer);
    }
    return Status;
  }

  //
  // Initialize ImageContext
  //
  ImageContext.Handle = Buffer;
  ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory;

  //
  // Get information about the image being loaded
  //
  Status = PeCoffLoaderGetImageInfo (&ImageContext);
  if (EFI_ERROR (Status)) {
    if (Buffer != NULL) {
      Status = gBS->FreePool (Buffer);
    }
    return Status;
  }
  //
  // if Loading module at Fixed Address feature is enabled, then  cut out a memory range started from TESG BASE
  // to hold the Smm driver code
  //
  if (PcdGet64(PcdLoadModuleAtFixAddressEnable) != 0) {
    //
    // Get the fixed loading address assigned by Build tool
    //
    Status = GetPeCoffImageFixLoadingAssignedAddress (&ImageContext);
    if (!EFI_ERROR (Status)) {
      //
      // Since the memory range to load Smm core alreay been cut out, so no need to allocate and free this range
      // following statements is to bypass SmmFreePages
      //
      PageCount = 0;
      DstBuffer = (UINTN)gLoadModuleAtFixAddressSmramBase;   
    } else {
       DEBUG ((EFI_D_INFO|EFI_D_LOAD, "LOADING MODULE FIXED ERROR: Failed to load module at fixed address. \n"));
       //
       // allocate the memory to load the SMM driver
       //
       PageCount = (UINTN)EFI_SIZE_TO_PAGES((UINTN)ImageContext.ImageSize + ImageContext.SectionAlignment);
       DstBuffer = (UINTN)(-1);
     
       Status = SmmAllocatePages (
                   AllocateMaxAddress,
                   EfiRuntimeServicesCode,
                   PageCount,
                   &DstBuffer
                   );
       if (EFI_ERROR (Status)) {
         if (Buffer != NULL) {
           Status = gBS->FreePool (Buffer);
         } 
         return Status;
       }     
      ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)DstBuffer;
    }
  } else {
     PageCount = (UINTN)EFI_SIZE_TO_PAGES((UINTN)ImageContext.ImageSize + ImageContext.SectionAlignment);
     DstBuffer = (UINTN)(-1);
     
     Status = SmmAllocatePages (
                  AllocateMaxAddress,
                  EfiRuntimeServicesCode,
                  PageCount,
                  &DstBuffer
                  );
     if (EFI_ERROR (Status)) {
       if (Buffer != NULL) {
         Status = gBS->FreePool (Buffer);
       }
       return Status;
     }
     
     ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)DstBuffer;
  }
  //
  // Align buffer on section boundry
  //
  ImageContext.ImageAddress += ImageContext.SectionAlignment - 1;
  ImageContext.ImageAddress &= ~(ImageContext.SectionAlignment - 1);

  //
  // Load the image to our new buffer
  //
  Status = PeCoffLoaderLoadImage (&ImageContext);
  if (EFI_ERROR (Status)) {
    if (Buffer != NULL) {
      Status = gBS->FreePool (Buffer);
    }
    SmmFreePages (DstBuffer, PageCount);
    return Status;
  }

  //
  // Relocate the image in our new buffer
  //
  Status = PeCoffLoaderRelocateImage (&ImageContext);
  if (EFI_ERROR (Status)) {
    if (Buffer != NULL) {
      Status = gBS->FreePool (Buffer);
    }
    SmmFreePages (DstBuffer, PageCount);
    return Status;
  }

  //
  // Flush the instruction cache so the image data are written before we execute it
  //
  InvalidateInstructionCacheRange ((VOID *)(UINTN) ImageContext.ImageAddress, (UINTN) ImageContext.ImageSize);

  //
  // Save Image EntryPoint in DriverEntry
  //
  DriverEntry->ImageEntryPoint  = ImageContext.EntryPoint;
  DriverEntry->ImageBuffer      = DstBuffer; 
  DriverEntry->NumberOfPage     = PageCount;

  //
  // Allocate a Loaded Image Protocol in EfiBootServicesData
  //
  Status = gBS->AllocatePool (EfiBootServicesData, sizeof (EFI_LOADED_IMAGE_PROTOCOL), (VOID **)&DriverEntry->LoadedImage);
  if (EFI_ERROR (Status)) {
    if (Buffer != NULL) {
      Status = gBS->FreePool (Buffer);
    }
    SmmFreePages (DstBuffer, PageCount);
    return Status;
  }

  //
  // Fill in the remaining fields of the Loaded Image Protocol instance.
  // Note: ImageBase is an SMRAM address that can not be accessed outside of SMRAM if SMRAM window is closed.
  //
  DriverEntry->LoadedImage->Revision      = EFI_LOADED_IMAGE_PROTOCOL_REVISION;
  DriverEntry->LoadedImage->ParentHandle  = gSmmCorePrivate->SmmIplImageHandle;
  DriverEntry->LoadedImage->SystemTable   = gST;
  DriverEntry->LoadedImage->DeviceHandle  = DeviceHandle;

  //
  // Make an EfiBootServicesData buffer copy of FilePath
  //
  Status = gBS->AllocatePool (EfiBootServicesData, GetDevicePathSize (FilePath), (VOID **)&DriverEntry->LoadedImage->FilePath);
  if (EFI_ERROR (Status)) {
    if (Buffer != NULL) {
      Status = gBS->FreePool (Buffer);
    }
    SmmFreePages (DstBuffer, PageCount);
    return Status;
  }
  CopyMem (DriverEntry->LoadedImage->FilePath, FilePath, GetDevicePathSize (FilePath));

  DriverEntry->LoadedImage->ImageBase     = (VOID *)(UINTN)DriverEntry->ImageBuffer;
  DriverEntry->LoadedImage->ImageSize     = ImageContext.ImageSize;
  DriverEntry->LoadedImage->ImageCodeType = EfiRuntimeServicesCode;
  DriverEntry->LoadedImage->ImageDataType = EfiRuntimeServicesData;

  //
  // Create a new image handle in the UEFI handle database for the SMM Driver
  //
  DriverEntry->ImageHandle = NULL;
  Status = gBS->InstallMultipleProtocolInterfaces (
                  &DriverEntry->ImageHandle,
                  &gEfiLoadedImageProtocolGuid, DriverEntry->LoadedImage,
                  NULL
                  );

  //
  // Print the load address and the PDB file name if it is available
  //

  DEBUG_CODE_BEGIN ();

    UINTN Index;
    UINTN StartIndex;
    CHAR8 EfiFileName[256];


    DEBUG ((DEBUG_INFO | DEBUG_LOAD,
           "Loading SMM driver at 0x%11p EntryPoint=0x%11p ",
           (VOID *)(UINTN) ImageContext.ImageAddress,
           FUNCTION_ENTRY_POINT (ImageContext.EntryPoint)));


    //
    // Print Module Name by Pdb file path.
    // Windows and Unix style file path are all trimmed correctly.
    //
    if (ImageContext.PdbPointer != NULL) {
      StartIndex = 0;
      for (Index = 0; ImageContext.PdbPointer[Index] != 0; Index++) {
        if ((ImageContext.PdbPointer[Index] == '\\') || (ImageContext.PdbPointer[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~255.
      // If the length is bigger than 255, trim the redudant characters to avoid overflow in array boundary.
      //
      for (Index = 0; Index < sizeof (EfiFileName) - 4; Index++) {
        EfiFileName[Index] = ImageContext.PdbPointer[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)); // &Image->ImageContext.PdbPointer[StartIndex]));
    }
    DEBUG ((DEBUG_INFO | DEBUG_LOAD, "\n"));

  DEBUG_CODE_END ();

  //
  // Free buffer allocated by Fv->ReadSection.
  //
  // The UEFI Boot Services FreePool() function must be used because Fv->ReadSection 
  // used the UEFI Boot Services AllocatePool() function
  //
  Status = gBS->FreePool(Buffer);
  return Status;  
}
Пример #2
0
/**

  Loads and relocates a PE/COFF image into memory.
  If the image is not relocatable, it will not be loaded into memory and be loaded as XIP image.

  @param Pe32Data        - The base address of the PE/COFF file that is to be loaded and relocated
  @param ImageAddress    - The base address of the relocated PE/COFF image
  @param ImageSize       - The size of the relocated PE/COFF image
  @param EntryPoint      - The entry point of the relocated PE/COFF image

  @retval EFI_SUCCESS           The file was loaded and relocated
  @retval EFI_OUT_OF_RESOURCES  There was not enough memory to load and relocate the PE/COFF file
  @retval EFI_WARN_BUFFER_TOO_SMALL 
                                There is not enough heap to allocate the requested size.
                                This will not prevent the XIP image from being invoked.

**/
EFI_STATUS
LoadAndRelocatePeCoffImage (
  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;

  Private = PEI_CORE_INSTANCE_FROM_PS_THIS (GetPeiServicesTablePointer ());

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

  ASSERT_EFI_ERROR (Status);

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

  //
  // When Image has no reloc section, it can't be relocated into memory.
  //
  if (ImageContext.RelocationsStripped && (Private->PeiMemoryInstalled) && (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME || PcdGetBool (PcdShadowPeimOnS3Boot))) {
    DEBUG ((EFI_D_INFO|EFI_D_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, boot mode is not S3, and image is relocatable.
  //
  if ((!ImageContext.RelocationsStripped) && (Private->PeiMemoryInstalled) && (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME || 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 ((EFI_D_INFO|EFI_D_LOAD, "LOADING MODULE FIXED ERROR: Failed to load module at fixed address. \n"));
        //
        // The PEIM is not assiged valid address, try to allocate page to load it.
        //
        ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) AllocatePages (EFI_SIZE_TO_PAGES ((UINT32) AlignImageSize));
      }
    } else {
      ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) AllocatePages (EFI_SIZE_TO_PAGES ((UINT32) AlignImageSize));
    }
    if (ImageContext.ImageAddress != 0) {
      //
      // 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)) {
    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;
}
Пример #3
0
/**

  Loads and relocates a PE/COFF image into memory.
  If the image is not relocatable, it will not be loaded into memory and be loaded as XIP image.

  @param Pe32Data        - The base address of the PE/COFF file that is to be loaded and relocated
  @param ImageAddress    - The base address of the relocated PE/COFF image
  @param ImageSize       - The size of the relocated PE/COFF image
  @param EntryPoint      - The entry point of the relocated PE/COFF image

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

**/
EFI_STATUS
LoadAndRelocatePeCoffImage (
  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;

  Private = PEI_CORE_INSTANCE_FROM_PS_THIS (GetPeiServicesTablePointer ());

  ZeroMem (&ImageContext, sizeof (ImageContext));
  ImageContext.Handle = Pe32Data;
  Status              = GetImageReadFunction (&ImageContext);

  ASSERT_EFI_ERROR (Status);

  Status = PeCoffLoaderGetImageInfo (&ImageContext);
  if (EFI_ERROR (Status)) {
    return Status;
  }
  //
  // When Image has no reloc section, it can't be relocated into memory.
  //
  if (ImageContext.RelocationsStripped && (Private->PeiMemoryInstalled) && (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME)) {
    DEBUG ((EFI_D_INFO|EFI_D_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, boot mode is not S3, and image is relocatable.
  //
  if ((!ImageContext.RelocationsStripped) && (Private->PeiMemoryInstalled) && (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME)) {
    if (PcdGet64(PcdLoadModuleAtFixAddressEnable) != 0) {
      Status = GetPeCoffImageFixLoadingAssignedAddress(&ImageContext, Private);
      if (EFI_ERROR (Status)){
        DEBUG ((EFI_D_INFO|EFI_D_LOAD, "LOADING MODULE FIXED ERROR: Failed to load module at fixed address. \n"));
        //
        // The PEIM is not assiged valid address, try to allocate page to load it.
        //
        ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) AllocatePages (EFI_SIZE_TO_PAGES ((UINT32) ImageContext.ImageSize));
      }
    } else {
      ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) AllocatePages (EFI_SIZE_TO_PAGES ((UINT32) ImageContext.ImageSize));
    }
    ASSERT (ImageContext.ImageAddress != 0);
    if (ImageContext.ImageAddress == 0) {
      return EFI_OUT_OF_RESOURCES;
    }

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

  //
  // Load the image to our new buffer
  //
  Status = PeCoffLoaderLoadImage (&ImageContext);
  if (EFI_ERROR (Status)) {
    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.RelocationsStripped) && (Private->PeiMemoryInstalled) && (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME)) {
    InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize);
  }

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

  return EFI_SUCCESS;
}
Пример #4
0
/**

  Loads and relocates a PE/COFF image into memory.
  If the image is not relocatable, it will not be loaded into memory and be loaded as XIP image.

  @param FileHandle      - Pointer to the FFS file header of the image.
  @param Pe32Data        - The base address of the PE/COFF file that is to be loaded and relocated
  @param ImageAddress    - The base address of the relocated PE/COFF image
  @param ImageSize       - The size of the relocated PE/COFF image
  @param EntryPoint      - The entry point of the relocated PE/COFF image

  @retval EFI_SUCCESS           The file was loaded and relocated
  @retval EFI_OUT_OF_RESOURCES  There was not enough memory to load and relocate the PE/COFF file
  @retval EFI_WARN_BUFFER_TOO_SMALL
                                There is not enough heap to allocate the requested size.
                                This will not prevent the XIP image from being invoked.

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

  //
  // Initilize 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) ||
      (!IsS3Boot && (PcdGetBool (PcdShadowPeimOnBoot) || IsRegisterForShadow)) || (IsS3Boot && PcdGetBool (PcdShadowPeimOnS3Boot)))) {
    DEBUG ((EFI_D_INFO|EFI_D_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) ||
      (!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 ((EFI_D_INFO|EFI_D_LOAD, "LOADING MODULE FIXED ERROR: Failed to load module at fixed address. \n"));
        //
        // The PEIM is not assiged 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;
}
Пример #5
0
/**
  Load the SMM Core image into SMRAM and executes the SMM Core from SMRAM.

  @param[in] SmramRange  Descriptor for the range of SMRAM to reload the 
                         currently executing image.
  @param[in] Context     Context to pass into SMM Core

  @return  EFI_STATUS

**/
EFI_STATUS
ExecuteSmmCoreFromSmram (
  IN EFI_SMRAM_DESCRIPTOR  *SmramRange,
  IN VOID                  *Context
  )
{
  EFI_STATUS                    Status;
  VOID                          *SourceBuffer;
  UINTN                         SourceSize;
  PE_COFF_LOADER_IMAGE_CONTEXT  ImageContext;
  UINTN                         PageCount;
  EFI_PHYSICAL_ADDRESS          DestinationBuffer;
  EFI_IMAGE_ENTRY_POINT         EntryPoint;

  //
  // Search all Firmware Volumes for a PE/COFF image in a file of type SMM_CORE
  //  
  Status = GetSectionFromAnyFvByFileType (
             EFI_FV_FILETYPE_SMM_CORE, 
             0,
             EFI_SECTION_PE32, 
             0,
             &SourceBuffer, 
             &SourceSize
             );
  if (EFI_ERROR (Status)) {
    return Status;
  }
  
  //
  // Initilize ImageContext
  //
  ImageContext.Handle    = SourceBuffer;
  ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory;

  //
  // Get information about the image being loaded
  //
  Status = PeCoffLoaderGetImageInfo (&ImageContext);
  if (EFI_ERROR (Status)) {
    return Status;
  }
  //
  // if Loading module at Fixed Address feature is enabled, the SMM core driver will be loaded to 
  // the address assigned by build tool.
  //
  if (PcdGet64(PcdLoadModuleAtFixAddressEnable) != 0) {
    //
    // Get the fixed loading address assigned by Build tool
    //
    Status = GetPeCoffImageFixLoadingAssignedAddress (&ImageContext);
    if (!EFI_ERROR (Status)) {
      //
      // Since the memory range to load SMM CORE will be cut out in SMM core, so no need to allocate and free this range
      //
      PageCount = 0;
     } else {
      DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED ERROR: Loading module at fixed address at address failed\n"));
      //
      // Allocate memory for the image being loaded from the EFI_SRAM_DESCRIPTOR 
      // specified by SmramRange
      //
      PageCount = (UINTN)EFI_SIZE_TO_PAGES((UINTN)ImageContext.ImageSize + ImageContext.SectionAlignment);

      ASSERT ((SmramRange->PhysicalSize & EFI_PAGE_MASK) == 0);
      ASSERT (SmramRange->PhysicalSize > EFI_PAGES_TO_SIZE (PageCount));

      SmramRange->PhysicalSize -= EFI_PAGES_TO_SIZE (PageCount);
      DestinationBuffer = SmramRange->CpuStart + SmramRange->PhysicalSize;

      //
      // Align buffer on section boundry
      //
      ImageContext.ImageAddress = DestinationBuffer;
    }
  } else {
    //
    // Allocate memory for the image being loaded from the EFI_SRAM_DESCRIPTOR 
    // specified by SmramRange
    //
    PageCount = (UINTN)EFI_SIZE_TO_PAGES((UINTN)ImageContext.ImageSize + ImageContext.SectionAlignment);

    ASSERT ((SmramRange->PhysicalSize & EFI_PAGE_MASK) == 0);
    ASSERT (SmramRange->PhysicalSize > EFI_PAGES_TO_SIZE (PageCount));

    SmramRange->PhysicalSize -= EFI_PAGES_TO_SIZE (PageCount);
    DestinationBuffer = SmramRange->CpuStart + SmramRange->PhysicalSize;

    //
    // Align buffer on section boundry
    //
    ImageContext.ImageAddress = DestinationBuffer;
  }
  
  ImageContext.ImageAddress += ImageContext.SectionAlignment - 1;
  ImageContext.ImageAddress &= ~(ImageContext.SectionAlignment - 1);

  //
  // Print debug message showing SMM Core load address.
  //
  DEBUG ((DEBUG_INFO, "SMM IPL loading SMM Core at SMRAM address %p\n", (VOID *)(UINTN)ImageContext.ImageAddress));

  //
  // Load the image to our new buffer
  //
  Status = PeCoffLoaderLoadImage (&ImageContext);
  if (!EFI_ERROR (Status)) {
    //
    // Relocate the image in our new buffer
    //
    Status = PeCoffLoaderRelocateImage (&ImageContext);
    if (!EFI_ERROR (Status)) {
      //
      // Flush the instruction cache so the image data are written before we execute it
      //
      InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize);

      //
      // Print debug message showing SMM Core entry point address.
      //
      DEBUG ((DEBUG_INFO, "SMM IPL calling SMM Core at SMRAM address %p\n", (VOID *)(UINTN)ImageContext.EntryPoint));

      //
      // Execute image
      //
      EntryPoint = (EFI_IMAGE_ENTRY_POINT)(UINTN)ImageContext.EntryPoint;
      Status = EntryPoint ((EFI_HANDLE)Context, gST);
    }
  }

  //
  // If the load operation, relocate operation, or the image execution return an
  // error, then free memory allocated from the EFI_SRAM_DESCRIPTOR specified by 
  // SmramRange
  //
  if (EFI_ERROR (Status)) {
    SmramRange->PhysicalSize += EFI_PAGES_TO_SIZE (PageCount);
  }

  //
  // Always free memory allocted by GetFileBufferByFilePath ()
  //
  FreePool (SourceBuffer);

  return Status;
}