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 LOADED_IMAGE_PRIVATE_DATA
*mCurrentImage
= NULL
;
22 LOAD_PE32_IMAGE_PRIVATE_DATA mLoadPe32PrivateData
= {
23 LOAD_PE32_IMAGE_PRIVATE_DATA_SIGNATURE
,
33 // This code is needed to build the Image handle for the DXE Core
35 LOADED_IMAGE_PRIVATE_DATA mCorePrivateImage
= {
36 LOADED_IMAGE_PRIVATE_DATA_SIGNATURE
, // Signature
38 EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER
, // Image type
39 TRUE
, // If entrypoint has been called
42 EFI_LOADED_IMAGE_INFORMATION_REVISION
, // Revision
43 NULL
, // Parent handle
44 NULL
, // System handle
46 NULL
, // Device handle
55 EfiBootServicesCode
, // ImageCodeType
56 EfiBootServicesData
// ImageDataType
58 (EFI_PHYSICAL_ADDRESS
)0, // ImageBasePage
62 EFI_SUCCESS
, // Status
70 NULL
// LoadedImageDevicePath
76 Add the Image Services to EFI Boot Services Table and install the protocol
77 interfaces for this image.
79 @param HobStart The HOB to initialize
85 CoreInitializeImageServices (
90 LOADED_IMAGE_PRIVATE_DATA
*Image
;
91 EFI_PHYSICAL_ADDRESS DxeCoreImageBaseAddress
;
92 UINT64 DxeCoreImageLength
;
93 VOID
*DxeCoreEntryPoint
;
94 EFI_PEI_HOB_POINTERS DxeCoreHob
;
96 // Searching for image hob
98 DxeCoreHob
.Raw
= HobStart
;
99 while ((DxeCoreHob
.Raw
= GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION
, DxeCoreHob
.Raw
)) != NULL
) {
100 if (CompareGuid (&DxeCoreHob
.MemoryAllocationModule
->MemoryAllocationHeader
.Name
, &gEfiHobMemoryAllocModuleGuid
)) {
106 DxeCoreHob
.Raw
= GET_NEXT_HOB (DxeCoreHob
);
108 ASSERT (DxeCoreHob
.Raw
!= NULL
);
110 DxeCoreImageBaseAddress
= DxeCoreHob
.MemoryAllocationModule
->MemoryAllocationHeader
.MemoryBaseAddress
;
111 DxeCoreImageLength
= DxeCoreHob
.MemoryAllocationModule
->MemoryAllocationHeader
.MemoryLength
;
112 DxeCoreEntryPoint
= (VOID
*) (UINTN
) DxeCoreHob
.MemoryAllocationModule
->EntryPoint
;
113 gDxeCoreFileName
= &DxeCoreHob
.MemoryAllocationModule
->ModuleName
;
115 // Initialize the fields for an internal driver
117 Image
= &mCorePrivateImage
;
119 Image
->EntryPoint
= (EFI_IMAGE_ENTRY_POINT
)(UINTN
)DxeCoreEntryPoint
;
120 Image
->ImageBasePage
= DxeCoreImageBaseAddress
;
121 Image
->NumberOfPages
= (UINTN
)(EFI_SIZE_TO_PAGES((UINTN
)(DxeCoreImageLength
)));
122 Image
->Tpl
= gEfiCurrentTpl
;
123 Image
->Info
.SystemTable
= gDxeCoreST
;
124 Image
->Info
.ImageBase
= (VOID
*)(UINTN
)DxeCoreImageBaseAddress
;
125 Image
->Info
.ImageSize
= DxeCoreImageLength
;
128 // Install the protocol interfaces for this image
130 Status
= CoreInstallProtocolInterface (
132 &gEfiLoadedImageProtocolGuid
,
133 EFI_NATIVE_INTERFACE
,
136 ASSERT_EFI_ERROR (Status
);
138 mCurrentImage
= Image
;
141 // Fill in DXE globals
143 gDxeCoreImageHandle
= Image
->Handle
;
144 gDxeCoreLoadedImage
= &Image
->Info
;
147 // Export DXE Core PE Loader functionality
149 return CoreInstallProtocolInterface (
150 &mLoadPe32PrivateData
.Handle
,
151 &gEfiLoadPeImageProtocolGuid
,
152 EFI_NATIVE_INTERFACE
,
153 &mLoadPe32PrivateData
.Pe32Image
159 Loads, relocates, and invokes a PE/COFF image
161 @param BootPolicy If TRUE, indicates that the request originates
162 from the boot manager, and that the boot
163 manager is attempting to load FilePath as a
165 @param Pe32Handle The handle of PE32 image
166 @param Image PE image to be loaded
167 @param DstBuffer The buffer to store the image
168 @param EntryPoint A pointer to the entry point
169 @param Attribute The bit mask of attributes to set for the load
172 @retval EFI_SUCCESS The file was loaded, relocated, and invoked
173 @retval EFI_OUT_OF_RESOURCES There was not enough memory to load and
174 relocate the PE/COFF file
175 @retval EFI_INVALID_PARAMETER Invalid parameter
176 @retval EFI_BUFFER_TOO_SMALL Buffer for image is too small
181 IN BOOLEAN BootPolicy
,
183 IN LOADED_IMAGE_PRIVATE_DATA
*Image
,
184 IN EFI_PHYSICAL_ADDRESS DstBuffer OPTIONAL
,
185 OUT EFI_PHYSICAL_ADDRESS
*EntryPoint OPTIONAL
,
190 BOOLEAN DstBufAlocated
;
193 EFI_TCG_PLATFORM_PROTOCOL
*TcgPlatformProtocol
;
194 IMAGE_FILE_HANDLE
*FHandle
;
197 ZeroMem (&Image
->ImageContext
, sizeof (Image
->ImageContext
));
199 Image
->ImageContext
.Handle
= Pe32Handle
;
200 Image
->ImageContext
.ImageRead
= (PE_COFF_LOADER_READ_FILE
)CoreReadImageFile
;
203 // Get information about the image being loaded
205 Status
= PeCoffLoaderGetImageInfo (&Image
->ImageContext
);
206 if (EFI_ERROR (Status
)) {
210 if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Image
->ImageContext
.Machine
)) {
211 if (!EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED (Image
->ImageContext
.Machine
)) {
213 // The PE/COFF loader can support loading image types that can be executed.
214 // If we loaded an image type that we can not execute return EFI_UNSUPORTED.
216 return EFI_UNSUPPORTED
;
221 // Set EFI memory type based on ImageType
223 switch (Image
->ImageContext
.ImageType
) {
224 case EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION
:
225 Image
->ImageContext
.ImageCodeMemoryType
= EfiLoaderCode
;
226 Image
->ImageContext
.ImageDataMemoryType
= EfiLoaderData
;
228 case EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER
:
229 Image
->ImageContext
.ImageCodeMemoryType
= EfiBootServicesCode
;
230 Image
->ImageContext
.ImageDataMemoryType
= EfiBootServicesData
;
232 case EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
:
233 case EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER
:
234 Image
->ImageContext
.ImageCodeMemoryType
= EfiRuntimeServicesCode
;
235 Image
->ImageContext
.ImageDataMemoryType
= EfiRuntimeServicesData
;
238 Image
->ImageContext
.ImageError
= IMAGE_ERROR_INVALID_SUBSYSTEM
;
239 return EFI_UNSUPPORTED
;
242 // Get the image base address in the original PeImage.
244 LinkTimeBase
= (UINTN
) Image
->ImageContext
.ImageAddress
;
247 // Allocate memory of the correct memory type aligned on the required image boundry
249 DstBufAlocated
= FALSE
;
250 if (DstBuffer
== 0) {
252 // Allocate Destination Buffer as caller did not pass it in
255 if (Image
->ImageContext
.SectionAlignment
> EFI_PAGE_SIZE
) {
256 Size
= (UINTN
)Image
->ImageContext
.ImageSize
+ Image
->ImageContext
.SectionAlignment
;
258 Size
= (UINTN
)Image
->ImageContext
.ImageSize
;
261 Image
->NumberOfPages
= EFI_SIZE_TO_PAGES (Size
);
264 // If the image relocations have not been stripped, then load at any address.
265 // Otherwise load at the address at which it was linked.
267 // Memory below 1MB should be treated reserved for CSM and there should be
268 // no modules whose preferred load addresses are below 1MB.
270 Status
= EFI_OUT_OF_RESOURCES
;
271 if (Image
->ImageContext
.ImageAddress
>= 0x100000 || Image
->ImageContext
.RelocationsStripped
) {
272 Status
= CoreAllocatePages (
274 (EFI_MEMORY_TYPE
) (Image
->ImageContext
.ImageCodeMemoryType
),
275 Image
->NumberOfPages
,
276 &Image
->ImageContext
.ImageAddress
279 if (EFI_ERROR (Status
) && !Image
->ImageContext
.RelocationsStripped
) {
280 Status
= CoreAllocatePages (
282 (EFI_MEMORY_TYPE
) (Image
->ImageContext
.ImageCodeMemoryType
),
283 Image
->NumberOfPages
,
284 &Image
->ImageContext
.ImageAddress
287 if (EFI_ERROR (Status
)) {
290 DstBufAlocated
= TRUE
;
293 // Caller provided the destination buffer
296 if (Image
->ImageContext
.RelocationsStripped
&& (Image
->ImageContext
.ImageAddress
!= DstBuffer
)) {
298 // If the image relocations were stripped, and the caller provided a
299 // destination buffer address that does not match the address that the
300 // image is linked at, then the image cannot be loaded.
302 return EFI_INVALID_PARAMETER
;
305 if (Image
->NumberOfPages
!= 0 &&
306 Image
->NumberOfPages
<
307 (EFI_SIZE_TO_PAGES ((UINTN
)Image
->ImageContext
.ImageSize
+ Image
->ImageContext
.SectionAlignment
))) {
308 Image
->NumberOfPages
= EFI_SIZE_TO_PAGES ((UINTN
)Image
->ImageContext
.ImageSize
+ Image
->ImageContext
.SectionAlignment
);
309 return EFI_BUFFER_TOO_SMALL
;
312 Image
->NumberOfPages
= EFI_SIZE_TO_PAGES ((UINTN
)Image
->ImageContext
.ImageSize
+ Image
->ImageContext
.SectionAlignment
);
313 Image
->ImageContext
.ImageAddress
= DstBuffer
;
316 Image
->ImageBasePage
= Image
->ImageContext
.ImageAddress
;
317 Image
->ImageContext
.ImageAddress
=
318 (Image
->ImageContext
.ImageAddress
+ Image
->ImageContext
.SectionAlignment
- 1) &
319 ~((UINTN
)Image
->ImageContext
.SectionAlignment
- 1);
322 // Load the image from the file into the allocated memory
324 Status
= PeCoffLoaderLoadImage (&Image
->ImageContext
);
325 if (EFI_ERROR (Status
)) {
330 // If this is a Runtime Driver, then allocate memory for the FixupData that
331 // is used to relocate the image when SetVirtualAddressMap() is called. The
332 // relocation is done by the Runtime AP.
334 if ((Attribute
& EFI_LOAD_PE_IMAGE_ATTRIBUTE_RUNTIME_REGISTRATION
) != 0) {
335 if (Image
->ImageContext
.ImageType
== EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
) {
336 Image
->ImageContext
.FixupData
= CoreAllocateRuntimePool ((UINTN
)(Image
->ImageContext
.FixupDataSize
));
337 if (Image
->ImageContext
.FixupData
== NULL
) {
338 Status
= EFI_OUT_OF_RESOURCES
;
345 // Measure the image before applying fixup
347 Status
= CoreLocateProtocol (
348 &gEfiTcgPlatformProtocolGuid
,
350 (VOID
**) &TcgPlatformProtocol
352 if (!EFI_ERROR (Status
)) {
353 FHandle
= (IMAGE_FILE_HANDLE
*) Image
->ImageContext
.Handle
;
354 Status
= TcgPlatformProtocol
->MeasurePeImage (
356 (EFI_PHYSICAL_ADDRESS
) (UINTN
) FHandle
->Source
,
359 Image
->ImageContext
.ImageType
,
360 Image
->Info
.DeviceHandle
,
364 ASSERT_EFI_ERROR (Status
);
368 // Relocate the image in memory
370 Status
= PeCoffLoaderRelocateImage (&Image
->ImageContext
);
371 if (EFI_ERROR (Status
)) {
376 // Flush the Instruction Cache
378 InvalidateInstructionCacheRange ((VOID
*)(UINTN
)Image
->ImageContext
.ImageAddress
, (UINTN
)Image
->ImageContext
.ImageSize
);
381 // Copy the machine type from the context to the image private data. This
382 // is needed during image unload to know if we should call an EBC protocol
383 // to unload the image.
385 Image
->Machine
= Image
->ImageContext
.Machine
;
388 // Get the image entry point. If it's an EBC image, then call into the
389 // interpreter to create a thunk for the entry point and use the returned
390 // value for the entry point.
392 Image
->EntryPoint
= (EFI_IMAGE_ENTRY_POINT
)(UINTN
)Image
->ImageContext
.EntryPoint
;
393 if (Image
->ImageContext
.Machine
== EFI_IMAGE_MACHINE_EBC
) {
395 // Locate the EBC interpreter protocol
397 Status
= CoreLocateProtocol (&gEfiEbcProtocolGuid
, NULL
, (VOID
**)&Image
->Ebc
);
398 if (EFI_ERROR(Status
)) {
399 DEBUG ((DEBUG_LOAD
| DEBUG_ERROR
, "CoreLoadPeImage: There is no EBC interpreter for an EBC image.\n"));
404 // Register a callback for flushing the instruction cache so that created
405 // thunks can be flushed.
407 Status
= Image
->Ebc
->RegisterICacheFlush (Image
->Ebc
, (EBC_ICACHE_FLUSH
)InvalidateInstructionCacheRange
);
408 if (EFI_ERROR(Status
)) {
413 // Create a thunk for the image's entry point. This will be the new
414 // entry point for the image.
416 Status
= Image
->Ebc
->CreateThunk (
419 (VOID
*)(UINTN
)Image
->ImageContext
.EntryPoint
,
420 (VOID
**)&Image
->EntryPoint
422 if (EFI_ERROR(Status
)) {
428 // Fill in the image information for the Loaded Image Protocol
430 Image
->Type
= Image
->ImageContext
.ImageType
;
431 Image
->Info
.ImageBase
= (VOID
*)(UINTN
)Image
->ImageContext
.ImageAddress
;
432 Image
->Info
.ImageSize
= Image
->ImageContext
.ImageSize
;
433 Image
->Info
.ImageCodeType
= (EFI_MEMORY_TYPE
) (Image
->ImageContext
.ImageCodeMemoryType
);
434 Image
->Info
.ImageDataType
= (EFI_MEMORY_TYPE
) (Image
->ImageContext
.ImageDataMemoryType
);
435 if ((Attribute
& EFI_LOAD_PE_IMAGE_ATTRIBUTE_RUNTIME_REGISTRATION
) != 0) {
436 if (Image
->ImageContext
.ImageType
== EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
) {
438 // Make a list off all the RT images so we can let the RT AP know about them.
440 Image
->RuntimeData
= CoreAllocateRuntimePool (sizeof(EFI_RUNTIME_IMAGE_ENTRY
));
441 if (Image
->RuntimeData
== NULL
) {
444 Image
->RuntimeData
->ImageBase
= Image
->Info
.ImageBase
;
445 Image
->RuntimeData
->ImageSize
= (UINT64
) (Image
->Info
.ImageSize
);
446 Image
->RuntimeData
->RelocationData
= Image
->ImageContext
.FixupData
;
447 Image
->RuntimeData
->Handle
= Image
->Handle
;
448 InsertTailList (&gRuntime
->ImageHead
, &Image
->RuntimeData
->Link
);
453 // Fill in the entry point of the image if it is available
455 if (EntryPoint
!= NULL
) {
456 *EntryPoint
= Image
->ImageContext
.EntryPoint
;
460 // Print the load address and the PDB file name if it is available
467 CHAR8 EfiFileName
[256];
469 if (Image
->ImageContext
.Machine
!= IMAGE_FILE_MACHINE_IA64
) {
470 DEBUG ((DEBUG_INFO
| DEBUG_LOAD
,
471 "Loading driver at 0x%10p EntryPoint=0x%10p ",
472 (VOID
*)(UINTN
)Image
->ImageContext
.ImageAddress
,
473 (VOID
*)(UINTN
)Image
->ImageContext
.EntryPoint
));
476 // For IPF Image, the real entry point should be print.
478 DEBUG ((DEBUG_INFO
| DEBUG_LOAD
,
479 "Loading driver at 0x%10p EntryPoint=0x%10p ",
480 (VOID
*)(UINTN
)Image
->ImageContext
.ImageAddress
,
481 (VOID
*)(UINTN
)(*(UINT64
*)(UINTN
)Image
->ImageContext
.EntryPoint
)));
485 // Print Module Name by Pdb file path
487 if (Image
->ImageContext
.PdbPointer
!= NULL
) {
489 for (Index
= 0; Image
->ImageContext
.PdbPointer
[Index
] != 0; Index
++) {
490 if (Image
->ImageContext
.PdbPointer
[Index
] == '\\') {
491 StartIndex
= Index
+ 1;
495 // Copy the PDB file name to our temporary string, and replace .pdb with .efi
497 for (Index
= 0; Index
< sizeof (EfiFileName
); Index
++) {
498 EfiFileName
[Index
] = Image
->ImageContext
.PdbPointer
[Index
+ StartIndex
];
499 if (EfiFileName
[Index
] == 0) {
500 EfiFileName
[Index
] = '.';
502 if (EfiFileName
[Index
] == '.') {
503 EfiFileName
[Index
+ 1] = 'e';
504 EfiFileName
[Index
+ 2] = 'f';
505 EfiFileName
[Index
+ 3] = 'i';
506 EfiFileName
[Index
+ 4] = 0;
510 DEBUG ((DEBUG_INFO
| DEBUG_LOAD
, "%a", EfiFileName
)); // &Image->ImageContext.PdbPointer[StartIndex]));
512 DEBUG ((DEBUG_INFO
| DEBUG_LOAD
, "\n"));
524 if (DstBufAlocated
) {
525 CoreFreePages (Image
->ImageContext
.ImageAddress
, Image
->NumberOfPages
);
528 if (Image
->ImageContext
.FixupData
!= NULL
) {
529 CoreFreePool (Image
->ImageContext
.FixupData
);
538 Get the image's private data from its handle.
540 @param ImageHandle The image handle
542 @return Return the image private data associated with ImageHandle.
545 LOADED_IMAGE_PRIVATE_DATA
*
546 CoreLoadedImageInfo (
547 IN EFI_HANDLE ImageHandle
551 EFI_LOADED_IMAGE_PROTOCOL
*LoadedImage
;
552 LOADED_IMAGE_PRIVATE_DATA
*Image
;
554 Status
= CoreHandleProtocol (
556 &gEfiLoadedImageProtocolGuid
,
557 (VOID
**)&LoadedImage
559 if (!EFI_ERROR (Status
)) {
560 Image
= LOADED_IMAGE_PRIVATE_DATA_FROM_THIS (LoadedImage
);
562 DEBUG ((DEBUG_LOAD
, "CoreLoadedImageInfo: Not an ImageHandle %x\n", ImageHandle
));
571 Loads an EFI image into memory and returns a handle to the image.
573 @param BootPolicy If TRUE, indicates that the request originates
574 from the boot manager, and that the boot
575 manager is attempting to load FilePath as a
577 @param ParentImageHandle The caller's image handle.
578 @param FilePath The specific file path from which the image is
580 @param SourceBuffer If not NULL, a pointer to the memory location
581 containing a copy of the image to be loaded.
582 @param SourceSize The size in bytes of SourceBuffer.
583 @param DstBuffer The buffer to store the image
584 @param NumberOfPages If not NULL, it inputs a pointer to the page
585 number of DstBuffer and outputs a pointer to
586 the page number of the image. If this number is
587 not enough, return EFI_BUFFER_TOO_SMALL and
588 this parameter contains the required number.
589 @param ImageHandle Pointer to the returned image handle that is
590 created when the image is successfully loaded.
591 @param EntryPoint A pointer to the entry point
592 @param Attribute The bit mask of attributes to set for the load
595 @retval EFI_SUCCESS The image was loaded into memory.
596 @retval EFI_NOT_FOUND The FilePath was not found.
597 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
598 @retval EFI_BUFFER_TOO_SMALL The buffer is too small
599 @retval EFI_UNSUPPORTED The image type is not supported, or the device
600 path cannot be parsed to locate the proper
601 protocol for loading the file.
602 @retval EFI_OUT_OF_RESOURCES Image was not loaded due to insufficient
607 CoreLoadImageCommon (
608 IN BOOLEAN BootPolicy
,
609 IN EFI_HANDLE ParentImageHandle
,
610 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
611 IN VOID
*SourceBuffer OPTIONAL
,
613 IN EFI_PHYSICAL_ADDRESS DstBuffer OPTIONAL
,
614 IN OUT UINTN
*NumberOfPages OPTIONAL
,
615 OUT EFI_HANDLE
*ImageHandle
,
616 OUT EFI_PHYSICAL_ADDRESS
*EntryPoint OPTIONAL
,
620 LOADED_IMAGE_PRIVATE_DATA
*Image
;
621 LOADED_IMAGE_PRIVATE_DATA
*ParentImage
;
622 IMAGE_FILE_HANDLE FHand
;
624 EFI_STATUS SecurityStatus
;
625 EFI_HANDLE DeviceHandle
;
626 UINT32 AuthenticationStatus
;
627 EFI_DEVICE_PATH_PROTOCOL
*OriginalFilePath
;
628 EFI_DEVICE_PATH_PROTOCOL
*HandleFilePath
;
631 SecurityStatus
= EFI_SUCCESS
;
633 ASSERT (gEfiCurrentTpl
< TPL_NOTIFY
);
637 // The caller must pass in a valid ParentImageHandle
639 if (ImageHandle
== NULL
|| ParentImageHandle
== NULL
) {
640 return EFI_INVALID_PARAMETER
;
643 ParentImage
= CoreLoadedImageInfo (ParentImageHandle
);
644 if (ParentImage
== NULL
) {
645 DEBUG((DEBUG_LOAD
|DEBUG_ERROR
, "LoadImageEx: Parent handle not an image handle\n"));
646 return EFI_INVALID_PARAMETER
;
650 // Get simple read access to the source file
652 OriginalFilePath
= FilePath
;
653 Status
= CoreOpenImageFile (
660 &AuthenticationStatus
662 if (Status
== EFI_ALREADY_STARTED
) {
665 } else if (EFI_ERROR (Status
)) {
670 // Verify the Authentication Status through the Security Architectural Protocol
672 if ((gSecurity
!= NULL
) && (OriginalFilePath
!= NULL
)) {
673 SecurityStatus
= gSecurity
->FileAuthenticationState (
675 AuthenticationStatus
,
678 if (EFI_ERROR (SecurityStatus
) && SecurityStatus
!= EFI_SECURITY_VIOLATION
) {
679 Status
= SecurityStatus
;
687 // Allocate a new image structure
689 Image
= CoreAllocateZeroBootServicesPool (sizeof(LOADED_IMAGE_PRIVATE_DATA
));
691 return EFI_OUT_OF_RESOURCES
;
695 // Pull out just the file portion of the DevicePath for the LoadedImage FilePath
697 FilePath
= OriginalFilePath
;
698 Status
= CoreHandleProtocol (DeviceHandle
, &gEfiDevicePathProtocolGuid
, (VOID
**)&HandleFilePath
);
699 if (!EFI_ERROR (Status
)) {
700 FilePathSize
= CoreDevicePathSize (HandleFilePath
) - sizeof(EFI_DEVICE_PATH_PROTOCOL
);
701 FilePath
= (EFI_DEVICE_PATH_PROTOCOL
*) ( ((UINT8
*)FilePath
) + FilePathSize
);
705 // Initialize the fields for an internal driver
707 Image
->Signature
= LOADED_IMAGE_PRIVATE_DATA_SIGNATURE
;
708 Image
->Info
.SystemTable
= gDxeCoreST
;
709 Image
->Info
.DeviceHandle
= DeviceHandle
;
710 Image
->Info
.Revision
= EFI_LOADED_IMAGE_PROTOCOL_REVISION
;
711 Image
->Info
.FilePath
= CoreDuplicateDevicePath (FilePath
);
712 Image
->Info
.ParentHandle
= ParentImageHandle
;
715 if (NumberOfPages
!= NULL
) {
716 Image
->NumberOfPages
= *NumberOfPages
;
718 Image
->NumberOfPages
= 0 ;
722 // Install the protocol interfaces for this image
723 // don't fire notifications yet
725 Status
= CoreInstallProtocolInterfaceNotify (
727 &gEfiLoadedImageProtocolGuid
,
728 EFI_NATIVE_INTERFACE
,
732 if (EFI_ERROR (Status
)) {
737 // Load the image. If EntryPoint is Null, it will not be set.
739 Status
= CoreLoadPeImage (BootPolicy
, &FHand
, Image
, DstBuffer
, EntryPoint
, Attribute
);
740 if (EFI_ERROR (Status
)) {
741 if ((Status
== EFI_BUFFER_TOO_SMALL
) || (Status
== EFI_OUT_OF_RESOURCES
)) {
742 if (NumberOfPages
!= NULL
) {
743 *NumberOfPages
= Image
->NumberOfPages
;
749 if (NumberOfPages
!= NULL
) {
750 *NumberOfPages
= Image
->NumberOfPages
;
754 // Register the image in the Debug Image Info Table if the attribute is set
756 if ((Attribute
& EFI_LOAD_PE_IMAGE_ATTRIBUTE_DEBUG_IMAGE_INFO_TABLE_REGISTRATION
) != 0) {
757 CoreNewDebugImageInfoEntry (EFI_DEBUG_IMAGE_INFO_TYPE_NORMAL
, &Image
->Info
, Image
->Handle
);
761 //Reinstall loaded image protocol to fire any notifications
763 Status
= CoreReinstallProtocolInterface (
765 &gEfiLoadedImageProtocolGuid
,
769 if (EFI_ERROR (Status
)) {
774 // If DevicePath parameter to the LoadImage() is not NULL, then make a copy of DevicePath,
775 // otherwise Loaded Image Device Path Protocol is installed with a NULL interface pointer.
777 if (OriginalFilePath
!= NULL
) {
778 Image
->LoadedImageDevicePath
= CoreDuplicateDevicePath (OriginalFilePath
);
782 // Install Loaded Image Device Path Protocol onto the image handle of a PE/COFE image
784 Status
= CoreInstallProtocolInterface (
786 &gEfiLoadedImageDevicePathProtocolGuid
,
787 EFI_NATIVE_INTERFACE
,
788 Image
->LoadedImageDevicePath
790 if (EFI_ERROR (Status
)) {
795 // Success. Return the image handle
797 *ImageHandle
= Image
->Handle
;
801 // All done accessing the source file
802 // If we allocated the Source buffer, free it
804 if (FHand
.FreeBuffer
) {
805 CoreFreePool (FHand
.Source
);
809 // There was an error. If there's an Image structure, free it
811 if (EFI_ERROR (Status
)) {
813 CoreUnloadAndCloseImage (Image
, (BOOLEAN
)(DstBuffer
== 0));
816 } else if (EFI_ERROR (SecurityStatus
)) {
817 Status
= SecurityStatus
;
827 Loads an EFI image into memory and returns a handle to the image.
829 @param BootPolicy If TRUE, indicates that the request originates
830 from the boot manager, and that the boot
831 manager is attempting to load FilePath as a
833 @param ParentImageHandle The caller's image handle.
834 @param FilePath The specific file path from which the image is
836 @param SourceBuffer If not NULL, a pointer to the memory location
837 containing a copy of the image to be loaded.
838 @param SourceSize The size in bytes of SourceBuffer.
839 @param ImageHandle Pointer to the returned image handle that is
840 created when the image is successfully loaded.
842 @retval EFI_SUCCESS The image was loaded into memory.
843 @retval EFI_NOT_FOUND The FilePath was not found.
844 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
845 @retval EFI_UNSUPPORTED The image type is not supported, or the device
846 path cannot be parsed to locate the proper
847 protocol for loading the file.
848 @retval EFI_OUT_OF_RESOURCES Image was not loaded due to insufficient
855 IN BOOLEAN BootPolicy
,
856 IN EFI_HANDLE ParentImageHandle
,
857 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
858 IN VOID
*SourceBuffer OPTIONAL
,
860 OUT EFI_HANDLE
*ImageHandle
865 PERF_START (NULL
, "LoadImage", NULL
, 0);
867 Status
= CoreLoadImageCommon (
873 (EFI_PHYSICAL_ADDRESS
) (UINTN
) NULL
,
877 EFI_LOAD_PE_IMAGE_ATTRIBUTE_RUNTIME_REGISTRATION
| EFI_LOAD_PE_IMAGE_ATTRIBUTE_DEBUG_IMAGE_INFO_TABLE_REGISTRATION
880 PERF_END (NULL
, "LoadImage", NULL
, 0);
888 Loads an EFI image into memory and returns a handle to the image with extended parameters.
890 @param This Calling context
891 @param ParentImageHandle The caller's image handle.
892 @param FilePath The specific file path from which the image is
894 @param SourceBuffer If not NULL, a pointer to the memory location
895 containing a copy of the image to be loaded.
896 @param SourceSize The size in bytes of SourceBuffer.
897 @param DstBuffer The buffer to store the image.
898 @param NumberOfPages For input, specifies the space size of the
899 image by caller if not NULL. For output,
900 specifies the actual space size needed.
901 @param ImageHandle Image handle for output.
902 @param EntryPoint Image entry point for output.
903 @param Attribute The bit mask of attributes to set for the load
906 @retval EFI_SUCCESS The image was loaded into memory.
907 @retval EFI_NOT_FOUND The FilePath was not found.
908 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
909 @retval EFI_UNSUPPORTED The image type is not supported, or the device
910 path cannot be parsed to locate the proper
911 protocol for loading the file.
912 @retval EFI_OUT_OF_RESOURCES Image was not loaded due to insufficient
919 IN EFI_PE32_IMAGE_PROTOCOL
*This
,
920 IN EFI_HANDLE ParentImageHandle
,
921 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
922 IN VOID
*SourceBuffer OPTIONAL
,
924 IN EFI_PHYSICAL_ADDRESS DstBuffer OPTIONAL
,
925 OUT UINTN
*NumberOfPages OPTIONAL
,
926 OUT EFI_HANDLE
*ImageHandle
,
927 OUT EFI_PHYSICAL_ADDRESS
*EntryPoint OPTIONAL
,
931 return CoreLoadImageCommon (
947 Transfer control to a loaded image's entry point.
949 @param ImageHandle Handle of image to be started.
950 @param ExitDataSize Pointer of the size to ExitData
951 @param ExitData Pointer to a pointer to a data buffer that
952 includes a Null-terminated Unicode string,
953 optionally followed by additional binary data.
954 The string is a description that the caller may
955 use to further indicate the reason for the
958 @retval EFI_INVALID_PARAMETER Invalid parameter
959 @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate
960 @retval EFI_SUCCESS Successfully transfer control to the image's
967 IN EFI_HANDLE ImageHandle
,
968 OUT UINTN
*ExitDataSize
,
969 OUT CHAR16
**ExitData OPTIONAL
973 LOADED_IMAGE_PRIVATE_DATA
*Image
;
974 LOADED_IMAGE_PRIVATE_DATA
*LastImage
;
975 UINT64 HandleDatabaseKey
;
978 Image
= CoreLoadedImageInfo (ImageHandle
);
979 if (Image
== NULL_HANDLE
|| Image
->Started
) {
980 return EFI_INVALID_PARAMETER
;
984 // Don't profile Objects or invalid start requests
986 PERF_START (ImageHandle
, START_IMAGE_TOK
, NULL
, 0);
990 // Push the current start image context, and
991 // link the current image to the head. This is the
992 // only image that can call Exit()
994 HandleDatabaseKey
= CoreGetHandleDatabaseKey ();
995 LastImage
= mCurrentImage
;
996 mCurrentImage
= Image
;
997 Image
->Tpl
= gEfiCurrentTpl
;
1000 // Set long jump for Exit() support
1001 // JumpContext must be aligned on a CPU specific boundary.
1002 // Overallocate the buffer and force the required alignment
1004 Image
->JumpBuffer
= CoreAllocateBootServicesPool (sizeof (BASE_LIBRARY_JUMP_BUFFER
) + BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT
);
1005 if (Image
->JumpBuffer
== NULL
) {
1006 PERF_END (ImageHandle
, START_IMAGE_TOK
, NULL
, 0);
1007 return EFI_OUT_OF_RESOURCES
;
1009 Image
->JumpContext
= ALIGN_POINTER (Image
->JumpBuffer
, BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT
);
1011 SetJumpFlag
= SetJump (Image
->JumpContext
);
1013 // The initial call to SetJump() must always return 0.
1014 // Subsequent calls to LongJump() cause a non-zero value to be returned by SetJump().
1016 if (SetJumpFlag
== 0) {
1018 // Call the image's entry point
1020 Image
->Started
= TRUE
;
1021 Image
->Status
= Image
->EntryPoint (ImageHandle
, Image
->Info
.SystemTable
);
1024 // Add some debug information if the image returned with error.
1025 // This make the user aware and check if the driver image have already released
1026 // all the resource in this situation.
1028 DEBUG_CODE_BEGIN ();
1029 if (EFI_ERROR (Image
->Status
)) {
1030 DEBUG ((DEBUG_ERROR
, "Error: Image at %10p start failed: %r\n", Image
->Info
.ImageBase
, Image
->Status
));
1035 // If the image returns, exit it through Exit()
1037 CoreExit (ImageHandle
, Image
->Status
, 0, NULL
);
1041 // Image has completed. Verify the tpl is the same
1043 ASSERT (Image
->Tpl
== gEfiCurrentTpl
);
1044 CoreRestoreTpl (Image
->Tpl
);
1046 CoreFreePool (Image
->JumpBuffer
);
1049 // Pop the current start image context
1051 mCurrentImage
= LastImage
;
1054 // Go connect any handles that were created or modified while the image executed.
1056 CoreConnectHandlesByKey (HandleDatabaseKey
);
1059 // Handle the image's returned ExitData
1061 DEBUG_CODE_BEGIN ();
1062 if (Image
->ExitDataSize
!= 0 || Image
->ExitData
!= NULL
) {
1066 "StartImage: ExitDataSize %d, ExitData %x",
1067 Image
->ExitDataSize
,
1070 if (Image
->ExitData
!= NULL
) {
1071 DEBUG ((DEBUG_LOAD
, " (%hs)", Image
->ExitData
));
1073 DEBUG ((DEBUG_LOAD
, "\n"));
1078 // Return the exit data to the caller
1080 if (ExitData
!= NULL
&& ExitDataSize
!= NULL
) {
1081 *ExitDataSize
= Image
->ExitDataSize
;
1082 *ExitData
= Image
->ExitData
;
1085 // Caller doesn't want the exit data, free it
1087 CoreFreePool (Image
->ExitData
);
1088 Image
->ExitData
= NULL
;
1092 // Save the Status because Image will get destroyed if it is unloaded.
1094 Status
= Image
->Status
;
1097 // If the image returned an error, or if the image is an application
1100 if (EFI_ERROR (Image
->Status
) || Image
->Type
== EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION
) {
1101 CoreUnloadAndCloseImage (Image
, TRUE
);
1107 PERF_END (ImageHandle
, START_IMAGE_TOK
, NULL
, 0);
1114 Unloads EFI image from memory.
1116 @param Image EFI image
1117 @param FreePage Free allocated pages
1121 CoreUnloadAndCloseImage (
1122 IN LOADED_IMAGE_PRIVATE_DATA
*Image
,
1128 EFI_HANDLE
*HandleBuffer
;
1130 EFI_GUID
**ProtocolGuidArray
;
1132 UINTN ProtocolIndex
;
1133 EFI_OPEN_PROTOCOL_INFORMATION_ENTRY
*OpenInfo
;
1134 UINTN OpenInfoCount
;
1135 UINTN OpenInfoIndex
;
1137 if (Image
->Ebc
!= NULL
) {
1139 // If EBC protocol exists we must perform cleanups for this image.
1141 Image
->Ebc
->UnloadImage (Image
->Ebc
, Image
->Handle
);
1145 // Unload image, free Image->ImageContext->ModHandle
1147 PeCoffLoaderUnloadImage (&Image
->ImageContext
);
1150 // Free our references to the image handle
1152 if (Image
->Handle
!= NULL_HANDLE
) {
1154 Status
= CoreLocateHandleBuffer (
1161 if (!EFI_ERROR (Status
)) {
1162 for (HandleIndex
= 0; HandleIndex
< HandleCount
; HandleIndex
++) {
1163 Status
= CoreProtocolsPerHandle (
1164 HandleBuffer
[HandleIndex
],
1168 if (!EFI_ERROR (Status
)) {
1169 for (ProtocolIndex
= 0; ProtocolIndex
< ArrayCount
; ProtocolIndex
++) {
1170 Status
= CoreOpenProtocolInformation (
1171 HandleBuffer
[HandleIndex
],
1172 ProtocolGuidArray
[ProtocolIndex
],
1176 if (!EFI_ERROR (Status
)) {
1177 for (OpenInfoIndex
= 0; OpenInfoIndex
< OpenInfoCount
; OpenInfoIndex
++) {
1178 if (OpenInfo
[OpenInfoIndex
].AgentHandle
== Image
->Handle
) {
1179 Status
= CoreCloseProtocol (
1180 HandleBuffer
[HandleIndex
],
1181 ProtocolGuidArray
[ProtocolIndex
],
1183 OpenInfo
[OpenInfoIndex
].ControllerHandle
1187 if (OpenInfo
!= NULL
) {
1188 CoreFreePool(OpenInfo
);
1192 if (ProtocolGuidArray
!= NULL
) {
1193 CoreFreePool(ProtocolGuidArray
);
1197 if (HandleBuffer
!= NULL
) {
1198 CoreFreePool (HandleBuffer
);
1202 CoreRemoveDebugImageInfoEntry (Image
->Handle
);
1204 Status
= CoreUninstallProtocolInterface (
1206 &gEfiLoadedImageDevicePathProtocolGuid
,
1207 Image
->LoadedImageDevicePath
1210 Status
= CoreUninstallProtocolInterface (
1212 &gEfiLoadedImageProtocolGuid
,
1218 if (Image
->RuntimeData
!= NULL
) {
1219 if (Image
->RuntimeData
->Link
.ForwardLink
!= NULL
) {
1221 // Remove the Image from the Runtime Image list as we are about to Free it!
1223 RemoveEntryList (&Image
->RuntimeData
->Link
);
1225 CoreFreePool (Image
->RuntimeData
);
1229 // Free the Image from memory
1231 if ((Image
->ImageBasePage
!= 0) && FreePage
) {
1232 CoreFreePages (Image
->ImageBasePage
, Image
->NumberOfPages
);
1236 // Done with the Image structure
1238 if (Image
->Info
.FilePath
!= NULL
) {
1239 CoreFreePool (Image
->Info
.FilePath
);
1242 if (Image
->LoadedImageDevicePath
!= NULL
) {
1243 CoreFreePool (Image
->LoadedImageDevicePath
);
1246 if (Image
->FixupData
!= NULL
) {
1247 CoreFreePool (Image
->FixupData
);
1250 CoreFreePool (Image
);
1257 Terminates the currently loaded EFI image and returns control to boot services.
1259 @param ImageHandle Handle that identifies the image. This
1260 parameter is passed to the image on entry.
1261 @param Status The image's exit code.
1262 @param ExitDataSize The size, in bytes, of ExitData. Ignored if
1263 ExitStatus is EFI_SUCCESS.
1264 @param ExitData Pointer to a data buffer that includes a
1265 Null-terminated Unicode string, optionally
1266 followed by additional binary data. The string
1267 is a description that the caller may use to
1268 further indicate the reason for the image's
1271 @retval EFI_INVALID_PARAMETER Image handle is NULL or it is not current
1273 @retval EFI_SUCCESS Successfully terminates the currently loaded
1275 @retval EFI_ACCESS_DENIED Should never reach there.
1276 @retval EFI_OUT_OF_RESOURCES Could not allocate pool
1282 IN EFI_HANDLE ImageHandle
,
1283 IN EFI_STATUS Status
,
1284 IN UINTN ExitDataSize
,
1285 IN CHAR16
*ExitData OPTIONAL
1288 LOADED_IMAGE_PRIVATE_DATA
*Image
;
1292 // Prevent possible reentrance to this function
1293 // for the same ImageHandle
1295 OldTpl
= CoreRaiseTpl (TPL_NOTIFY
);
1297 Image
= CoreLoadedImageInfo (ImageHandle
);
1298 if (Image
== NULL_HANDLE
) {
1299 Status
= EFI_INVALID_PARAMETER
;
1303 if (!Image
->Started
) {
1305 // The image has not been started so just free its resources
1307 CoreUnloadAndCloseImage (Image
, TRUE
);
1308 Status
= EFI_SUCCESS
;
1313 // Image has been started, verify this image can exit
1315 if (Image
!= mCurrentImage
) {
1316 DEBUG ((DEBUG_LOAD
|DEBUG_ERROR
, "Exit: Image is not exitable image\n"));
1317 Status
= EFI_INVALID_PARAMETER
;
1324 Image
->Status
= Status
;
1327 // If there's ExitData info, move it
1329 if (ExitData
!= NULL
) {
1330 Image
->ExitDataSize
= ExitDataSize
;
1331 Image
->ExitData
= CoreAllocateBootServicesPool (Image
->ExitDataSize
);
1332 if (Image
->ExitData
== NULL
) {
1333 Status
= EFI_OUT_OF_RESOURCES
;
1336 CopyMem (Image
->ExitData
, ExitData
, Image
->ExitDataSize
);
1339 CoreRestoreTpl (OldTpl
);
1341 // return to StartImage
1343 LongJump (Image
->JumpContext
, (UINTN
)-1);
1346 // If we return from LongJump, then it is an error
1349 Status
= EFI_ACCESS_DENIED
;
1351 CoreRestoreTpl (OldTpl
);
1361 @param ImageHandle Handle that identifies the image to be
1364 @retval EFI_SUCCESS The image has been unloaded.
1365 @retval EFI_UNSUPPORTED The image has been sarted, and does not support
1367 @retval EFI_INVALID_PARAMPETER ImageHandle is not a valid image handle.
1373 IN EFI_HANDLE ImageHandle
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
) {
1389 // The image handle is not valid
1391 Status
= EFI_INVALID_PARAMETER
;
1395 if (Image
->Started
) {
1397 // The image has been started, request it to unload.
1399 Status
= EFI_UNSUPPORTED
;
1400 if (Image
->Info
.Unload
!= NULL
) {
1401 Status
= Image
->Info
.Unload (ImageHandle
);
1406 // This Image hasn't been started, thus it can be unloaded
1408 Status
= EFI_SUCCESS
;
1412 if (!EFI_ERROR (Status
)) {
1414 // if the Image was not started or Unloaded O.K. then clean up
1416 CoreUnloadAndCloseImage (Image
, TRUE
);
1420 CoreRestoreTpl (OldTpl
);
1427 Unload the specified image.
1429 @param This Indicates the calling context.
1430 @param ImageHandle The specified image handle.
1432 @retval EFI_INVALID_PARAMETER Image handle is NULL.
1433 @retval EFI_UNSUPPORTED Attempt to unload an unsupported image.
1434 @retval EFI_SUCCESS Image successfully unloaded.
1440 IN EFI_PE32_IMAGE_PROTOCOL
*This
,
1441 IN EFI_HANDLE ImageHandle
1444 return CoreUnloadImage (ImageHandle
);