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.
18 #define EFI_LOAD_PE_IMAGE_ATTRIBUTE_NONE 0x00
19 #define EFI_LOAD_PE_IMAGE_ATTRIBUTE_RUNTIME_REGISTRATION 0x01
20 #define EFI_LOAD_PE_IMAGE_ATTRIBUTE_DEBUG_IMAGE_INFO_TABLE_REGISTRATION 0x02
25 LOADED_IMAGE_PRIVATE_DATA
*mCurrentImage
= NULL
;
29 // This code is needed to build the Image handle for the DXE Core
31 LOADED_IMAGE_PRIVATE_DATA mCorePrivateImage
= {
32 LOADED_IMAGE_PRIVATE_DATA_SIGNATURE
, // Signature
34 EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER
, // Image type
35 TRUE
, // If entrypoint has been called
38 EFI_LOADED_IMAGE_INFORMATION_REVISION
, // Revision
39 NULL
, // Parent handle
40 NULL
, // System handle
42 NULL
, // Device handle
51 EfiBootServicesCode
, // ImageCodeType
52 EfiBootServicesData
// ImageDataType
54 (EFI_PHYSICAL_ADDRESS
)0, // ImageBasePage
58 EFI_SUCCESS
, // Status
66 NULL
// LoadedImageDevicePath
72 Add the Image Services to EFI Boot Services Table and install the protocol
73 interfaces for this image.
75 @param HobStart The HOB to initialize
81 CoreInitializeImageServices (
86 LOADED_IMAGE_PRIVATE_DATA
*Image
;
87 EFI_PHYSICAL_ADDRESS DxeCoreImageBaseAddress
;
88 UINT64 DxeCoreImageLength
;
89 VOID
*DxeCoreEntryPoint
;
90 EFI_PEI_HOB_POINTERS DxeCoreHob
;
92 // Searching for image hob
94 DxeCoreHob
.Raw
= HobStart
;
95 while ((DxeCoreHob
.Raw
= GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION
, DxeCoreHob
.Raw
)) != NULL
) {
96 if (CompareGuid (&DxeCoreHob
.MemoryAllocationModule
->MemoryAllocationHeader
.Name
, &gEfiHobMemoryAllocModuleGuid
)) {
102 DxeCoreHob
.Raw
= GET_NEXT_HOB (DxeCoreHob
);
104 ASSERT (DxeCoreHob
.Raw
!= NULL
);
106 DxeCoreImageBaseAddress
= DxeCoreHob
.MemoryAllocationModule
->MemoryAllocationHeader
.MemoryBaseAddress
;
107 DxeCoreImageLength
= DxeCoreHob
.MemoryAllocationModule
->MemoryAllocationHeader
.MemoryLength
;
108 DxeCoreEntryPoint
= (VOID
*) (UINTN
) DxeCoreHob
.MemoryAllocationModule
->EntryPoint
;
109 gDxeCoreFileName
= &DxeCoreHob
.MemoryAllocationModule
->ModuleName
;
111 // Initialize the fields for an internal driver
113 Image
= &mCorePrivateImage
;
115 Image
->EntryPoint
= (EFI_IMAGE_ENTRY_POINT
)(UINTN
)DxeCoreEntryPoint
;
116 Image
->ImageBasePage
= DxeCoreImageBaseAddress
;
117 Image
->NumberOfPages
= (UINTN
)(EFI_SIZE_TO_PAGES((UINTN
)(DxeCoreImageLength
)));
118 Image
->Tpl
= gEfiCurrentTpl
;
119 Image
->Info
.SystemTable
= gDxeCoreST
;
120 Image
->Info
.ImageBase
= (VOID
*)(UINTN
)DxeCoreImageBaseAddress
;
121 Image
->Info
.ImageSize
= DxeCoreImageLength
;
124 // Install the protocol interfaces for this image
126 Status
= CoreInstallProtocolInterface (
128 &gEfiLoadedImageProtocolGuid
,
129 EFI_NATIVE_INTERFACE
,
132 ASSERT_EFI_ERROR (Status
);
134 mCurrentImage
= Image
;
137 // Fill in DXE globals
139 gDxeCoreImageHandle
= Image
->Handle
;
140 gDxeCoreLoadedImage
= &Image
->Info
;
143 // Export DXE Core PE Loader functionality
150 Loads, relocates, and invokes a PE/COFF image
152 @param BootPolicy If TRUE, indicates that the request originates
153 from the boot manager, and that the boot
154 manager is attempting to load FilePath as a
156 @param Pe32Handle The handle of PE32 image
157 @param Image PE image to be loaded
158 @param DstBuffer The buffer to store the image
159 @param EntryPoint A pointer to the entry point
160 @param Attribute The bit mask of attributes to set for the load
163 @retval EFI_SUCCESS The file was loaded, relocated, and invoked
164 @retval EFI_OUT_OF_RESOURCES There was not enough memory to load and
165 relocate the PE/COFF file
166 @retval EFI_INVALID_PARAMETER Invalid parameter
167 @retval EFI_BUFFER_TOO_SMALL Buffer for image is too small
172 IN BOOLEAN BootPolicy
,
174 IN LOADED_IMAGE_PRIVATE_DATA
*Image
,
175 IN EFI_PHYSICAL_ADDRESS DstBuffer OPTIONAL
,
176 OUT EFI_PHYSICAL_ADDRESS
*EntryPoint OPTIONAL
,
181 BOOLEAN DstBufAlocated
;
184 ZeroMem (&Image
->ImageContext
, sizeof (Image
->ImageContext
));
186 Image
->ImageContext
.Handle
= Pe32Handle
;
187 Image
->ImageContext
.ImageRead
= (PE_COFF_LOADER_READ_FILE
)CoreReadImageFile
;
190 // Get information about the image being loaded
192 Status
= PeCoffLoaderGetImageInfo (&Image
->ImageContext
);
193 if (EFI_ERROR (Status
)) {
197 if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Image
->ImageContext
.Machine
)) {
198 if (!EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED (Image
->ImageContext
.Machine
)) {
200 // The PE/COFF loader can support loading image types that can be executed.
201 // If we loaded an image type that we can not execute return EFI_UNSUPORTED.
203 return EFI_UNSUPPORTED
;
208 // Set EFI memory type based on ImageType
210 switch (Image
->ImageContext
.ImageType
) {
211 case EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION
:
212 Image
->ImageContext
.ImageCodeMemoryType
= EfiLoaderCode
;
213 Image
->ImageContext
.ImageDataMemoryType
= EfiLoaderData
;
215 case EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER
:
216 Image
->ImageContext
.ImageCodeMemoryType
= EfiBootServicesCode
;
217 Image
->ImageContext
.ImageDataMemoryType
= EfiBootServicesData
;
219 case EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
:
220 case EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER
:
221 Image
->ImageContext
.ImageCodeMemoryType
= EfiRuntimeServicesCode
;
222 Image
->ImageContext
.ImageDataMemoryType
= EfiRuntimeServicesData
;
225 Image
->ImageContext
.ImageError
= IMAGE_ERROR_INVALID_SUBSYSTEM
;
226 return EFI_UNSUPPORTED
;
230 // Allocate memory of the correct memory type aligned on the required image boundry
232 DstBufAlocated
= FALSE
;
233 if (DstBuffer
== 0) {
235 // Allocate Destination Buffer as caller did not pass it in
238 if (Image
->ImageContext
.SectionAlignment
> EFI_PAGE_SIZE
) {
239 Size
= (UINTN
)Image
->ImageContext
.ImageSize
+ Image
->ImageContext
.SectionAlignment
;
241 Size
= (UINTN
)Image
->ImageContext
.ImageSize
;
244 Image
->NumberOfPages
= EFI_SIZE_TO_PAGES (Size
);
247 // If the image relocations have not been stripped, then load at any address.
248 // Otherwise load at the address at which it was linked.
250 // Memory below 1MB should be treated reserved for CSM and there should be
251 // no modules whose preferred load addresses are below 1MB.
253 Status
= EFI_OUT_OF_RESOURCES
;
254 if (Image
->ImageContext
.ImageAddress
>= 0x100000 || Image
->ImageContext
.RelocationsStripped
) {
255 Status
= CoreAllocatePages (
257 (EFI_MEMORY_TYPE
) (Image
->ImageContext
.ImageCodeMemoryType
),
258 Image
->NumberOfPages
,
259 &Image
->ImageContext
.ImageAddress
262 if (EFI_ERROR (Status
) && !Image
->ImageContext
.RelocationsStripped
) {
263 Status
= CoreAllocatePages (
265 (EFI_MEMORY_TYPE
) (Image
->ImageContext
.ImageCodeMemoryType
),
266 Image
->NumberOfPages
,
267 &Image
->ImageContext
.ImageAddress
270 if (EFI_ERROR (Status
)) {
273 DstBufAlocated
= TRUE
;
276 // Caller provided the destination buffer
279 if (Image
->ImageContext
.RelocationsStripped
&& (Image
->ImageContext
.ImageAddress
!= DstBuffer
)) {
281 // If the image relocations were stripped, and the caller provided a
282 // destination buffer address that does not match the address that the
283 // image is linked at, then the image cannot be loaded.
285 return EFI_INVALID_PARAMETER
;
288 if (Image
->NumberOfPages
!= 0 &&
289 Image
->NumberOfPages
<
290 (EFI_SIZE_TO_PAGES ((UINTN
)Image
->ImageContext
.ImageSize
+ Image
->ImageContext
.SectionAlignment
))) {
291 Image
->NumberOfPages
= EFI_SIZE_TO_PAGES ((UINTN
)Image
->ImageContext
.ImageSize
+ Image
->ImageContext
.SectionAlignment
);
292 return EFI_BUFFER_TOO_SMALL
;
295 Image
->NumberOfPages
= EFI_SIZE_TO_PAGES ((UINTN
)Image
->ImageContext
.ImageSize
+ Image
->ImageContext
.SectionAlignment
);
296 Image
->ImageContext
.ImageAddress
= DstBuffer
;
299 Image
->ImageBasePage
= Image
->ImageContext
.ImageAddress
;
300 if (!Image
->ImageContext
.IsTeImage
) {
301 Image
->ImageContext
.ImageAddress
=
302 (Image
->ImageContext
.ImageAddress
+ Image
->ImageContext
.SectionAlignment
- 1) &
303 ~((UINTN
)Image
->ImageContext
.SectionAlignment
- 1);
307 // Load the image from the file into the allocated memory
309 Status
= PeCoffLoaderLoadImage (&Image
->ImageContext
);
310 if (EFI_ERROR (Status
)) {
315 // If this is a Runtime Driver, then allocate memory for the FixupData that
316 // is used to relocate the image when SetVirtualAddressMap() is called. The
317 // relocation is done by the Runtime AP.
319 if ((Attribute
& EFI_LOAD_PE_IMAGE_ATTRIBUTE_RUNTIME_REGISTRATION
) != 0) {
320 if (Image
->ImageContext
.ImageType
== EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
) {
321 Image
->ImageContext
.FixupData
= AllocateRuntimePool ((UINTN
)(Image
->ImageContext
.FixupDataSize
));
322 if (Image
->ImageContext
.FixupData
== NULL
) {
323 Status
= EFI_OUT_OF_RESOURCES
;
330 // Relocate the image in memory
332 Status
= PeCoffLoaderRelocateImage (&Image
->ImageContext
);
333 if (EFI_ERROR (Status
)) {
338 // Flush the Instruction Cache
340 InvalidateInstructionCacheRange ((VOID
*)(UINTN
)Image
->ImageContext
.ImageAddress
, (UINTN
)Image
->ImageContext
.ImageSize
);
343 // Copy the machine type from the context to the image private data. This
344 // is needed during image unload to know if we should call an EBC protocol
345 // to unload the image.
347 Image
->Machine
= Image
->ImageContext
.Machine
;
350 // Get the image entry point. If it's an EBC image, then call into the
351 // interpreter to create a thunk for the entry point and use the returned
352 // value for the entry point.
354 Image
->EntryPoint
= (EFI_IMAGE_ENTRY_POINT
)(UINTN
)Image
->ImageContext
.EntryPoint
;
355 if (Image
->ImageContext
.Machine
== EFI_IMAGE_MACHINE_EBC
) {
357 // Locate the EBC interpreter protocol
359 Status
= CoreLocateProtocol (&gEfiEbcProtocolGuid
, NULL
, (VOID
**)&Image
->Ebc
);
360 if (EFI_ERROR(Status
)) {
361 DEBUG ((DEBUG_LOAD
| DEBUG_ERROR
, "CoreLoadPeImage: There is no EBC interpreter for an EBC image.\n"));
366 // Register a callback for flushing the instruction cache so that created
367 // thunks can be flushed.
369 Status
= Image
->Ebc
->RegisterICacheFlush (Image
->Ebc
, (EBC_ICACHE_FLUSH
)InvalidateInstructionCacheRange
);
370 if (EFI_ERROR(Status
)) {
375 // Create a thunk for the image's entry point. This will be the new
376 // entry point for the image.
378 Status
= Image
->Ebc
->CreateThunk (
381 (VOID
*)(UINTN
) Image
->ImageContext
.EntryPoint
,
382 (VOID
**) &Image
->EntryPoint
384 if (EFI_ERROR(Status
)) {
390 // Fill in the image information for the Loaded Image Protocol
392 Image
->Type
= Image
->ImageContext
.ImageType
;
393 Image
->Info
.ImageBase
= (VOID
*)(UINTN
)Image
->ImageContext
.ImageAddress
;
394 Image
->Info
.ImageSize
= Image
->ImageContext
.ImageSize
;
395 Image
->Info
.ImageCodeType
= (EFI_MEMORY_TYPE
) (Image
->ImageContext
.ImageCodeMemoryType
);
396 Image
->Info
.ImageDataType
= (EFI_MEMORY_TYPE
) (Image
->ImageContext
.ImageDataMemoryType
);
397 if ((Attribute
& EFI_LOAD_PE_IMAGE_ATTRIBUTE_RUNTIME_REGISTRATION
) != 0) {
398 if (Image
->ImageContext
.ImageType
== EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
) {
400 // Make a list off all the RT images so we can let the RT AP know about them.
402 Image
->RuntimeData
= AllocateRuntimePool (sizeof(EFI_RUNTIME_IMAGE_ENTRY
));
403 if (Image
->RuntimeData
== NULL
) {
406 Image
->RuntimeData
->ImageBase
= Image
->Info
.ImageBase
;
407 Image
->RuntimeData
->ImageSize
= (UINT64
) (Image
->Info
.ImageSize
);
408 Image
->RuntimeData
->RelocationData
= Image
->ImageContext
.FixupData
;
409 Image
->RuntimeData
->Handle
= Image
->Handle
;
410 InsertTailList (&gRuntime
->ImageHead
, &Image
->RuntimeData
->Link
);
415 // Fill in the entry point of the image if it is available
417 if (EntryPoint
!= NULL
) {
418 *EntryPoint
= Image
->ImageContext
.EntryPoint
;
422 // Print the load address and the PDB file name if it is available
429 CHAR8 EfiFileName
[256];
432 DEBUG ((DEBUG_INFO
| DEBUG_LOAD
,
433 "Loading driver at 0x%11p EntryPoint=0x%11p ",
434 (VOID
*)(UINTN
) Image
->ImageContext
.ImageAddress
,
435 FUNCTION_ENTRY_POINT (Image
->ImageContext
.EntryPoint
)));
439 // Print Module Name by Pdb file path.
440 // Windows and Unix style file path are all trimmed correctly.
442 if (Image
->ImageContext
.PdbPointer
!= NULL
) {
444 for (Index
= 0; Image
->ImageContext
.PdbPointer
[Index
] != 0; Index
++) {
445 if ((Image
->ImageContext
.PdbPointer
[Index
] == '\\') || (Image
->ImageContext
.PdbPointer
[Index
] == '/')) {
446 StartIndex
= Index
+ 1;
450 // Copy the PDB file name to our temporary string, and replace .pdb with .efi
451 // The PDB file name is limited in the range of 0~255.
452 // If the length is bigger than 255, trim the redudant characters to avoid overflow in array boundary.
454 for (Index
= 0; Index
< sizeof (EfiFileName
) - 4; Index
++) {
455 EfiFileName
[Index
] = Image
->ImageContext
.PdbPointer
[Index
+ StartIndex
];
456 if (EfiFileName
[Index
] == 0) {
457 EfiFileName
[Index
] = '.';
459 if (EfiFileName
[Index
] == '.') {
460 EfiFileName
[Index
+ 1] = 'e';
461 EfiFileName
[Index
+ 2] = 'f';
462 EfiFileName
[Index
+ 3] = 'i';
463 EfiFileName
[Index
+ 4] = 0;
468 if (Index
== sizeof (EfiFileName
) - 4) {
469 EfiFileName
[Index
] = 0;
471 DEBUG ((DEBUG_INFO
| DEBUG_LOAD
, "%a", EfiFileName
)); // &Image->ImageContext.PdbPointer[StartIndex]));
473 DEBUG ((DEBUG_INFO
| DEBUG_LOAD
, "\n"));
485 if (DstBufAlocated
) {
486 CoreFreePages (Image
->ImageContext
.ImageAddress
, Image
->NumberOfPages
);
489 if (Image
->ImageContext
.FixupData
!= NULL
) {
490 CoreFreePool (Image
->ImageContext
.FixupData
);
499 Get the image's private data from its handle.
501 @param ImageHandle The image handle
503 @return Return the image private data associated with ImageHandle.
506 LOADED_IMAGE_PRIVATE_DATA
*
507 CoreLoadedImageInfo (
508 IN EFI_HANDLE ImageHandle
512 EFI_LOADED_IMAGE_PROTOCOL
*LoadedImage
;
513 LOADED_IMAGE_PRIVATE_DATA
*Image
;
515 Status
= CoreHandleProtocol (
517 &gEfiLoadedImageProtocolGuid
,
518 (VOID
**)&LoadedImage
520 if (!EFI_ERROR (Status
)) {
521 Image
= LOADED_IMAGE_PRIVATE_DATA_FROM_THIS (LoadedImage
);
523 DEBUG ((DEBUG_LOAD
, "CoreLoadedImageInfo: Not an ImageHandle %p\n", ImageHandle
));
532 Unloads EFI image from memory.
534 @param Image EFI image
535 @param FreePage Free allocated pages
539 CoreUnloadAndCloseImage (
540 IN LOADED_IMAGE_PRIVATE_DATA
*Image
,
546 EFI_HANDLE
*HandleBuffer
;
548 EFI_GUID
**ProtocolGuidArray
;
551 EFI_OPEN_PROTOCOL_INFORMATION_ENTRY
*OpenInfo
;
555 if (Image
->Ebc
!= NULL
) {
557 // If EBC protocol exists we must perform cleanups for this image.
559 Image
->Ebc
->UnloadImage (Image
->Ebc
, Image
->Handle
);
563 // Unload image, free Image->ImageContext->ModHandle
565 PeCoffLoaderUnloadImage (&Image
->ImageContext
);
568 // Free our references to the image handle
570 if (Image
->Handle
!= NULL
) {
572 Status
= CoreLocateHandleBuffer (
579 if (!EFI_ERROR (Status
)) {
580 for (HandleIndex
= 0; HandleIndex
< HandleCount
; HandleIndex
++) {
581 Status
= CoreProtocolsPerHandle (
582 HandleBuffer
[HandleIndex
],
586 if (!EFI_ERROR (Status
)) {
587 for (ProtocolIndex
= 0; ProtocolIndex
< ArrayCount
; ProtocolIndex
++) {
588 Status
= CoreOpenProtocolInformation (
589 HandleBuffer
[HandleIndex
],
590 ProtocolGuidArray
[ProtocolIndex
],
594 if (!EFI_ERROR (Status
)) {
595 for (OpenInfoIndex
= 0; OpenInfoIndex
< OpenInfoCount
; OpenInfoIndex
++) {
596 if (OpenInfo
[OpenInfoIndex
].AgentHandle
== Image
->Handle
) {
597 Status
= CoreCloseProtocol (
598 HandleBuffer
[HandleIndex
],
599 ProtocolGuidArray
[ProtocolIndex
],
601 OpenInfo
[OpenInfoIndex
].ControllerHandle
605 if (OpenInfo
!= NULL
) {
606 CoreFreePool(OpenInfo
);
610 if (ProtocolGuidArray
!= NULL
) {
611 CoreFreePool(ProtocolGuidArray
);
615 if (HandleBuffer
!= NULL
) {
616 CoreFreePool (HandleBuffer
);
620 CoreRemoveDebugImageInfoEntry (Image
->Handle
);
622 Status
= CoreUninstallProtocolInterface (
624 &gEfiLoadedImageDevicePathProtocolGuid
,
625 Image
->LoadedImageDevicePath
628 Status
= CoreUninstallProtocolInterface (
630 &gEfiLoadedImageProtocolGuid
,
636 if (Image
->RuntimeData
!= NULL
) {
637 if (Image
->RuntimeData
->Link
.ForwardLink
!= NULL
) {
639 // Remove the Image from the Runtime Image list as we are about to Free it!
641 RemoveEntryList (&Image
->RuntimeData
->Link
);
643 CoreFreePool (Image
->RuntimeData
);
647 // Free the Image from memory
649 if ((Image
->ImageBasePage
!= 0) && FreePage
) {
650 CoreFreePages (Image
->ImageBasePage
, Image
->NumberOfPages
);
654 // Done with the Image structure
656 if (Image
->Info
.FilePath
!= NULL
) {
657 CoreFreePool (Image
->Info
.FilePath
);
660 if (Image
->LoadedImageDevicePath
!= NULL
) {
661 CoreFreePool (Image
->LoadedImageDevicePath
);
664 if (Image
->FixupData
!= NULL
) {
665 CoreFreePool (Image
->FixupData
);
668 CoreFreePool (Image
);
673 Loads an EFI image into memory and returns a handle to the image.
675 @param BootPolicy If TRUE, indicates that the request originates
676 from the boot manager, and that the boot
677 manager is attempting to load FilePath as a
679 @param ParentImageHandle The caller's image handle.
680 @param FilePath The specific file path from which the image is
682 @param SourceBuffer If not NULL, a pointer to the memory location
683 containing a copy of the image to be loaded.
684 @param SourceSize The size in bytes of SourceBuffer.
685 @param DstBuffer The buffer to store the image
686 @param NumberOfPages If not NULL, it inputs a pointer to the page
687 number of DstBuffer and outputs a pointer to
688 the page number of the image. If this number is
689 not enough, return EFI_BUFFER_TOO_SMALL and
690 this parameter contains the required number.
691 @param ImageHandle Pointer to the returned image handle that is
692 created when the image is successfully loaded.
693 @param EntryPoint A pointer to the entry point
694 @param Attribute The bit mask of attributes to set for the load
697 @retval EFI_SUCCESS The image was loaded into memory.
698 @retval EFI_NOT_FOUND The FilePath was not found.
699 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
700 @retval EFI_BUFFER_TOO_SMALL The buffer is too small
701 @retval EFI_UNSUPPORTED The image type is not supported, or the device
702 path cannot be parsed to locate the proper
703 protocol for loading the file.
704 @retval EFI_OUT_OF_RESOURCES Image was not loaded due to insufficient
709 CoreLoadImageCommon (
710 IN BOOLEAN BootPolicy
,
711 IN EFI_HANDLE ParentImageHandle
,
712 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
713 IN VOID
*SourceBuffer OPTIONAL
,
715 IN EFI_PHYSICAL_ADDRESS DstBuffer OPTIONAL
,
716 IN OUT UINTN
*NumberOfPages OPTIONAL
,
717 OUT EFI_HANDLE
*ImageHandle
,
718 OUT EFI_PHYSICAL_ADDRESS
*EntryPoint OPTIONAL
,
722 LOADED_IMAGE_PRIVATE_DATA
*Image
;
723 LOADED_IMAGE_PRIVATE_DATA
*ParentImage
;
724 IMAGE_FILE_HANDLE FHand
;
726 EFI_STATUS SecurityStatus
;
727 EFI_HANDLE DeviceHandle
;
728 UINT32 AuthenticationStatus
;
729 EFI_DEVICE_PATH_PROTOCOL
*OriginalFilePath
;
730 EFI_DEVICE_PATH_PROTOCOL
*HandleFilePath
;
733 SecurityStatus
= EFI_SUCCESS
;
735 ASSERT (gEfiCurrentTpl
< TPL_NOTIFY
);
739 // The caller must pass in a valid ParentImageHandle
741 if (ImageHandle
== NULL
|| ParentImageHandle
== NULL
) {
742 return EFI_INVALID_PARAMETER
;
745 ParentImage
= CoreLoadedImageInfo (ParentImageHandle
);
746 if (ParentImage
== NULL
) {
747 DEBUG((DEBUG_LOAD
|DEBUG_ERROR
, "LoadImageEx: Parent handle not an image handle\n"));
748 return EFI_INVALID_PARAMETER
;
752 // Get simple read access to the source file
754 OriginalFilePath
= FilePath
;
755 Status
= CoreOpenImageFile (
762 &AuthenticationStatus
764 if (Status
== EFI_ALREADY_STARTED
) {
767 } else if (EFI_ERROR (Status
)) {
772 // Verify the Authentication Status through the Security Architectural Protocol
774 if ((gSecurity
!= NULL
) && (OriginalFilePath
!= NULL
)) {
775 SecurityStatus
= gSecurity
->FileAuthenticationState (
777 AuthenticationStatus
,
780 if (EFI_ERROR (SecurityStatus
) && SecurityStatus
!= EFI_SECURITY_VIOLATION
) {
781 Status
= SecurityStatus
;
789 // Allocate a new image structure
791 Image
= AllocateZeroPool (sizeof(LOADED_IMAGE_PRIVATE_DATA
));
793 return EFI_OUT_OF_RESOURCES
;
797 // Pull out just the file portion of the DevicePath for the LoadedImage FilePath
799 FilePath
= OriginalFilePath
;
800 Status
= CoreHandleProtocol (DeviceHandle
, &gEfiDevicePathProtocolGuid
, (VOID
**)&HandleFilePath
);
801 if (!EFI_ERROR (Status
)) {
802 FilePathSize
= GetDevicePathSize (HandleFilePath
) - sizeof(EFI_DEVICE_PATH_PROTOCOL
);
803 FilePath
= (EFI_DEVICE_PATH_PROTOCOL
*) (((UINT8
*)FilePath
) + FilePathSize
);
807 // Initialize the fields for an internal driver
809 Image
->Signature
= LOADED_IMAGE_PRIVATE_DATA_SIGNATURE
;
810 Image
->Info
.SystemTable
= gDxeCoreST
;
811 Image
->Info
.DeviceHandle
= DeviceHandle
;
812 Image
->Info
.Revision
= EFI_LOADED_IMAGE_PROTOCOL_REVISION
;
813 Image
->Info
.FilePath
= DuplicateDevicePath (FilePath
);
814 Image
->Info
.ParentHandle
= ParentImageHandle
;
817 if (NumberOfPages
!= NULL
) {
818 Image
->NumberOfPages
= *NumberOfPages
;
820 Image
->NumberOfPages
= 0 ;
824 // Install the protocol interfaces for this image
825 // don't fire notifications yet
827 Status
= CoreInstallProtocolInterfaceNotify (
829 &gEfiLoadedImageProtocolGuid
,
830 EFI_NATIVE_INTERFACE
,
834 if (EFI_ERROR (Status
)) {
839 // Load the image. If EntryPoint is Null, it will not be set.
841 Status
= CoreLoadPeImage (BootPolicy
, &FHand
, Image
, DstBuffer
, EntryPoint
, Attribute
);
842 if (EFI_ERROR (Status
)) {
843 if ((Status
== EFI_BUFFER_TOO_SMALL
) || (Status
== EFI_OUT_OF_RESOURCES
)) {
844 if (NumberOfPages
!= NULL
) {
845 *NumberOfPages
= Image
->NumberOfPages
;
851 if (NumberOfPages
!= NULL
) {
852 *NumberOfPages
= Image
->NumberOfPages
;
856 // Register the image in the Debug Image Info Table if the attribute is set
858 if ((Attribute
& EFI_LOAD_PE_IMAGE_ATTRIBUTE_DEBUG_IMAGE_INFO_TABLE_REGISTRATION
) != 0) {
859 CoreNewDebugImageInfoEntry (EFI_DEBUG_IMAGE_INFO_TYPE_NORMAL
, &Image
->Info
, Image
->Handle
);
863 //Reinstall loaded image protocol to fire any notifications
865 Status
= CoreReinstallProtocolInterface (
867 &gEfiLoadedImageProtocolGuid
,
871 if (EFI_ERROR (Status
)) {
876 // If DevicePath parameter to the LoadImage() is not NULL, then make a copy of DevicePath,
877 // otherwise Loaded Image Device Path Protocol is installed with a NULL interface pointer.
879 if (OriginalFilePath
!= NULL
) {
880 Image
->LoadedImageDevicePath
= DuplicateDevicePath (OriginalFilePath
);
884 // Install Loaded Image Device Path Protocol onto the image handle of a PE/COFE image
886 Status
= CoreInstallProtocolInterface (
888 &gEfiLoadedImageDevicePathProtocolGuid
,
889 EFI_NATIVE_INTERFACE
,
890 Image
->LoadedImageDevicePath
892 if (EFI_ERROR (Status
)) {
897 // Success. Return the image handle
899 *ImageHandle
= Image
->Handle
;
903 // All done accessing the source file
904 // If we allocated the Source buffer, free it
906 if (FHand
.FreeBuffer
) {
907 CoreFreePool (FHand
.Source
);
911 // There was an error. If there's an Image structure, free it
913 if (EFI_ERROR (Status
)) {
915 CoreUnloadAndCloseImage (Image
, (BOOLEAN
)(DstBuffer
== 0));
918 } else if (EFI_ERROR (SecurityStatus
)) {
919 Status
= SecurityStatus
;
929 Loads an EFI image into memory and returns a handle to the image.
931 @param BootPolicy If TRUE, indicates that the request originates
932 from the boot manager, and that the boot
933 manager is attempting to load FilePath as a
935 @param ParentImageHandle The caller's image handle.
936 @param FilePath The specific file path from which the image is
938 @param SourceBuffer If not NULL, a pointer to the memory location
939 containing a copy of the image to be loaded.
940 @param SourceSize The size in bytes of SourceBuffer.
941 @param ImageHandle Pointer to the returned image handle that is
942 created when the image is successfully loaded.
944 @retval EFI_SUCCESS The image was loaded into memory.
945 @retval EFI_NOT_FOUND The FilePath was not found.
946 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
947 @retval EFI_UNSUPPORTED The image type is not supported, or the device
948 path cannot be parsed to locate the proper
949 protocol for loading the file.
950 @retval EFI_OUT_OF_RESOURCES Image was not loaded due to insufficient
957 IN BOOLEAN BootPolicy
,
958 IN EFI_HANDLE ParentImageHandle
,
959 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
960 IN VOID
*SourceBuffer OPTIONAL
,
962 OUT EFI_HANDLE
*ImageHandle
970 Tick
= GetPerformanceCounter ();
973 Status
= CoreLoadImageCommon (
979 (EFI_PHYSICAL_ADDRESS
) (UINTN
) NULL
,
983 EFI_LOAD_PE_IMAGE_ATTRIBUTE_RUNTIME_REGISTRATION
| EFI_LOAD_PE_IMAGE_ATTRIBUTE_DEBUG_IMAGE_INFO_TABLE_REGISTRATION
986 PERF_START (*ImageHandle
, "LoadImage:", NULL
, Tick
);
987 PERF_END (*ImageHandle
, "LoadImage:", NULL
, 0);
994 Transfer control to a loaded image's entry point.
996 @param ImageHandle Handle of image to be started.
997 @param ExitDataSize Pointer of the size to ExitData
998 @param ExitData Pointer to a pointer to a data buffer that
999 includes a Null-terminated Unicode string,
1000 optionally followed by additional binary data.
1001 The string is a description that the caller may
1002 use to further indicate the reason for the
1005 @retval EFI_INVALID_PARAMETER Invalid parameter
1006 @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate
1007 @retval EFI_SUCCESS Successfully transfer control to the image's
1014 IN EFI_HANDLE ImageHandle
,
1015 OUT UINTN
*ExitDataSize
,
1016 OUT CHAR16
**ExitData OPTIONAL
1020 LOADED_IMAGE_PRIVATE_DATA
*Image
;
1021 LOADED_IMAGE_PRIVATE_DATA
*LastImage
;
1022 UINT64 HandleDatabaseKey
;
1025 Image
= CoreLoadedImageInfo (ImageHandle
);
1026 if (Image
== NULL
|| Image
->Started
) {
1027 return EFI_INVALID_PARAMETER
;
1031 // Don't profile Objects or invalid start requests
1033 PERF_START (ImageHandle
, "StartImage:", NULL
, 0);
1037 // Push the current start image context, and
1038 // link the current image to the head. This is the
1039 // only image that can call Exit()
1041 HandleDatabaseKey
= CoreGetHandleDatabaseKey ();
1042 LastImage
= mCurrentImage
;
1043 mCurrentImage
= Image
;
1044 Image
->Tpl
= gEfiCurrentTpl
;
1047 // Set long jump for Exit() support
1048 // JumpContext must be aligned on a CPU specific boundary.
1049 // Overallocate the buffer and force the required alignment
1051 Image
->JumpBuffer
= AllocatePool (sizeof (BASE_LIBRARY_JUMP_BUFFER
) + BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT
);
1052 if (Image
->JumpBuffer
== NULL
) {
1053 PERF_END (ImageHandle
, "StartImage:", NULL
, 0);
1054 return EFI_OUT_OF_RESOURCES
;
1056 Image
->JumpContext
= ALIGN_POINTER (Image
->JumpBuffer
, BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT
);
1058 SetJumpFlag
= SetJump (Image
->JumpContext
);
1060 // The initial call to SetJump() must always return 0.
1061 // Subsequent calls to LongJump() cause a non-zero value to be returned by SetJump().
1063 if (SetJumpFlag
== 0) {
1065 // Call the image's entry point
1067 Image
->Started
= TRUE
;
1068 Image
->Status
= Image
->EntryPoint (ImageHandle
, Image
->Info
.SystemTable
);
1071 // Add some debug information if the image returned with error.
1072 // This make the user aware and check if the driver image have already released
1073 // all the resource in this situation.
1075 DEBUG_CODE_BEGIN ();
1076 if (EFI_ERROR (Image
->Status
)) {
1077 DEBUG ((DEBUG_ERROR
, "Error: Image at %11p start failed: %r\n", Image
->Info
.ImageBase
, Image
->Status
));
1082 // If the image returns, exit it through Exit()
1084 CoreExit (ImageHandle
, Image
->Status
, 0, NULL
);
1088 // Image has completed. Verify the tpl is the same
1090 ASSERT (Image
->Tpl
== gEfiCurrentTpl
);
1091 CoreRestoreTpl (Image
->Tpl
);
1093 CoreFreePool (Image
->JumpBuffer
);
1096 // Pop the current start image context
1098 mCurrentImage
= LastImage
;
1101 // Go connect any handles that were created or modified while the image executed.
1103 CoreConnectHandlesByKey (HandleDatabaseKey
);
1106 // Handle the image's returned ExitData
1108 DEBUG_CODE_BEGIN ();
1109 if (Image
->ExitDataSize
!= 0 || Image
->ExitData
!= NULL
) {
1111 DEBUG ((DEBUG_LOAD
, "StartImage: ExitDataSize %d, ExitData %p", (UINT32
)Image
->ExitDataSize
, Image
->ExitData
));
1112 if (Image
->ExitData
!= NULL
) {
1113 DEBUG ((DEBUG_LOAD
, " (%hs)", Image
->ExitData
));
1115 DEBUG ((DEBUG_LOAD
, "\n"));
1120 // Return the exit data to the caller
1122 if (ExitData
!= NULL
&& ExitDataSize
!= NULL
) {
1123 *ExitDataSize
= Image
->ExitDataSize
;
1124 *ExitData
= Image
->ExitData
;
1127 // Caller doesn't want the exit data, free it
1129 CoreFreePool (Image
->ExitData
);
1130 Image
->ExitData
= NULL
;
1134 // Save the Status because Image will get destroyed if it is unloaded.
1136 Status
= Image
->Status
;
1139 // If the image returned an error, or if the image is an application
1142 if (EFI_ERROR (Image
->Status
) || Image
->Type
== EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION
) {
1143 CoreUnloadAndCloseImage (Image
, TRUE
);
1149 PERF_END (ImageHandle
, "StartImage:", NULL
, 0);
1154 Terminates the currently loaded EFI image and returns control to boot services.
1156 @param ImageHandle Handle that identifies the image. This
1157 parameter is passed to the image on entry.
1158 @param Status The image's exit code.
1159 @param ExitDataSize The size, in bytes, of ExitData. Ignored if
1160 ExitStatus is EFI_SUCCESS.
1161 @param ExitData Pointer to a data buffer that includes a
1162 Null-terminated Unicode string, optionally
1163 followed by additional binary data. The string
1164 is a description that the caller may use to
1165 further indicate the reason for the image's
1168 @retval EFI_INVALID_PARAMETER Image handle is NULL or it is not current
1170 @retval EFI_SUCCESS Successfully terminates the currently loaded
1172 @retval EFI_ACCESS_DENIED Should never reach there.
1173 @retval EFI_OUT_OF_RESOURCES Could not allocate pool
1179 IN EFI_HANDLE ImageHandle
,
1180 IN EFI_STATUS Status
,
1181 IN UINTN ExitDataSize
,
1182 IN CHAR16
*ExitData OPTIONAL
1185 LOADED_IMAGE_PRIVATE_DATA
*Image
;
1189 // Prevent possible reentrance to this function
1190 // for the same ImageHandle
1192 OldTpl
= CoreRaiseTpl (TPL_NOTIFY
);
1194 Image
= CoreLoadedImageInfo (ImageHandle
);
1195 if (Image
== NULL
) {
1196 Status
= EFI_INVALID_PARAMETER
;
1200 if (!Image
->Started
) {
1202 // The image has not been started so just free its resources
1204 CoreUnloadAndCloseImage (Image
, TRUE
);
1205 Status
= EFI_SUCCESS
;
1210 // Image has been started, verify this image can exit
1212 if (Image
!= mCurrentImage
) {
1213 DEBUG ((DEBUG_LOAD
|DEBUG_ERROR
, "Exit: Image is not exitable image\n"));
1214 Status
= EFI_INVALID_PARAMETER
;
1221 Image
->Status
= Status
;
1224 // If there's ExitData info, move it
1226 if (ExitData
!= NULL
) {
1227 Image
->ExitDataSize
= ExitDataSize
;
1228 Image
->ExitData
= AllocatePool (Image
->ExitDataSize
);
1229 if (Image
->ExitData
== NULL
) {
1230 Status
= EFI_OUT_OF_RESOURCES
;
1233 CopyMem (Image
->ExitData
, ExitData
, Image
->ExitDataSize
);
1236 CoreRestoreTpl (OldTpl
);
1238 // return to StartImage
1240 LongJump (Image
->JumpContext
, (UINTN
)-1);
1243 // If we return from LongJump, then it is an error
1246 Status
= EFI_ACCESS_DENIED
;
1248 CoreRestoreTpl (OldTpl
);
1258 @param ImageHandle Handle that identifies the image to be
1261 @retval EFI_SUCCESS The image has been unloaded.
1262 @retval EFI_UNSUPPORTED The image has been sarted, and does not support
1264 @retval EFI_INVALID_PARAMPETER ImageHandle is not a valid image handle.
1270 IN EFI_HANDLE ImageHandle
1274 LOADED_IMAGE_PRIVATE_DATA
*Image
;
1276 Image
= CoreLoadedImageInfo (ImageHandle
);
1277 if (Image
== NULL
) {
1279 // The image handle is not valid
1281 Status
= EFI_INVALID_PARAMETER
;
1285 if (Image
->Started
) {
1287 // The image has been started, request it to unload.
1289 Status
= EFI_UNSUPPORTED
;
1290 if (Image
->Info
.Unload
!= NULL
) {
1291 Status
= Image
->Info
.Unload (ImageHandle
);
1296 // This Image hasn't been started, thus it can be unloaded
1298 Status
= EFI_SUCCESS
;
1302 if (!EFI_ERROR (Status
)) {
1304 // if the Image was not started or Unloaded O.K. then clean up
1306 CoreUnloadAndCloseImage (Image
, TRUE
);