예제 #1
0
/**
  Allocates one or more 4KB pages of a certain memory type.

  Allocates the number of 4KB pages of a certain memory type and returns a pointer to the allocated
  buffer.  The buffer returned is aligned on a 4KB boundary.  If Pages is 0, then NULL is returned.
  If there is not enough memory remaining to satisfy the request, then NULL is returned.

  @param  MemoryType            The type of memory to allocate.
  @param  Pages                 The number of 4 KB pages to allocate.

  @return A pointer to the allocated buffer or NULL if allocation fails.

**/
VOID *
InternalAllocatePages (
  IN EFI_MEMORY_TYPE  MemoryType,  
  IN UINTN            Pages
  )
{
  EFI_STATUS            Status;
  EFI_PHYSICAL_ADDRESS  Memory; 

  if (Pages == 0) {
    return NULL;
  }

  Status = SmmAllocatePages (AllocateAnyPages, MemoryType, Pages, &Memory);
  if (EFI_ERROR (Status)) {
    return NULL;
  }
  return (VOID *) (UINTN) Memory;
}
예제 #2
0
/**
  Allocates one or more 4KB pages of a certain memory type at a specified alignment.

  Allocates the number of 4KB pages specified by Pages of a certain memory type with an alignment
  specified by Alignment.  The allocated buffer is returned.  If Pages is 0, then NULL is returned.
  If there is not enough memory at the specified alignment remaining to satisfy the request, then
  NULL is returned.
  If Alignment is not a power of two and Alignment is not zero, then ASSERT().
  If Pages plus EFI_SIZE_TO_PAGES (Alignment) overflows, then ASSERT().

  @param  MemoryType            The type of memory to allocate.
  @param  Pages                 The number of 4 KB pages to allocate.
  @param  Alignment             The requested alignment of the allocation.  Must be a power of two.
                                If Alignment is zero, then byte alignment is used.

  @return A pointer to the allocated buffer or NULL if allocation fails.

**/
VOID *
InternalAllocateAlignedPages (
  IN EFI_MEMORY_TYPE  MemoryType,  
  IN UINTN            Pages,
  IN UINTN            Alignment
  )
{
  EFI_STATUS            Status;
  EFI_PHYSICAL_ADDRESS  Memory;
  UINTN                 AlignedMemory;
  UINTN                 AlignmentMask;
  UINTN                 UnalignedPages;
  UINTN                 RealPages;

  //
  // Alignment must be a power of two or zero.
  //
  ASSERT ((Alignment & (Alignment - 1)) == 0);
 
  if (Pages == 0) {
    return NULL;
  }
  if (Alignment > EFI_PAGE_SIZE) {
    //
    // Caculate the total number of pages since alignment is larger than page size.
    //
    AlignmentMask  = Alignment - 1;
    RealPages      = Pages + EFI_SIZE_TO_PAGES (Alignment);
    //
    // Make sure that Pages plus EFI_SIZE_TO_PAGES (Alignment) does not overflow.
    //
    ASSERT (RealPages > Pages);
 
    Status         = SmmAllocatePages (AllocateAnyPages, MemoryType, RealPages, &Memory);
    if (EFI_ERROR (Status)) {
      return NULL;
    }
    AlignedMemory  = ((UINTN) Memory + AlignmentMask) & ~AlignmentMask;
    UnalignedPages = EFI_SIZE_TO_PAGES (AlignedMemory - (UINTN) Memory);
    if (UnalignedPages > 0) {
      //
      // Free first unaligned page(s).
      //
      Status = SmmFreePages (Memory, UnalignedPages);
      ASSERT_EFI_ERROR (Status);
    }
    Memory         = (EFI_PHYSICAL_ADDRESS) (AlignedMemory + EFI_PAGES_TO_SIZE (Pages));
    UnalignedPages = RealPages - Pages - UnalignedPages;
    if (UnalignedPages > 0) {
      //
      // Free last unaligned page(s).
      //
      Status = SmmFreePages (Memory, UnalignedPages);
      ASSERT_EFI_ERROR (Status);
    }
  } else {
    //
    // Do not over-allocate pages in this case.
    //
    Status = SmmAllocatePages (AllocateAnyPages, MemoryType, Pages, &Memory);
    if (EFI_ERROR (Status)) {
      return NULL;
    }
    AlignedMemory  = (UINTN) Memory;
  }
  return (VOID *) AlignedMemory;
}
예제 #3
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;  
}