#include <Protocol/LoadedImage.h>\r
#include <Protocol/SmmCpuSaveState.h>\r
#include <Protocol/MpService.h>\r
+#include <Protocol/LoadPe32Image.h>\r
\r
///\r
/// Structure for tracking paired information of registered Framework SMI handler\r
\r
EFI_HANDLE mDispatchHandle;\r
EFI_SMM_CPU_PROTOCOL *mSmmCpu;\r
+EFI_PE32_IMAGE_PROTOCOL *mLoadPe32Image;\r
EFI_GUID mEfiSmmCpuIoGuid = EFI_SMM_CPU_IO_GUID;\r
EFI_SMM_BASE_HELPER_READY_PROTOCOL *mSmmBaseHelperReady;\r
EFI_SMM_SYSTEM_TABLE *mFrameworkSmst;\r
/**\r
Load a given Framework SMM driver into SMRAM and invoke its entry point.\r
\r
+ @param[in] ParentImageHandle Parent Image Handle.\r
@param[in] FilePath Location of the image to be installed as the handler.\r
@param[in] SourceBuffer Optional source buffer in case the image file\r
is in memory.\r
**/\r
EFI_STATUS\r
LoadImage (\r
+ IN EFI_HANDLE ParentImageHandle,\r
IN EFI_DEVICE_PATH_PROTOCOL *FilePath,\r
IN VOID *SourceBuffer,\r
IN UINTN SourceSize,\r
OUT EFI_HANDLE *ImageHandle\r
)\r
{\r
- EFI_STATUS Status;\r
- UINTN PageCount;\r
- EFI_PHYSICAL_ADDRESS Buffer;\r
- PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;\r
- EFI_HANDLE PesudoImageHandle;\r
- UINTN NumHandles;\r
- UINTN Index;\r
- EFI_HANDLE *HandleBuffer;\r
- EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;\r
- EFI_DEVICE_PATH *LoadedImageDevicePath;\r
- UINTN DevicePathSize;\r
+ EFI_STATUS Status;\r
+ UINTN PageCount;\r
+ UINTN OrgPageCount;\r
+ EFI_PHYSICAL_ADDRESS DstBuffer;\r
\r
if (FilePath == NULL || ImageHandle == NULL) { \r
return EFI_INVALID_PARAMETER;\r
}\r
\r
- ///\r
- /// Assume Framework SMM driver has an image copy in memory before registering itself into SMRAM.\r
- /// Currently only supports load Framework SMM driver from existing image copy in memory.\r
- /// Load PE32 Image Protocol can be used to support loading Framework SMM driver directly from FV.\r
- ///\r
- if (SourceBuffer == NULL) {\r
- Status = gBS->LocateHandleBuffer (\r
- ByProtocol,\r
- &gEfiLoadedImageDevicePathProtocolGuid,\r
- NULL,\r
- &NumHandles,\r
- &HandleBuffer\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return EFI_UNSUPPORTED;\r
- }\r
-\r
- DevicePathSize = GetDevicePathSize (FilePath);\r
-\r
- for (Index = 0; Index < NumHandles; Index++) {\r
- Status = gBS->HandleProtocol (\r
- HandleBuffer[Index],\r
- &gEfiLoadedImageDevicePathProtocolGuid,\r
- (VOID **)&LoadedImageDevicePath\r
+ PageCount = 1;\r
+ do {\r
+ OrgPageCount = PageCount;\r
+ DstBuffer = (UINTN)-1;\r
+ Status = gSmst->SmmAllocatePages (\r
+ AllocateMaxAddress,\r
+ EfiRuntimeServicesCode,\r
+ PageCount,\r
+ &DstBuffer\r
);\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- if (GetDevicePathSize (LoadedImageDevicePath) == DevicePathSize &&\r
- CompareMem (LoadedImageDevicePath, FilePath, DevicePathSize) == 0) {\r
- break;\r
- } \r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
}\r
\r
- if (Index < NumHandles) {\r
- Status = gBS->HandleProtocol (\r
- HandleBuffer[Index],\r
- &gEfiLoadedImageProtocolGuid,\r
- (VOID **)&LoadedImage\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
- \r
- SourceBuffer = LoadedImage->ImageBase;\r
- gBS->FreePool (HandleBuffer);\r
- } else {\r
- gBS->FreePool (HandleBuffer);\r
- return EFI_UNSUPPORTED;\r
+ Status = mLoadPe32Image->LoadPeImage (\r
+ mLoadPe32Image,\r
+ ParentImageHandle,\r
+ FilePath,\r
+ SourceBuffer,\r
+ SourceSize,\r
+ DstBuffer,\r
+ &PageCount,\r
+ ImageHandle,\r
+ NULL,\r
+ EFI_LOAD_PE_IMAGE_ATTRIBUTE_NONE\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ FreePages ((VOID *)(UINTN)DstBuffer, OrgPageCount);\r
}\r
- }\r
+ } while (Status == EFI_BUFFER_TOO_SMALL);\r
\r
- ImageContext.Handle = SourceBuffer;\r
- ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory;\r
-\r
- ///\r
- /// Get information about the image being loaded\r
- ///\r
- Status = PeCoffLoaderGetImageInfo (&ImageContext);\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
-\r
- ///\r
- /// Allocate buffer for loading image into SMRAM\r
- ///\r
- PageCount = (UINTN)EFI_SIZE_TO_PAGES (ImageContext.ImageSize + ImageContext.SectionAlignment);\r
- Status = gSmst->SmmAllocatePages (AllocateAnyPages, EfiRuntimeServicesCode, PageCount, &Buffer);\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
-\r
- ImageContext.ImageAddress = (PHYSICAL_ADDRESS)Buffer;\r
-\r
- ///\r
- /// Align buffer on section boundry\r
- ///\r
- ImageContext.ImageAddress += ImageContext.SectionAlignment - 1;\r
- ImageContext.ImageAddress &= ~(ImageContext.SectionAlignment - 1);\r
-\r
- ///\r
- /// Load the image into SMRAM\r
- ///\r
- Status = PeCoffLoaderLoadImage (&ImageContext);\r
- if (EFI_ERROR (Status)) {\r
- goto Error;\r
- }\r
-\r
- ///\r
- /// Relocate the image in our new buffer\r
- ///\r
- Status = PeCoffLoaderRelocateImage (&ImageContext);\r
- if (EFI_ERROR (Status)) {\r
- goto Error;\r
- }\r
-\r
- ///\r
- /// Flush the instruction cache so the image data are written before we execute it\r
- ///\r
- InvalidateInstructionCacheRange ((VOID *)(UINTN) ImageContext.ImageAddress, (UINTN) ImageContext.ImageSize);\r
-\r
- ///\r
- /// Update MP state in Framework SMST before transferring control to Framework SMM driver entry point\r
- /// in case it may invoke AP\r
- ///\r
- mFrameworkSmst->CurrentlyExecutingCpu = gSmst->CurrentlyExecutingCpu;\r
-\r
- ///\r
- /// For Framework SMM, ImageHandle does not have to be a UEFI image handle. The only requirement is that the \r
- /// ImageHandle is a unique value. Use image base address as the unique value.\r
- ///\r
- PesudoImageHandle = (EFI_HANDLE)(UINTN)ImageContext.ImageAddress;\r
-\r
- Status = ((EFI_IMAGE_ENTRY_POINT)(UINTN)ImageContext.EntryPoint) (PesudoImageHandle, gST);\r
if (!EFI_ERROR (Status)) {\r
- *ImageHandle = PesudoImageHandle;\r
- return EFI_SUCCESS;\r
+ ///\r
+ /// Update MP state in Framework SMST before transferring control to Framework SMM driver entry point\r
+ /// in case it may invoke AP\r
+ ///\r
+ mFrameworkSmst->CurrentlyExecutingCpu = gSmst->CurrentlyExecutingCpu;\r
+\r
+ Status = gBS->StartImage (*ImageHandle, NULL, NULL);\r
+ if (EFI_ERROR (Status)) {\r
+ mLoadPe32Image->UnLoadPeImage (mLoadPe32Image, *ImageHandle);\r
+ *ImageHandle = NULL;\r
+ FreePages ((VOID *)(UINTN)DstBuffer, PageCount);\r
+ }\r
}\r
\r
-Error:\r
- FreePages ((VOID *)(UINTN)Buffer, PageCount);\r
- return EFI_SUCCESS;\r
+ return Status;\r
}\r
\r
+\r
/** \r
Thunk service of EFI_SMM_BASE_PROTOCOL.Register().\r
\r
Status = EFI_UNSUPPORTED;\r
} else {\r
Status = LoadImage (\r
+ FunctionData->SmmBaseImageHandle,\r
FunctionData->Args.Register.FilePath,\r
FunctionData->Args.Register.SourceBuffer,\r
FunctionData->Args.Register.SourceSize,\r
Status = gSmst->SmmLocateProtocol (&gEfiSmmCpuProtocolGuid, NULL, (VOID **) &mSmmCpu);\r
ASSERT_EFI_ERROR (Status);\r
\r
+ ///\r
+ /// Locate PE32 Image Protocol which is used later to load Framework SMM driver\r
+ ///\r
+ Status = SystemTable->BootServices->LocateProtocol (&gEfiLoadPeImageProtocolGuid, NULL, (VOID **) &mLoadPe32Image);\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
//\r
// Get MP Services Protocol\r
//\r