summaryrefslogtreecommitdiff
path: root/EDK/Foundation/Core/Dxe/Image
diff options
context:
space:
mode:
Diffstat (limited to 'EDK/Foundation/Core/Dxe/Image')
-rw-r--r--EDK/Foundation/Core/Dxe/Image/Image.c1626
-rw-r--r--EDK/Foundation/Core/Dxe/Image/Image.h399
-rw-r--r--EDK/Foundation/Core/Dxe/Image/ImageFile.c646
3 files changed, 2671 insertions, 0 deletions
diff --git a/EDK/Foundation/Core/Dxe/Image/Image.c b/EDK/Foundation/Core/Dxe/Image/Image.c
new file mode 100644
index 0000000..bdf1783
--- /dev/null
+++ b/EDK/Foundation/Core/Dxe/Image/Image.c
@@ -0,0 +1,1626 @@
+/*++
+
+Copyright (c) 2004 - 2012, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+
+ Image.c
+
+Abstract:
+
+ Core image handling services
+
+--*/
+
+#include "Image.h"
+#include "EfiHobLib.h"
+#include "EfiPerf.h"
+
+//
+// Module Globals
+//
+
+LOADED_IMAGE_PRIVATE_DATA *mCurrentImage = NULL;
+
+LOAD_PE32_IMAGE_PRIVATE_DATA mLoadPe32PrivateData = {
+ LOAD_PE32_IMAGE_PRIVATE_DATA_SIGNATURE,
+ NULL,
+ CoreLoadImageEx,
+ CoreUnloadImageEx
+};
+
+
+//
+// This code is needed to build the Image handle for the DXE Core
+//
+LOADED_IMAGE_PRIVATE_DATA mCorePrivateImage = {
+ LOADED_IMAGE_PRIVATE_DATA_SIGNATURE, // Signature
+ NULL, // Image handle
+ EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER, // Image type
+ TRUE, // If entrypoint has been called
+ NULL, // EntryPoint
+ {
+ EFI_LOADED_IMAGE_INFORMATION_REVISION, // Revision
+ NULL, // Parent handle
+ NULL, // System handle
+
+ NULL, // Device handle
+ NULL, // File path
+ NULL, // Reserved
+
+ 0, // LoadOptionsSize
+ NULL, // LoadOptions
+
+ NULL, // ImageBase
+ 0, // ImageSize
+ EfiBootServicesCode, // ImageCodeType
+ EfiBootServicesData // ImageDataType
+ },
+#if (EFI_SPECIFICATION_VERSION >= 0x0002000A)
+ NULL, // Loaded Image Device Path
+#endif
+ (EFI_PHYSICAL_ADDRESS)0, // ImageBasePage
+ 0, // NumberOfPages
+ NULL, // FixupData
+ 0, // Tpl
+ EFI_SUCCESS, // Status
+ 0, // ExitDataSize
+ NULL, // ExitData
+ NULL, // JumpContext
+ 0, // Machine
+ NULL, // Ebc
+ NULL, // RuntimeData
+};
+
+
+STATIC
+EFI_STATUS
+EFIAPI
+CoreFlushICache (
+ IN EFI_PHYSICAL_ADDRESS Start,
+ IN UINT64 Length
+ );
+
+EFI_STATUS
+GetTimerValue (
+ OUT UINT64 *TimerValue
+ );
+
+EFI_STATUS
+CoreInitializeImageServices (
+ IN VOID *HobStart
+ )
+/*++
+
+Routine Description:
+
+ Add the Image Services to EFI Boot Services Table and install the protocol
+ interfaces for this image.
+
+Arguments:
+
+ HobStart - The HOB to initialize
+
+Returns:
+
+ Status code.
+
+--*/
+{
+ EFI_STATUS Status;
+ LOADED_IMAGE_PRIVATE_DATA *Image;
+ EFI_PHYSICAL_ADDRESS DxeCoreImageBaseAddress;
+ UINT64 DxeCoreImageLength;
+ VOID *DxeCoreEntryPoint;
+
+
+ //
+ // Searching for image hob
+ //
+ Status = GetDxeCoreHobInfo (
+ HobStart,
+ &DxeCoreImageBaseAddress,
+ &DxeCoreImageLength,
+ &DxeCoreEntryPoint,
+ &gDxeCoreFileName
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Initialize the fields for an internal driver
+ //
+ Image = &mCorePrivateImage;
+
+ Image->EntryPoint = (EFI_IMAGE_ENTRY_POINT)(UINTN)DxeCoreEntryPoint;
+ Image->ImageBasePage = DxeCoreImageBaseAddress;
+ Image->NumberOfPages = (UINTN)(EFI_SIZE_TO_PAGES((UINTN)(DxeCoreImageLength)));
+ Image->Tpl = gEfiCurrentTpl;
+ Image->Info.SystemTable = gST;
+ Image->Info.ImageBase = (VOID *)(UINTN)DxeCoreImageBaseAddress;
+ Image->Info.ImageSize = DxeCoreImageLength;
+
+ //
+ // Install the protocol interfaces for this image
+ //
+ Status = CoreInstallProtocolInterface (
+ &Image->Handle,
+ &gEfiLoadedImageProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &Image->Info
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Install Debug Mask Protocol
+ //
+ DEBUG_CODE (
+ if (!EFI_ERROR (Status)) {
+ Status = InstallCoreDebugMaskProtocol(Image->Handle);
+ ASSERT_EFI_ERROR (Status);
+ }
+ )
+
+ mCurrentImage = Image;
+
+ //
+ // Fill in DXE globals
+ //
+ gDxeCoreImageHandle = Image->Handle;
+ gDxeCoreLoadedImage = &Image->Info;
+
+ //
+ // Export DXE Core PE Loader functionality
+ //
+ return CoreInstallProtocolInterface (
+ &mLoadPe32PrivateData.Handle,
+ &gEfiLoadPeImageGuid,
+ EFI_NATIVE_INTERFACE,
+ &mLoadPe32PrivateData.Pe32Image
+ );
+}
+
+
+STATIC
+EFI_STATUS
+CoreLoadPeImage (
+ IN BOOLEAN BootPolicy,
+ IN VOID *Pe32Handle,
+ IN LOADED_IMAGE_PRIVATE_DATA *Image,
+ IN EFI_PHYSICAL_ADDRESS DstBuffer OPTIONAL,
+ OUT EFI_PHYSICAL_ADDRESS *EntryPoint OPTIONAL,
+ IN UINT32 Attribute,
+ IN BOOLEAN CrossLoad
+ )
+/*++
+
+Routine Description:
+
+ Loads, relocates, and invokes a PE/COFF image.
+
+Arguments:
+
+ Pe32Handle - The handle of PE32 image.
+ Image - PE image to be loaded.
+ DstBuffer - The buffer to store the image.
+ EntryPoint - A pointer to the entry point.
+ Attribute - The bit mask of attributes to set for the load PE image.
+ CrossLoad - Whether expect to support cross architecture loading.
+
+Returns:
+
+ EFI_SUCCESS - The file was loaded, relocated, and invoked.
+ EFI_OUT_OF_RESOURCES - There was not enough memory to load and relocate the PE/COFF file.
+ EFI_INVALID_PARAMETER - Invalid parameter.
+ EFI_BUFFER_TOO_SMALL - Buffer for image is too small.
+
+--*/
+{
+ EFI_STATUS Status;
+ BOOLEAN DstBufAlocated;
+ UINTN Size;
+ EFI_IMAGE_NT_HEADERS64 *PeHdr;
+ EFI_TCG_PLATFORM_PROTOCOL *TcgPlatformProtocol;
+ IMAGE_FILE_HANDLE *FHandle;
+ BOOLEAN NeedAllocateAddress;
+#ifdef EFI_LOAD_DRIVER_AT_FIXED_OFFSET
+ BOOLEAN OffsetMode;
+ STATIC BOOLEAN PrintTopAddress = TRUE;
+#endif
+
+ DEBUG_CODE (
+ UINTN Index;
+ UINTN StartIndex;
+ CHAR8 EfiFileName[256];
+ )
+
+ EfiCommonLibZeroMem (&(Image->ImageContext), sizeof (Image->ImageContext));
+
+ Image->ImageContext.Handle = Pe32Handle;
+ Image->ImageContext.ImageRead = (EFI_PEI_PE_COFF_LOADER_READ_FILE) CoreReadImageFile;
+
+ //
+ // Get information about the image being loaded.
+ //
+ Status = gEfiPeiPeCoffLoader->GetImageInfo (gEfiPeiPeCoffLoader, &(Image->ImageContext));
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Check the processor architecture of the image
+ //
+ if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Image->ImageContext.Machine)) {
+ if (CrossLoad) {
+ if (!EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED (Image->ImageContext.Machine)) {
+ return EFI_UNSUPPORTED;
+ }
+ } else {
+ return EFI_UNSUPPORTED;
+ }
+ }
+
+ //
+ // Allocate memory of the correct memory type aligned on the required image boundary.
+ //
+ DstBufAlocated = FALSE;
+ if (DstBuffer == 0) {
+ //
+ // Allocate Destination Buffer as caller did not pass it in.
+ //
+
+ if (Image->ImageContext.SectionAlignment > EFI_PAGE_SIZE) {
+ Size = (UINTN) Image->ImageContext.ImageSize + Image->ImageContext.SectionAlignment;
+ } else {
+ Size = (UINTN) Image->ImageContext.ImageSize;
+ }
+
+ Image->NumberOfPages = EFI_SIZE_TO_PAGES (Size);
+ //
+ // Following code is to support load a PE image at fixed offset relative to TOLM
+ //
+#ifdef EFI_LOAD_DRIVER_AT_FIXED_OFFSET
+ {
+ typedef struct {
+ EFI_PHYSICAL_ADDRESS BaseAddress;
+ EFI_PHYSICAL_ADDRESS MaximumAddress;
+ UINT64 CurrentNumberOfPages;
+ UINT64 NumberOfPages;
+ UINTN InformationIndex;
+ BOOLEAN Special;
+ BOOLEAN Runtime;
+ } EFI_MEMORY_TYPE_STAISTICS;
+
+
+ extern EFI_MEMORY_TYPE_STAISTICS mMemoryTypeStatistics[EfiMaxMemoryType + 1];
+ INT32 Offset;
+ UINTN ReadSize = sizeof (UINT32);
+
+ if (PrintTopAddress) {
+ DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Runtime code top address: %lX\n", mMemoryTypeStatistics[EfiRuntimeServicesCode].MaximumAddress + 1));
+ DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Boot time code top address: %lX\n", mMemoryTypeStatistics[EfiBootServicesCode].MaximumAddress + 1));
+ PrintTopAddress = FALSE;
+ }
+ OffsetMode = FALSE;
+ Status = Image->ImageContext.ImageRead (
+ Image->ImageContext.Handle,
+ Image->ImageContext.PeCoffHeaderOffset + 12,
+ &ReadSize,
+ &Offset
+ );
+ if (!EFI_ERROR (Status) && Offset != 0 &&
+ Image->ImageContext.ImageCodeMemoryType != EfiLoaderCode) {
+ OffsetMode = TRUE;
+ Image->ImageContext.ImageAddress = mMemoryTypeStatistics[Image->ImageContext.ImageCodeMemoryType].MaximumAddress + 1 - Offset;
+ }
+ }
+#endif
+
+ //
+ // If the image relocations are stripped, or fixed address/offset feature is valid,
+ // try to load the image to the specified address first.
+ // Otherwise try to load the image at any page if image relocations are available.
+ //
+ NeedAllocateAddress = FALSE;
+ if (Image->ImageContext.RelocationsStripped) {
+ NeedAllocateAddress = TRUE;
+ }
+#ifdef EFI_LOAD_DRIVER_AT_FIXED_ADDRESS
+ NeedAllocateAddress = TRUE;
+#endif
+#ifdef EFI_LOAD_DRIVER_AT_FIXED_OFFSET
+ if (OffsetMode) {
+ NeedAllocateAddress = TRUE;
+ }
+#endif
+ Status = EFI_OUT_OF_RESOURCES;
+ if (NeedAllocateAddress) {
+ Status = CoreAllocatePages (
+ AllocateAddress,
+ Image->ImageContext.ImageCodeMemoryType,
+ Image->NumberOfPages,
+ &Image->ImageContext.ImageAddress
+ );
+#ifdef EFI_LOAD_DRIVER_AT_FIXED_OFFSET
+ if (EFI_ERROR (Status) && OffsetMode) {
+ DEBUG((EFI_D_ERROR, "\nOffset mode load failure!"));
+ }
+#endif
+ }
+ if (EFI_ERROR (Status) && !Image->ImageContext.RelocationsStripped) {
+ Status = CoreAllocatePages (
+ AllocateAnyPages,
+ Image->ImageContext.ImageCodeMemoryType,
+ Image->NumberOfPages,
+ &Image->ImageContext.ImageAddress
+ );
+ }
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ DstBufAlocated = TRUE;
+ } else {
+ //
+ // Caller provided the destination buffer.
+ //
+
+ if (Image->ImageContext.RelocationsStripped && (Image->ImageContext.ImageAddress != DstBuffer)) {
+ //
+ // If the image relocations were stripped, and the caller provided a
+ // destination buffer address that does not match the address that the
+ // image is linked at, then the image cannot be loaded.
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Size = EFI_SIZE_TO_PAGES ((UINTN) Image->ImageContext.ImageSize + Image->ImageContext.SectionAlignment);
+
+ if ((Image->NumberOfPages != 0) && (Image->NumberOfPages < Size)) {
+ Image->NumberOfPages = Size;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ Image->NumberOfPages = Size;
+ Image->ImageContext.ImageAddress = DstBuffer;
+ }
+
+ Image->ImageBasePage = Image->ImageContext.ImageAddress;
+ Image->ImageContext.ImageAddress =
+ (Image->ImageContext.ImageAddress + Image->ImageContext.SectionAlignment - 1) &
+ ~((UINTN) Image->ImageContext.SectionAlignment - 1);
+
+ //
+ // Load the image from the file into the allocated memory
+ //
+ Status = gEfiPeiPeCoffLoader->LoadImage (gEfiPeiPeCoffLoader, &(Image->ImageContext));
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // If this is a Runtime Driver, then allocate memory for the FixupData that
+ // is used to relocate the image when SetVirtualAddressMap() is called. The
+ // relocation is done by the Runtime AP.
+ //
+ if (Attribute & EFI_LOAD_PE_IMAGE_ATTRIBUTE_RUNTIME_REGISTRATION) {
+ if (Image->ImageContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER &&
+ EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Image->ImageContext.Machine)) {
+ Image->ImageContext.FixupData = CoreAllocateRuntimePool ((UINTN)(Image->ImageContext.FixupDataSize));
+ if (Image->ImageContext.FixupData == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+ }
+ }
+
+ //
+ // Measure the image before applying fixup
+ //
+ Status = CoreLocateProtocol (
+ &gEfiTcgPlatformProtocolGuid,
+ NULL,
+ &TcgPlatformProtocol
+ );
+ if (!EFI_ERROR (Status) && (TcgPlatformProtocol != NULL)) {
+ PeHdr = (EFI_IMAGE_NT_HEADERS64 *)(UINTN) (
+ Image->ImageContext.ImageAddress +
+ Image->ImageContext.PeCoffHeaderOffset
+ );
+ FHandle = (IMAGE_FILE_HANDLE *)Image->ImageContext.Handle;
+
+ Status = TcgPlatformProtocol->MeasurePeImage (
+ BootPolicy,
+ (EFI_PHYSICAL_ADDRESS)FHandle->Source,
+ FHandle->SourceSize,
+ (UINTN) PeHdr->OptionalHeader.ImageBase,
+ Image->ImageContext.ImageType,
+ Image->Info.DeviceHandle,
+ Image->Info.FilePath
+ );
+
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ //
+ // Relocate the image in memory
+ //
+ Status = gEfiPeiPeCoffLoader->RelocateImage (gEfiPeiPeCoffLoader, &(Image->ImageContext));
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Flush the Instruction Cache
+ //
+ Status = CoreFlushICache (Image->ImageContext.ImageAddress, Image->ImageContext.ImageSize);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Get the image entry point. If it's an EBC image, then call into the
+ // interpreter to create a thunk for the entry point and use the returned
+ // value for the entry point.
+ //
+ Image->EntryPoint = (EFI_IMAGE_ENTRY_POINT) (UINTN) Image->ImageContext.EntryPoint;
+
+ //
+ // Copy the machine type from the context to the image private data. This
+ // is needed during image unload to know if we should call an EBC protocol
+ // to unload the image.
+ //
+ Image->Machine = Image->ImageContext.Machine;
+ if (Image->ImageContext.Machine == EFI_IMAGE_MACHINE_EBC) {
+ //
+ // Locate the EBC interpreter protocol
+ //
+ Status = CoreLocateProtocol (&gEfiEbcProtocolGuid, NULL, &Image->Ebc);
+ if (EFI_ERROR (Status) || (Image->Ebc == NULL)) {
+ goto Done;
+ }
+
+ //
+ // Register a callback for flushing the instruction cache so that created
+ // thunks can be flushed.
+ //
+ Status = Image->Ebc->RegisterICacheFlush (Image->Ebc, CoreFlushICache);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Create a thunk for the image's entry point. This will be the new
+ // entry point for the image.
+ //
+ Status = Image->Ebc->CreateThunk (
+ Image->Ebc,
+ Image->Handle,
+ (VOID *)(UINTN)Image->ImageContext.EntryPoint,
+ (VOID **)&Image->EntryPoint
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ }
+
+ //
+ // Fill in the image information for the Loaded Image Protocol
+ //
+ Image->Type = Image->ImageContext.ImageType;
+ Image->Info.ImageBase = (VOID *) (UINTN) Image->ImageContext.ImageAddress;
+ Image->Info.ImageSize = Image->ImageContext.ImageSize;
+ Image->Info.ImageCodeType = Image->ImageContext.ImageCodeMemoryType;
+ Image->Info.ImageDataType = Image->ImageContext.ImageDataMemoryType;
+
+ if (Attribute & EFI_LOAD_PE_IMAGE_ATTRIBUTE_RUNTIME_REGISTRATION) {
+ if (Image->ImageContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) {
+ //
+ // Make a list off all the RT images so we can let the RT AP know about them.
+ //
+ Image->RuntimeData = CoreAllocateRuntimePool (sizeof(EFI_RUNTIME_IMAGE_ENTRY));
+ if (Image->RuntimeData == NULL) {
+ goto Done;
+ }
+ Image->RuntimeData->ImageBase = Image->Info.ImageBase;
+ Image->RuntimeData->ImageSize = (UINT64) (Image->Info.ImageSize);
+ Image->RuntimeData->RelocationData = Image->ImageContext.FixupData;
+ Image->RuntimeData->Handle = Image->Handle;
+ InsertTailList (&gRuntime->ImageHead, &Image->RuntimeData->Link);
+ }
+ }
+
+ //
+ // Fill in the entry point of the image if it is available
+ //
+ if (EntryPoint != NULL) {
+ *EntryPoint = Image->ImageContext.EntryPoint;
+ }
+
+ //
+ // Print the load address and the PDB file name if it is available
+ //
+
+ DEBUG_CODE (
+ {
+ DEBUG ((
+ EFI_D_INFO | EFI_D_LOAD,
+ "Loading driver at 0x%x EntryPoint=0x%x ",
+ (UINTN) Image->ImageContext.ImageAddress,
+ (UINTN) Image->ImageContext.EntryPoint
+ ));
+ if (Image->ImageContext.PdbPointer != NULL) {
+ StartIndex = 0;
+ for (Index = 0; Image->ImageContext.PdbPointer[Index] != 0; Index++) {
+ if (Image->ImageContext.PdbPointer[Index] == '\\') {
+ StartIndex = Index + 1;
+ }
+ }
+ //
+ // Copy the PDB file name to our temporary string, and replace .pdb with .efi
+ //
+ for (Index = 0; Index < sizeof (EfiFileName); Index++) {
+ EfiFileName[Index] = Image->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;
+ }
+ }
+ DEBUG ((EFI_D_INFO | EFI_D_LOAD, "%a", EfiFileName));
+ }
+ DEBUG ((EFI_D_INFO | EFI_D_LOAD, "\n"));
+ }
+ );
+
+ return EFI_SUCCESS;
+
+Done:
+
+ //
+ // Free memory.
+ //
+
+ if (DstBufAlocated) {
+ CoreFreePages (Image->ImageContext.ImageAddress, Image->NumberOfPages);
+ }
+
+ if (Image->ImageContext.FixupData != NULL) {
+ CoreFreePool (Image->ImageContext.FixupData);
+ }
+
+ return Status;
+}
+
+
+LOADED_IMAGE_PRIVATE_DATA *
+CoreLoadedImageInfo (
+ IN EFI_HANDLE ImageHandle
+ )
+/*++
+
+Routine Description:
+
+ Get the image's private data from its handle.
+
+Arguments:
+
+ ImageHandle - The image handle
+
+Returns:
+
+ Return the image private data associated with ImageHandle.
+
+--*/
+{
+ EFI_STATUS Status;
+ EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
+ LOADED_IMAGE_PRIVATE_DATA *Image;
+
+ Status = CoreHandleProtocol (
+ ImageHandle,
+ &gEfiLoadedImageProtocolGuid,
+ &LoadedImage
+ );
+ if (!EFI_ERROR (Status)) {
+ Image = LOADED_IMAGE_PRIVATE_DATA_FROM_THIS (LoadedImage);
+ } else {
+ DEBUG ((EFI_D_LOAD, "CoreLoadedImageInfo: Not an ImageHandle %x\n", ImageHandle));
+ Image = NULL;
+ }
+
+ return Image;
+}
+
+
+EFI_STATUS
+CoreLoadImageCommon (
+ IN BOOLEAN BootPolicy,
+ IN EFI_HANDLE ParentImageHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ IN VOID *SourceBuffer OPTIONAL,
+ IN UINTN SourceSize,
+ IN EFI_PHYSICAL_ADDRESS DstBuffer OPTIONAL,
+ IN OUT UINTN *NumberOfPages OPTIONAL,
+ OUT EFI_HANDLE *ImageHandle,
+ OUT EFI_PHYSICAL_ADDRESS *EntryPoint OPTIONAL,
+ IN UINT32 Attribute,
+ IN BOOLEAN CrossLoad
+ )
+/*++
+
+Routine Description:
+
+ Loads an EFI image into memory and returns a handle to the image.
+
+Arguments:
+
+ BootPolicy - If TRUE, indicates that the request originates from the boot manager,
+ and that the boot manager is attempting to load FilePath as a boot selection.
+ ParentImageHandle - The caller's image handle.
+ FilePath - The specific file path from which the image is loaded.
+ SourceBuffer - If not NULL, a pointer to the memory location containing a copy of
+ the image to be loaded.
+ SourceSize - The size in bytes of SourceBuffer.
+ DstBuffer - The buffer to store the image
+ NumberOfPages - If not NULL, on input a pointer to the page number of DstBuffer and on
+ output a pointer to the page number of the image. If this number of DstBuffer
+ is not enough, return EFI_BUFFER_TOO_SMALL and this parameter contain
+ the required number.
+ ImageHandle - Pointer to the returned image handle that is created when the image
+ is successfully loaded.
+ EntryPoint - A pointer to the entry point
+ Attribute - The bit mask of attributes to set for the load PE image
+ CrossLoad - Whether expect to support cross architecture loading
+
+Returns:
+
+ EFI_SUCCESS - The image was loaded into memory.
+ EFI_NOT_FOUND - The FilePath was not found.
+ EFI_INVALID_PARAMETER - One of the parameters has an invalid value.
+ EFI_BUFFER_TOO_SMALL - The buffer is too small
+ EFI_UNSUPPORTED - The image type is not supported, or the device path cannot be
+ parsed to locate the proper protocol for loading the file.
+ EFI_OUT_OF_RESOURCES - Image was not loaded due to insufficient resources.
+--*/
+{
+ LOADED_IMAGE_PRIVATE_DATA *Image;
+ LOADED_IMAGE_PRIVATE_DATA *ParentImage;
+ IMAGE_FILE_HANDLE FHand;
+ EFI_STATUS Status;
+ EFI_STATUS SecurityStatus;
+ EFI_HANDLE DeviceHandle;
+ UINT32 AuthenticationStatus;
+ EFI_DEVICE_PATH_PROTOCOL *OriginalFilePath;
+ EFI_DEVICE_PATH_PROTOCOL *HandleFilePath;
+ UINTN FilePathSize;
+
+ SecurityStatus = EFI_SUCCESS;
+
+ ASSERT (gEfiCurrentTpl < EFI_TPL_NOTIFY);
+ ParentImage = NULL;
+
+ //
+ // The caller must pass in a valid ParentImageHandle
+ //
+ if (ImageHandle == NULL || ParentImageHandle == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ParentImage = CoreLoadedImageInfo (ParentImageHandle);
+ if (ParentImage == NULL) {
+ DEBUG((EFI_D_LOAD|EFI_D_ERROR, "LoadImageEx: Parent handle not an image handle\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Get simple read access to the source file
+ //
+ OriginalFilePath = FilePath;
+ Status = CoreOpenImageFile (
+ BootPolicy,
+ SourceBuffer,
+ SourceSize,
+ &FilePath,
+ &DeviceHandle,
+ &FHand,
+ &AuthenticationStatus
+ );
+ if (Status == EFI_ALREADY_STARTED) {
+ Image = NULL;
+ goto Done;
+ } else if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Verify the Authentication Status through the Security Architectural Protocol
+ //
+ if ((gSecurity != NULL) && (OriginalFilePath != NULL)) {
+ SecurityStatus = gSecurity->FileAuthenticationState (
+ gSecurity,
+ AuthenticationStatus,
+ OriginalFilePath
+ );
+ if (EFI_ERROR (SecurityStatus) && SecurityStatus != EFI_SECURITY_VIOLATION) {
+ Status = SecurityStatus;
+ Image = NULL;
+ goto Done;
+ }
+ }
+
+
+ //
+ // Allocate a new image structure
+ //
+ Image = CoreAllocateZeroBootServicesPool (sizeof(LOADED_IMAGE_PRIVATE_DATA));
+ if (Image == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Pull out just the file portion of the DevicePath for the LoadedImage FilePath
+ //
+ FilePath = OriginalFilePath;
+ Status = CoreHandleProtocol (DeviceHandle, &gEfiDevicePathProtocolGuid, &HandleFilePath);
+ if (!EFI_ERROR (Status)) {
+ FilePathSize = CoreDevicePathSize (HandleFilePath) - sizeof(EFI_DEVICE_PATH_PROTOCOL);
+ FilePath = (EFI_DEVICE_PATH_PROTOCOL *) ( ((UINT8 *)FilePath) + FilePathSize );
+ }
+
+ //
+ // Initialize the fields for an internal driver
+ //
+ Image->Signature = LOADED_IMAGE_PRIVATE_DATA_SIGNATURE;
+ Image->Info.SystemTable = gST;
+ Image->Info.DeviceHandle = DeviceHandle;
+ Image->Info.Revision = EFI_LOADED_IMAGE_INFORMATION_REVISION;
+ Image->Info.FilePath = CoreDuplicateDevicePath (FilePath);
+ Image->Info.ParentHandle = ParentImageHandle;
+
+ if (NumberOfPages != NULL) {
+ Image->NumberOfPages = *NumberOfPages ;
+ } else {
+ Image->NumberOfPages = 0 ;
+ }
+
+ //
+ // Install the protocol interfaces for this image
+ // don't fire notifications yet
+ //
+ Status = CoreInstallProtocolInterfaceNotify (
+ &Image->Handle,
+ &gEfiLoadedImageProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &Image->Info,
+ FALSE
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Install Debug Mask Protocol
+ //
+ DEBUG_CODE (
+ Status = InstallDebugMaskProtocol(Image->Handle);
+ ASSERT_EFI_ERROR (Status);
+ )
+
+ //
+ // Load the image. If EntryPoint is Null, it will not be set.
+ //
+ Status = CoreLoadPeImage (BootPolicy, &FHand, Image, DstBuffer, EntryPoint, Attribute, CrossLoad);
+ if (EFI_ERROR (Status)) {
+ if ((Status == EFI_BUFFER_TOO_SMALL) || (Status == EFI_OUT_OF_RESOURCES)) {
+ if (NumberOfPages != NULL) {
+ *NumberOfPages = Image->NumberOfPages;
+ }
+ }
+ goto Done;
+ }
+ if (NumberOfPages != NULL) {
+ *NumberOfPages = Image->NumberOfPages;
+ }
+
+ //
+ // Register the image in the Debug Image Info Table if the attribute is set
+ //
+ if (Attribute & EFI_LOAD_PE_IMAGE_ATTRIBUTE_DEBUG_IMAGE_INFO_TABLE_REGISTRATION) {
+ CoreNewDebugImageInfoEntry (EFI_DEBUG_IMAGE_INFO_TYPE_NORMAL, &Image->Info, Image->Handle);
+ }
+
+ //
+ //Reinstall loaded image protocol to fire any notifications
+ //
+ Status = CoreReinstallProtocolInterface (
+ Image->Handle,
+ &gEfiLoadedImageProtocolGuid,
+ &Image->Info,
+ &Image->Info
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+#if (EFI_SPECIFICATION_VERSION >= 0x0002000A)
+ //
+ // If DevicePath parameter to the LoadImage() is not NULL, then make a copy of DevicePath,
+ // otherwise Loaded Image Device Path Protocol is installed with a NULL interface pointer.
+ //
+ if (OriginalFilePath != NULL) {
+ Image->LoadedImageDevicePath = CoreDuplicateDevicePath (OriginalFilePath);
+ }
+
+ //
+ // Install Loaded Image Device Path Protocol onto the image handle of a PE/COFE image
+ //
+ Status = CoreInstallProtocolInterface (
+ &Image->Handle,
+ &gEfiLoadedImageDevicePathProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ Image->LoadedImageDevicePath
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Install HII Package List Protocol onto the image handle
+ //
+ if (Image->ImageContext.HiiResourceData != 0) {
+ Status = CoreInstallProtocolInterface (
+ &Image->Handle,
+ &gEfiHiiPackageListProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ (VOID *) (UINTN) Image->ImageContext.HiiResourceData
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ }
+#endif
+
+ //
+ // Success. Return the image handle
+ //
+ *ImageHandle = Image->Handle;
+
+Done:
+ //
+ // All done accessing the source file
+ // If we allocated the Source buffer, free it
+ //
+ if (FHand.FreeBuffer) {
+ CoreFreePool (FHand.Source);
+ }
+
+ //
+ // There was an error. If there's an Image structure, free it
+ //
+ if (EFI_ERROR (Status)) {
+ if (Image != NULL) {
+ CoreUnloadAndCloseImage (Image, (BOOLEAN)(DstBuffer == 0));
+ *ImageHandle = NULL;
+ }
+ } else if (EFI_ERROR (SecurityStatus)) {
+ Status = SecurityStatus;
+ }
+
+ return Status;
+}
+
+
+EFI_BOOTSERVICE
+EFI_STATUS
+EFIAPI
+CoreLoadImage (
+ IN BOOLEAN BootPolicy,
+ IN EFI_HANDLE ParentImageHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ IN VOID *SourceBuffer OPTIONAL,
+ IN UINTN SourceSize,
+ OUT EFI_HANDLE *ImageHandle
+ )
+/*++
+
+Routine Description:
+
+ Loads an EFI image into memory and returns a handle to the image.
+
+Arguments:
+
+ BootPolicy - If TRUE, indicates that the request originates from the boot manager,
+ and that the boot manager is attempting to load FilePath as a boot selection.
+ ParentImageHandle - The caller's image handle.
+ FilePath - The specific file path from which the image is loaded.
+ SourceBuffer - If not NULL, a pointer to the memory location containing a copy of
+ the image to be loaded.
+ SourceSize - The size in bytes of SourceBuffer.
+ ImageHandle - Pointer to the returned image handle that is created when the image
+ is successfully loaded.
+
+Returns:
+
+ EFI_SUCCESS - The image was loaded into memory.
+ EFI_NOT_FOUND - The FilePath was not found.
+ EFI_INVALID_PARAMETER - One of the parameters has an invalid value.
+ EFI_UNSUPPORTED - The image type is not supported, or the device path cannot be
+ parsed to locate the proper protocol for loading the file.
+ EFI_OUT_OF_RESOURCES - Image was not loaded due to insufficient resources.
+--*/
+{
+ EFI_STATUS Status;
+ UINT64 Ticker;
+
+ GetTimerValue (&Ticker);
+
+ Status = CoreLoadImageCommon (
+ BootPolicy,
+ ParentImageHandle,
+ FilePath,
+ SourceBuffer,
+ SourceSize,
+ (EFI_PHYSICAL_ADDRESS)NULL,
+ NULL,
+ ImageHandle,
+ NULL,
+ EFI_LOAD_PE_IMAGE_ATTRIBUTE_RUNTIME_REGISTRATION | EFI_LOAD_PE_IMAGE_ATTRIBUTE_DEBUG_IMAGE_INFO_TABLE_REGISTRATION,
+ FALSE
+ );
+
+ if (!EFI_ERROR (Status)) {
+ PERF_START (0, L"LoadImage", NULL, Ticker);
+ PERF_END (*ImageHandle, L"LoadImage", NULL, 0);
+ } else {
+ PERF_START (0, L"Load Failed", L"CoreLoadImage", Ticker);
+ PERF_END (0, L"Load Failed", L"CoreLoadImage", 0);
+ }
+
+ return Status;
+}
+
+
+EFI_STATUS
+EFIAPI
+CoreLoadImageEx (
+ IN EFI_PE32_IMAGE_PROTOCOL *This,
+ IN EFI_HANDLE ParentImageHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ IN VOID *SourceBuffer OPTIONAL,
+ IN UINTN SourceSize,
+ IN EFI_PHYSICAL_ADDRESS DstBuffer OPTIONAL,
+ OUT UINTN *NumberOfPages OPTIONAL,
+ OUT EFI_HANDLE *ImageHandle,
+ OUT EFI_PHYSICAL_ADDRESS *EntryPoint OPTIONAL,
+ IN UINT32 Attribute
+ )
+/*++
+
+Routine Description:
+
+ Loads an EFI image into memory and returns a handle to the image with extended parameters.
+
+Arguments:
+
+ This - Calling context
+ ParentImageHandle - The caller's image handle.
+ FilePath - The specific file path from which the image is loaded.
+ SourceBuffer - If not NULL, a pointer to the memory location containing a copy of
+ the image to be loaded.
+ SourceSize - The size in bytes of SourceBuffer.
+ DstBuffer - The buffer to store the image.
+ NumberOfPages - For input, specifies the space size of the image by caller if not NULL.
+ For output, specifies the actual space size needed.
+ ImageHandle - Image handle for output.
+ EntryPoint - Image entry point for output.
+ Attribute - The bit mask of attributes to set for the load PE image.
+
+Returns:
+
+ EFI_SUCCESS - The image was loaded into memory.
+ EFI_NOT_FOUND - The FilePath was not found.
+ EFI_INVALID_PARAMETER - One of the parameters has an invalid value.
+ EFI_UNSUPPORTED - The image type is not supported, or the device path cannot be
+ parsed to locate the proper protocol for loading the file.
+ EFI_OUT_OF_RESOURCES - Image was not loaded due to insufficient resources.
+--*/
+{
+ return CoreLoadImageCommon (
+ FALSE,
+ ParentImageHandle,
+ FilePath,
+ SourceBuffer,
+ SourceSize,
+ DstBuffer,
+ NumberOfPages,
+ ImageHandle,
+ EntryPoint,
+ Attribute,
+ TRUE
+ );
+}
+
+
+
+EFI_BOOTSERVICE
+EFI_STATUS
+EFIAPI
+CoreStartImage (
+ IN EFI_HANDLE ImageHandle,
+ OUT UINTN *ExitDataSize,
+ OUT CHAR16 **ExitData OPTIONAL
+ )
+/*++
+
+Routine Description:
+
+ Transfer control to a loaded image's entry point.
+
+Arguments:
+
+ ImageHandle - Handle of image to be started.
+
+ ExitDataSize - Pointer of the size to ExitData
+
+ ExitData - Pointer to a pointer to a data buffer that includes a Null-terminated
+ Unicode string, optionally followed by additional binary data. The string
+ is a description that the caller may use to further indicate the reason for
+ the image¡¯s exit.
+
+Returns:
+
+ EFI_INVALID_PARAMETER - Invalid parameter
+
+ EFI_OUT_OF_RESOURCES - No enough buffer to allocate
+
+ EFI_SUCCESS - Successfully transfer control to the image's entry point.
+
+--*/
+{
+ EFI_STATUS Status;
+ LOADED_IMAGE_PRIVATE_DATA *Image;
+ LOADED_IMAGE_PRIVATE_DATA *LastImage;
+ UINT64 HandleDatabaseKey;
+
+ Image = CoreLoadedImageInfo (ImageHandle);
+ if (Image == NULL_HANDLE || Image->Started) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Cannot start image of an unsupported processor architecture
+ //
+ if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Image->ImageContext.Machine)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Don't profile Objects or invalid start requests
+ //
+ PERF_START (ImageHandle, START_IMAGE_TOK, NULL, 0);
+
+ //
+ // Push the current start image context, and
+ // link the current image to the head. This is the
+ // only image that can call Exit()
+ //
+ HandleDatabaseKey = CoreGetHandleDatabaseKey();
+ LastImage = mCurrentImage;
+ mCurrentImage = Image;
+ Image->Tpl = gEfiCurrentTpl;
+
+ //
+ // Set long jump for Exit() support
+ //
+ Image->JumpContext = CoreAllocateBootServicesPool (gEfiPeiTransferControl->JumpContextSize);
+ if (Image->JumpContext == NULL) {
+ PERF_END (ImageHandle, START_IMAGE_TOK, NULL, 0);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = gEfiPeiTransferControl->SetJump (gEfiPeiTransferControl, Image->JumpContext);
+ //
+ // The SetJump returns EFI_SUCCESS when LongJump Buffer has been armed
+ // SetJump returns EFI_WARN_RETURN_FROM_LONG_JUMP as a result of the LongJump
+ // All other return values for SetJump are undefined.
+ //
+ if (Status == EFI_SUCCESS) {
+
+ //
+ // Call the image's entry point
+ //
+ Image->Started = TRUE;
+ Image->Status = Image->EntryPoint (ImageHandle, Image->Info.SystemTable);
+
+ //
+ // Add some debug information if the image returned with error.
+ // This make the user aware and check if the driver image have already released
+ // all the resource in this situation.
+ //
+ DEBUG_CODE (
+ if (EFI_ERROR (Image->Status)) {
+ DEBUG ((EFI_D_ERROR, "Error: Image at %08X start failed: %x\n", Image->Info.ImageBase, Image->Status));
+ }
+ )
+
+ //
+ // If the image returns, exit it through Exit()
+ //
+ CoreExit (ImageHandle, Image->Status, 0, NULL);
+ }
+
+ //
+ // Image has completed. Verify the tpl is the same
+ //
+ ASSERT (Image->Tpl == gEfiCurrentTpl);
+ CoreRestoreTpl (Image->Tpl);
+
+ CoreFreePool (Image->JumpContext);
+
+ //
+ // Pop the current start image context
+ //
+ mCurrentImage = LastImage;
+
+ //
+ // Go connect any handles that were created or modified while the image executed.
+ //
+ CoreConnectHandlesByKey (HandleDatabaseKey);
+
+ //
+ // Handle the image's returned ExitData
+ //
+ DEBUG_CODE (
+ if (Image->ExitDataSize != 0 || Image->ExitData != NULL) {
+
+ DEBUG (
+ (EFI_D_LOAD,
+ "StartImage: ExitDataSize %d, ExitData %x",
+ Image->ExitDataSize,
+ Image->ExitData)
+ );
+ if (Image->ExitData != NULL) {
+ DEBUG ((EFI_D_LOAD, " (%hs)", Image->ExitData));
+ }
+ DEBUG ((EFI_D_LOAD, "\n"));
+ }
+ )
+
+ //
+ // Return the exit data to the caller
+ //
+ if (ExitData != NULL && ExitDataSize != NULL) {
+ *ExitDataSize = Image->ExitDataSize;
+ *ExitData = Image->ExitData;
+ } else {
+ //
+ // Caller doesn't want the exit data, free it
+ //
+ CoreFreePool (Image->ExitData);
+ Image->ExitData = NULL;
+ }
+
+ //
+ // Save the Status because Image will get destroyed if it is unloaded.
+ //
+ Status = Image->Status;
+
+ //
+ // If the image returned an error, or if the image is an application
+ // unload it
+ //
+ if (EFI_ERROR (Image->Status) || Image->Type == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) {
+ CoreUnloadAndCloseImage (Image, TRUE);
+ }
+
+ //
+ // Done
+ //
+ PERF_END (ImageHandle, START_IMAGE_TOK, NULL, 0);
+ return Status;
+}
+
+
+VOID
+CoreUnloadAndCloseImage (
+ IN LOADED_IMAGE_PRIVATE_DATA *Image,
+ IN BOOLEAN FreePage
+ )
+/*++
+
+Routine Description:
+
+ Unloads EFI image from memory.
+
+Arguments:
+
+ Image - EFI image
+ FreePage - Free allocated pages
+
+Returns:
+
+ None
+
+--*/
+{
+ EFI_STATUS Status;
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+ UINTN HandleIndex;
+ EFI_GUID **ProtocolGuidArray;
+ UINTN ArrayCount;
+ UINTN ProtocolIndex;
+ EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfo;
+ UINTN OpenInfoCount;
+ UINTN OpenInfoIndex;
+
+ if (Image->Ebc != NULL) {
+ //
+ // If EBC protocol exists we must perform cleanups for this image.
+ //
+ Image->Ebc->UnloadImage (Image->Ebc, Image->Handle);
+ }
+
+ //
+ // Unload image, free Image->ImageContext->ModHandle
+ //
+ gEfiPeiPeCoffLoader->UnloadImage (&Image->ImageContext);
+
+ //
+ // Free our references to the image handle
+ //
+ if (Image->Handle != NULL_HANDLE) {
+
+ Status = CoreLocateHandleBuffer (
+ AllHandles,
+ NULL,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+ if (!EFI_ERROR (Status)) {
+ for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) {
+ Status = CoreProtocolsPerHandle (
+ HandleBuffer[HandleIndex],
+ &ProtocolGuidArray,
+ &ArrayCount
+ );
+ if (!EFI_ERROR (Status)) {
+ for (ProtocolIndex = 0; ProtocolIndex < ArrayCount; ProtocolIndex++) {
+ Status = CoreOpenProtocolInformation (
+ HandleBuffer[HandleIndex],
+ ProtocolGuidArray[ProtocolIndex],
+ &OpenInfo,
+ &OpenInfoCount
+ );
+ if (!EFI_ERROR (Status)) {
+ for (OpenInfoIndex = 0; OpenInfoIndex < OpenInfoCount; OpenInfoIndex++) {
+ if (OpenInfo[OpenInfoIndex].AgentHandle == Image->Handle) {
+ Status = CoreCloseProtocol (
+ HandleBuffer[HandleIndex],
+ ProtocolGuidArray[ProtocolIndex],
+ Image->Handle,
+ OpenInfo[OpenInfoIndex].ControllerHandle
+ );
+ }
+ }
+ if (OpenInfo != NULL) {
+ CoreFreePool(OpenInfo);
+ }
+ }
+ }
+ if (ProtocolGuidArray != NULL) {
+ CoreFreePool(ProtocolGuidArray);
+ }
+ }
+ }
+ if (HandleBuffer != NULL) {
+ CoreFreePool (HandleBuffer);
+ }
+ }
+
+ CoreRemoveDebugImageInfoEntry (Image->Handle);
+
+ Status = CoreUninstallProtocolInterface (
+ Image->Handle,
+ &gEfiLoadedImageProtocolGuid,
+ &Image->Info
+ );
+
+#if (EFI_SPECIFICATION_VERSION >= 0x0002000A)
+ Status = CoreUninstallProtocolInterface (
+ Image->Handle,
+ &gEfiLoadedImageDevicePathProtocolGuid,
+ Image->LoadedImageDevicePath
+ );
+
+ if (Image->LoadedImageDevicePath != NULL) {
+ CoreFreePool (Image->LoadedImageDevicePath);
+ }
+
+ if (Image->ImageContext.HiiResourceData != 0) {
+ Status = CoreUninstallProtocolInterface (
+ Image->Handle,
+ &gEfiHiiPackageListProtocolGuid,
+ (VOID *) (UINTN) Image->ImageContext.HiiResourceData
+ );
+ }
+#endif
+
+ //
+ // Uninstall Debug Mask Protocol
+ //
+ DEBUG_CODE (
+ Status = UninstallDebugMaskProtocol(Image->Handle);
+ ASSERT_EFI_ERROR (Status);
+ )
+
+ }
+
+ if (Image->RuntimeData != NULL) {
+ if (Image->RuntimeData->Link.ForwardLink != NULL) {
+ //
+ // Remove the Image from the Runtime Image list as we are about to Free it!
+ //
+ RemoveEntryList (&Image->RuntimeData->Link);
+ }
+ CoreFreePool (Image->RuntimeData);
+ }
+
+ //
+ // Free the Image from memory
+ //
+ if ((Image->ImageBasePage != 0) && FreePage) {
+ CoreFreePages (Image->ImageBasePage, Image->NumberOfPages);
+ }
+
+ //
+ // Done with the Image structure
+ //
+ if (Image->Info.FilePath != NULL) {
+ CoreFreePool (Image->Info.FilePath);
+ }
+
+ if (Image->FixupData != NULL) {
+ CoreFreePool (Image->FixupData);
+ }
+
+ CoreFreePool (Image);
+}
+
+
+EFI_BOOTSERVICE
+EFI_STATUS
+EFIAPI
+CoreExit (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_STATUS Status,
+ IN UINTN ExitDataSize,
+ IN CHAR16 *ExitData OPTIONAL
+ )
+/*++
+
+Routine Description:
+
+ Terminates the currently loaded EFI image and returns control to boot services.
+
+Arguments:
+
+ ImageHandle - Handle that identifies the image. This parameter is passed to the image
+ on entry.
+ Status - The image¡¯s exit code.
+ ExitDataSize - The size, in bytes, of ExitData. Ignored if ExitStatus is
+ EFI_SUCCESS.
+ ExitData - Pointer to a data buffer that includes a Null-terminated Unicode string,
+ optionally followed by additional binary data. The string is a
+ description that the caller may use to further indicate the reason for
+ the image¡¯s exit.
+
+Returns:
+
+ EFI_INVALID_PARAMETER - Image handle is NULL or it is not current image.
+
+ EFI_SUCCESS - Successfully terminates the currently loaded EFI image.
+
+ EFI_ACCESS_DENIED - Should never reach there.
+
+ EFI_OUT_OF_RESOURCES - Could not allocate pool
+
+--*/
+{
+ LOADED_IMAGE_PRIVATE_DATA *Image;
+
+ Image = CoreLoadedImageInfo (ImageHandle);
+ if (Image == NULL_HANDLE) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!Image->Started) {
+ //
+ // The image has not been started so just free its resources
+ //
+ CoreUnloadAndCloseImage (Image, TRUE);
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Image has been started, verify this image can exit
+ //
+ if (Image != mCurrentImage) {
+ DEBUG ((EFI_D_LOAD|EFI_D_ERROR, "Exit: Image is not exitable image\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Set status
+ //
+ Image->Status = Status;
+
+ //
+ // If there's ExitData info, move it
+ //
+ if (ExitData != NULL) {
+ Image->ExitDataSize = ExitDataSize;
+ Image->ExitData = CoreAllocateBootServicesPool (Image->ExitDataSize);
+ if (Image->ExitData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ EfiCommonLibCopyMem (Image->ExitData, ExitData, Image->ExitDataSize);
+ }
+
+ //
+ // return to StartImage
+ //
+ Status = gEfiPeiTransferControl->LongJump (gEfiPeiTransferControl, Image->JumpContext);
+
+ //
+ // If we return from LongJump, then it is an error
+ //
+ ASSERT (FALSE);
+ return EFI_ACCESS_DENIED;
+}
+
+
+EFI_BOOTSERVICE
+EFI_STATUS
+EFIAPI
+CoreUnloadImage (
+ IN EFI_HANDLE ImageHandle
+ )
+/*++
+
+Routine Description:
+
+ Unloads an image.
+
+Arguments:
+
+ ImageHandle - Handle that identifies the image to be unloaded.
+
+Returns:
+
+ EFI_SUCCESS - The image has been unloaded.
+ EFI_UNSUPPORTED - The image has been sarted, and does not support unload.
+ EFI_INVALID_PARAMPETER - ImageHandle is not a valid image handle.
+
+--*/
+{
+ EFI_STATUS Status;
+ LOADED_IMAGE_PRIVATE_DATA *Image;
+
+ Image = CoreLoadedImageInfo (ImageHandle);
+ if (Image == NULL ) {
+ //
+ // The image handle is not valid
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Image->Started) {
+ //
+ // The image has been started, request it to unload.
+ //
+ Status = EFI_UNSUPPORTED;
+ if (Image->Info.Unload != NULL) {
+ Status = Image->Info.Unload (ImageHandle);
+ }
+
+ } else {
+ //
+ // This Image hasn't been started, thus it can be unloaded
+ //
+ Status = EFI_SUCCESS;
+ }
+
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // if the Image was not started or Unloaded O.K. then clean up
+ //
+ CoreUnloadAndCloseImage (Image, TRUE);
+ }
+
+ return Status;
+}
+
+
+EFI_STATUS
+EFIAPI
+CoreUnloadImageEx (
+ IN EFI_PE32_IMAGE_PROTOCOL *This,
+ IN EFI_HANDLE ImageHandle
+ )
+/*++
+
+Routine Description:
+
+ Unload the specified image.
+
+Arguments:
+
+ This - Indicates the calling context.
+
+ ImageHandle - The specified image handle.
+
+Returns:
+
+ EFI_INVALID_PARAMETER - Image handle is NULL.
+
+ EFI_UNSUPPORTED - Attempt to unload an unsupported image.
+
+ EFI_SUCCESS - Image successfully unloaded.
+
+--*/
+{
+ return CoreUnloadImage (ImageHandle);
+}
+
+
+
+//
+// This callback function is used by the EBC interpreter driver to flush the
+// processor instruction cache after creating thunks. We're simply hiding
+// the "this" pointer that must be passed into the real flush function.
+//
+STATIC
+EFI_STATUS
+EFIAPI
+CoreFlushICache (
+ IN EFI_PHYSICAL_ADDRESS Start,
+ IN UINT64 Length
+ )
+/*++
+
+Routine Description:
+
+ flush the processor instruction cache.
+
+Arguments:
+
+ Start - Start adddress in memory to flush.
+
+ Length - Length of memory to flush.
+
+Returns:
+
+--*/
+{
+ return gEfiPeiFlushInstructionCache->Flush (
+ gEfiPeiFlushInstructionCache,
+ Start,
+ Length
+ );
+}
+
+
diff --git a/EDK/Foundation/Core/Dxe/Image/Image.h b/EDK/Foundation/Core/Dxe/Image/Image.h
new file mode 100644
index 0000000..6cee212
--- /dev/null
+++ b/EDK/Foundation/Core/Dxe/Image/Image.h
@@ -0,0 +1,399 @@
+/*++
+
+Copyright (c) 2004 - 2008, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+
+ Image.h
+
+Abstract:
+
+ EFI image loader
+
+--*/
+
+
+#ifndef _IMAGE_H_
+#define _IMAGE_H_
+
+
+#include "Tiano.h"
+#include "LinkedList.h"
+#include "DxeCore.h"
+
+#include EFI_PROTOCOL_PRODUCER (LoadedImage)
+#include EFI_PROTOCOL_PRODUCER (LoadPe32Image)
+#if (EFI_SPECIFICATION_VERSION >= 0x0002000A)
+#include EFI_PROTOCOL_PRODUCER (LoadedImageDevicePath)
+#include EFI_PROTOCOL_CONSUMER (LoadFile2)
+#include EFI_PROTOCOL_PRODUCER (HiiPackageList)
+#endif
+
+#include EFI_PROTOCOL_CONSUMER (Ebc)
+#include EFI_PROTOCOL_CONSUMER (SimpleFileSystem)
+#include EFI_PROTOCOL_CONSUMER (FileInfo)
+#include EFI_PROTOCOL_CONSUMER (LoadFile)
+#include EFI_PROTOCOL_CONSUMER (FirmwareVolume)
+
+#define LOADED_IMAGE_PRIVATE_DATA_SIGNATURE EFI_SIGNATURE_32('l','d','r','i')
+
+typedef struct {
+ UINTN Signature; // Data Signature
+ EFI_HANDLE Handle; // Image handle
+ UINTN Type; // Image type
+
+ BOOLEAN Started; // If entrypoint has been called
+
+ EFI_IMAGE_ENTRY_POINT EntryPoint; // The image's entry point
+ EFI_LOADED_IMAGE_PROTOCOL Info; // loaded image protocol
+
+#if (EFI_SPECIFICATION_VERSION >= 0x0002000A)
+ EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath; // Loaded Image Device Path Protocl pointer
+#endif
+
+ EFI_PHYSICAL_ADDRESS ImageBasePage; // Location in memory
+ UINTN NumberOfPages; // Number of pages
+
+ CHAR8 *FixupData; // Original fixup data
+
+ EFI_TPL Tpl; // Tpl of started image
+ EFI_STATUS Status; // Status returned by started image
+
+ UINTN ExitDataSize; // Size of ExitData from started image
+ VOID *ExitData; // Pointer to exit data from started image
+ VOID *JumpContext; // Pointer to buffer for context save/retore
+ UINT16 Machine; // Machine type from PE image
+
+ EFI_EBC_PROTOCOL *Ebc; // EBC Protocol pointer
+
+ EFI_RUNTIME_IMAGE_ENTRY *RuntimeData; // Runtime image list
+
+ EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; // PeCoffLoader ImageContext
+} LOADED_IMAGE_PRIVATE_DATA;
+
+#define LOADED_IMAGE_PRIVATE_DATA_FROM_THIS(a) \
+ CR(a, LOADED_IMAGE_PRIVATE_DATA, Info, LOADED_IMAGE_PRIVATE_DATA_SIGNATURE)
+
+
+#define LOAD_PE32_IMAGE_PRIVATE_DATA_SIGNATURE EFI_SIGNATURE_32('l','p','e','i')
+
+typedef struct {
+ UINTN Signature;
+ EFI_HANDLE Handle;
+ EFI_PE32_IMAGE_PROTOCOL Pe32Image;
+} LOAD_PE32_IMAGE_PRIVATE_DATA;
+
+#define LOAD_PE32_IMAGE_PRIVATE_DATA_FROM_THIS(a) \
+ CR(a, LOAD_PE32_IMAGE_PRIVATE_DATA, Pe32Image, LOAD_PE32_IMAGE_PRIVATE_DATA_SIGNATURE)
+
+//
+// Private Data Types
+//
+#define IMAGE_FILE_HANDLE_SIGNATURE EFI_SIGNATURE_32('i','m','g','f')
+typedef struct {
+ UINTN Signature;
+ BOOLEAN FreeBuffer;
+ VOID *Source;
+ UINTN SourceSize;
+} IMAGE_FILE_HANDLE;
+
+
+//
+// Abstractions for reading image contents
+//
+
+EFI_STATUS
+CoreOpenImageFile (
+ IN BOOLEAN BootPolicy,
+ IN VOID *SourceBuffer OPTIONAL,
+ IN UINTN SourceSize,
+ IN OUT EFI_DEVICE_PATH_PROTOCOL **FilePath,
+ OUT EFI_HANDLE *DeviceHandle,
+ IN IMAGE_FILE_HANDLE *ImageFileHandle,
+ OUT UINT32 *AuthenticationStatus
+ )
+/*++
+
+Routine Description:
+
+ Opens a file for (simple) reading. The simple read abstraction
+ will access the file either from a memory copy, from a file
+ system interface, or from the load file interface.
+
+Arguments:
+
+ BootPolicy - Policy for Open Image File.
+ SourceBuffer - Pointer to the memory location containing copy
+ of the image to be loaded.
+ SourceSize - The size in bytes of SourceBuffer.
+ FilePath - The specific file path from which the image is loaded
+ DeviceHandle - Pointer to the return device handle.
+ ImageFileHandle - Pointer to the image file handle.
+ AuthenticationStatus - Pointer to a caller-allocated UINT32 in which the authentication status is returned.
+
+Returns:
+
+ A handle to access the file
+
+--*/
+;
+
+
+EFI_STATUS
+EFIAPI
+CoreReadImageFile (
+ IN VOID *UserHandle,
+ IN UINTN Offset,
+ IN OUT UINTN *ReadSize,
+ OUT VOID *Buffer
+ )
+/*++
+
+Routine Description:
+
+ Read image file (specified by UserHandle) into user specified buffer with specified offset
+ and length.
+
+Arguments:
+
+ UserHandle - Image file handle
+
+ Offset - Offset to the source file
+
+ ReadSize - For input, pointer of size to read;
+ For output, pointer of size actually read.
+
+ Buffer - Buffer to write into
+
+Returns:
+
+ EFI_SUCCESS - Successfully read the specified part of file into buffer.
+
+--*/
+;
+
+VOID
+EFIAPI
+CoreCloseImageFile (
+ IN IMAGE_FILE_HANDLE *ImageFileHandle
+ )
+/*++
+
+Routine Description:
+
+ A function out of date, should be removed.
+
+Arguments:
+
+ ImageFileHandle - Handle of the file to close
+
+Returns:
+
+ None
+
+--*/
+;
+
+//
+// Image processing worker functions
+//
+EFI_STATUS
+CoreDevicePathToInterface (
+ IN EFI_GUID *Protocol,
+ IN OUT EFI_DEVICE_PATH_PROTOCOL **FilePath,
+ OUT VOID **Interface,
+ OUT EFI_HANDLE *Handle
+ )
+/*++
+
+Routine Description:
+
+ Search a handle to a device on a specified device path that supports a specified protocol,
+ interface of that protocol on that handle is another output.
+
+Arguments:
+
+ Protocol - The protocol to search for
+
+ FilePath - The specified device path
+
+ Interface - Interface of the protocol on the handle
+
+ Handle - The handle to the device on the specified device path that supports the protocol.
+
+Returns:
+
+ Status code.
+
+--*/
+;
+
+STATIC
+EFI_STATUS
+CoreLoadPeImage (
+ IN BOOLEAN BootPolicy,
+ IN VOID *Pe32Handle,
+ IN LOADED_IMAGE_PRIVATE_DATA *Image,
+ IN EFI_PHYSICAL_ADDRESS DstBuffer OPTIONAL,
+ OUT EFI_PHYSICAL_ADDRESS *EntryPoint OPTIONAL,
+ IN UINT32 Attribute,
+ IN BOOLEAN CrossLoad
+ )
+/*++
+
+Routine Description:
+
+ Loads, relocates, and invokes a PE/COFF image
+
+Arguments:
+
+ Pe32Handle - The handle of PE32 image
+ Image - PE image to be loaded
+ DstBuffer - The buffer to store the image
+ EntryPoint - A pointer to the entry point
+ Attribute - The bit mask of attributes to set for the load PE image
+ CrossLoad - Whether expect to support cross architecture loading
+
+Returns:
+
+ EFI_SUCCESS - The file was loaded, relocated, and invoked
+
+ EFI_OUT_OF_RESOURCES - There was not enough memory to load and relocate the PE/COFF file
+
+ EFI_INVALID_PARAMETER - Invalid parameter
+
+ EFI_BUFFER_TOO_SMALL - Buffer for image is too small
+
+--*/
+;
+
+LOADED_IMAGE_PRIVATE_DATA *
+CoreLoadedImageInfo (
+ IN EFI_HANDLE ImageHandle
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ ImageHandle - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+VOID
+CoreUnloadAndCloseImage (
+ IN LOADED_IMAGE_PRIVATE_DATA *Image,
+ IN BOOLEAN FreePage
+ )
+/*++
+
+Routine Description:
+
+ Unloads EFI image from memory.
+
+Arguments:
+
+ Image - EFI image
+ FreePage - Free allocated pages
+
+Returns:
+
+ None
+
+--*/
+;
+
+
+//
+// Exported Image functions
+//
+
+EFI_STATUS
+EFIAPI
+CoreLoadImageEx (
+ IN EFI_PE32_IMAGE_PROTOCOL *This,
+ IN EFI_HANDLE ParentImageHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ IN VOID *SourceBuffer OPTIONAL,
+ IN UINTN SourceSize,
+ IN EFI_PHYSICAL_ADDRESS DstBuffer OPTIONAL,
+ OUT UINTN *NumberOfPages OPTIONAL,
+ OUT EFI_HANDLE *ImageHandle,
+ OUT EFI_PHYSICAL_ADDRESS *EntryPoint OPTIONAL,
+ IN UINT32 Attribute
+ )
+/*++
+
+Routine Description:
+
+ Loads an EFI image into memory and returns a handle to the image with extended parameters.
+
+Arguments:
+
+ ParentImageHandle - The caller's image handle.
+ FilePath - The specific file path from which the image is loaded.
+ SourceBuffer - If not NULL, a pointer to the memory location containing a copy of
+ the image to be loaded.
+ SourceSize - The size in bytes of SourceBuffer.
+ DstBuffer - The buffer to store the image.
+ NumberOfPages - For input, specifies the space size of the image by caller if not NULL.
+ For output, specifies the actual space size needed.
+ ImageHandle - Image handle for output.
+ EntryPoint - Image entry point for output.
+ Attribute - The bit mask of attributes to set for the load PE image.
+
+Returns:
+
+ EFI_SUCCESS - The image was loaded into memory.
+ EFI_NOT_FOUND - The FilePath was not found.
+ EFI_INVALID_PARAMETER - One of the parameters has an invalid value.
+ EFI_UNSUPPORTED - The image type is not supported, or the device path cannot be
+ parsed to locate the proper protocol for loading the file.
+ EFI_OUT_OF_RESOURCES - Image was not loaded due to insufficient resources.
+--*/
+;
+
+EFI_STATUS
+EFIAPI
+CoreUnloadImageEx (
+ IN EFI_PE32_IMAGE_PROTOCOL *This,
+ IN EFI_HANDLE ImageHandle
+ )
+/*++
+
+Routine Description:
+
+ Unload the specified image.
+
+Arguments:
+
+ This - Indicates the calling context.
+
+ ImageHandle - The specified image handle.
+
+Returns:
+
+ EFI_INVALID_PARAMETER - Image handle is NULL.
+
+ EFI_UNSUPPORTED - Attempt to unload an unsupported image.
+
+ EFI_SUCCESS - Image successfully unloaded.
+
+--*/
+;
+#endif
diff --git a/EDK/Foundation/Core/Dxe/Image/ImageFile.c b/EDK/Foundation/Core/Dxe/Image/ImageFile.c
new file mode 100644
index 0000000..462446f
--- /dev/null
+++ b/EDK/Foundation/Core/Dxe/Image/ImageFile.c
@@ -0,0 +1,646 @@
+/*++
+
+Copyright (c) 2004 - 2011, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+
+ ImageFile.c
+
+
+Abstract:
+
+
+
+
+Revision History
+
+--*/
+
+#include "Image.h"
+#include "DxeCore.h"
+
+
+VOID
+CoreDevicePathToFileName (
+ IN FILEPATH_DEVICE_PATH *FilePath,
+ OUT CHAR16 **String
+ );
+
+
+
+EFI_STATUS
+CoreOpenImageFile (
+ IN BOOLEAN BootPolicy,
+ IN VOID *SourceBuffer OPTIONAL,
+ IN UINTN SourceSize,
+ IN OUT EFI_DEVICE_PATH_PROTOCOL **FilePath,
+ OUT EFI_HANDLE *DeviceHandle,
+ IN IMAGE_FILE_HANDLE *ImageFileHandle,
+ OUT UINT32 *AuthenticationStatus
+ )
+/*++
+
+Routine Description:
+
+ Opens a file for (simple) reading. The simple read abstraction
+ will access the file either from a memory copy, from a file
+ system interface, or from the load file interface.
+
+Arguments:
+
+ BootPolicy - Policy for Open Image File.
+ SourceBuffer - Pointer to the memory location containing copy
+ of the image to be loaded.
+ SourceSize - The size in bytes of SourceBuffer.
+ FilePath - The specific file path from which the image is loaded
+ DeviceHandle - Pointer to the return device handle.
+ ImageFileHandle - Pointer to the image file handle.
+ AuthenticationStatus - Pointer to a caller-allocated UINT32 in which the authentication status is returned.
+
+Returns:
+
+ EFI_SUCCESS - Image file successfully opened.
+
+ EFI_LOAD_ERROR - If the caller passed a copy of the file, and SourceSize is 0.
+
+ EFI_INVALID_PARAMETER - File path is not valid.
+
+ EFI_NOT_FOUND - File not found.
+
+--*/
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *TempFilePath;
+ FILEPATH_DEVICE_PATH *FilePathNode;
+ MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FwVolFilePathNode;
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Volume;
+ EFI_FILE_HANDLE FileHandle;
+ EFI_FILE_HANDLE LastHandle;
+ EFI_LOAD_FILE_PROTOCOL *LoadFile;
+#if (EFI_SPECIFICATION_VERSION >= 0x0002000A)
+ EFI_LOAD_FILE2_PROTOCOL *LoadFile2;
+#endif
+ EFI_SECTION_TYPE SectionType;
+ UINT8 *Pe32Buffer;
+ UINTN Pe32BufferSize;
+ EFI_FV_FILETYPE Type;
+ EFI_FV_FILE_ATTRIBUTES Attrib;
+ EFI_FILE_INFO *FileInfo;
+ UINTN FileInfoSize;
+ EFI_GUID *NameGuid;
+ FILEPATH_DEVICE_PATH *OriginalFilePathNode;
+#if (PI_SPECIFICATION_VERSION < 0x00010000)
+ EFI_FIRMWARE_VOLUME_PROTOCOL *FwVol;
+#else
+ EFI_FIRMWARE_VOLUME2_PROTOCOL *FwVol;
+#endif
+
+ *AuthenticationStatus = 0;
+ EfiCommonLibZeroMem (ImageFileHandle, sizeof (IMAGE_FILE_HANDLE));
+ ImageFileHandle->Signature = IMAGE_FILE_HANDLE_SIGNATURE;
+
+ //
+ // If the caller passed a copy of the file, then just use it
+ //
+ if (SourceBuffer != NULL) {
+ ImageFileHandle->Source = SourceBuffer;
+ ImageFileHandle->SourceSize = SourceSize;
+ *DeviceHandle = NULL;
+ CoreLocateDevicePath (&gEfiDevicePathProtocolGuid, FilePath, DeviceHandle);
+ if (SourceSize > 0) {
+ Status = EFI_SUCCESS;
+ } else {
+ Status = EFI_LOAD_ERROR;
+ }
+ goto Done;
+ }
+
+ //
+ // Make sure FilePath is valid
+ //
+ if (*FilePath == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check to see if it's in a Firmware Volume
+ //
+ FwVolFilePathNode = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) *FilePath;
+ Status = CoreDevicePathToInterface (
+ #if (PI_SPECIFICATION_VERSION < 0x00010000)
+ &gEfiFirmwareVolumeProtocolGuid,
+ #else
+ &gEfiFirmwareVolume2ProtocolGuid,
+ #endif
+ (EFI_DEVICE_PATH_PROTOCOL **)&FwVolFilePathNode,
+ (VOID*)&FwVol,
+ DeviceHandle
+ );
+ if (!EFI_ERROR (Status) && (FwVol != NULL)) {
+ //
+ // For FwVol File system there is only a single file name that is a GUID.
+ //
+ NameGuid = CoreGetNameGuidFromFwVolDevicePathNode (FwVolFilePathNode);
+ if (NameGuid != NULL) {
+
+ SectionType = EFI_SECTION_PE32;
+ Pe32Buffer = NULL;
+ Status = FwVol->ReadSection (
+ FwVol,
+ &FwVolFilePathNode->NameGuid,
+ SectionType,
+ 0,
+ &Pe32Buffer,
+ &Pe32BufferSize,
+ AuthenticationStatus
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // Try a raw file, since a PE32 SECTION does not exist
+ //
+ if (Pe32Buffer != NULL) {
+ CoreFreePool (Pe32Buffer);
+ *AuthenticationStatus = 0;
+ }
+ Pe32Buffer = NULL;
+ Status = FwVol->ReadFile (
+ FwVol,
+ &FwVolFilePathNode->NameGuid,
+ &Pe32Buffer,
+ &Pe32BufferSize,
+ &Type,
+ &Attrib,
+ AuthenticationStatus
+ );
+ }
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // One of the reads passed so we are done
+ //
+ ImageFileHandle->Source = Pe32Buffer;
+ ImageFileHandle->SourceSize = Pe32BufferSize;
+ ImageFileHandle->FreeBuffer = TRUE;
+ goto Done;
+ }
+ }
+ }
+
+ //
+ // Attempt to access the file via a file system interface
+ //
+ FilePathNode = (FILEPATH_DEVICE_PATH *) *FilePath;
+ Status = CoreDevicePathToInterface (
+ &gEfiSimpleFileSystemProtocolGuid,
+ (EFI_DEVICE_PATH_PROTOCOL **)&FilePathNode,
+ (VOID*)&Volume,
+ DeviceHandle
+ );
+ if (!EFI_ERROR (Status) && (Volume != NULL)) {
+ //
+ // Open the Volume to get the File System handle
+ //
+ Status = Volume->OpenVolume (Volume, &FileHandle);
+ if (!EFI_ERROR (Status)) {
+ //
+ // Duplicate the device path to avoid the access to unaligned device path node.
+ // Because the device path consists of one or more FILE PATH MEDIA DEVICE PATH
+ // nodes, It assures the fields in device path nodes are 2 byte aligned.
+ //
+ FilePathNode = (FILEPATH_DEVICE_PATH *) CoreDuplicateDevicePath(
+ (EFI_DEVICE_PATH_PROTOCOL *)(UINTN)FilePathNode
+ );
+ if (FilePathNode == NULL) {
+ FileHandle->Close (FileHandle);
+ FileHandle = NULL;
+ Status = EFI_OUT_OF_RESOURCES;
+ } else {
+ OriginalFilePathNode = FilePathNode;
+ //
+ // Parse each MEDIA_FILEPATH_DP node. There may be more than one, since the
+ // directory information and filename can be seperate. The goal is to inch
+ // our way down each device path node and close the previous node
+ //
+ while (!IsDevicePathEnd (&FilePathNode->Header)) {
+ if (DevicePathType (&FilePathNode->Header) != MEDIA_DEVICE_PATH ||
+ DevicePathSubType (&FilePathNode->Header) != MEDIA_FILEPATH_DP) {
+ Status = EFI_UNSUPPORTED;
+ }
+
+ if (EFI_ERROR (Status)) {
+ //
+ // Exit loop on Error
+ //
+ break;
+ }
+
+ LastHandle = FileHandle;
+ FileHandle = NULL;
+ Status = LastHandle->Open (
+ LastHandle,
+ &FileHandle,
+ FilePathNode->PathName,
+ EFI_FILE_MODE_READ,
+ 0
+ );
+
+ //
+ // Close the previous node
+ //
+ LastHandle->Close (LastHandle);
+
+ FilePathNode = (FILEPATH_DEVICE_PATH *) NextDevicePathNode (&FilePathNode->Header);
+ }
+ //
+ // Free the allocated memory pool
+ //
+ CoreFreePool (OriginalFilePathNode);
+ }
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // We have found the file. Now we need to read it. Before we can read the file we need to
+ // figure out how big the file is.
+ //
+ FileInfo = NULL;
+ FileInfoSize = sizeof (EFI_FILE_INFO);
+ while (CoreGrowBuffer (&Status, &FileInfo, FileInfoSize)) {
+ //
+ // Automatically allocate buffer of the correct size and make the call
+ //
+ Status = FileHandle->GetInfo (
+ FileHandle,
+ &gEfiFileInfoGuid,
+ &FileInfoSize,
+ FileInfo
+ );
+ }
+ if (!EFI_ERROR (Status) && (FileInfo != NULL)) {
+ //
+ // Allocate space for the file
+ //
+ ImageFileHandle->Source = CoreAllocateBootServicesPool ((UINTN)FileInfo->FileSize);
+ if (ImageFileHandle->Source != NULL) {
+ //
+ // Read the file into the buffer we allocated
+ //
+ ImageFileHandle->SourceSize = (UINTN)FileInfo->FileSize;
+ ImageFileHandle->FreeBuffer = TRUE;
+ Status = FileHandle->Read (FileHandle, &ImageFileHandle->SourceSize, ImageFileHandle->Source);
+ } else {
+ Status = EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Close the file since we are done
+ //
+ FileHandle->Close (FileHandle);
+ CoreFreePool (FileInfo);
+ goto Done;
+ }
+
+ if (FileInfo != NULL) {
+ CoreFreePool (FileInfo);
+ }
+ }
+ if (FileHandle != NULL) {
+ FileHandle->Close (FileHandle);
+ }
+ }
+ }
+
+
+#if (EFI_SPECIFICATION_VERSION >= 0x0002000A)
+ //
+ // Try LoadFile2 style
+ //
+ if (!BootPolicy) {
+ TempFilePath = *FilePath;
+ Status = CoreDevicePathToInterface (
+ &gEfiLoadFile2ProtocolGuid,
+ &TempFilePath,
+ (VOID*)&LoadFile2,
+ DeviceHandle
+ );
+ if (!EFI_ERROR (Status) && (LoadFile2 != NULL)) {
+ //
+ // Call LoadFile2 with the correct buffer size
+ //
+ while (CoreGrowBuffer (&Status, &ImageFileHandle->Source, ImageFileHandle->SourceSize)) {
+ Status = LoadFile2->LoadFile (
+ LoadFile2,
+ TempFilePath,
+ BootPolicy,
+ &ImageFileHandle->SourceSize,
+ ImageFileHandle->Source
+ );
+ //
+ // If success or other error happens, stop loop
+ //
+ if (Status != EFI_BUFFER_TOO_SMALL) {
+ break;
+ }
+ }
+
+ if (!EFI_ERROR (Status)) {
+ ImageFileHandle->FreeBuffer = TRUE;
+ goto Done;
+ }
+ }
+ }
+#endif
+
+ //
+ // Try LoadFile style
+ //
+ TempFilePath = *FilePath;
+ Status = CoreDevicePathToInterface (
+ &gEfiLoadFileProtocolGuid,
+ &TempFilePath,
+ (VOID*)&LoadFile,
+ DeviceHandle
+ );
+ if (!EFI_ERROR (Status) && (LoadFile != NULL)) {
+ //
+ // Call LoadFile with the correct buffer size
+ //
+ while (CoreGrowBuffer (&Status, &ImageFileHandle->Source, ImageFileHandle->SourceSize)) {
+ Status = LoadFile->LoadFile (
+ LoadFile,
+ TempFilePath,
+ BootPolicy,
+ &ImageFileHandle->SourceSize,
+ ImageFileHandle->Source
+ );
+ //
+ // If success or other error happens, stop loop
+ //
+ if (Status != EFI_BUFFER_TOO_SMALL) {
+ break;
+ }
+ }
+
+ if (!EFI_ERROR (Status) || Status == EFI_ALREADY_STARTED) {
+ ImageFileHandle->FreeBuffer = TRUE;
+ goto Done;
+ }
+ }
+
+ //
+ // Nothing else to try
+ //
+ DEBUG ((EFI_D_LOAD|EFI_D_WARN, "CoreOpenImageFile: Device did not support a known load protocol\n"));
+ Status = EFI_NOT_FOUND;
+
+Done:
+
+ //
+ // If the file was not accessed, clean up
+ //
+ if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {
+ if (ImageFileHandle->FreeBuffer) {
+ //
+ // Free the source buffer if we allocated it
+ //
+ CoreFreePool (ImageFileHandle->Source);
+ }
+ }
+
+ return Status;
+}
+
+
+
+EFI_STATUS
+EFIAPI
+CoreReadImageFile (
+ IN VOID *UserHandle,
+ IN UINTN Offset,
+ IN OUT UINTN *ReadSize,
+ OUT VOID *Buffer
+ )
+/*++
+
+Routine Description:
+
+ Read image file (specified by UserHandle) into user specified buffer with specified offset
+ and length.
+
+Arguments:
+
+ UserHandle - Image file handle
+
+ Offset - Offset to the source file
+
+ ReadSize - For input, pointer of size to read;
+ For output, pointer of size actually read.
+
+ Buffer - Buffer to write into
+
+Returns:
+
+ EFI_SUCCESS - Successfully read the specified part of file into buffer.
+
+--*/
+{
+ UINTN EndPosition;
+ IMAGE_FILE_HANDLE *FHand;
+
+ FHand = (IMAGE_FILE_HANDLE *)UserHandle;
+ ASSERT (FHand->Signature == IMAGE_FILE_HANDLE_SIGNATURE);
+
+ //
+ // Move data from our local copy of the file
+ //
+ EndPosition = Offset + *ReadSize;
+ if (EndPosition > FHand->SourceSize) {
+ *ReadSize = (UINT32)(FHand->SourceSize - Offset);
+ }
+ if (Offset >= FHand->SourceSize) {
+ *ReadSize = 0;
+ }
+
+ EfiCommonLibCopyMem (Buffer, (CHAR8 *)FHand->Source + Offset, *ReadSize);
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+CoreDevicePathToInterface (
+ IN EFI_GUID *Protocol,
+ IN EFI_DEVICE_PATH_PROTOCOL **FilePath,
+ OUT VOID **Interface,
+ OUT EFI_HANDLE *Handle
+ )
+/*++
+
+Routine Description:
+
+ Search a handle to a device on a specified device path that supports a specified protocol,
+ interface of that protocol on that handle is another output.
+
+Arguments:
+
+ Protocol - The protocol to search for
+
+ FilePath - The specified device path
+
+ Interface - Interface of the protocol on the handle
+
+ Handle - The handle to the device on the specified device path that supports the protocol.
+
+Returns:
+
+ Status code.
+
+--*/
+{
+ EFI_STATUS Status;
+
+ Status = CoreLocateDevicePath (Protocol, FilePath, Handle);
+ if (!EFI_ERROR (Status)) {
+ Status = CoreHandleProtocol (*Handle, Protocol, Interface);
+ }
+ return Status;
+}
+
+
+VOID
+CoreDevicePathToFileName (
+ IN FILEPATH_DEVICE_PATH *FilePath,
+ OUT CHAR16 **String
+ )
+/*++
+
+Routine Description:
+
+ Transfer a device's full path a string.
+
+Arguments:
+
+ FilePath - Device path
+
+ String - The string represent the device's full path
+
+Returns:
+
+ None
+
+--*/
+{
+ UINTN StringSize;
+ FILEPATH_DEVICE_PATH *FilePathNode;
+ CHAR16 *Str;
+
+ *String = NULL;
+ StringSize = 0;
+ FilePathNode = FilePath;
+ while (!IsDevicePathEnd (&FilePathNode->Header)) {
+
+ //
+ // For filesystem access each node should be a filepath component
+ //
+ if (DevicePathType (&FilePathNode->Header) != MEDIA_DEVICE_PATH ||
+ DevicePathSubType (&FilePathNode->Header) != MEDIA_FILEPATH_DP) {
+
+ return;
+ }
+
+ StringSize += EfiStrLen (FilePathNode->PathName);
+
+ FilePathNode = (FILEPATH_DEVICE_PATH *) NextDevicePathNode (&FilePathNode->Header);
+ }
+
+ *String = CoreAllocateBootServicesPool (StringSize);
+ if (*String == NULL) {
+ return;
+ }
+
+ FilePathNode = FilePath;
+ Str = *String;
+ while (!IsDevicePathEnd (&FilePathNode->Header)) {
+ EfiStrCat (Str, FilePathNode->PathName);
+ FilePathNode = (FILEPATH_DEVICE_PATH *) NextDevicePathNode (&FilePathNode->Header);
+ }
+}
+
+
+BOOLEAN
+CoreGrowBuffer (
+ IN OUT EFI_STATUS *Status,
+ IN OUT VOID **Buffer,
+ IN UINTN BufferSize
+ )
+/*++
+
+Routine Description:
+
+ Helper function called as part of the code needed
+ to allocate the proper sized buffer for various
+ EFI interfaces.
+
+Arguments:
+
+ Status - Current status
+
+ Buffer - Current allocated buffer, or NULL
+
+ BufferSize - Current buffer size needed
+
+Returns:
+
+ TRUE - if the buffer was reallocated and the caller
+ should try the API again.
+
+ FALSE - buffer could not be allocated and the caller
+ should not try the API again.
+
+--*/
+{
+ BOOLEAN TryAgain;
+
+ TryAgain = FALSE;
+ //
+ // If this is an initial request, buffer will be null with a new buffer size
+ //
+ if (*Buffer == NULL) {
+ *Status = EFI_BUFFER_TOO_SMALL;
+ }
+
+ if (BufferSize == 0) {
+ return TRUE;
+ }
+
+ //
+ // If the status code is "buffer too small", resize the buffer
+ //
+
+ if (*Status == EFI_BUFFER_TOO_SMALL) {
+ if (*Buffer != NULL) {
+ CoreFreePool (*Buffer);
+ }
+
+ *Buffer = CoreAllocateBootServicesPool (BufferSize);
+ if (*Buffer != NULL) {
+ TryAgain = TRUE;
+ } else {
+ *Status = EFI_OUT_OF_RESOURCES;
+ }
+ }
+
+ //
+ // If there's an error, free the buffer
+ //
+ if ((!TryAgain) && (EFI_ERROR (*Status)) && (*Buffer)) {
+ CoreFreePool (*Buffer);
+ *Buffer = NULL;
+ }
+
+ return TryAgain;
+}
+