2 Core image handling services to load and unload PeImage.
4 Copyright (c) 2006 - 2008, Intel Corporation. <BR>
5 All rights reserved. This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
20 SPIN_LOCK mUnloadImageLock
;
22 LOADED_IMAGE_PRIVATE_DATA
*mCurrentImage
= NULL
;
24 LOAD_PE32_IMAGE_PRIVATE_DATA mLoadPe32PrivateData
= {
25 LOAD_PE32_IMAGE_PRIVATE_DATA_SIGNATURE
,
35 // This code is needed to build the Image handle for the DXE Core
37 LOADED_IMAGE_PRIVATE_DATA mCorePrivateImage
= {
38 LOADED_IMAGE_PRIVATE_DATA_SIGNATURE
, // Signature
40 EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER
, // Image type
41 TRUE
, // If entrypoint has been called
44 EFI_LOADED_IMAGE_INFORMATION_REVISION
, // Revision
45 NULL
, // Parent handle
46 NULL
, // System handle
48 NULL
, // Device handle
57 EfiBootServicesCode
, // ImageCodeType
58 EfiBootServicesData
// ImageDataType
60 (EFI_PHYSICAL_ADDRESS
)0, // ImageBasePage
64 EFI_SUCCESS
, // Status
72 NULL
// LoadedImageDevicePath
78 Add the Image Services to EFI Boot Services Table and install the protocol
79 interfaces for this image.
81 @param HobStart The HOB to initialize
87 CoreInitializeImageServices (
92 LOADED_IMAGE_PRIVATE_DATA
*Image
;
93 EFI_PHYSICAL_ADDRESS DxeCoreImageBaseAddress
;
94 UINT64 DxeCoreImageLength
;
95 VOID
*DxeCoreEntryPoint
;
96 EFI_PEI_HOB_POINTERS DxeCoreHob
;
98 // Searching for image hob
100 DxeCoreHob
.Raw
= HobStart
;
101 while ((DxeCoreHob
.Raw
= GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION
, DxeCoreHob
.Raw
)) != NULL
) {
102 if (CompareGuid (&DxeCoreHob
.MemoryAllocationModule
->MemoryAllocationHeader
.Name
, &gEfiHobMemoryAllocModuleGuid
)) {
108 DxeCoreHob
.Raw
= GET_NEXT_HOB (DxeCoreHob
);
110 ASSERT (DxeCoreHob
.Raw
!= NULL
);
112 DxeCoreImageBaseAddress
= DxeCoreHob
.MemoryAllocationModule
->MemoryAllocationHeader
.MemoryBaseAddress
;
113 DxeCoreImageLength
= DxeCoreHob
.MemoryAllocationModule
->MemoryAllocationHeader
.MemoryLength
;
114 DxeCoreEntryPoint
= (VOID
*) (UINTN
) DxeCoreHob
.MemoryAllocationModule
->EntryPoint
;
115 gDxeCoreFileName
= &DxeCoreHob
.MemoryAllocationModule
->ModuleName
;
117 // Initialize the fields for an internal driver
119 Image
= &mCorePrivateImage
;
121 Image
->EntryPoint
= (EFI_IMAGE_ENTRY_POINT
)(UINTN
)DxeCoreEntryPoint
;
122 Image
->ImageBasePage
= DxeCoreImageBaseAddress
;
123 Image
->NumberOfPages
= (UINTN
)(EFI_SIZE_TO_PAGES((UINTN
)(DxeCoreImageLength
)));
124 Image
->Tpl
= gEfiCurrentTpl
;
125 Image
->Info
.SystemTable
= gDxeCoreST
;
126 Image
->Info
.ImageBase
= (VOID
*)(UINTN
)DxeCoreImageBaseAddress
;
127 Image
->Info
.ImageSize
= DxeCoreImageLength
;
130 // Install the protocol interfaces for this image
132 Status
= CoreInstallProtocolInterface (
134 &gEfiLoadedImageProtocolGuid
,
135 EFI_NATIVE_INTERFACE
,
138 ASSERT_EFI_ERROR (Status
);
140 mCurrentImage
= Image
;
143 // Initialize spin lock
145 InitializeSpinLock (&mUnloadImageLock
);
148 // Fill in DXE globals
150 gDxeCoreImageHandle
= Image
->Handle
;
151 gDxeCoreLoadedImage
= &Image
->Info
;
154 // Export DXE Core PE Loader functionality
156 return CoreInstallProtocolInterface (
157 &mLoadPe32PrivateData
.Handle
,
158 &gEfiLoadPeImageProtocolGuid
,
159 EFI_NATIVE_INTERFACE
,
160 &mLoadPe32PrivateData
.Pe32Image
166 Loads, relocates, and invokes a PE/COFF image
168 @param BootPolicy If TRUE, indicates that the request originates
169 from the boot manager, and that the boot
170 manager is attempting to load FilePath as a
172 @param Pe32Handle The handle of PE32 image
173 @param Image PE image to be loaded
174 @param DstBuffer The buffer to store the image
175 @param EntryPoint A pointer to the entry point
176 @param Attribute The bit mask of attributes to set for the load
179 @retval EFI_SUCCESS The file was loaded, relocated, and invoked
180 @retval EFI_OUT_OF_RESOURCES There was not enough memory to load and
181 relocate the PE/COFF file
182 @retval EFI_INVALID_PARAMETER Invalid parameter
183 @retval EFI_BUFFER_TOO_SMALL Buffer for image is too small
188 IN BOOLEAN BootPolicy
,
190 IN LOADED_IMAGE_PRIVATE_DATA
*Image
,
191 IN EFI_PHYSICAL_ADDRESS DstBuffer OPTIONAL
,
192 OUT EFI_PHYSICAL_ADDRESS
*EntryPoint OPTIONAL
,
197 BOOLEAN DstBufAlocated
;
200 EFI_TCG_PLATFORM_PROTOCOL
*TcgPlatformProtocol
;
201 IMAGE_FILE_HANDLE
*FHandle
;
204 ZeroMem (&Image
->ImageContext
, sizeof (Image
->ImageContext
));
206 Image
->ImageContext
.Handle
= Pe32Handle
;
207 Image
->ImageContext
.ImageRead
= (PE_COFF_LOADER_READ_FILE
)CoreReadImageFile
;
210 // Get information about the image being loaded
212 Status
= PeCoffLoaderGetImageInfo (&Image
->ImageContext
);
213 if (EFI_ERROR (Status
)) {
217 if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Image
->ImageContext
.Machine
)) {
218 if (!EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED (Image
->ImageContext
.Machine
)) {
220 // The PE/COFF loader can support loading image types that can be executed.
221 // If we loaded an image type that we can not execute return EFI_UNSUPORTED.
223 return EFI_UNSUPPORTED
;
228 // Set EFI memory type based on ImageType
230 switch (Image
->ImageContext
.ImageType
) {
231 case EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION
:
232 Image
->ImageContext
.ImageCodeMemoryType
= EfiLoaderCode
;
233 Image
->ImageContext
.ImageDataMemoryType
= EfiLoaderData
;
235 case EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER
:
236 Image
->ImageContext
.ImageCodeMemoryType
= EfiBootServicesCode
;
237 Image
->ImageContext
.ImageDataMemoryType
= EfiBootServicesData
;
239 case EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
:
240 case EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER
:
241 Image
->ImageContext
.ImageCodeMemoryType
= EfiRuntimeServicesCode
;
242 Image
->ImageContext
.ImageDataMemoryType
= EfiRuntimeServicesData
;
245 Image
->ImageContext
.ImageError
= IMAGE_ERROR_INVALID_SUBSYSTEM
;
246 return EFI_UNSUPPORTED
;
249 // Get the image base address in the original PeImage.
251 LinkTimeBase
= (UINTN
) Image
->ImageContext
.ImageAddress
;
254 // Allocate memory of the correct memory type aligned on the required image boundry
256 DstBufAlocated
= FALSE
;
257 if (DstBuffer
== 0) {
259 // Allocate Destination Buffer as caller did not pass it in
262 if (Image
->ImageContext
.SectionAlignment
> EFI_PAGE_SIZE
) {
263 Size
= (UINTN
)Image
->ImageContext
.ImageSize
+ Image
->ImageContext
.SectionAlignment
;
265 Size
= (UINTN
)Image
->ImageContext
.ImageSize
;
268 Image
->NumberOfPages
= EFI_SIZE_TO_PAGES (Size
);
271 // If the image relocations have not been stripped, then load at any address.
272 // Otherwise load at the address at which it was linked.
274 // Memory below 1MB should be treated reserved for CSM and there should be
275 // no modules whose preferred load addresses are below 1MB.
277 Status
= EFI_OUT_OF_RESOURCES
;
278 if (Image
->ImageContext
.ImageAddress
>= 0x100000 || Image
->ImageContext
.RelocationsStripped
) {
279 Status
= CoreAllocatePages (
281 (EFI_MEMORY_TYPE
) (Image
->ImageContext
.ImageCodeMemoryType
),
282 Image
->NumberOfPages
,
283 &Image
->ImageContext
.ImageAddress
286 if (EFI_ERROR (Status
) && !Image
->ImageContext
.RelocationsStripped
) {
287 Status
= CoreAllocatePages (
289 (EFI_MEMORY_TYPE
) (Image
->ImageContext
.ImageCodeMemoryType
),
290 Image
->NumberOfPages
,
291 &Image
->ImageContext
.ImageAddress
294 if (EFI_ERROR (Status
)) {
297 DstBufAlocated
= TRUE
;
300 // Caller provided the destination buffer
303 if (Image
->ImageContext
.RelocationsStripped
&& (Image
->ImageContext
.ImageAddress
!= DstBuffer
)) {
305 // If the image relocations were stripped, and the caller provided a
306 // destination buffer address that does not match the address that the
307 // image is linked at, then the image cannot be loaded.
309 return EFI_INVALID_PARAMETER
;
312 if (Image
->NumberOfPages
!= 0 &&
313 Image
->NumberOfPages
<
314 (EFI_SIZE_TO_PAGES ((UINTN
)Image
->ImageContext
.ImageSize
+ Image
->ImageContext
.SectionAlignment
))) {
315 Image
->NumberOfPages
= EFI_SIZE_TO_PAGES ((UINTN
)Image
->ImageContext
.ImageSize
+ Image
->ImageContext
.SectionAlignment
);
316 return EFI_BUFFER_TOO_SMALL
;
319 Image
->NumberOfPages
= EFI_SIZE_TO_PAGES ((UINTN
)Image
->ImageContext
.ImageSize
+ Image
->ImageContext
.SectionAlignment
);
320 Image
->ImageContext
.ImageAddress
= DstBuffer
;
323 Image
->ImageBasePage
= Image
->ImageContext
.ImageAddress
;
324 Image
->ImageContext
.ImageAddress
=
325 (Image
->ImageContext
.ImageAddress
+ Image
->ImageContext
.SectionAlignment
- 1) &
326 ~((UINTN
)Image
->ImageContext
.SectionAlignment
- 1);
329 // Load the image from the file into the allocated memory
331 Status
= PeCoffLoaderLoadImage (&Image
->ImageContext
);
332 if (EFI_ERROR (Status
)) {
337 // If this is a Runtime Driver, then allocate memory for the FixupData that
338 // is used to relocate the image when SetVirtualAddressMap() is called. The
339 // relocation is done by the Runtime AP.
341 if ((Attribute
& EFI_LOAD_PE_IMAGE_ATTRIBUTE_RUNTIME_REGISTRATION
) != 0) {
342 if (Image
->ImageContext
.ImageType
== EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
) {
343 Image
->ImageContext
.FixupData
= AllocateRuntimePool ((UINTN
)(Image
->ImageContext
.FixupDataSize
));
344 if (Image
->ImageContext
.FixupData
== NULL
) {
345 Status
= EFI_OUT_OF_RESOURCES
;
352 // Measure the image before applying fixup
354 Status
= CoreLocateProtocol (
355 &gEfiTcgPlatformProtocolGuid
,
357 (VOID
**) &TcgPlatformProtocol
359 if (!EFI_ERROR (Status
)) {
360 FHandle
= (IMAGE_FILE_HANDLE
*) Image
->ImageContext
.Handle
;
361 Status
= TcgPlatformProtocol
->MeasurePeImage (
363 (EFI_PHYSICAL_ADDRESS
) (UINTN
) FHandle
->Source
,
366 Image
->ImageContext
.ImageType
,
367 Image
->Info
.DeviceHandle
,
371 ASSERT_EFI_ERROR (Status
);
375 // Relocate the image in memory
377 Status
= PeCoffLoaderRelocateImage (&Image
->ImageContext
);
378 if (EFI_ERROR (Status
)) {
383 // Flush the Instruction Cache
385 InvalidateInstructionCacheRange ((VOID
*)(UINTN
)Image
->ImageContext
.ImageAddress
, (UINTN
)Image
->ImageContext
.ImageSize
);
388 // Copy the machine type from the context to the image private data. This
389 // is needed during image unload to know if we should call an EBC protocol
390 // to unload the image.
392 Image
->Machine
= Image
->ImageContext
.Machine
;
395 // Get the image entry point. If it's an EBC image, then call into the
396 // interpreter to create a thunk for the entry point and use the returned
397 // value for the entry point.
399 Image
->EntryPoint
= (EFI_IMAGE_ENTRY_POINT
)(UINTN
)Image
->ImageContext
.EntryPoint
;
400 if (Image
->ImageContext
.Machine
== EFI_IMAGE_MACHINE_EBC
) {
402 // Locate the EBC interpreter protocol
404 Status
= CoreLocateProtocol (&gEfiEbcProtocolGuid
, NULL
, (VOID
**)&Image
->Ebc
);
405 if (EFI_ERROR(Status
)) {
406 DEBUG ((DEBUG_LOAD
| DEBUG_ERROR
, "CoreLoadPeImage: There is no EBC interpreter for an EBC image.\n"));
411 // Register a callback for flushing the instruction cache so that created
412 // thunks can be flushed.
414 Status
= Image
->Ebc
->RegisterICacheFlush (Image
->Ebc
, (EBC_ICACHE_FLUSH
)InvalidateInstructionCacheRange
);
415 if (EFI_ERROR(Status
)) {
420 // Create a thunk for the image's entry point. This will be the new
421 // entry point for the image.
423 Status
= Image
->Ebc
->CreateThunk (
426 (VOID
*)(UINTN
) Image
->ImageContext
.EntryPoint
,
427 (VOID
**) &Image
->EntryPoint
429 if (EFI_ERROR(Status
)) {
435 // Fill in the image information for the Loaded Image Protocol
437 Image
->Type
= Image
->ImageContext
.ImageType
;
438 Image
->Info
.ImageBase
= (VOID
*)(UINTN
)Image
->ImageContext
.ImageAddress
;
439 Image
->Info
.ImageSize
= Image
->ImageContext
.ImageSize
;
440 Image
->Info
.ImageCodeType
= (EFI_MEMORY_TYPE
) (Image
->ImageContext
.ImageCodeMemoryType
);
441 Image
->Info
.ImageDataType
= (EFI_MEMORY_TYPE
) (Image
->ImageContext
.ImageDataMemoryType
);
442 if ((Attribute
& EFI_LOAD_PE_IMAGE_ATTRIBUTE_RUNTIME_REGISTRATION
) != 0) {
443 if (Image
->ImageContext
.ImageType
== EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
) {
445 // Make a list off all the RT images so we can let the RT AP know about them.
447 Image
->RuntimeData
= AllocateRuntimePool (sizeof(EFI_RUNTIME_IMAGE_ENTRY
));
448 if (Image
->RuntimeData
== NULL
) {
451 Image
->RuntimeData
->ImageBase
= Image
->Info
.ImageBase
;
452 Image
->RuntimeData
->ImageSize
= (UINT64
) (Image
->Info
.ImageSize
);
453 Image
->RuntimeData
->RelocationData
= Image
->ImageContext
.FixupData
;
454 Image
->RuntimeData
->Handle
= Image
->Handle
;
455 InsertTailList (&gRuntime
->ImageHead
, &Image
->RuntimeData
->Link
);
460 // Fill in the entry point of the image if it is available
462 if (EntryPoint
!= NULL
) {
463 *EntryPoint
= Image
->ImageContext
.EntryPoint
;
467 // Print the load address and the PDB file name if it is available
474 CHAR8 EfiFileName
[256];
477 DEBUG ((DEBUG_INFO
| DEBUG_LOAD
,
478 "Loading driver at 0x%11p EntryPoint=0x%11p ",
479 (VOID
*)(UINTN
) Image
->ImageContext
.ImageAddress
,
480 FUNCTION_ENTRY_POINT ((UINTN
) Image
->ImageContext
.EntryPoint
)));
484 // Print Module Name by Pdb file path
486 if (Image
->ImageContext
.PdbPointer
!= NULL
) {
488 for (Index
= 0; Image
->ImageContext
.PdbPointer
[Index
] != 0; Index
++) {
489 if (Image
->ImageContext
.PdbPointer
[Index
] == '\\') {
490 StartIndex
= Index
+ 1;
494 // Copy the PDB file name to our temporary string, and replace .pdb with .efi
496 for (Index
= 0; Index
< sizeof (EfiFileName
); Index
++) {
497 EfiFileName
[Index
] = Image
->ImageContext
.PdbPointer
[Index
+ StartIndex
];
498 if (EfiFileName
[Index
] == 0) {
499 EfiFileName
[Index
] = '.';
501 if (EfiFileName
[Index
] == '.') {
502 EfiFileName
[Index
+ 1] = 'e';
503 EfiFileName
[Index
+ 2] = 'f';
504 EfiFileName
[Index
+ 3] = 'i';
505 EfiFileName
[Index
+ 4] = 0;
509 DEBUG ((DEBUG_INFO
| DEBUG_LOAD
, "%a", EfiFileName
)); // &Image->ImageContext.PdbPointer[StartIndex]));
511 DEBUG ((DEBUG_INFO
| DEBUG_LOAD
, "\n"));
523 if (DstBufAlocated
) {
524 CoreFreePages (Image
->ImageContext
.ImageAddress
, Image
->NumberOfPages
);
527 if (Image
->ImageContext
.FixupData
!= NULL
) {
528 CoreFreePool (Image
->ImageContext
.FixupData
);
537 Get the image's private data from its handle.
539 @param ImageHandle The image handle
541 @return Return the image private data associated with ImageHandle.
544 LOADED_IMAGE_PRIVATE_DATA
*
545 CoreLoadedImageInfo (
546 IN EFI_HANDLE ImageHandle
550 EFI_LOADED_IMAGE_PROTOCOL
*LoadedImage
;
551 LOADED_IMAGE_PRIVATE_DATA
*Image
;
553 Status
= CoreHandleProtocol (
555 &gEfiLoadedImageProtocolGuid
,
556 (VOID
**)&LoadedImage
558 if (!EFI_ERROR (Status
)) {
559 Image
= LOADED_IMAGE_PRIVATE_DATA_FROM_THIS (LoadedImage
);
561 DEBUG ((DEBUG_LOAD
, "CoreLoadedImageInfo: Not an ImageHandle %p\n", ImageHandle
));
570 Loads an EFI image into memory and returns a handle to the image.
572 @param BootPolicy If TRUE, indicates that the request originates
573 from the boot manager, and that the boot
574 manager is attempting to load FilePath as a
576 @param ParentImageHandle The caller's image handle.
577 @param FilePath The specific file path from which the image is
579 @param SourceBuffer If not NULL, a pointer to the memory location
580 containing a copy of the image to be loaded.
581 @param SourceSize The size in bytes of SourceBuffer.
582 @param DstBuffer The buffer to store the image
583 @param NumberOfPages If not NULL, it inputs a pointer to the page
584 number of DstBuffer and outputs a pointer to
585 the page number of the image. If this number is
586 not enough, return EFI_BUFFER_TOO_SMALL and
587 this parameter contains the required number.
588 @param ImageHandle Pointer to the returned image handle that is
589 created when the image is successfully loaded.
590 @param EntryPoint A pointer to the entry point
591 @param Attribute The bit mask of attributes to set for the load
594 @retval EFI_SUCCESS The image was loaded into memory.
595 @retval EFI_NOT_FOUND The FilePath was not found.
596 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
597 @retval EFI_BUFFER_TOO_SMALL The buffer is too small
598 @retval EFI_UNSUPPORTED The image type is not supported, or the device
599 path cannot be parsed to locate the proper
600 protocol for loading the file.
601 @retval EFI_OUT_OF_RESOURCES Image was not loaded due to insufficient
606 CoreLoadImageCommon (
607 IN BOOLEAN BootPolicy
,
608 IN EFI_HANDLE ParentImageHandle
,
609 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
610 IN VOID
*SourceBuffer OPTIONAL
,
612 IN EFI_PHYSICAL_ADDRESS DstBuffer OPTIONAL
,
613 IN OUT UINTN
*NumberOfPages OPTIONAL
,
614 OUT EFI_HANDLE
*ImageHandle
,
615 OUT EFI_PHYSICAL_ADDRESS
*EntryPoint OPTIONAL
,
619 LOADED_IMAGE_PRIVATE_DATA
*Image
;
620 LOADED_IMAGE_PRIVATE_DATA
*ParentImage
;
621 IMAGE_FILE_HANDLE FHand
;
623 EFI_STATUS SecurityStatus
;
624 EFI_HANDLE DeviceHandle
;
625 UINT32 AuthenticationStatus
;
626 EFI_DEVICE_PATH_PROTOCOL
*OriginalFilePath
;
627 EFI_DEVICE_PATH_PROTOCOL
*HandleFilePath
;
630 SecurityStatus
= EFI_SUCCESS
;
632 ASSERT (gEfiCurrentTpl
< TPL_NOTIFY
);
636 // The caller must pass in a valid ParentImageHandle
638 if (ImageHandle
== NULL
|| ParentImageHandle
== NULL
) {
639 return EFI_INVALID_PARAMETER
;
642 ParentImage
= CoreLoadedImageInfo (ParentImageHandle
);
643 if (ParentImage
== NULL
) {
644 DEBUG((DEBUG_LOAD
|DEBUG_ERROR
, "LoadImageEx: Parent handle not an image handle\n"));
645 return EFI_INVALID_PARAMETER
;
649 // Get simple read access to the source file
651 OriginalFilePath
= FilePath
;
652 Status
= CoreOpenImageFile (
659 &AuthenticationStatus
661 if (Status
== EFI_ALREADY_STARTED
) {
664 } else if (EFI_ERROR (Status
)) {
669 // Verify the Authentication Status through the Security Architectural Protocol
671 if ((gSecurity
!= NULL
) && (OriginalFilePath
!= NULL
)) {
672 SecurityStatus
= gSecurity
->FileAuthenticationState (
674 AuthenticationStatus
,
677 if (EFI_ERROR (SecurityStatus
) && SecurityStatus
!= EFI_SECURITY_VIOLATION
) {
678 Status
= SecurityStatus
;
686 // Allocate a new image structure
688 Image
= AllocateZeroPool (sizeof(LOADED_IMAGE_PRIVATE_DATA
));
690 return EFI_OUT_OF_RESOURCES
;
694 // Pull out just the file portion of the DevicePath for the LoadedImage FilePath
696 FilePath
= OriginalFilePath
;
697 Status
= CoreHandleProtocol (DeviceHandle
, &gEfiDevicePathProtocolGuid
, (VOID
**)&HandleFilePath
);
698 if (!EFI_ERROR (Status
)) {
699 FilePathSize
= GetDevicePathSize (HandleFilePath
) - sizeof(EFI_DEVICE_PATH_PROTOCOL
);
700 FilePath
= (EFI_DEVICE_PATH_PROTOCOL
*) (((UINT8
*)FilePath
) + FilePathSize
);
704 // Initialize the fields for an internal driver
706 Image
->Signature
= LOADED_IMAGE_PRIVATE_DATA_SIGNATURE
;
707 Image
->Info
.SystemTable
= gDxeCoreST
;
708 Image
->Info
.DeviceHandle
= DeviceHandle
;
709 Image
->Info
.Revision
= EFI_LOADED_IMAGE_PROTOCOL_REVISION
;
710 Image
->Info
.FilePath
= DuplicateDevicePath (FilePath
);
711 Image
->Info
.ParentHandle
= ParentImageHandle
;
714 if (NumberOfPages
!= NULL
) {
715 Image
->NumberOfPages
= *NumberOfPages
;
717 Image
->NumberOfPages
= 0 ;
721 // Install the protocol interfaces for this image
722 // don't fire notifications yet
724 Status
= CoreInstallProtocolInterfaceNotify (
726 &gEfiLoadedImageProtocolGuid
,
727 EFI_NATIVE_INTERFACE
,
731 if (EFI_ERROR (Status
)) {
736 // Load the image. If EntryPoint is Null, it will not be set.
738 Status
= CoreLoadPeImage (BootPolicy
, &FHand
, Image
, DstBuffer
, EntryPoint
, Attribute
);
739 if (EFI_ERROR (Status
)) {
740 if ((Status
== EFI_BUFFER_TOO_SMALL
) || (Status
== EFI_OUT_OF_RESOURCES
)) {
741 if (NumberOfPages
!= NULL
) {
742 *NumberOfPages
= Image
->NumberOfPages
;
748 if (NumberOfPages
!= NULL
) {
749 *NumberOfPages
= Image
->NumberOfPages
;
753 // Register the image in the Debug Image Info Table if the attribute is set
755 if ((Attribute
& EFI_LOAD_PE_IMAGE_ATTRIBUTE_DEBUG_IMAGE_INFO_TABLE_REGISTRATION
) != 0) {
756 CoreNewDebugImageInfoEntry (EFI_DEBUG_IMAGE_INFO_TYPE_NORMAL
, &Image
->Info
, Image
->Handle
);
760 //Reinstall loaded image protocol to fire any notifications
762 Status
= CoreReinstallProtocolInterface (
764 &gEfiLoadedImageProtocolGuid
,
768 if (EFI_ERROR (Status
)) {
773 // If DevicePath parameter to the LoadImage() is not NULL, then make a copy of DevicePath,
774 // otherwise Loaded Image Device Path Protocol is installed with a NULL interface pointer.
776 if (OriginalFilePath
!= NULL
) {
777 Image
->LoadedImageDevicePath
= DuplicateDevicePath (OriginalFilePath
);
781 // Install Loaded Image Device Path Protocol onto the image handle of a PE/COFE image
783 Status
= CoreInstallProtocolInterface (
785 &gEfiLoadedImageDevicePathProtocolGuid
,
786 EFI_NATIVE_INTERFACE
,
787 Image
->LoadedImageDevicePath
789 if (EFI_ERROR (Status
)) {
794 // Success. Return the image handle
796 *ImageHandle
= Image
->Handle
;
800 // All done accessing the source file
801 // If we allocated the Source buffer, free it
803 if (FHand
.FreeBuffer
) {
804 CoreFreePool (FHand
.Source
);
808 // There was an error. If there's an Image structure, free it
810 if (EFI_ERROR (Status
)) {
812 CoreUnloadAndCloseImage (Image
, (BOOLEAN
)(DstBuffer
== 0));
815 } else if (EFI_ERROR (SecurityStatus
)) {
816 Status
= SecurityStatus
;
826 Loads an EFI image into memory and returns a handle to the image.
828 @param BootPolicy If TRUE, indicates that the request originates
829 from the boot manager, and that the boot
830 manager is attempting to load FilePath as a
832 @param ParentImageHandle The caller's image handle.
833 @param FilePath The specific file path from which the image is
835 @param SourceBuffer If not NULL, a pointer to the memory location
836 containing a copy of the image to be loaded.
837 @param SourceSize The size in bytes of SourceBuffer.
838 @param ImageHandle Pointer to the returned image handle that is
839 created when the image is successfully loaded.
841 @retval EFI_SUCCESS The image was loaded into memory.
842 @retval EFI_NOT_FOUND The FilePath was not found.
843 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
844 @retval EFI_UNSUPPORTED The image type is not supported, or the device
845 path cannot be parsed to locate the proper
846 protocol for loading the file.
847 @retval EFI_OUT_OF_RESOURCES Image was not loaded due to insufficient
854 IN BOOLEAN BootPolicy
,
855 IN EFI_HANDLE ParentImageHandle
,
856 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
857 IN VOID
*SourceBuffer OPTIONAL
,
859 OUT EFI_HANDLE
*ImageHandle
864 PERF_START (NULL
, "LoadImage", NULL
, 0);
866 Status
= CoreLoadImageCommon (
872 (EFI_PHYSICAL_ADDRESS
) (UINTN
) NULL
,
876 EFI_LOAD_PE_IMAGE_ATTRIBUTE_RUNTIME_REGISTRATION
| EFI_LOAD_PE_IMAGE_ATTRIBUTE_DEBUG_IMAGE_INFO_TABLE_REGISTRATION
879 PERF_END (NULL
, "LoadImage", NULL
, 0);
887 Loads an EFI image into memory and returns a handle to the image with extended parameters.
889 @param This Calling context
890 @param ParentImageHandle The caller's image handle.
891 @param FilePath The specific file path from which the image is
893 @param SourceBuffer If not NULL, a pointer to the memory location
894 containing a copy of the image to be loaded.
895 @param SourceSize The size in bytes of SourceBuffer.
896 @param DstBuffer The buffer to store the image.
897 @param NumberOfPages For input, specifies the space size of the
898 image by caller if not NULL. For output,
899 specifies the actual space size needed.
900 @param ImageHandle Image handle for output.
901 @param EntryPoint Image entry point for output.
902 @param Attribute The bit mask of attributes to set for the load
905 @retval EFI_SUCCESS The image was loaded into memory.
906 @retval EFI_NOT_FOUND The FilePath was not found.
907 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
908 @retval EFI_UNSUPPORTED The image type is not supported, or the device
909 path cannot be parsed to locate the proper
910 protocol for loading the file.
911 @retval EFI_OUT_OF_RESOURCES Image was not loaded due to insufficient
918 IN EFI_PE32_IMAGE_PROTOCOL
*This
,
919 IN EFI_HANDLE ParentImageHandle
,
920 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
921 IN VOID
*SourceBuffer OPTIONAL
,
923 IN EFI_PHYSICAL_ADDRESS DstBuffer OPTIONAL
,
924 OUT UINTN
*NumberOfPages OPTIONAL
,
925 OUT EFI_HANDLE
*ImageHandle
,
926 OUT EFI_PHYSICAL_ADDRESS
*EntryPoint OPTIONAL
,
930 return CoreLoadImageCommon (
946 Transfer control to a loaded image's entry point.
948 @param ImageHandle Handle of image to be started.
949 @param ExitDataSize Pointer of the size to ExitData
950 @param ExitData Pointer to a pointer to a data buffer that
951 includes a Null-terminated Unicode string,
952 optionally followed by additional binary data.
953 The string is a description that the caller may
954 use to further indicate the reason for the
957 @retval EFI_INVALID_PARAMETER Invalid parameter
958 @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate
959 @retval EFI_SUCCESS Successfully transfer control to the image's
966 IN EFI_HANDLE ImageHandle
,
967 OUT UINTN
*ExitDataSize
,
968 OUT CHAR16
**ExitData OPTIONAL
972 LOADED_IMAGE_PRIVATE_DATA
*Image
;
973 LOADED_IMAGE_PRIVATE_DATA
*LastImage
;
974 UINT64 HandleDatabaseKey
;
977 Image
= CoreLoadedImageInfo (ImageHandle
);
978 if (Image
== NULL
|| Image
->Started
) {
979 return EFI_INVALID_PARAMETER
;
983 // Don't profile Objects or invalid start requests
985 PERF_START (ImageHandle
, START_IMAGE_TOK
, NULL
, 0);
989 // Push the current start image context, and
990 // link the current image to the head. This is the
991 // only image that can call Exit()
993 HandleDatabaseKey
= CoreGetHandleDatabaseKey ();
994 LastImage
= mCurrentImage
;
995 mCurrentImage
= Image
;
996 Image
->Tpl
= gEfiCurrentTpl
;
999 // Set long jump for Exit() support
1000 // JumpContext must be aligned on a CPU specific boundary.
1001 // Overallocate the buffer and force the required alignment
1003 Image
->JumpBuffer
= AllocatePool (sizeof (BASE_LIBRARY_JUMP_BUFFER
) + BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT
);
1004 if (Image
->JumpBuffer
== NULL
) {
1005 PERF_END (ImageHandle
, START_IMAGE_TOK
, NULL
, 0);
1006 return EFI_OUT_OF_RESOURCES
;
1008 Image
->JumpContext
= ALIGN_POINTER (Image
->JumpBuffer
, BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT
);
1010 SetJumpFlag
= SetJump (Image
->JumpContext
);
1012 // The initial call to SetJump() must always return 0.
1013 // Subsequent calls to LongJump() cause a non-zero value to be returned by SetJump().
1015 if (SetJumpFlag
== 0) {
1017 // Call the image's entry point
1019 Image
->Started
= TRUE
;
1020 Image
->Status
= Image
->EntryPoint (ImageHandle
, Image
->Info
.SystemTable
);
1023 // Add some debug information if the image returned with error.
1024 // This make the user aware and check if the driver image have already released
1025 // all the resource in this situation.
1027 DEBUG_CODE_BEGIN ();
1028 if (EFI_ERROR (Image
->Status
)) {
1029 DEBUG ((DEBUG_ERROR
, "Error: Image at %11p start failed: %r\n", Image
->Info
.ImageBase
, Image
->Status
));
1034 // If the image returns, exit it through Exit()
1036 CoreExit (ImageHandle
, Image
->Status
, 0, NULL
);
1040 // Image has completed. Verify the tpl is the same
1042 ASSERT (Image
->Tpl
== gEfiCurrentTpl
);
1043 CoreRestoreTpl (Image
->Tpl
);
1045 CoreFreePool (Image
->JumpBuffer
);
1048 // Pop the current start image context
1050 mCurrentImage
= LastImage
;
1053 // Go connect any handles that were created or modified while the image executed.
1055 CoreConnectHandlesByKey (HandleDatabaseKey
);
1058 // Handle the image's returned ExitData
1060 DEBUG_CODE_BEGIN ();
1061 if (Image
->ExitDataSize
!= 0 || Image
->ExitData
!= NULL
) {
1063 DEBUG ((DEBUG_LOAD
, "StartImage: ExitDataSize %d, ExitData %x", Image
->ExitDataSize
, Image
->ExitData
));
1064 if (Image
->ExitData
!= NULL
) {
1065 DEBUG ((DEBUG_LOAD
, " (%hs)", Image
->ExitData
));
1067 DEBUG ((DEBUG_LOAD
, "\n"));
1072 // Return the exit data to the caller
1074 if (ExitData
!= NULL
&& ExitDataSize
!= NULL
) {
1075 *ExitDataSize
= Image
->ExitDataSize
;
1076 *ExitData
= Image
->ExitData
;
1079 // Caller doesn't want the exit data, free it
1081 CoreFreePool (Image
->ExitData
);
1082 Image
->ExitData
= NULL
;
1086 // Save the Status because Image will get destroyed if it is unloaded.
1088 Status
= Image
->Status
;
1091 // If the image returned an error, or if the image is an application
1094 if (EFI_ERROR (Image
->Status
) || Image
->Type
== EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION
) {
1095 CoreUnloadAndCloseImage (Image
, TRUE
);
1101 PERF_END (ImageHandle
, START_IMAGE_TOK
, NULL
, 0);
1108 Unloads EFI image from memory.
1110 @param Image EFI image
1111 @param FreePage Free allocated pages
1115 CoreUnloadAndCloseImage (
1116 IN LOADED_IMAGE_PRIVATE_DATA
*Image
,
1122 EFI_HANDLE
*HandleBuffer
;
1124 EFI_GUID
**ProtocolGuidArray
;
1126 UINTN ProtocolIndex
;
1127 EFI_OPEN_PROTOCOL_INFORMATION_ENTRY
*OpenInfo
;
1128 UINTN OpenInfoCount
;
1129 UINTN OpenInfoIndex
;
1131 if (Image
->Ebc
!= NULL
) {
1133 // If EBC protocol exists we must perform cleanups for this image.
1135 Image
->Ebc
->UnloadImage (Image
->Ebc
, Image
->Handle
);
1139 // Unload image, free Image->ImageContext->ModHandle
1141 PeCoffLoaderUnloadImage (&Image
->ImageContext
);
1144 // Free our references to the image handle
1146 if (Image
->Handle
!= NULL
) {
1148 Status
= CoreLocateHandleBuffer (
1155 if (!EFI_ERROR (Status
)) {
1156 for (HandleIndex
= 0; HandleIndex
< HandleCount
; HandleIndex
++) {
1157 Status
= CoreProtocolsPerHandle (
1158 HandleBuffer
[HandleIndex
],
1162 if (!EFI_ERROR (Status
)) {
1163 for (ProtocolIndex
= 0; ProtocolIndex
< ArrayCount
; ProtocolIndex
++) {
1164 Status
= CoreOpenProtocolInformation (
1165 HandleBuffer
[HandleIndex
],
1166 ProtocolGuidArray
[ProtocolIndex
],
1170 if (!EFI_ERROR (Status
)) {
1171 for (OpenInfoIndex
= 0; OpenInfoIndex
< OpenInfoCount
; OpenInfoIndex
++) {
1172 if (OpenInfo
[OpenInfoIndex
].AgentHandle
== Image
->Handle
) {
1173 Status
= CoreCloseProtocol (
1174 HandleBuffer
[HandleIndex
],
1175 ProtocolGuidArray
[ProtocolIndex
],
1177 OpenInfo
[OpenInfoIndex
].ControllerHandle
1181 if (OpenInfo
!= NULL
) {
1182 CoreFreePool(OpenInfo
);
1186 if (ProtocolGuidArray
!= NULL
) {
1187 CoreFreePool(ProtocolGuidArray
);
1191 if (HandleBuffer
!= NULL
) {
1192 CoreFreePool (HandleBuffer
);
1196 CoreRemoveDebugImageInfoEntry (Image
->Handle
);
1198 Status
= CoreUninstallProtocolInterface (
1200 &gEfiLoadedImageDevicePathProtocolGuid
,
1201 Image
->LoadedImageDevicePath
1204 Status
= CoreUninstallProtocolInterface (
1206 &gEfiLoadedImageProtocolGuid
,
1212 if (Image
->RuntimeData
!= NULL
) {
1213 if (Image
->RuntimeData
->Link
.ForwardLink
!= NULL
) {
1215 // Remove the Image from the Runtime Image list as we are about to Free it!
1217 RemoveEntryList (&Image
->RuntimeData
->Link
);
1219 CoreFreePool (Image
->RuntimeData
);
1223 // Free the Image from memory
1225 if ((Image
->ImageBasePage
!= 0) && FreePage
) {
1226 CoreFreePages (Image
->ImageBasePage
, Image
->NumberOfPages
);
1230 // Done with the Image structure
1232 if (Image
->Info
.FilePath
!= NULL
) {
1233 CoreFreePool (Image
->Info
.FilePath
);
1236 if (Image
->LoadedImageDevicePath
!= NULL
) {
1237 CoreFreePool (Image
->LoadedImageDevicePath
);
1240 if (Image
->FixupData
!= NULL
) {
1241 CoreFreePool (Image
->FixupData
);
1244 CoreFreePool (Image
);
1251 Terminates the currently loaded EFI image and returns control to boot services.
1253 @param ImageHandle Handle that identifies the image. This
1254 parameter is passed to the image on entry.
1255 @param Status The image's exit code.
1256 @param ExitDataSize The size, in bytes, of ExitData. Ignored if
1257 ExitStatus is EFI_SUCCESS.
1258 @param ExitData Pointer to a data buffer that includes a
1259 Null-terminated Unicode string, optionally
1260 followed by additional binary data. The string
1261 is a description that the caller may use to
1262 further indicate the reason for the image's
1265 @retval EFI_INVALID_PARAMETER Image handle is NULL or it is not current
1267 @retval EFI_SUCCESS Successfully terminates the currently loaded
1269 @retval EFI_ACCESS_DENIED Should never reach there.
1270 @retval EFI_OUT_OF_RESOURCES Could not allocate pool
1276 IN EFI_HANDLE ImageHandle
,
1277 IN EFI_STATUS Status
,
1278 IN UINTN ExitDataSize
,
1279 IN CHAR16
*ExitData OPTIONAL
1282 LOADED_IMAGE_PRIVATE_DATA
*Image
;
1286 // Prevent possible reentrance to this function
1287 // for the same ImageHandle
1289 OldTpl
= CoreRaiseTpl (TPL_NOTIFY
);
1291 Image
= CoreLoadedImageInfo (ImageHandle
);
1292 if (Image
== NULL
) {
1293 Status
= EFI_INVALID_PARAMETER
;
1297 if (!Image
->Started
) {
1299 // The image has not been started so just free its resources
1301 CoreUnloadAndCloseImage (Image
, TRUE
);
1302 Status
= EFI_SUCCESS
;
1307 // Image has been started, verify this image can exit
1309 if (Image
!= mCurrentImage
) {
1310 DEBUG ((DEBUG_LOAD
|DEBUG_ERROR
, "Exit: Image is not exitable image\n"));
1311 Status
= EFI_INVALID_PARAMETER
;
1318 Image
->Status
= Status
;
1321 // If there's ExitData info, move it
1323 if (ExitData
!= NULL
) {
1324 Image
->ExitDataSize
= ExitDataSize
;
1325 Image
->ExitData
= AllocatePool (Image
->ExitDataSize
);
1326 if (Image
->ExitData
== NULL
) {
1327 Status
= EFI_OUT_OF_RESOURCES
;
1330 CopyMem (Image
->ExitData
, ExitData
, Image
->ExitDataSize
);
1333 CoreRestoreTpl (OldTpl
);
1335 // return to StartImage
1337 LongJump (Image
->JumpContext
, (UINTN
)-1);
1340 // If we return from LongJump, then it is an error
1343 Status
= EFI_ACCESS_DENIED
;
1345 CoreRestoreTpl (OldTpl
);
1355 @param ImageHandle Handle that identifies the image to be
1358 @retval EFI_SUCCESS The image has been unloaded.
1359 @retval EFI_UNSUPPORTED The image has been sarted, and does not support
1361 @retval EFI_INVALID_PARAMPETER ImageHandle is not a valid image handle.
1367 IN EFI_HANDLE ImageHandle
1371 LOADED_IMAGE_PRIVATE_DATA
*Image
;
1374 // Prevent possible reentrance to this function
1375 // for the same ImageHandle
1377 if (!AcquireSpinLockOrFail (&mUnloadImageLock
)) {
1378 return EFI_UNSUPPORTED
;
1381 Image
= CoreLoadedImageInfo (ImageHandle
);
1382 if (Image
== NULL
) {
1384 // The image handle is not valid
1386 Status
= EFI_INVALID_PARAMETER
;
1390 if (Image
->Started
) {
1392 // The image has been started, request it to unload.
1394 Status
= EFI_UNSUPPORTED
;
1395 if (Image
->Info
.Unload
!= NULL
) {
1396 Status
= Image
->Info
.Unload (ImageHandle
);
1401 // This Image hasn't been started, thus it can be unloaded
1403 Status
= EFI_SUCCESS
;
1407 if (!EFI_ERROR (Status
)) {
1409 // if the Image was not started or Unloaded O.K. then clean up
1411 CoreUnloadAndCloseImage (Image
, TRUE
);
1415 ReleaseSpinLock (&mUnloadImageLock
);
1422 Unload the specified image.
1424 @param This Indicates the calling context.
1425 @param ImageHandle The specified image handle.
1427 @retval EFI_INVALID_PARAMETER Image handle is NULL.
1428 @retval EFI_UNSUPPORTED Attempt to unload an unsupported image.
1429 @retval EFI_SUCCESS Image successfully unloaded.
1435 IN EFI_PE32_IMAGE_PROTOCOL
*This
,
1436 IN EFI_HANDLE ImageHandle
1439 return CoreUnloadImage (ImageHandle
);