Example #1
0
VOID
SetBreakpoint (
  IN UINT32 Address
  )
{
  ARM_SOFTWARE_BREAKPOINT *Breakpoint;

  Breakpoint = SearchBreakpointList (Address);

  if (Breakpoint != NULL) {
    return;
  }

  // create and fill breakpoint structure
  Breakpoint = AllocatePool (sizeof(ARM_SOFTWARE_BREAKPOINT));

  Breakpoint->Signature   = ARM_SOFTWARE_BREAKPOINT_SIGNATURE;
  Breakpoint->Address     = Address;
  Breakpoint->Instruction = *(UINT32 *)Address;
  
  // Add it to the list
  InsertTailList (&BreakpointList, &Breakpoint->Link);

  // Insert the software breakpoint
  *(UINT32 *)Address = GDB_ARM_BKPT;
  InvalidateInstructionCacheRange ((VOID *)Address, 4);

  //DEBUG((EFI_D_ERROR, "SetBreakpoint at 0x%08x (was: 0x%08x is:0x%08x)\n", Address, Breakpoint->Instruction, *(UINT32 *)Address));
}
Example #2
0
/**
  Initialize debug agent.

  This function is used to set up debug environment to support source level debugging.
  If certain Debug Agent Library instance has to save some private data in the stack,
  this function must work on the mode that doesn't return to the caller, then
  the caller needs to wrap up all rest of logic after InitializeDebugAgent() into one
  function and pass it into InitializeDebugAgent(). InitializeDebugAgent() is
  responsible to invoke the passing-in function at the end of InitializeDebugAgent().

  If the parameter Function is not NULL, Debug Agent Libary instance will invoke it by
  passing in the Context to be its parameter.

  If Function() is NULL, Debug Agent Library instance will return after setup debug
  environment.

  @param[in] InitFlag     Init flag is used to decide the initialize process.
  @param[in] Context      Context needed according to InitFlag; it was optional.
  @param[in] Function     Continue function called by debug agent library; it was
                          optional.

**/
VOID
EFIAPI
InitializeDebugAgent (
  IN UINT32                InitFlag,
  IN VOID                  *Context, OPTIONAL
  IN DEBUG_AGENT_CONTINUE  Function  OPTIONAL
  )
{
  UINTN                Offset;
  UINTN                Length;
  BOOLEAN              IrqEnabled;
  UINT64               *VectorBase;


  //
  // Disable interrupts
  //
  IrqEnabled = ArmGetInterruptState ();
  ArmDisableInterrupts ();
  ArmDisableFiq ();

  //
  // Copy an implementation of the ARM exception vectors to PcdCpuVectorBaseAddress.
  //
  Length = (UINTN)ExceptionHandlersEnd - (UINTN)ExceptionHandlersStart;

  //
  // Reserve space for the exception handlers
  //
  VectorBase = (UINT64 *)(UINTN)PcdGet64 (PcdCpuVectorBaseAddress);


  // Copy our assembly code into the page that contains the exception vectors.
  CopyMem ((VOID *)VectorBase, (VOID *)ExceptionHandlersStart, Length);

  //
  // Patch in the common Assembly exception handler
  //
  Offset = (UINTN)CommonExceptionEntry - (UINTN)ExceptionHandlersStart;
  *(UINTN *) (((UINT8 *)VectorBase) + Offset) = (UINTN)AsmCommonExceptionEntry;

  // Flush Caches since we updated executable stuff
  InvalidateInstructionCacheRange ((VOID *)PcdGet64(PcdCpuVectorBaseAddress), Length);

  // setup a timer so gdb can break in via ctrl-c
  DebugAgentTimerIntialize ();

  if (IrqEnabled) {
    ArmEnableInterrupts ();
  }

  if (Function != NULL) {
    Function (Context);
  }

  return;
}
Example #3
0
EFI_STATUS
EFIAPI
LoadPeCoffImage (
  IN  VOID                                      *PeCoffImage,
  OUT EFI_PHYSICAL_ADDRESS                      *ImageAddress,
  OUT UINT64                                    *ImageSize,
  OUT EFI_PHYSICAL_ADDRESS                      *EntryPoint
  )
{
  RETURN_STATUS                 Status;
  PE_COFF_LOADER_IMAGE_CONTEXT  ImageContext;
  VOID                           *Buffer;

  ZeroMem (&ImageContext, sizeof (ImageContext));
    
  ImageContext.Handle    = PeCoffImage;
  ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory;

  Status = PeCoffLoaderGetImageInfo (&ImageContext);
  ASSERT_EFI_ERROR (Status);
  

  //
  // Allocate Memory for the image
  //
  Buffer = AllocatePages (EFI_SIZE_TO_PAGES((UINT32)ImageContext.ImageSize));
  ASSERT (Buffer != 0);


  ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)Buffer;

  //
  // Load the image to our new buffer
  //
  Status = PeCoffLoaderLoadImage (&ImageContext);
  ASSERT_EFI_ERROR (Status);

  //
  // Relocate the image in our new buffer
  //
  Status = PeCoffLoaderRelocateImage (&ImageContext);
  ASSERT_EFI_ERROR (Status);


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

  //
  // Flush not needed for all architectures. We could have a processor specific
  // function in this library that does the no-op if needed.
  //
  InvalidateInstructionCacheRange ((VOID *)(UINTN)*ImageAddress, (UINTN)*ImageSize);

  return Status;
}
Example #4
0
/** 
 Remove Single Step in the SystemContext
 
 @param	SystemContext	Register content at time of the exception
 **/
VOID
RemoveSingleStep (
  IN  EFI_SYSTEM_CONTEXT  SystemContext
  )
{
  if (!mSingleStepActive) {
    return;
  }
  
  if (mSingleStepDataSize == sizeof (UINT16)) {
    *(UINT16 *)mSingleStepPC = (UINT16)mSingleStepData;
  } else {
    //DEBUG((EFI_D_ERROR, "RemoveSingleStep at 0x%08x (was: 0x%08x is:0x%08x)\n", SystemContext.SystemContextArm->PC, *(UINT32 *)mSingleStepPC, mSingleStepData));
    *(UINT32 *)mSingleStepPC = mSingleStepData;
  }
  InvalidateInstructionCacheRange ((VOID *)mSingleStepPC, mSingleStepDataSize);
  mSingleStepActive = FALSE;
}
Example #5
0
/** 
 Insert Single Step in the SystemContext
 
 @param	SystemContext	Register content at time of the exception
 **/
VOID
AddSingleStep (
  IN EFI_SYSTEM_CONTEXT SystemContext
  )
{
  if (mSingleStepActive) {
    // Currently don't support nesting
    return;
  }
  mSingleStepActive = TRUE;
  
  mSingleStepPC = SystemContext.SystemContextArm->PC;

  mSingleStepDataSize = sizeof (UINT32);
  mSingleStepData = (*(UINT32 *)mSingleStepPC); 
  *(UINT32 *)mSingleStepPC = GDB_ARM_BKPT;
  if (*(UINT32 *)mSingleStepPC != GDB_ARM_BKPT) {
    // For some reason our breakpoint did not take
    mSingleStepActive = FALSE;
  }

  InvalidateInstructionCacheRange ((VOID *)mSingleStepPC, mSingleStepDataSize);
  //DEBUG((EFI_D_ERROR, "AddSingleStep at 0x%08x (was: 0x%08x is:0x%08x)\n", SystemContext.SystemContextArm->PC, mSingleStepData, *(UINT32 *)mSingleStepPC));
}
Example #6
0
VOID
ClearBreakpoint (
  IN UINT32 Address
  )
{
  ARM_SOFTWARE_BREAKPOINT *Breakpoint;

  Breakpoint = SearchBreakpointList (Address);

  if (Breakpoint == NULL) {
    return;
  }

  // Add it to the list
  RemoveEntryList (&Breakpoint->Link);

  // Restore the original instruction
  *(UINT32 *)Address = Breakpoint->Instruction;
  InvalidateInstructionCacheRange ((VOID *)Address, 4);

  //DEBUG((EFI_D_ERROR, "ClearBreakpoint at 0x%08x (was: 0x%08x is:0x%08x)\n", Address, GDB_ARM_BKPT, *(UINT32 *)Address));

  FreePool (Breakpoint);
}
Example #7
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;  
}
Example #8
0
/**
  Relocate this image under 4G memory for IPF.

  @param  ImageHandle  Handle of driver image.
  @param  SystemTable  Pointer to system table.

  @retval EFI_SUCCESS  Image successfully relocated.
  @retval EFI_ABORTED  Failed to relocate image.

**/
EFI_STATUS
RelocateImageUnder4GIfNeeded (
  IN EFI_HANDLE           ImageHandle,
  IN EFI_SYSTEM_TABLE     *SystemTable
  )
{
  EFI_STATUS                         Status;
  EFI_LOADED_IMAGE_PROTOCOL          *LoadedImage;
  UINTN                              NumberOfPages;
  EFI_PHYSICAL_ADDRESS               LoadedImageBase;
  PE_COFF_LOADER_IMAGE_CONTEXT       ImageContext;
  EFI_PHYSICAL_ADDRESS               MemoryAddress;
  EFI_HANDLE                         NewImageHandle;

  Status = gBS->HandleProtocol (
                    ImageHandle,
                    &gEfiLoadedImageProtocolGuid,
                    (VOID *) &LoadedImage
                    );

  if (!EFI_ERROR (Status)) {
    LoadedImageBase = (EFI_PHYSICAL_ADDRESS) (UINTN) LoadedImage->ImageBase;
    if (LoadedImageBase > 0xffffffff) {
      NumberOfPages = (UINTN) (DivU64x32(LoadedImage->ImageSize, EFI_PAGE_SIZE) + 1);

      //
      // Allocate buffer below 4GB here
      //
      Status = AllocateLegacyMemory (
                AllocateMaxAddress,
                0x7FFFFFFF,
                NumberOfPages,  // do we have to convert this to pages??
                &MemoryAddress
                );
      if (EFI_ERROR (Status)) {
        return Status;
      }

      ZeroMem (&ImageContext, sizeof (PE_COFF_LOADER_IMAGE_CONTEXT));
      ImageContext.Handle    = (VOID *)(UINTN)LoadedImageBase;
      ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory;

      //
      // Get information about the image being loaded
      //
      Status = PeCoffLoaderGetImageInfo (&ImageContext);
      if (EFI_ERROR (Status)) {
        return Status;
      }
      ImageContext.ImageAddress = (PHYSICAL_ADDRESS)MemoryAddress;
      //
      // Align buffer on section boundary
      //
      ImageContext.ImageAddress += ImageContext.SectionAlignment - 1;
     ImageContext.ImageAddress &= ~((PHYSICAL_ADDRESS)ImageContext.SectionAlignment - 1);

      //
      // Load the image to our new buffer
      //
      Status = PeCoffLoaderLoadImage (&ImageContext);
      if (EFI_ERROR (Status)) {
        gBS->FreePages (MemoryAddress, NumberOfPages);
        return Status;
      }

      //
      // Relocate the image in our new buffer
      //
      Status = PeCoffLoaderRelocateImage (&ImageContext);
      if (EFI_ERROR (Status)) {
        gBS->FreePages (MemoryAddress, NumberOfPages);
        return Status;
      }

      //
      // Create a new handle with gEfiCallerIdGuid to be used as the ImageHandle fore the reloaded image
      // 
      NewImageHandle = NULL;
      Status = gBS->InstallProtocolInterface (
                      &NewImageHandle,
                      &gEfiCallerIdGuid,
                      EFI_NATIVE_INTERFACE,
                      NULL
                      );

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

      Status = ((EFI_IMAGE_ENTRY_POINT)(UINTN)(ImageContext.EntryPoint)) (NewImageHandle, SystemTable);
      if (EFI_ERROR (Status)) {
        gBS->FreePages (MemoryAddress, NumberOfPages);
        return Status;
      }
      //
      // return error directly the BS will unload this image
      //
      return EFI_ABORTED;
    }
  }
  return EFI_SUCCESS;
}
Example #9
0
File: Image.c Project: B-Rich/edk2
/**

  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;
}
Example #10
0
/**
  Entrypoint of Boot script exector driver, this function will be executed in
  normal boot phase and invoked by DXE dispatch.

  @param[in] ImageHandle    The firmware allocated handle for the EFI image.
  @param[in] SystemTable    A pointer to the EFI System Table.

  @retval EFI_SUCCESS       The entry point is executed successfully.
  @retval other             Some error occurs when executing this entry point.
**/
EFI_STATUS
EFIAPI
BootScriptExecutorEntryPoint (
    IN EFI_HANDLE           ImageHandle,
    IN EFI_SYSTEM_TABLE     *SystemTable
)
{
    UINT8                                         *Buffer;
    UINTN                                         BufferSize;
    UINTN                                         Pages;
    EFI_PHYSICAL_ADDRESS                          FfsBuffer;
    PE_COFF_LOADER_IMAGE_CONTEXT                  ImageContext;
    BOOT_SCRIPT_EXECUTOR_VARIABLE                 *EfiBootScriptExecutorVariable;
    EFI_PHYSICAL_ADDRESS                          BootScriptExecutorBuffer;
    EFI_STATUS                                    Status;
    VOID                                          *DevicePath;
    EFI_HANDLE                                    NewImageHandle;

    //
    // Test if the gEfiCallerIdGuid of this image is already installed. if not, the entry
    // point is loaded by DXE code which is the first time loaded. or else, it is already
    // be reloaded be itself.This is a work-around
    //
    Status = gBS->LocateProtocol (&gEfiCallerIdGuid, NULL, &DevicePath);
    if (EFI_ERROR (Status)) {

        //
        // This is the first-time loaded by DXE core. reload itself to NVS mem
        //
        //
        // A workarouond: Here we install a dummy handle
        //
        NewImageHandle = NULL;
        Status = gBS->InstallProtocolInterface (
                     &NewImageHandle,
                     &gEfiCallerIdGuid,
                     EFI_NATIVE_INTERFACE,
                     NULL
                 );

        Status = GetSectionFromAnyFv  (
                     &gEfiCallerIdGuid,
                     EFI_SECTION_PE32,
                     0,
                     (VOID **) &Buffer,
                     &BufferSize
                 );
        ImageContext.Handle    = Buffer;
        ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory;
        //
        // Get information about the image being loaded
        //
        Status = PeCoffLoaderGetImageInfo (&ImageContext);
        if (EFI_ERROR (Status)) {
            return Status;
        }
        Pages = EFI_SIZE_TO_PAGES(BufferSize + ImageContext.SectionAlignment);
        FfsBuffer = 0xFFFFFFFF;
        Status = gBS->AllocatePages (
                     AllocateMaxAddress,
                     EfiACPIMemoryNVS,
                     Pages,
                     &FfsBuffer
                 );
        if (EFI_ERROR (Status)) {
            return EFI_OUT_OF_RESOURCES;
        }
        ImageContext.ImageAddress = (PHYSICAL_ADDRESS)(UINTN)FfsBuffer;
        //
        // 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)) {
            gBS->FreePages (FfsBuffer, Pages);
            return Status;
        }

        //
        // Relocate the image in our new buffer
        //
        Status = PeCoffLoaderRelocateImage (&ImageContext);

        if (EFI_ERROR (Status)) {
            PeCoffLoaderUnloadImage (&ImageContext);
            gBS->FreePages (FfsBuffer, Pages);
            return Status;
        }
        //
        // Flush the instruction cache so the image data is written before we execute it
        //
        InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize);
        Status = ((EFI_IMAGE_ENTRY_POINT)(UINTN)(ImageContext.EntryPoint)) (NewImageHandle, SystemTable);
        if (EFI_ERROR (Status)) {
            gBS->FreePages (FfsBuffer, Pages);
            return Status;
        }
        //
        // Additional step for BootScript integrity
        // Save BootScriptExecutor image
        //
        Status = SaveLockBox (
                     &mBootScriptExecutorImageGuid,
                     (VOID *)(UINTN)ImageContext.ImageAddress,
                     (UINTN)ImageContext.ImageSize
                 );
        ASSERT_EFI_ERROR (Status);

        Status = SetLockBoxAttributes (&mBootScriptExecutorImageGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE);
        ASSERT_EFI_ERROR (Status);

    } else {
        //
        // the entry point is invoked after reloading. following code only run in  ACPI NVS
        //
        BufferSize = sizeof (BOOT_SCRIPT_EXECUTOR_VARIABLE);

        BootScriptExecutorBuffer = 0xFFFFFFFF;
        Pages = EFI_SIZE_TO_PAGES(BufferSize);
        Status = gBS->AllocatePages (
                     AllocateMaxAddress,
                     EfiACPIMemoryNVS,
                     Pages,
                     &BootScriptExecutorBuffer
                 );
        if (EFI_ERROR (Status)) {
            return EFI_OUT_OF_RESOURCES;
        }

        EfiBootScriptExecutorVariable = (BOOT_SCRIPT_EXECUTOR_VARIABLE *)(UINTN)BootScriptExecutorBuffer;
        EfiBootScriptExecutorVariable->BootScriptExecutorEntrypoint = (UINTN) S3BootScriptExecutorEntryFunction ;

        Status = SaveLockBox (
                     &gEfiBootScriptExecutorVariableGuid,
                     &BootScriptExecutorBuffer,
                     sizeof(BootScriptExecutorBuffer)
                 );
        ASSERT_EFI_ERROR (Status);

        //
        // Additional step for BootScript integrity
        // Save BootScriptExecutor context
        //
        Status = SaveLockBox (
                     &gEfiBootScriptExecutorContextGuid,
                     EfiBootScriptExecutorVariable,
                     sizeof(*EfiBootScriptExecutorVariable)
                 );
        ASSERT_EFI_ERROR (Status);

        Status = SetLockBoxAttributes (&gEfiBootScriptExecutorContextGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE);
        ASSERT_EFI_ERROR (Status);

    }

    return EFI_SUCCESS;
}
Example #11
0
File: Image.c Project: lersek/edk2
/**

  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;
}
Example #12
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;
}
Example #13
0
/**
  This routine is entry point of ScriptSave driver.

  @param  ImageHandle           Handle for this drivers loaded image protocol.
  @param  SystemTable           EFI system table.

  @retval EFI_OUT_OF_RESOURCES  No enough resource
  @retval EFI_SUCCESS           Succesfully installed the ScriptSave driver.
  @retval other                 Errors occured.

**/
EFI_STATUS
EFIAPI
InitializeScriptSaveOnS3SaveState (
  IN EFI_HANDLE           ImageHandle,
  IN EFI_SYSTEM_TABLE     *SystemTable
  )
{
  UINT8                                         *Buffer;
  UINTN                                         BufferSize;
  PE_COFF_LOADER_IMAGE_CONTEXT                  ImageContext;
  BOOT_SCRIPT_THUNK_DATA                        *BootScriptThunkData;
  EFI_STATUS                                    Status;
  VOID                                          *DevicePath;
  EFI_PHYSICAL_ADDRESS                          MemoryAddress;
  UINTN                                         PageNumber;
  EFI_HANDLE                                    NewImageHandle;

  //
  // Test if the gEfiCallerIdGuid of this image is already installed. if not, the entry
  // point is loaded by DXE code which is the first time loaded. or else, it is already
  // be reloaded be itself.This is a work-around
  //
  Status = gBS->LocateProtocol (&gEfiCallerIdGuid, NULL, &DevicePath);
  if (EFI_ERROR (Status)) {
    //
    // This is the first-time loaded by DXE core. reload itself to RESERVED mem
    //
    //
    // A workaround: Here we install a dummy handle
    //
    NewImageHandle = NULL;
    Status = gBS->InstallProtocolInterface (
                    &NewImageHandle,
                    &gEfiCallerIdGuid,
                    EFI_NATIVE_INTERFACE,
                    NULL
                    );
    ASSERT_EFI_ERROR (Status);

    Status = GetSectionFromAnyFv  (
               &gEfiCallerIdGuid,
               EFI_SECTION_PE32,
               0,
               (VOID **) &Buffer,
               &BufferSize
               );
    ASSERT_EFI_ERROR (Status);
    ImageContext.Handle    = Buffer;
    ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory;
    //
    // Get information about the image being loaded
    //
    Status = PeCoffLoaderGetImageInfo (&ImageContext);
    ASSERT_EFI_ERROR (Status);

    MemoryAddress = SIZE_4GB - 1;
    if (ImageContext.SectionAlignment > EFI_PAGE_SIZE) {
      PageNumber = EFI_SIZE_TO_PAGES ((UINTN) (ImageContext.ImageSize + ImageContext.SectionAlignment));
    } else {
      PageNumber = EFI_SIZE_TO_PAGES ((UINTN) ImageContext.ImageSize);
    }
    Status  = gBS->AllocatePages (
                     AllocateMaxAddress,
                     EfiReservedMemoryType,
                     PageNumber,
                     &MemoryAddress
                     );
    ASSERT_EFI_ERROR (Status);
    ImageContext.ImageAddress = (PHYSICAL_ADDRESS)(UINTN)MemoryAddress;
    //
    // 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);
    ASSERT_EFI_ERROR (Status);

    //
    // Relocate the image in our new buffer
    //
    Status = PeCoffLoaderRelocateImage (&ImageContext);
    ASSERT_EFI_ERROR (Status);

    //
    // Free the buffer allocated by ReadSection since the image has been relocated in the new buffer
    //
    gBS->FreePool (Buffer);

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

    RegisterMemoryProfileImage (
      &gEfiCallerIdGuid,
      ImageContext.ImageAddress,
      ImageContext.ImageSize,
      EFI_FV_FILETYPE_DRIVER
    );

    Status = ((EFI_IMAGE_ENTRY_POINT)(UINTN)(ImageContext.EntryPoint)) (NewImageHandle, SystemTable);
    ASSERT_EFI_ERROR (Status);

    //
    // Additional step for BootScriptThunk integrity
    //

    //
    // Allocate BootScriptThunkData
    //
    BootScriptThunkData = AllocatePool (sizeof (BOOT_SCRIPT_THUNK_DATA));
    ASSERT (BootScriptThunkData != NULL);

    BootScriptThunkData->BootScriptThunkBase   = ImageContext.ImageAddress;
    BootScriptThunkData->BootScriptThunkLength = ImageContext.ImageSize;
    //
    // Set BootScriptThunkData
    //
    PcdSet64 (BootScriptThunkDataPtr, (UINT64)(UINTN)BootScriptThunkData); 
    return EFI_SUCCESS;
  } else {
    //
    // the entry point is invoked after reloading. following code only run in RESERVED mem
    //

    //
    // Locate and cache PI S3 Save State Protocol.
    //
    Status = gBS->LocateProtocol (
                    &gEfiS3SaveStateProtocolGuid, 
                    NULL, 
                    (VOID **) &mS3SaveState
                    );
    ASSERT_EFI_ERROR (Status);

    return gBS->InstallProtocolInterface (
                  &mHandle,
                  &gEfiBootScriptSaveProtocolGuid,
                  EFI_NATIVE_INTERFACE,
                  &mS3ScriptSave
                  );
  }
}
Example #14
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;
}
Example #15
0
/**
  This is the Event notification function to reload BootScriptExecutor image
  to RESERVED mem and save it to LockBox.
  
  @param    Event   Pointer to this event
  @param    Context Event handler private data 
 **/
VOID
EFIAPI
ReadyToLockEventNotify (
  IN EFI_EVENT  Event,
  IN VOID       *Context
  )
{
  EFI_STATUS                                    Status;
  VOID                                          *Interface;
  UINT8                                         *Buffer;
  UINTN                                         BufferSize;
  EFI_HANDLE                                    NewImageHandle;
  UINTN                                         Pages;
  EFI_PHYSICAL_ADDRESS                          FfsBuffer;
  PE_COFF_LOADER_IMAGE_CONTEXT                  ImageContext;

  Status = gBS->LocateProtocol (&gEfiDxeSmmReadyToLockProtocolGuid, NULL, &Interface);
  if (EFI_ERROR (Status)) {
    return;
  }

  //
  // A workaround: Here we install a dummy handle
  //
  NewImageHandle = NULL;
  Status = gBS->InstallProtocolInterface (
                  &NewImageHandle,
                  &gEfiCallerIdGuid,
                  EFI_NATIVE_INTERFACE,
                  NULL
                  );
  ASSERT_EFI_ERROR (Status);

  //
  // Reload BootScriptExecutor image itself to RESERVED mem
  //
  Status = GetSectionFromAnyFv  (
             &gEfiCallerIdGuid,
             EFI_SECTION_PE32,
             0,
             (VOID **) &Buffer,
             &BufferSize
             );
  ASSERT_EFI_ERROR (Status);
  ImageContext.Handle    = Buffer;
  ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory;
  //
  // Get information about the image being loaded
  //
  Status = PeCoffLoaderGetImageInfo (&ImageContext);
  ASSERT_EFI_ERROR (Status);
  if (ImageContext.SectionAlignment > EFI_PAGE_SIZE) {
    Pages = EFI_SIZE_TO_PAGES ((UINTN) (ImageContext.ImageSize + ImageContext.SectionAlignment));
  } else {
    Pages = EFI_SIZE_TO_PAGES ((UINTN) ImageContext.ImageSize);
  }
  FfsBuffer = 0xFFFFFFFF;
  Status = gBS->AllocatePages (
                  AllocateMaxAddress,
                  EfiReservedMemoryType,
                  Pages,
                  &FfsBuffer
                  );
  ASSERT_EFI_ERROR (Status);
  ImageContext.ImageAddress = (PHYSICAL_ADDRESS)(UINTN)FfsBuffer;
  //
  // Align buffer on section boundry
  //
  ImageContext.ImageAddress += ImageContext.SectionAlignment - 1;
  ImageContext.ImageAddress &= ~((EFI_PHYSICAL_ADDRESS)(ImageContext.SectionAlignment - 1));
  //
  // Load the image to our new buffer
  //
  Status = PeCoffLoaderLoadImage (&ImageContext);
  ASSERT_EFI_ERROR (Status);

  //
  // Relocate the image in our new buffer
  //
  Status = PeCoffLoaderRelocateImage (&ImageContext);
  ASSERT_EFI_ERROR (Status);

  //
  // Free the buffer allocated by ReadSection since the image has been relocated in the new buffer
  //
  gBS->FreePool (Buffer);

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

  RegisterMemoryProfileImage (
    &gEfiCallerIdGuid,
    ImageContext.ImageAddress,
    ImageContext.ImageSize,
    EFI_FV_FILETYPE_DRIVER
    );

  Status = ((EFI_IMAGE_ENTRY_POINT)(UINTN)(ImageContext.EntryPoint)) (NewImageHandle, gST);
  ASSERT_EFI_ERROR (Status);

  //
  // Additional step for BootScript integrity
  // Save BootScriptExecutor image
  //
  Status = SaveLockBox (
             &mBootScriptExecutorImageGuid,
             (VOID *)(UINTN)ImageContext.ImageAddress,
             (UINTN)ImageContext.ImageSize
             );
  ASSERT_EFI_ERROR (Status);

  Status = SetLockBoxAttributes (&mBootScriptExecutorImageGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE);
  ASSERT_EFI_ERROR (Status);

  gBS->CloseEvent (Event);
}
Example #16
0
/**
  Relocate this image under 4G memory.

  @param  ImageHandle  Handle of driver image.
  @param  SystemTable  Pointer to system table.

  @retval EFI_SUCCESS  Image successfully relocated.
  @retval EFI_ABORTED  Failed to relocate image.

**/
EFI_STATUS
RelocateImageUnder4GIfNeeded (
  IN EFI_HANDLE           ImageHandle,
  IN EFI_SYSTEM_TABLE     *SystemTable
  )
{
  EFI_STATUS                                    Status;
  UINT8                                         *Buffer;
  UINTN                                         BufferSize;
  EFI_HANDLE                                    NewImageHandle;
  UINTN                                         Pages;
  EFI_PHYSICAL_ADDRESS                          FfsBuffer;
  PE_COFF_LOADER_IMAGE_CONTEXT                  ImageContext;
  VOID                                          *Interface;

  //
  // If it is already <4G, no need do relocate
  //
  if ((UINTN)RelocateImageUnder4GIfNeeded < 0xFFFFFFFF) {
    return EFI_SUCCESS;
  }

  //
  // If locate gEfiCallerIdGuid success, it means 2nd entry.
  //
  Status = gBS->LocateProtocol (&gEfiCallerIdGuid, NULL, &Interface);
  if (!EFI_ERROR (Status)) {
    DEBUG ((DEBUG_INFO, "FspNotifyDxe - 2nd entry\n"));
    return EFI_SUCCESS;
  }

  DEBUG ((DEBUG_INFO, "FspNotifyDxe - 1st entry\n"));

  //
  // Here we install a dummy handle
  //
  NewImageHandle = NULL;
  Status = gBS->InstallProtocolInterface (
                  &NewImageHandle,
                  &gEfiCallerIdGuid,
                  EFI_NATIVE_INTERFACE,
                  NULL
                  );
  ASSERT_EFI_ERROR (Status);

  //
  // Reload image itself to <4G mem
  //
  Status = GetSectionFromAnyFv  (
             &gEfiCallerIdGuid,
             EFI_SECTION_PE32,
             0,
             (VOID **) &Buffer,
             &BufferSize
             );
  ASSERT_EFI_ERROR (Status);
  ImageContext.Handle    = Buffer;
  ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory;
  //
  // Get information about the image being loaded
  //
  Status = PeCoffLoaderGetImageInfo (&ImageContext);
  ASSERT_EFI_ERROR (Status);
  if (ImageContext.SectionAlignment > EFI_PAGE_SIZE) {
    Pages = EFI_SIZE_TO_PAGES ((UINTN) (ImageContext.ImageSize + ImageContext.SectionAlignment));
  } else {
    Pages = EFI_SIZE_TO_PAGES ((UINTN) ImageContext.ImageSize);
  }
  FfsBuffer = 0xFFFFFFFF;
  Status = gBS->AllocatePages (
                  AllocateMaxAddress,
                  EfiBootServicesCode,
                  Pages,
                  &FfsBuffer
                  );
  ASSERT_EFI_ERROR (Status);
  ImageContext.ImageAddress = (PHYSICAL_ADDRESS)(UINTN)FfsBuffer;
  //
  // Align buffer on section boundry
  //
  ImageContext.ImageAddress += ImageContext.SectionAlignment - 1;
  ImageContext.ImageAddress &= ~((EFI_PHYSICAL_ADDRESS)(ImageContext.SectionAlignment - 1));
  //
  // Load the image to our new buffer
  //
  Status = PeCoffLoaderLoadImage (&ImageContext);
  ASSERT_EFI_ERROR (Status);

  //
  // Relocate the image in our new buffer
  //
  Status = PeCoffLoaderRelocateImage (&ImageContext);
  ASSERT_EFI_ERROR (Status);

  //
  // Free the buffer allocated by ReadSection since the image has been relocated in the new buffer
  //
  gBS->FreePool (Buffer);

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

  DEBUG ((DEBUG_INFO, "Loading driver at 0x%08x EntryPoint=0x%08x\n", (UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.EntryPoint));
  Status = ((EFI_IMAGE_ENTRY_POINT)(UINTN)(ImageContext.EntryPoint)) (NewImageHandle, gST);
  if (EFI_ERROR (Status)) {
    DEBUG ((DEBUG_ERROR, "Error: Image at 0x%08x start failed: %r\n", ImageContext.ImageAddress, Status));
    gBS->FreePages (FfsBuffer, Pages);
  }

  //
  // return error to unload >4G copy, if we already relocate itself to <4G.
  //
  return EFI_ALREADY_STARTED;
}
Example #17
0
/**

  Changes the runtime addressing mode of EFI firmware from physical to virtual.


  @param MemoryMapSize   The size in bytes of VirtualMap.
  @param DescriptorSize  The size in bytes of an entry in the VirtualMap.
  @param DescriptorVersion The version of the structure entries in VirtualMap.
  @param VirtualMap      An array of memory descriptors which contain new virtual
                         address mapping information for all runtime ranges.

  @retval  EFI_SUCCESS            The virtual address map has been applied.
  @retval  EFI_UNSUPPORTED        EFI firmware is not at runtime, or the EFI firmware is already in
                                  virtual address mapped mode.
  @retval  EFI_INVALID_PARAMETER  DescriptorSize or DescriptorVersion is invalid.
  @retval  EFI_NO_MAPPING         A virtual address was not supplied for a range in the memory
                                  map that requires a mapping.
  @retval  EFI_NOT_FOUND          A virtual address was supplied for an address that is not found
                                  in the memory map.

**/
EFI_STATUS
EFIAPI
RuntimeDriverSetVirtualAddressMap (
    IN UINTN                  MemoryMapSize,
    IN UINTN                  DescriptorSize,
    IN UINT32                 DescriptorVersion,
    IN EFI_MEMORY_DESCRIPTOR  *VirtualMap
)
{
    EFI_STATUS                    Status;
    EFI_RUNTIME_EVENT_ENTRY       *RuntimeEvent;
    EFI_RUNTIME_IMAGE_ENTRY       *RuntimeImage;
    LIST_ENTRY                    *Link;
    EFI_PHYSICAL_ADDRESS          VirtImageBase;

    //
    // Can only switch to virtual addresses once the memory map is locked down,
    // and can only set it once
    //
    if (!mRuntime.AtRuntime || mRuntime.VirtualMode) {
        return EFI_UNSUPPORTED;
    }
    //
    // Only understand the original descriptor format
    //
    if (DescriptorVersion != EFI_MEMORY_DESCRIPTOR_VERSION || DescriptorSize < sizeof (EFI_MEMORY_DESCRIPTOR)) {
        return EFI_INVALID_PARAMETER;
    }
    //
    // We are now committed to go to virtual mode, so lets get to it!
    //
    mRuntime.VirtualMode = TRUE;

    //
    // ConvertPointer() needs this mVirtualMap to do the conversion. So set up
    // globals we need to parse the virtual address map.
    //
    mVirtualMapDescriptorSize = DescriptorSize;
    mVirtualMapMaxIndex       = MemoryMapSize / DescriptorSize;
    mVirtualMap               = VirtualMap;

    //
    // ReporstStatusCodeLib will check and make sure this service can be called in runtime mode.
    //
    REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_SOFTWARE_EFI_RUNTIME_SERVICE | EFI_SW_RS_PC_SET_VIRTUAL_ADDRESS_MAP));

    //
    // Signal all the EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE events.
    // All runtime events are stored in a list in Runtime AP.
    //
    for (Link = mRuntime.EventHead.ForwardLink; Link != &mRuntime.EventHead; Link = Link->ForwardLink) {
        RuntimeEvent = BASE_CR (Link, EFI_RUNTIME_EVENT_ENTRY, Link);
        if ((RuntimeEvent->Type & EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE) == EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE) {
            RuntimeEvent->NotifyFunction (
                RuntimeEvent->Event,
                RuntimeEvent->NotifyContext
            );
        }
    }

    //
    // Relocate runtime images. All runtime images are stored in a list in Runtime AP.
    //
    for (Link = mRuntime.ImageHead.ForwardLink; Link != &mRuntime.ImageHead; Link = Link->ForwardLink) {
        RuntimeImage = BASE_CR (Link, EFI_RUNTIME_IMAGE_ENTRY, Link);
        //
        // We don't want to relocate our selves, as we only run in physical mode.
        //
        if (mMyImageBase != RuntimeImage->ImageBase) {

            VirtImageBase = (EFI_PHYSICAL_ADDRESS) (UINTN) RuntimeImage->ImageBase;
            Status  = RuntimeDriverConvertPointer (0, (VOID **) &VirtImageBase);
            ASSERT_EFI_ERROR (Status);

            PeCoffLoaderRelocateImageForRuntime (
                (EFI_PHYSICAL_ADDRESS) (UINTN) RuntimeImage->ImageBase,
                VirtImageBase,
                (UINTN) RuntimeImage->ImageSize,
                RuntimeImage->RelocationData
            );

            InvalidateInstructionCacheRange (RuntimeImage->ImageBase, (UINTN) RuntimeImage->ImageSize);
        }
    }

    //
    // Convert all the Runtime Services except ConvertPointer() and SetVirtualAddressMap()
    // and recompute the CRC-32
    //
    RuntimeDriverConvertInternalPointer ((VOID **) &gRT->GetTime);
    RuntimeDriverConvertInternalPointer ((VOID **) &gRT->SetTime);
    RuntimeDriverConvertInternalPointer ((VOID **) &gRT->GetWakeupTime);
    RuntimeDriverConvertInternalPointer ((VOID **) &gRT->SetWakeupTime);
    RuntimeDriverConvertInternalPointer ((VOID **) &gRT->ResetSystem);
    RuntimeDriverConvertInternalPointer ((VOID **) &gRT->GetNextHighMonotonicCount);
    RuntimeDriverConvertInternalPointer ((VOID **) &gRT->GetVariable);
    RuntimeDriverConvertInternalPointer ((VOID **) &gRT->SetVariable);
    RuntimeDriverConvertInternalPointer ((VOID **) &gRT->GetNextVariableName);
    RuntimeDriverConvertInternalPointer ((VOID **) &gRT->QueryVariableInfo);
    RuntimeDriverConvertInternalPointer ((VOID **) &gRT->UpdateCapsule);
    RuntimeDriverConvertInternalPointer ((VOID **) &gRT->QueryCapsuleCapabilities);
    RuntimeDriverCalculateEfiHdrCrc (&gRT->Hdr);

    //
    // UEFI don't require System Configuration Tables Conversion.
    //

    //
    // Convert the runtime fields of the EFI System Table and recompute the CRC-32
    //
    RuntimeDriverConvertInternalPointer ((VOID **) &gST->FirmwareVendor);
    RuntimeDriverConvertInternalPointer ((VOID **) &gST->ConfigurationTable);
    RuntimeDriverConvertInternalPointer ((VOID **) &gST->RuntimeServices);
    RuntimeDriverCalculateEfiHdrCrc (&gST->Hdr);

    //
    // At this point, gRT and gST are physical pointers, but the contents of these tables
    // have been converted to runtime.
    //
    //
    // mVirtualMap is only valid during SetVirtualAddressMap() call
    //
    mVirtualMap = NULL;

    return EFI_SUCCESS;
}
Example #18
0
/**
  Relocate this image to reserved memory.

  @param  ImageHandle  Handle of driver image.
  @param  SystemTable  Pointer to system table.

  @retval EFI_SUCCESS  Image successfully relocated.
  @retval EFI_ABORTED  Failed to relocate image.

**/
EFI_STATUS
RelocateImageToReserved (
  IN EFI_HANDLE           ImageHandle,
  IN EFI_SYSTEM_TABLE     *SystemTable
  )
{
  EFI_LOADED_IMAGE_PROTOCOL                     *LoadedImage;
  EFI_STATUS                                    Status;
  UINT8                                         *Buffer;
  UINTN                                         BufferSize;
  EFI_HANDLE                                    NewImageHandle;
  UINTN                                         Pages;
  EFI_PHYSICAL_ADDRESS                          FfsBuffer;
  PE_COFF_LOADER_IMAGE_CONTEXT                  ImageContext;
  VOID                                          *Interface;

  //
  // If locate gEfiCallerIdGuid success, it means 2nd entry.
  //
  Status = gBS->LocateProtocol (&gEfiCallerIdGuid, NULL, &Interface);
  if (!EFI_ERROR (Status)) {
    DEBUG ((EFI_D_INFO, "StmService - 2nd entry\n"));
    return EFI_SUCCESS;
  }

  DEBUG ((EFI_D_INFO, "StmService - 1st entry\n"));

  //
  // Reload image itself to <4G mem
  //
  Status = GetSectionFromAnyFv  (
             &gEfiCallerIdGuid,
             EFI_SECTION_PE32,
             0,
             (VOID **) &Buffer,
             &BufferSize
             );
  ASSERT_EFI_ERROR (Status);
  ImageContext.Handle    = Buffer;
  ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory;
  //
  // Get information about the image being loaded
  //
  Status = PeCoffLoaderGetImageInfo (&ImageContext);
  ASSERT_EFI_ERROR (Status);
  if (ImageContext.SectionAlignment > EFI_PAGE_SIZE) {
    Pages = EFI_SIZE_TO_PAGES ((UINTN) (ImageContext.ImageSize + ImageContext.SectionAlignment));
  } else {
    Pages = EFI_SIZE_TO_PAGES ((UINTN) ImageContext.ImageSize);
  }
  FfsBuffer = 0xFFFFFFFF;
  Status = gBS->AllocatePages (
                  AllocateMaxAddress,
                  EfiReservedMemoryType,
                  Pages,
                  &FfsBuffer
                  );
  ASSERT_EFI_ERROR (Status);
  ImageContext.ImageAddress = (PHYSICAL_ADDRESS)(UINTN)FfsBuffer;
  //
  // Align buffer on section boundry
  //
  ImageContext.ImageAddress += ImageContext.SectionAlignment - 1;
  ImageContext.ImageAddress &= ~((EFI_PHYSICAL_ADDRESS)(ImageContext.SectionAlignment - 1));
  //
  // Load the image to our new buffer
  //
  Status = PeCoffLoaderLoadImage (&ImageContext);
  ASSERT_EFI_ERROR (Status);

  //
  // Relocate the image in our new buffer
  //
  Status = PeCoffLoaderRelocateImage (&ImageContext);
  ASSERT_EFI_ERROR (Status);

  //
  // Free the buffer allocated by ReadSection since the image has been relocated in the new buffer
  //
  gBS->FreePool (Buffer);

  //
  // Flush the instruction cache so the image data is written before we execute it
  //
  InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize);
    
  //
  // install loaded image
  //
  LoadedImage = AllocateZeroPool (sizeof(EFI_LOADED_IMAGE_PROTOCOL));
  ASSERT (LoadedImage != NULL);

  LoadedImage->Revision = EFI_LOADED_IMAGE_PROTOCOL_REVISION;
  LoadedImage->ParentHandle = NULL;
  LoadedImage->SystemTable = gST;
  LoadedImage->DeviceHandle = NULL;
  LoadedImage->LoadOptionsSize = 0;
  LoadedImage->LoadOptions = NULL;
  LoadedImage->ImageBase = (VOID *)(UINTN)ImageContext.ImageAddress;
  LoadedImage->ImageSize = ImageContext.ImageSize;
  LoadedImage->ImageCodeType = EfiReservedMemoryType;
  LoadedImage->ImageDataType = EfiReservedMemoryType;
  LoadedImage->Unload = NULL;

  NewImageHandle = NULL;
  Status = gBS->InstallMultipleProtocolInterfaces (
                  &NewImageHandle,
                  &gEfiCallerIdGuid, LoadedImage,
                  NULL
                  );
  ASSERT_EFI_ERROR (Status);
  DEBUG ((EFI_D_INFO, "NewImageHandle - 0x%x\n", NewImageHandle));

  //
  // Call entrypoint
  //
  DEBUG ((EFI_D_INFO, "Loading driver at 0x%08x EntryPoint=0x%08x\n", (UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.EntryPoint));
  Status = ((EFI_IMAGE_ENTRY_POINT)(UINTN)(ImageContext.EntryPoint)) (NewImageHandle, gST);
  if (EFI_ERROR (Status)) {
    DEBUG ((EFI_D_ERROR, "Error: Image at 0x%08x start failed: %r\n", ImageContext.ImageAddress, Status));
    gBS->FreePages (FfsBuffer, Pages);
  }

  //
  // return error to unload DXE copy, if we already relocate itself to reserved memory.
  //
  return EFI_ACCESS_DENIED;
}