2 Core image handling services to load and unload PeImage.
4 Copyright (c) 2006 - 2009, 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.
21 LOADED_IMAGE_PRIVATE_DATA
*mCurrentImage
= NULL
;
23 LOAD_PE32_IMAGE_PRIVATE_DATA mLoadPe32PrivateData
= {
24 LOAD_PE32_IMAGE_PRIVATE_DATA_SIGNATURE
,
34 // This code is needed to build the Image handle for the DXE Core
36 LOADED_IMAGE_PRIVATE_DATA mCorePrivateImage
= {
37 LOADED_IMAGE_PRIVATE_DATA_SIGNATURE
, // Signature
39 EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER
, // Image type
40 TRUE
, // If entrypoint has been called
43 EFI_LOADED_IMAGE_INFORMATION_REVISION
, // Revision
44 NULL
, // Parent handle
45 NULL
, // System handle
47 NULL
, // Device handle
56 EfiBootServicesCode
, // ImageCodeType
57 EfiBootServicesData
// ImageDataType
59 (EFI_PHYSICAL_ADDRESS
)0, // ImageBasePage
63 EFI_SUCCESS
, // Status
71 NULL
// LoadedImageDevicePath
77 Add the Image Services to EFI Boot Services Table and install the protocol
78 interfaces for this image.
80 @param HobStart The HOB to initialize
86 CoreInitializeImageServices (
91 LOADED_IMAGE_PRIVATE_DATA
*Image
;
92 EFI_PHYSICAL_ADDRESS DxeCoreImageBaseAddress
;
93 UINT64 DxeCoreImageLength
;
94 VOID
*DxeCoreEntryPoint
;
95 EFI_PEI_HOB_POINTERS DxeCoreHob
;
97 // Searching for image hob
99 DxeCoreHob
.Raw
= HobStart
;
100 while ((DxeCoreHob
.Raw
= GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION
, DxeCoreHob
.Raw
)) != NULL
) {
101 if (CompareGuid (&DxeCoreHob
.MemoryAllocationModule
->MemoryAllocationHeader
.Name
, &gEfiHobMemoryAllocModuleGuid
)) {
107 DxeCoreHob
.Raw
= GET_NEXT_HOB (DxeCoreHob
);
109 ASSERT (DxeCoreHob
.Raw
!= NULL
);
111 DxeCoreImageBaseAddress
= DxeCoreHob
.MemoryAllocationModule
->MemoryAllocationHeader
.MemoryBaseAddress
;
112 DxeCoreImageLength
= DxeCoreHob
.MemoryAllocationModule
->MemoryAllocationHeader
.MemoryLength
;
113 DxeCoreEntryPoint
= (VOID
*) (UINTN
) DxeCoreHob
.MemoryAllocationModule
->EntryPoint
;
114 gDxeCoreFileName
= &DxeCoreHob
.MemoryAllocationModule
->ModuleName
;
116 // Initialize the fields for an internal driver
118 Image
= &mCorePrivateImage
;
120 Image
->EntryPoint
= (EFI_IMAGE_ENTRY_POINT
)(UINTN
)DxeCoreEntryPoint
;
121 Image
->ImageBasePage
= DxeCoreImageBaseAddress
;
122 Image
->NumberOfPages
= (UINTN
)(EFI_SIZE_TO_PAGES((UINTN
)(DxeCoreImageLength
)));
123 Image
->Tpl
= gEfiCurrentTpl
;
124 Image
->Info
.SystemTable
= gDxeCoreST
;
125 Image
->Info
.ImageBase
= (VOID
*)(UINTN
)DxeCoreImageBaseAddress
;
126 Image
->Info
.ImageSize
= DxeCoreImageLength
;
129 // Install the protocol interfaces for this image
131 Status
= CoreInstallProtocolInterface (
133 &gEfiLoadedImageProtocolGuid
,
134 EFI_NATIVE_INTERFACE
,
137 ASSERT_EFI_ERROR (Status
);
139 mCurrentImage
= Image
;
142 // Fill in DXE globals
144 gDxeCoreImageHandle
= Image
->Handle
;
145 gDxeCoreLoadedImage
= &Image
->Info
;
147 if (FeaturePcdGet (PcdFrameworkCompatibilitySupport
)) {
149 // Export DXE Core PE Loader functionality for backward compatibility.
151 Status
= CoreInstallProtocolInterface (
152 &mLoadPe32PrivateData
.Handle
,
153 &gEfiLoadPeImageProtocolGuid
,
154 EFI_NATIVE_INTERFACE
,
155 &mLoadPe32PrivateData
.Pe32Image
163 Read image file (specified by UserHandle) into user specified buffer with specified offset
166 @param UserHandle Image file handle
167 @param Offset Offset to the source file
168 @param ReadSize For input, pointer of size to read; For output,
169 pointer of size actually read.
170 @param Buffer Buffer to write into
172 @retval EFI_SUCCESS Successfully read the specified part of file
181 IN OUT UINTN
*ReadSize
,
186 IMAGE_FILE_HANDLE
*FHand
;
188 FHand
= (IMAGE_FILE_HANDLE
*)UserHandle
;
189 ASSERT (FHand
->Signature
== IMAGE_FILE_HANDLE_SIGNATURE
);
192 // Move data from our local copy of the file
194 EndPosition
= Offset
+ *ReadSize
;
195 if (EndPosition
> FHand
->SourceSize
) {
196 *ReadSize
= (UINT32
)(FHand
->SourceSize
- Offset
);
198 if (Offset
>= FHand
->SourceSize
) {
202 CopyMem (Buffer
, (CHAR8
*)FHand
->Source
+ Offset
, *ReadSize
);
207 Loads, relocates, and invokes a PE/COFF image
209 @param BootPolicy If TRUE, indicates that the request originates
210 from the boot manager, and that the boot
211 manager is attempting to load FilePath as a
213 @param Pe32Handle The handle of PE32 image
214 @param Image PE image to be loaded
215 @param DstBuffer The buffer to store the image
216 @param EntryPoint A pointer to the entry point
217 @param Attribute The bit mask of attributes to set for the load
220 @retval EFI_SUCCESS The file was loaded, relocated, and invoked
221 @retval EFI_OUT_OF_RESOURCES There was not enough memory to load and
222 relocate the PE/COFF file
223 @retval EFI_INVALID_PARAMETER Invalid parameter
224 @retval EFI_BUFFER_TOO_SMALL Buffer for image is too small
229 IN BOOLEAN BootPolicy
,
231 IN LOADED_IMAGE_PRIVATE_DATA
*Image
,
232 IN EFI_PHYSICAL_ADDRESS DstBuffer OPTIONAL
,
233 OUT EFI_PHYSICAL_ADDRESS
*EntryPoint OPTIONAL
,
238 BOOLEAN DstBufAlocated
;
241 ZeroMem (&Image
->ImageContext
, sizeof (Image
->ImageContext
));
243 Image
->ImageContext
.Handle
= Pe32Handle
;
244 Image
->ImageContext
.ImageRead
= (PE_COFF_LOADER_READ_FILE
)CoreReadImageFile
;
247 // Get information about the image being loaded
249 Status
= PeCoffLoaderGetImageInfo (&Image
->ImageContext
);
250 if (EFI_ERROR (Status
)) {
254 if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Image
->ImageContext
.Machine
)) {
255 if (!EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED (Image
->ImageContext
.Machine
)) {
257 // The PE/COFF loader can support loading image types that can be executed.
258 // If we loaded an image type that we can not execute return EFI_UNSUPORTED.
260 return EFI_UNSUPPORTED
;
265 // Set EFI memory type based on ImageType
267 switch (Image
->ImageContext
.ImageType
) {
268 case EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION
:
269 Image
->ImageContext
.ImageCodeMemoryType
= EfiLoaderCode
;
270 Image
->ImageContext
.ImageDataMemoryType
= EfiLoaderData
;
272 case EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER
:
273 Image
->ImageContext
.ImageCodeMemoryType
= EfiBootServicesCode
;
274 Image
->ImageContext
.ImageDataMemoryType
= EfiBootServicesData
;
276 case EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
:
277 case EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER
:
278 Image
->ImageContext
.ImageCodeMemoryType
= EfiRuntimeServicesCode
;
279 Image
->ImageContext
.ImageDataMemoryType
= EfiRuntimeServicesData
;
282 Image
->ImageContext
.ImageError
= IMAGE_ERROR_INVALID_SUBSYSTEM
;
283 return EFI_UNSUPPORTED
;
287 // Allocate memory of the correct memory type aligned on the required image boundry
289 DstBufAlocated
= FALSE
;
290 if (DstBuffer
== 0) {
292 // Allocate Destination Buffer as caller did not pass it in
295 if (Image
->ImageContext
.SectionAlignment
> EFI_PAGE_SIZE
) {
296 Size
= (UINTN
)Image
->ImageContext
.ImageSize
+ Image
->ImageContext
.SectionAlignment
;
298 Size
= (UINTN
)Image
->ImageContext
.ImageSize
;
301 Image
->NumberOfPages
= EFI_SIZE_TO_PAGES (Size
);
304 // If the image relocations have not been stripped, then load at any address.
305 // Otherwise load at the address at which it was linked.
307 // Memory below 1MB should be treated reserved for CSM and there should be
308 // no modules whose preferred load addresses are below 1MB.
310 Status
= EFI_OUT_OF_RESOURCES
;
311 if (Image
->ImageContext
.ImageAddress
>= 0x100000 || Image
->ImageContext
.RelocationsStripped
) {
312 Status
= CoreAllocatePages (
314 (EFI_MEMORY_TYPE
) (Image
->ImageContext
.ImageCodeMemoryType
),
315 Image
->NumberOfPages
,
316 &Image
->ImageContext
.ImageAddress
319 if (EFI_ERROR (Status
) && !Image
->ImageContext
.RelocationsStripped
) {
320 Status
= CoreAllocatePages (
322 (EFI_MEMORY_TYPE
) (Image
->ImageContext
.ImageCodeMemoryType
),
323 Image
->NumberOfPages
,
324 &Image
->ImageContext
.ImageAddress
327 if (EFI_ERROR (Status
)) {
330 DstBufAlocated
= TRUE
;
333 // Caller provided the destination buffer
336 if (Image
->ImageContext
.RelocationsStripped
&& (Image
->ImageContext
.ImageAddress
!= DstBuffer
)) {
338 // If the image relocations were stripped, and the caller provided a
339 // destination buffer address that does not match the address that the
340 // image is linked at, then the image cannot be loaded.
342 return EFI_INVALID_PARAMETER
;
345 if (Image
->NumberOfPages
!= 0 &&
346 Image
->NumberOfPages
<
347 (EFI_SIZE_TO_PAGES ((UINTN
)Image
->ImageContext
.ImageSize
+ Image
->ImageContext
.SectionAlignment
))) {
348 Image
->NumberOfPages
= EFI_SIZE_TO_PAGES ((UINTN
)Image
->ImageContext
.ImageSize
+ Image
->ImageContext
.SectionAlignment
);
349 return EFI_BUFFER_TOO_SMALL
;
352 Image
->NumberOfPages
= EFI_SIZE_TO_PAGES ((UINTN
)Image
->ImageContext
.ImageSize
+ Image
->ImageContext
.SectionAlignment
);
353 Image
->ImageContext
.ImageAddress
= DstBuffer
;
356 Image
->ImageBasePage
= Image
->ImageContext
.ImageAddress
;
357 if (!Image
->ImageContext
.IsTeImage
) {
358 Image
->ImageContext
.ImageAddress
=
359 (Image
->ImageContext
.ImageAddress
+ Image
->ImageContext
.SectionAlignment
- 1) &
360 ~((UINTN
)Image
->ImageContext
.SectionAlignment
- 1);
364 // Load the image from the file into the allocated memory
366 Status
= PeCoffLoaderLoadImage (&Image
->ImageContext
);
367 if (EFI_ERROR (Status
)) {
372 // If this is a Runtime Driver, then allocate memory for the FixupData that
373 // is used to relocate the image when SetVirtualAddressMap() is called. The
374 // relocation is done by the Runtime AP.
376 if ((Attribute
& EFI_LOAD_PE_IMAGE_ATTRIBUTE_RUNTIME_REGISTRATION
) != 0) {
377 if (Image
->ImageContext
.ImageType
== EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
) {
378 Image
->ImageContext
.FixupData
= AllocateRuntimePool ((UINTN
)(Image
->ImageContext
.FixupDataSize
));
379 if (Image
->ImageContext
.FixupData
== NULL
) {
380 Status
= EFI_OUT_OF_RESOURCES
;
387 // Relocate the image in memory
389 Status
= PeCoffLoaderRelocateImage (&Image
->ImageContext
);
390 if (EFI_ERROR (Status
)) {
395 // Flush the Instruction Cache
397 InvalidateInstructionCacheRange ((VOID
*)(UINTN
)Image
->ImageContext
.ImageAddress
, (UINTN
)Image
->ImageContext
.ImageSize
);
400 // Copy the machine type from the context to the image private data. This
401 // is needed during image unload to know if we should call an EBC protocol
402 // to unload the image.
404 Image
->Machine
= Image
->ImageContext
.Machine
;
407 // Get the image entry point. If it's an EBC image, then call into the
408 // interpreter to create a thunk for the entry point and use the returned
409 // value for the entry point.
411 Image
->EntryPoint
= (EFI_IMAGE_ENTRY_POINT
)(UINTN
)Image
->ImageContext
.EntryPoint
;
412 if (Image
->ImageContext
.Machine
== EFI_IMAGE_MACHINE_EBC
) {
414 // Locate the EBC interpreter protocol
416 Status
= CoreLocateProtocol (&gEfiEbcProtocolGuid
, NULL
, (VOID
**)&Image
->Ebc
);
417 if (EFI_ERROR(Status
)) {
418 DEBUG ((DEBUG_LOAD
| DEBUG_ERROR
, "CoreLoadPeImage: There is no EBC interpreter for an EBC image.\n"));
423 // Register a callback for flushing the instruction cache so that created
424 // thunks can be flushed.
426 Status
= Image
->Ebc
->RegisterICacheFlush (Image
->Ebc
, (EBC_ICACHE_FLUSH
)InvalidateInstructionCacheRange
);
427 if (EFI_ERROR(Status
)) {
432 // Create a thunk for the image's entry point. This will be the new
433 // entry point for the image.
435 Status
= Image
->Ebc
->CreateThunk (
438 (VOID
*)(UINTN
) Image
->ImageContext
.EntryPoint
,
439 (VOID
**) &Image
->EntryPoint
441 if (EFI_ERROR(Status
)) {
447 // Fill in the image information for the Loaded Image Protocol
449 Image
->Type
= Image
->ImageContext
.ImageType
;
450 Image
->Info
.ImageBase
= (VOID
*)(UINTN
)Image
->ImageContext
.ImageAddress
;
451 Image
->Info
.ImageSize
= Image
->ImageContext
.ImageSize
;
452 Image
->Info
.ImageCodeType
= (EFI_MEMORY_TYPE
) (Image
->ImageContext
.ImageCodeMemoryType
);
453 Image
->Info
.ImageDataType
= (EFI_MEMORY_TYPE
) (Image
->ImageContext
.ImageDataMemoryType
);
454 if ((Attribute
& EFI_LOAD_PE_IMAGE_ATTRIBUTE_RUNTIME_REGISTRATION
) != 0) {
455 if (Image
->ImageContext
.ImageType
== EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
) {
457 // Make a list off all the RT images so we can let the RT AP know about them.
459 Image
->RuntimeData
= AllocateRuntimePool (sizeof(EFI_RUNTIME_IMAGE_ENTRY
));
460 if (Image
->RuntimeData
== NULL
) {
463 Image
->RuntimeData
->ImageBase
= Image
->Info
.ImageBase
;
464 Image
->RuntimeData
->ImageSize
= (UINT64
) (Image
->Info
.ImageSize
);
465 Image
->RuntimeData
->RelocationData
= Image
->ImageContext
.FixupData
;
466 Image
->RuntimeData
->Handle
= Image
->Handle
;
467 InsertTailList (&gRuntime
->ImageHead
, &Image
->RuntimeData
->Link
);
472 // Fill in the entry point of the image if it is available
474 if (EntryPoint
!= NULL
) {
475 *EntryPoint
= Image
->ImageContext
.EntryPoint
;
479 // Print the load address and the PDB file name if it is available
486 CHAR8 EfiFileName
[256];
489 DEBUG ((DEBUG_INFO
| DEBUG_LOAD
,
490 "Loading driver at 0x%11p EntryPoint=0x%11p ",
491 (VOID
*)(UINTN
) Image
->ImageContext
.ImageAddress
,
492 FUNCTION_ENTRY_POINT (Image
->ImageContext
.EntryPoint
)));
496 // Print Module Name by Pdb file path.
497 // Windows and Unix style file path are all trimmed correctly.
499 if (Image
->ImageContext
.PdbPointer
!= NULL
) {
501 for (Index
= 0; Image
->ImageContext
.PdbPointer
[Index
] != 0; Index
++) {
502 if ((Image
->ImageContext
.PdbPointer
[Index
] == '\\') || (Image
->ImageContext
.PdbPointer
[Index
] == '/')) {
503 StartIndex
= Index
+ 1;
507 // Copy the PDB file name to our temporary string, and replace .pdb with .efi
508 // The PDB file name is limited in the range of 0~255.
509 // If the length is bigger than 255, trim the redudant characters to avoid overflow in array boundary.
511 for (Index
= 0; Index
< sizeof (EfiFileName
) - 4; Index
++) {
512 EfiFileName
[Index
] = Image
->ImageContext
.PdbPointer
[Index
+ StartIndex
];
513 if (EfiFileName
[Index
] == 0) {
514 EfiFileName
[Index
] = '.';
516 if (EfiFileName
[Index
] == '.') {
517 EfiFileName
[Index
+ 1] = 'e';
518 EfiFileName
[Index
+ 2] = 'f';
519 EfiFileName
[Index
+ 3] = 'i';
520 EfiFileName
[Index
+ 4] = 0;
525 if (Index
== sizeof (EfiFileName
) - 4) {
526 EfiFileName
[Index
] = 0;
528 DEBUG ((DEBUG_INFO
| DEBUG_LOAD
, "%a", EfiFileName
)); // &Image->ImageContext.PdbPointer[StartIndex]));
530 DEBUG ((DEBUG_INFO
| DEBUG_LOAD
, "\n"));
542 if (DstBufAlocated
) {
543 CoreFreePages (Image
->ImageContext
.ImageAddress
, Image
->NumberOfPages
);
546 if (Image
->ImageContext
.FixupData
!= NULL
) {
547 CoreFreePool (Image
->ImageContext
.FixupData
);
556 Get the image's private data from its handle.
558 @param ImageHandle The image handle
560 @return Return the image private data associated with ImageHandle.
563 LOADED_IMAGE_PRIVATE_DATA
*
564 CoreLoadedImageInfo (
565 IN EFI_HANDLE ImageHandle
569 EFI_LOADED_IMAGE_PROTOCOL
*LoadedImage
;
570 LOADED_IMAGE_PRIVATE_DATA
*Image
;
572 Status
= CoreHandleProtocol (
574 &gEfiLoadedImageProtocolGuid
,
575 (VOID
**)&LoadedImage
577 if (!EFI_ERROR (Status
)) {
578 Image
= LOADED_IMAGE_PRIVATE_DATA_FROM_THIS (LoadedImage
);
580 DEBUG ((DEBUG_LOAD
, "CoreLoadedImageInfo: Not an ImageHandle %p\n", ImageHandle
));
589 Unloads EFI image from memory.
591 @param Image EFI image
592 @param FreePage Free allocated pages
596 CoreUnloadAndCloseImage (
597 IN LOADED_IMAGE_PRIVATE_DATA
*Image
,
603 EFI_HANDLE
*HandleBuffer
;
605 EFI_GUID
**ProtocolGuidArray
;
608 EFI_OPEN_PROTOCOL_INFORMATION_ENTRY
*OpenInfo
;
612 if (Image
->Ebc
!= NULL
) {
614 // If EBC protocol exists we must perform cleanups for this image.
616 Image
->Ebc
->UnloadImage (Image
->Ebc
, Image
->Handle
);
620 // Unload image, free Image->ImageContext->ModHandle
622 PeCoffLoaderUnloadImage (&Image
->ImageContext
);
625 // Free our references to the image handle
627 if (Image
->Handle
!= NULL
) {
629 Status
= CoreLocateHandleBuffer (
636 if (!EFI_ERROR (Status
)) {
637 for (HandleIndex
= 0; HandleIndex
< HandleCount
; HandleIndex
++) {
638 Status
= CoreProtocolsPerHandle (
639 HandleBuffer
[HandleIndex
],
643 if (!EFI_ERROR (Status
)) {
644 for (ProtocolIndex
= 0; ProtocolIndex
< ArrayCount
; ProtocolIndex
++) {
645 Status
= CoreOpenProtocolInformation (
646 HandleBuffer
[HandleIndex
],
647 ProtocolGuidArray
[ProtocolIndex
],
651 if (!EFI_ERROR (Status
)) {
652 for (OpenInfoIndex
= 0; OpenInfoIndex
< OpenInfoCount
; OpenInfoIndex
++) {
653 if (OpenInfo
[OpenInfoIndex
].AgentHandle
== Image
->Handle
) {
654 Status
= CoreCloseProtocol (
655 HandleBuffer
[HandleIndex
],
656 ProtocolGuidArray
[ProtocolIndex
],
658 OpenInfo
[OpenInfoIndex
].ControllerHandle
662 if (OpenInfo
!= NULL
) {
663 CoreFreePool(OpenInfo
);
667 if (ProtocolGuidArray
!= NULL
) {
668 CoreFreePool(ProtocolGuidArray
);
672 if (HandleBuffer
!= NULL
) {
673 CoreFreePool (HandleBuffer
);
677 CoreRemoveDebugImageInfoEntry (Image
->Handle
);
679 Status
= CoreUninstallProtocolInterface (
681 &gEfiLoadedImageDevicePathProtocolGuid
,
682 Image
->LoadedImageDevicePath
685 Status
= CoreUninstallProtocolInterface (
687 &gEfiLoadedImageProtocolGuid
,
691 if (Image
->ImageContext
.HiiResourceData
!= 0) {
692 Status
= CoreUninstallProtocolInterface (
694 &gEfiHiiPackageListProtocolGuid
,
695 (VOID
*) (UINTN
) Image
->ImageContext
.HiiResourceData
701 if (Image
->RuntimeData
!= NULL
) {
702 if (Image
->RuntimeData
->Link
.ForwardLink
!= NULL
) {
704 // Remove the Image from the Runtime Image list as we are about to Free it!
706 RemoveEntryList (&Image
->RuntimeData
->Link
);
708 CoreFreePool (Image
->RuntimeData
);
712 // Free the Image from memory
714 if ((Image
->ImageBasePage
!= 0) && FreePage
) {
715 CoreFreePages (Image
->ImageBasePage
, Image
->NumberOfPages
);
719 // Done with the Image structure
721 if (Image
->Info
.FilePath
!= NULL
) {
722 CoreFreePool (Image
->Info
.FilePath
);
725 if (Image
->LoadedImageDevicePath
!= NULL
) {
726 CoreFreePool (Image
->LoadedImageDevicePath
);
729 if (Image
->FixupData
!= NULL
) {
730 CoreFreePool (Image
->FixupData
);
733 CoreFreePool (Image
);
738 Loads an EFI image into memory and returns a handle to the image.
740 @param BootPolicy If TRUE, indicates that the request originates
741 from the boot manager, and that the boot
742 manager is attempting to load FilePath as a
744 @param ParentImageHandle The caller's image handle.
745 @param FilePath The specific file path from which the image is
747 @param SourceBuffer If not NULL, a pointer to the memory location
748 containing a copy of the image to be loaded.
749 @param SourceSize The size in bytes of SourceBuffer.
750 @param DstBuffer The buffer to store the image
751 @param NumberOfPages If not NULL, it inputs a pointer to the page
752 number of DstBuffer and outputs a pointer to
753 the page number of the image. If this number is
754 not enough, return EFI_BUFFER_TOO_SMALL and
755 this parameter contains the required number.
756 @param ImageHandle Pointer to the returned image handle that is
757 created when the image is successfully loaded.
758 @param EntryPoint A pointer to the entry point
759 @param Attribute The bit mask of attributes to set for the load
762 @retval EFI_SUCCESS The image was loaded into memory.
763 @retval EFI_NOT_FOUND The FilePath was not found.
764 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
765 @retval EFI_BUFFER_TOO_SMALL The buffer is too small
766 @retval EFI_UNSUPPORTED The image type is not supported, or the device
767 path cannot be parsed to locate the proper
768 protocol for loading the file.
769 @retval EFI_OUT_OF_RESOURCES Image was not loaded due to insufficient
774 CoreLoadImageCommon (
775 IN BOOLEAN BootPolicy
,
776 IN EFI_HANDLE ParentImageHandle
,
777 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
778 IN VOID
*SourceBuffer OPTIONAL
,
780 IN EFI_PHYSICAL_ADDRESS DstBuffer OPTIONAL
,
781 IN OUT UINTN
*NumberOfPages OPTIONAL
,
782 OUT EFI_HANDLE
*ImageHandle
,
783 OUT EFI_PHYSICAL_ADDRESS
*EntryPoint OPTIONAL
,
787 LOADED_IMAGE_PRIVATE_DATA
*Image
;
788 LOADED_IMAGE_PRIVATE_DATA
*ParentImage
;
789 IMAGE_FILE_HANDLE FHand
;
791 EFI_STATUS SecurityStatus
;
792 EFI_HANDLE DeviceHandle
;
793 UINT32 AuthenticationStatus
;
794 EFI_DEVICE_PATH_PROTOCOL
*OriginalFilePath
;
795 EFI_DEVICE_PATH_PROTOCOL
*HandleFilePath
;
798 SecurityStatus
= EFI_SUCCESS
;
800 ASSERT (gEfiCurrentTpl
< TPL_NOTIFY
);
804 // The caller must pass in a valid ParentImageHandle
806 if (ImageHandle
== NULL
|| ParentImageHandle
== NULL
) {
807 return EFI_INVALID_PARAMETER
;
810 ParentImage
= CoreLoadedImageInfo (ParentImageHandle
);
811 if (ParentImage
== NULL
) {
812 DEBUG((DEBUG_LOAD
|DEBUG_ERROR
, "LoadImageEx: Parent handle not an image handle\n"));
813 return EFI_INVALID_PARAMETER
;
816 ZeroMem (&FHand
, sizeof (IMAGE_FILE_HANDLE
));
817 FHand
.Signature
= IMAGE_FILE_HANDLE_SIGNATURE
;
818 OriginalFilePath
= FilePath
;
819 HandleFilePath
= FilePath
;
821 Status
= EFI_SUCCESS
;
822 AuthenticationStatus
= 0;
824 // If the caller passed a copy of the file, then just use it
826 if (SourceBuffer
!= NULL
) {
827 FHand
.Source
= SourceBuffer
;
828 FHand
.SourceSize
= SourceSize
;
829 CoreLocateDevicePath (&gEfiDevicePathProtocolGuid
, &HandleFilePath
, &DeviceHandle
);
830 if (SourceSize
> 0) {
831 Status
= EFI_SUCCESS
;
833 Status
= EFI_LOAD_ERROR
;
836 if (FilePath
== NULL
) {
837 return EFI_INVALID_PARAMETER
;
840 // Get the source file buffer by its device path.
842 FHand
.Source
= GetFileBufferByFilePath (
846 &AuthenticationStatus
848 if (FHand
.Source
== NULL
) {
849 Status
= EFI_NOT_FOUND
;
852 // Try to get the image device handle by checking the match protocol.
854 FHand
.FreeBuffer
= TRUE
;
855 Status
= CoreLocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid
, &HandleFilePath
, &DeviceHandle
);
856 if (EFI_ERROR (Status
)) {
857 HandleFilePath
= FilePath
;
858 Status
= CoreLocateDevicePath (&gEfiSimpleFileSystemProtocolGuid
, &HandleFilePath
, &DeviceHandle
);
859 if (EFI_ERROR (Status
)) {
861 HandleFilePath
= FilePath
;
862 Status
= CoreLocateDevicePath (&gEfiLoadFile2ProtocolGuid
, &HandleFilePath
, &DeviceHandle
);
864 if (EFI_ERROR (Status
)) {
865 HandleFilePath
= FilePath
;
866 Status
= CoreLocateDevicePath (&gEfiLoadFileProtocolGuid
, &HandleFilePath
, &DeviceHandle
);
873 if (Status
== EFI_ALREADY_STARTED
) {
876 } else if (EFI_ERROR (Status
)) {
881 // Verify the Authentication Status through the Security Architectural Protocol
883 if ((gSecurity
!= NULL
) && (OriginalFilePath
!= NULL
)) {
884 SecurityStatus
= gSecurity
->FileAuthenticationState (
886 AuthenticationStatus
,
889 if (EFI_ERROR (SecurityStatus
) && SecurityStatus
!= EFI_SECURITY_VIOLATION
) {
890 Status
= SecurityStatus
;
898 // Allocate a new image structure
900 Image
= AllocateZeroPool (sizeof(LOADED_IMAGE_PRIVATE_DATA
));
902 return EFI_OUT_OF_RESOURCES
;
906 // Pull out just the file portion of the DevicePath for the LoadedImage FilePath
908 FilePath
= OriginalFilePath
;
909 Status
= CoreHandleProtocol (DeviceHandle
, &gEfiDevicePathProtocolGuid
, (VOID
**)&HandleFilePath
);
910 if (!EFI_ERROR (Status
)) {
911 FilePathSize
= GetDevicePathSize (HandleFilePath
) - sizeof(EFI_DEVICE_PATH_PROTOCOL
);
912 FilePath
= (EFI_DEVICE_PATH_PROTOCOL
*) (((UINT8
*)FilePath
) + FilePathSize
);
916 // Initialize the fields for an internal driver
918 Image
->Signature
= LOADED_IMAGE_PRIVATE_DATA_SIGNATURE
;
919 Image
->Info
.SystemTable
= gDxeCoreST
;
920 Image
->Info
.DeviceHandle
= DeviceHandle
;
921 Image
->Info
.Revision
= EFI_LOADED_IMAGE_PROTOCOL_REVISION
;
922 Image
->Info
.FilePath
= DuplicateDevicePath (FilePath
);
923 Image
->Info
.ParentHandle
= ParentImageHandle
;
926 if (NumberOfPages
!= NULL
) {
927 Image
->NumberOfPages
= *NumberOfPages
;
929 Image
->NumberOfPages
= 0 ;
933 // Install the protocol interfaces for this image
934 // don't fire notifications yet
936 Status
= CoreInstallProtocolInterfaceNotify (
938 &gEfiLoadedImageProtocolGuid
,
939 EFI_NATIVE_INTERFACE
,
943 if (EFI_ERROR (Status
)) {
948 // Load the image. If EntryPoint is Null, it will not be set.
950 Status
= CoreLoadPeImage (BootPolicy
, &FHand
, Image
, DstBuffer
, EntryPoint
, Attribute
);
951 if (EFI_ERROR (Status
)) {
952 if ((Status
== EFI_BUFFER_TOO_SMALL
) || (Status
== EFI_OUT_OF_RESOURCES
)) {
953 if (NumberOfPages
!= NULL
) {
954 *NumberOfPages
= Image
->NumberOfPages
;
960 if (NumberOfPages
!= NULL
) {
961 *NumberOfPages
= Image
->NumberOfPages
;
965 // Register the image in the Debug Image Info Table if the attribute is set
967 if ((Attribute
& EFI_LOAD_PE_IMAGE_ATTRIBUTE_DEBUG_IMAGE_INFO_TABLE_REGISTRATION
) != 0) {
968 CoreNewDebugImageInfoEntry (EFI_DEBUG_IMAGE_INFO_TYPE_NORMAL
, &Image
->Info
, Image
->Handle
);
972 //Reinstall loaded image protocol to fire any notifications
974 Status
= CoreReinstallProtocolInterface (
976 &gEfiLoadedImageProtocolGuid
,
980 if (EFI_ERROR (Status
)) {
985 // If DevicePath parameter to the LoadImage() is not NULL, then make a copy of DevicePath,
986 // otherwise Loaded Image Device Path Protocol is installed with a NULL interface pointer.
988 if (OriginalFilePath
!= NULL
) {
989 Image
->LoadedImageDevicePath
= DuplicateDevicePath (OriginalFilePath
);
993 // Install Loaded Image Device Path Protocol onto the image handle of a PE/COFE image
995 Status
= CoreInstallProtocolInterface (
997 &gEfiLoadedImageDevicePathProtocolGuid
,
998 EFI_NATIVE_INTERFACE
,
999 Image
->LoadedImageDevicePath
1001 if (EFI_ERROR (Status
)) {
1006 // Install HII Package List Protocol onto the image handle
1008 if (Image
->ImageContext
.HiiResourceData
!= 0) {
1009 Status
= CoreInstallProtocolInterface (
1011 &gEfiHiiPackageListProtocolGuid
,
1012 EFI_NATIVE_INTERFACE
,
1013 (VOID
*) (UINTN
) Image
->ImageContext
.HiiResourceData
1015 if (EFI_ERROR (Status
)) {
1021 // Success. Return the image handle
1023 *ImageHandle
= Image
->Handle
;
1027 // All done accessing the source file
1028 // If we allocated the Source buffer, free it
1030 if (FHand
.FreeBuffer
) {
1031 CoreFreePool (FHand
.Source
);
1035 // There was an error. If there's an Image structure, free it
1037 if (EFI_ERROR (Status
)) {
1038 if (Image
!= NULL
) {
1039 CoreUnloadAndCloseImage (Image
, (BOOLEAN
)(DstBuffer
== 0));
1040 *ImageHandle
= NULL
;
1042 } else if (EFI_ERROR (SecurityStatus
)) {
1043 Status
= SecurityStatus
;
1053 Loads an EFI image into memory and returns a handle to the image.
1055 @param BootPolicy If TRUE, indicates that the request originates
1056 from the boot manager, and that the boot
1057 manager is attempting to load FilePath as a
1059 @param ParentImageHandle The caller's image handle.
1060 @param FilePath The specific file path from which the image is
1062 @param SourceBuffer If not NULL, a pointer to the memory location
1063 containing a copy of the image to be loaded.
1064 @param SourceSize The size in bytes of SourceBuffer.
1065 @param ImageHandle Pointer to the returned image handle that is
1066 created when the image is successfully loaded.
1068 @retval EFI_SUCCESS The image was loaded into memory.
1069 @retval EFI_NOT_FOUND The FilePath was not found.
1070 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
1071 @retval EFI_UNSUPPORTED The image type is not supported, or the device
1072 path cannot be parsed to locate the proper
1073 protocol for loading the file.
1074 @retval EFI_OUT_OF_RESOURCES Image was not loaded due to insufficient
1081 IN BOOLEAN BootPolicy
,
1082 IN EFI_HANDLE ParentImageHandle
,
1083 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
1084 IN VOID
*SourceBuffer OPTIONAL
,
1085 IN UINTN SourceSize
,
1086 OUT EFI_HANDLE
*ImageHandle
1094 Tick
= GetPerformanceCounter ();
1097 Status
= CoreLoadImageCommon (
1103 (EFI_PHYSICAL_ADDRESS
) (UINTN
) NULL
,
1107 EFI_LOAD_PE_IMAGE_ATTRIBUTE_RUNTIME_REGISTRATION
| EFI_LOAD_PE_IMAGE_ATTRIBUTE_DEBUG_IMAGE_INFO_TABLE_REGISTRATION
1110 PERF_START (*ImageHandle
, "LoadImage:", NULL
, Tick
);
1111 PERF_END (*ImageHandle
, "LoadImage:", NULL
, 0);
1119 Loads an EFI image into memory and returns a handle to the image with extended parameters.
1121 @param This Calling context
1122 @param ParentImageHandle The caller's image handle.
1123 @param FilePath The specific file path from which the image is
1125 @param SourceBuffer If not NULL, a pointer to the memory location
1126 containing a copy of the image to be loaded.
1127 @param SourceSize The size in bytes of SourceBuffer.
1128 @param DstBuffer The buffer to store the image.
1129 @param NumberOfPages For input, specifies the space size of the
1130 image by caller if not NULL. For output,
1131 specifies the actual space size needed.
1132 @param ImageHandle Image handle for output.
1133 @param EntryPoint Image entry point for output.
1134 @param Attribute The bit mask of attributes to set for the load
1137 @retval EFI_SUCCESS The image was loaded into memory.
1138 @retval EFI_NOT_FOUND The FilePath was not found.
1139 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
1140 @retval EFI_UNSUPPORTED The image type is not supported, or the device
1141 path cannot be parsed to locate the proper
1142 protocol for loading the file.
1143 @retval EFI_OUT_OF_RESOURCES Image was not loaded due to insufficient
1150 IN EFI_PE32_IMAGE_PROTOCOL
*This
,
1151 IN EFI_HANDLE ParentImageHandle
,
1152 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
1153 IN VOID
*SourceBuffer OPTIONAL
,
1154 IN UINTN SourceSize
,
1155 IN EFI_PHYSICAL_ADDRESS DstBuffer OPTIONAL
,
1156 OUT UINTN
*NumberOfPages OPTIONAL
,
1157 OUT EFI_HANDLE
*ImageHandle
,
1158 OUT EFI_PHYSICAL_ADDRESS
*EntryPoint OPTIONAL
,
1162 return CoreLoadImageCommon (
1178 Transfer control to a loaded image's entry point.
1180 @param ImageHandle Handle of image to be started.
1181 @param ExitDataSize Pointer of the size to ExitData
1182 @param ExitData Pointer to a pointer to a data buffer that
1183 includes a Null-terminated Unicode string,
1184 optionally followed by additional binary data.
1185 The string is a description that the caller may
1186 use to further indicate the reason for the
1189 @retval EFI_INVALID_PARAMETER Invalid parameter
1190 @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate
1191 @retval EFI_SUCCESS Successfully transfer control to the image's
1198 IN EFI_HANDLE ImageHandle
,
1199 OUT UINTN
*ExitDataSize
,
1200 OUT CHAR16
**ExitData OPTIONAL
1204 LOADED_IMAGE_PRIVATE_DATA
*Image
;
1205 LOADED_IMAGE_PRIVATE_DATA
*LastImage
;
1206 UINT64 HandleDatabaseKey
;
1209 Image
= CoreLoadedImageInfo (ImageHandle
);
1210 if (Image
== NULL
|| Image
->Started
) {
1211 return EFI_INVALID_PARAMETER
;
1215 // The image to be started must have the machine type supported by DxeCore.
1217 ASSERT (EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Image
->Machine
));
1218 if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Image
->Machine
)) {
1219 return EFI_UNSUPPORTED
;
1223 // Don't profile Objects or invalid start requests
1225 PERF_START (ImageHandle
, "StartImage:", NULL
, 0);
1229 // Push the current start image context, and
1230 // link the current image to the head. This is the
1231 // only image that can call Exit()
1233 HandleDatabaseKey
= CoreGetHandleDatabaseKey ();
1234 LastImage
= mCurrentImage
;
1235 mCurrentImage
= Image
;
1236 Image
->Tpl
= gEfiCurrentTpl
;
1239 // Set long jump for Exit() support
1240 // JumpContext must be aligned on a CPU specific boundary.
1241 // Overallocate the buffer and force the required alignment
1243 Image
->JumpBuffer
= AllocatePool (sizeof (BASE_LIBRARY_JUMP_BUFFER
) + BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT
);
1244 if (Image
->JumpBuffer
== NULL
) {
1245 PERF_END (ImageHandle
, "StartImage:", NULL
, 0);
1246 return EFI_OUT_OF_RESOURCES
;
1248 Image
->JumpContext
= ALIGN_POINTER (Image
->JumpBuffer
, BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT
);
1250 SetJumpFlag
= SetJump (Image
->JumpContext
);
1252 // The initial call to SetJump() must always return 0.
1253 // Subsequent calls to LongJump() cause a non-zero value to be returned by SetJump().
1255 if (SetJumpFlag
== 0) {
1257 // Call the image's entry point
1259 Image
->Started
= TRUE
;
1260 Image
->Status
= Image
->EntryPoint (ImageHandle
, Image
->Info
.SystemTable
);
1263 // Add some debug information if the image returned with error.
1264 // This make the user aware and check if the driver image have already released
1265 // all the resource in this situation.
1267 DEBUG_CODE_BEGIN ();
1268 if (EFI_ERROR (Image
->Status
)) {
1269 DEBUG ((DEBUG_ERROR
, "Error: Image at %11p start failed: %r\n", Image
->Info
.ImageBase
, Image
->Status
));
1274 // If the image returns, exit it through Exit()
1276 CoreExit (ImageHandle
, Image
->Status
, 0, NULL
);
1280 // Image has completed. Verify the tpl is the same
1282 ASSERT (Image
->Tpl
== gEfiCurrentTpl
);
1283 CoreRestoreTpl (Image
->Tpl
);
1285 CoreFreePool (Image
->JumpBuffer
);
1288 // Pop the current start image context
1290 mCurrentImage
= LastImage
;
1293 // Go connect any handles that were created or modified while the image executed.
1295 CoreConnectHandlesByKey (HandleDatabaseKey
);
1298 // Handle the image's returned ExitData
1300 DEBUG_CODE_BEGIN ();
1301 if (Image
->ExitDataSize
!= 0 || Image
->ExitData
!= NULL
) {
1303 DEBUG ((DEBUG_LOAD
, "StartImage: ExitDataSize %d, ExitData %p", (UINT32
)Image
->ExitDataSize
, Image
->ExitData
));
1304 if (Image
->ExitData
!= NULL
) {
1305 DEBUG ((DEBUG_LOAD
, " (%hs)", Image
->ExitData
));
1307 DEBUG ((DEBUG_LOAD
, "\n"));
1312 // Return the exit data to the caller
1314 if (ExitData
!= NULL
&& ExitDataSize
!= NULL
) {
1315 *ExitDataSize
= Image
->ExitDataSize
;
1316 *ExitData
= Image
->ExitData
;
1319 // Caller doesn't want the exit data, free it
1321 CoreFreePool (Image
->ExitData
);
1322 Image
->ExitData
= NULL
;
1326 // Save the Status because Image will get destroyed if it is unloaded.
1328 Status
= Image
->Status
;
1331 // If the image returned an error, or if the image is an application
1334 if (EFI_ERROR (Image
->Status
) || Image
->Type
== EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION
) {
1335 CoreUnloadAndCloseImage (Image
, TRUE
);
1341 PERF_END (ImageHandle
, "StartImage:", NULL
, 0);
1346 Terminates the currently loaded EFI image and returns control to boot services.
1348 @param ImageHandle Handle that identifies the image. This
1349 parameter is passed to the image on entry.
1350 @param Status The image's exit code.
1351 @param ExitDataSize The size, in bytes, of ExitData. Ignored if
1352 ExitStatus is EFI_SUCCESS.
1353 @param ExitData Pointer to a data buffer that includes a
1354 Null-terminated Unicode string, optionally
1355 followed by additional binary data. The string
1356 is a description that the caller may use to
1357 further indicate the reason for the image's
1360 @retval EFI_INVALID_PARAMETER Image handle is NULL or it is not current
1362 @retval EFI_SUCCESS Successfully terminates the currently loaded
1364 @retval EFI_ACCESS_DENIED Should never reach there.
1365 @retval EFI_OUT_OF_RESOURCES Could not allocate pool
1371 IN EFI_HANDLE ImageHandle
,
1372 IN EFI_STATUS Status
,
1373 IN UINTN ExitDataSize
,
1374 IN CHAR16
*ExitData OPTIONAL
1377 LOADED_IMAGE_PRIVATE_DATA
*Image
;
1381 // Prevent possible reentrance to this function
1382 // for the same ImageHandle
1384 OldTpl
= CoreRaiseTpl (TPL_NOTIFY
);
1386 Image
= CoreLoadedImageInfo (ImageHandle
);
1387 if (Image
== NULL
) {
1388 Status
= EFI_INVALID_PARAMETER
;
1392 if (!Image
->Started
) {
1394 // The image has not been started so just free its resources
1396 CoreUnloadAndCloseImage (Image
, TRUE
);
1397 Status
= EFI_SUCCESS
;
1402 // Image has been started, verify this image can exit
1404 if (Image
!= mCurrentImage
) {
1405 DEBUG ((DEBUG_LOAD
|DEBUG_ERROR
, "Exit: Image is not exitable image\n"));
1406 Status
= EFI_INVALID_PARAMETER
;
1413 Image
->Status
= Status
;
1416 // If there's ExitData info, move it
1418 if (ExitData
!= NULL
) {
1419 Image
->ExitDataSize
= ExitDataSize
;
1420 Image
->ExitData
= AllocatePool (Image
->ExitDataSize
);
1421 if (Image
->ExitData
== NULL
) {
1422 Status
= EFI_OUT_OF_RESOURCES
;
1425 CopyMem (Image
->ExitData
, ExitData
, Image
->ExitDataSize
);
1428 CoreRestoreTpl (OldTpl
);
1430 // return to StartImage
1432 LongJump (Image
->JumpContext
, (UINTN
)-1);
1435 // If we return from LongJump, then it is an error
1438 Status
= EFI_ACCESS_DENIED
;
1440 CoreRestoreTpl (OldTpl
);
1450 @param ImageHandle Handle that identifies the image to be
1453 @retval EFI_SUCCESS The image has been unloaded.
1454 @retval EFI_UNSUPPORTED The image has been sarted, and does not support
1456 @retval EFI_INVALID_PARAMPETER ImageHandle is not a valid image handle.
1462 IN EFI_HANDLE ImageHandle
1466 LOADED_IMAGE_PRIVATE_DATA
*Image
;
1468 Image
= CoreLoadedImageInfo (ImageHandle
);
1469 if (Image
== NULL
) {
1471 // The image handle is not valid
1473 Status
= EFI_INVALID_PARAMETER
;
1477 if (Image
->Started
) {
1479 // The image has been started, request it to unload.
1481 Status
= EFI_UNSUPPORTED
;
1482 if (Image
->Info
.Unload
!= NULL
) {
1483 Status
= Image
->Info
.Unload (ImageHandle
);
1488 // This Image hasn't been started, thus it can be unloaded
1490 Status
= EFI_SUCCESS
;
1494 if (!EFI_ERROR (Status
)) {
1496 // if the Image was not started or Unloaded O.K. then clean up
1498 CoreUnloadAndCloseImage (Image
, TRUE
);
1508 Unload the specified image.
1510 @param This Indicates the calling context.
1511 @param ImageHandle The specified image handle.
1513 @retval EFI_INVALID_PARAMETER Image handle is NULL.
1514 @retval EFI_UNSUPPORTED Attempt to unload an unsupported image.
1515 @retval EFI_SUCCESS Image successfully unloaded.
1521 IN EFI_PE32_IMAGE_PROTOCOL
*This
,
1522 IN EFI_HANDLE ImageHandle
1525 return CoreUnloadImage (ImageHandle
);