3 Core image handling services to load and unload PeImage.
5 Copyright (c) 2006 - 2008, Intel Corporation
6 All rights reserved. This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 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
76 CoreInitializeImageServices (
83 Add the Image Services to EFI Boot Services Table and install the protocol
84 interfaces for this image.
88 HobStart - The HOB to initialize
97 LOADED_IMAGE_PRIVATE_DATA
*Image
;
98 EFI_PHYSICAL_ADDRESS DxeCoreImageBaseAddress
;
99 UINT64 DxeCoreImageLength
;
100 VOID
*DxeCoreEntryPoint
;
101 EFI_PEI_HOB_POINTERS DxeCoreHob
;
103 // Searching for image hob
105 DxeCoreHob
.Raw
= HobStart
;
106 while ((DxeCoreHob
.Raw
= GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION
, DxeCoreHob
.Raw
)) != NULL
) {
107 if (CompareGuid (&DxeCoreHob
.MemoryAllocationModule
->MemoryAllocationHeader
.Name
, &gEfiHobMemoryAllocModuleGuid
)) {
113 DxeCoreHob
.Raw
= GET_NEXT_HOB (DxeCoreHob
);
115 ASSERT (DxeCoreHob
.Raw
!= NULL
);
117 DxeCoreImageBaseAddress
= DxeCoreHob
.MemoryAllocationModule
->MemoryAllocationHeader
.MemoryBaseAddress
;
118 DxeCoreImageLength
= DxeCoreHob
.MemoryAllocationModule
->MemoryAllocationHeader
.MemoryLength
;
119 DxeCoreEntryPoint
= (VOID
*) (UINTN
) DxeCoreHob
.MemoryAllocationModule
->EntryPoint
;
120 gDxeCoreFileName
= &DxeCoreHob
.MemoryAllocationModule
->ModuleName
;
122 // Initialize the fields for an internal driver
124 Image
= &mCorePrivateImage
;
126 Image
->EntryPoint
= (EFI_IMAGE_ENTRY_POINT
)(UINTN
)DxeCoreEntryPoint
;
127 Image
->ImageBasePage
= DxeCoreImageBaseAddress
;
128 Image
->NumberOfPages
= (UINTN
)(EFI_SIZE_TO_PAGES((UINTN
)(DxeCoreImageLength
)));
129 Image
->Tpl
= gEfiCurrentTpl
;
130 Image
->Info
.SystemTable
= gDxeCoreST
;
131 Image
->Info
.ImageBase
= (VOID
*)(UINTN
)DxeCoreImageBaseAddress
;
132 Image
->Info
.ImageSize
= DxeCoreImageLength
;
135 // Install the protocol interfaces for this image
137 Status
= CoreInstallProtocolInterface (
139 &gEfiLoadedImageProtocolGuid
,
140 EFI_NATIVE_INTERFACE
,
143 ASSERT_EFI_ERROR (Status
);
145 mCurrentImage
= Image
;
148 // Fill in DXE globals
150 gDxeCoreImageHandle
= Image
->Handle
;
151 gDxeCoreLoadedImage
= &Image
->Info
;
154 // Export DXE Core PE Loader functionality
156 return CoreInstallProtocolInterface (
157 &mLoadPe32PrivateData
.Handle
,
158 &gEfiLoadPeImageProtocolGuid
,
159 EFI_NATIVE_INTERFACE
,
160 &mLoadPe32PrivateData
.Pe32Image
166 IN BOOLEAN BootPolicy
,
168 IN LOADED_IMAGE_PRIVATE_DATA
*Image
,
169 IN EFI_PHYSICAL_ADDRESS DstBuffer OPTIONAL
,
170 OUT EFI_PHYSICAL_ADDRESS
*EntryPoint OPTIONAL
,
177 Loads, relocates, and invokes a PE/COFF image
180 BootPolicy - If TRUE, indicates that the request originates from the boot manager,
181 and that the boot manager is attempting to load FilePath as a boot selection.
182 Pe32Handle - The handle of PE32 image
183 Image - PE image to be loaded
184 DstBuffer - The buffer to store the image
185 EntryPoint - A pointer to the entry point
186 Attribute - The bit mask of attributes to set for the load PE image
190 EFI_SUCCESS - The file was loaded, relocated, and invoked
192 EFI_OUT_OF_RESOURCES - There was not enough memory to load and relocate the PE/COFF file
194 EFI_INVALID_PARAMETER - Invalid parameter
196 EFI_BUFFER_TOO_SMALL - Buffer for image is too small
201 BOOLEAN DstBufAlocated
;
204 EFI_TCG_PLATFORM_PROTOCOL
*TcgPlatformProtocol
;
205 IMAGE_FILE_HANDLE
*FHandle
;
208 ZeroMem (&Image
->ImageContext
, sizeof (Image
->ImageContext
));
210 Image
->ImageContext
.Handle
= Pe32Handle
;
211 Image
->ImageContext
.ImageRead
= (PE_COFF_LOADER_READ_FILE
)CoreReadImageFile
;
214 // Get information about the image being loaded
216 Status
= PeCoffLoaderGetImageInfo (&Image
->ImageContext
);
217 if (EFI_ERROR (Status
)) {
221 if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Image
->ImageContext
.Machine
)) {
222 if (!EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED (Image
->ImageContext
.Machine
)) {
224 // The PE/COFF loader can support loading image types that can be executed.
225 // If we loaded an image type that we can not execute return EFI_UNSUPORTED.
227 return EFI_UNSUPPORTED
;
232 // Set EFI memory type based on ImageType
234 switch (Image
->ImageContext
.ImageType
) {
235 case EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION
:
236 Image
->ImageContext
.ImageCodeMemoryType
= EfiLoaderCode
;
237 Image
->ImageContext
.ImageDataMemoryType
= EfiLoaderData
;
239 case EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER
:
240 Image
->ImageContext
.ImageCodeMemoryType
= EfiBootServicesCode
;
241 Image
->ImageContext
.ImageDataMemoryType
= EfiBootServicesData
;
243 case EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
:
244 case EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER
:
245 Image
->ImageContext
.ImageCodeMemoryType
= EfiRuntimeServicesCode
;
246 Image
->ImageContext
.ImageDataMemoryType
= EfiRuntimeServicesData
;
249 Image
->ImageContext
.ImageError
= IMAGE_ERROR_INVALID_SUBSYSTEM
;
250 return EFI_UNSUPPORTED
;
253 // Get the image base address in the original PeImage.
255 LinkTimeBase
= (UINTN
) Image
->ImageContext
.ImageAddress
;
258 // Allocate memory of the correct memory type aligned on the required image boundry
260 DstBufAlocated
= FALSE
;
261 if (DstBuffer
== 0) {
263 // Allocate Destination Buffer as caller did not pass it in
266 if (Image
->ImageContext
.SectionAlignment
> EFI_PAGE_SIZE
) {
267 Size
= (UINTN
)Image
->ImageContext
.ImageSize
+ Image
->ImageContext
.SectionAlignment
;
269 Size
= (UINTN
)Image
->ImageContext
.ImageSize
;
272 Image
->NumberOfPages
= EFI_SIZE_TO_PAGES (Size
);
275 // If the image relocations have not been stripped, then load at any address.
276 // Otherwise load at the address at which it was linked.
278 // Memory below 1MB should be treated reserved for CSM and there should be
279 // no modules whose preferred load addresses are below 1MB.
281 Status
= EFI_OUT_OF_RESOURCES
;
282 if (Image
->ImageContext
.ImageAddress
>= 0x100000 || Image
->ImageContext
.RelocationsStripped
) {
283 Status
= CoreAllocatePages (
285 (EFI_MEMORY_TYPE
) (Image
->ImageContext
.ImageCodeMemoryType
),
286 Image
->NumberOfPages
,
287 &Image
->ImageContext
.ImageAddress
290 if (EFI_ERROR (Status
) && !Image
->ImageContext
.RelocationsStripped
) {
291 Status
= CoreAllocatePages (
293 (EFI_MEMORY_TYPE
) (Image
->ImageContext
.ImageCodeMemoryType
),
294 Image
->NumberOfPages
,
295 &Image
->ImageContext
.ImageAddress
298 if (EFI_ERROR (Status
)) {
301 DstBufAlocated
= TRUE
;
304 // Caller provided the destination buffer
307 if (Image
->ImageContext
.RelocationsStripped
&& (Image
->ImageContext
.ImageAddress
!= DstBuffer
)) {
309 // If the image relocations were stripped, and the caller provided a
310 // destination buffer address that does not match the address that the
311 // image is linked at, then the image cannot be loaded.
313 return EFI_INVALID_PARAMETER
;
316 if (Image
->NumberOfPages
!= 0 &&
317 Image
->NumberOfPages
<
318 (EFI_SIZE_TO_PAGES ((UINTN
)Image
->ImageContext
.ImageSize
+ Image
->ImageContext
.SectionAlignment
))) {
319 Image
->NumberOfPages
= EFI_SIZE_TO_PAGES ((UINTN
)Image
->ImageContext
.ImageSize
+ Image
->ImageContext
.SectionAlignment
);
320 return EFI_BUFFER_TOO_SMALL
;
323 Image
->NumberOfPages
= EFI_SIZE_TO_PAGES ((UINTN
)Image
->ImageContext
.ImageSize
+ Image
->ImageContext
.SectionAlignment
);
324 Image
->ImageContext
.ImageAddress
= DstBuffer
;
327 Image
->ImageBasePage
= Image
->ImageContext
.ImageAddress
;
328 Image
->ImageContext
.ImageAddress
=
329 (Image
->ImageContext
.ImageAddress
+ Image
->ImageContext
.SectionAlignment
- 1) &
330 ~((UINTN
)Image
->ImageContext
.SectionAlignment
- 1);
333 // Load the image from the file into the allocated memory
335 Status
= PeCoffLoaderLoadImage (&Image
->ImageContext
);
336 if (EFI_ERROR (Status
)) {
341 // If this is a Runtime Driver, then allocate memory for the FixupData that
342 // is used to relocate the image when SetVirtualAddressMap() is called. The
343 // relocation is done by the Runtime AP.
345 if (Attribute
& EFI_LOAD_PE_IMAGE_ATTRIBUTE_RUNTIME_REGISTRATION
) {
346 if (Image
->ImageContext
.ImageType
== EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
) {
347 Image
->ImageContext
.FixupData
= CoreAllocateRuntimePool ((UINTN
)(Image
->ImageContext
.FixupDataSize
));
348 if (Image
->ImageContext
.FixupData
== NULL
) {
349 Status
= EFI_OUT_OF_RESOURCES
;
356 // Measure the image before applying fixup
358 Status
= CoreLocateProtocol (
359 &gEfiTcgPlatformProtocolGuid
,
361 (VOID
**) &TcgPlatformProtocol
363 if (!EFI_ERROR (Status
)) {
364 FHandle
= (IMAGE_FILE_HANDLE
*) Image
->ImageContext
.Handle
;
365 Status
= TcgPlatformProtocol
->MeasurePeImage (
367 (EFI_PHYSICAL_ADDRESS
) (UINTN
) FHandle
->Source
,
370 Image
->ImageContext
.ImageType
,
371 Image
->Info
.DeviceHandle
,
375 ASSERT_EFI_ERROR (Status
);
379 // Relocate the image in memory
381 Status
= PeCoffLoaderRelocateImage (&Image
->ImageContext
);
382 if (EFI_ERROR (Status
)) {
387 // Flush the Instruction Cache
389 InvalidateInstructionCacheRange ((VOID
*)(UINTN
)Image
->ImageContext
.ImageAddress
, (UINTN
)Image
->ImageContext
.ImageSize
);
392 // Copy the machine type from the context to the image private data. This
393 // is needed during image unload to know if we should call an EBC protocol
394 // to unload the image.
396 Image
->Machine
= Image
->ImageContext
.Machine
;
399 // Get the image entry point. If it's an EBC image, then call into the
400 // interpreter to create a thunk for the entry point and use the returned
401 // value for the entry point.
403 Image
->EntryPoint
= (EFI_IMAGE_ENTRY_POINT
)(UINTN
)Image
->ImageContext
.EntryPoint
;
404 if (Image
->ImageContext
.Machine
== EFI_IMAGE_MACHINE_EBC
) {
406 // Locate the EBC interpreter protocol
408 Status
= CoreLocateProtocol (&gEfiEbcProtocolGuid
, NULL
, (VOID
**)&Image
->Ebc
);
409 if (EFI_ERROR(Status
)) {
414 // Register a callback for flushing the instruction cache so that created
415 // thunks can be flushed.
417 Status
= Image
->Ebc
->RegisterICacheFlush (Image
->Ebc
, (EBC_ICACHE_FLUSH
)InvalidateInstructionCacheRange
);
418 if (EFI_ERROR(Status
)) {
423 // Create a thunk for the image's entry point. This will be the new
424 // entry point for the image.
426 Status
= Image
->Ebc
->CreateThunk (
429 (VOID
*)(UINTN
)Image
->ImageContext
.EntryPoint
,
430 (VOID
**)&Image
->EntryPoint
432 if (EFI_ERROR(Status
)) {
438 // Fill in the image information for the Loaded Image Protocol
440 Image
->Type
= Image
->ImageContext
.ImageType
;
441 Image
->Info
.ImageBase
= (VOID
*)(UINTN
)Image
->ImageContext
.ImageAddress
;
442 Image
->Info
.ImageSize
= Image
->ImageContext
.ImageSize
;
443 Image
->Info
.ImageCodeType
= (EFI_MEMORY_TYPE
) (Image
->ImageContext
.ImageCodeMemoryType
);
444 Image
->Info
.ImageDataType
= (EFI_MEMORY_TYPE
) (Image
->ImageContext
.ImageDataMemoryType
);
445 if (Attribute
& EFI_LOAD_PE_IMAGE_ATTRIBUTE_RUNTIME_REGISTRATION
) {
446 if (Image
->ImageContext
.ImageType
== EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
) {
448 // Make a list off all the RT images so we can let the RT AP know about them.
450 Image
->RuntimeData
= CoreAllocateRuntimePool (sizeof(EFI_RUNTIME_IMAGE_ENTRY
));
451 if (Image
->RuntimeData
== NULL
) {
454 Image
->RuntimeData
->ImageBase
= Image
->Info
.ImageBase
;
455 Image
->RuntimeData
->ImageSize
= (UINT64
) (Image
->Info
.ImageSize
);
456 Image
->RuntimeData
->RelocationData
= Image
->ImageContext
.FixupData
;
457 Image
->RuntimeData
->Handle
= Image
->Handle
;
458 InsertTailList (&gRuntime
->ImageHead
, &Image
->RuntimeData
->Link
);
463 // Fill in the entry point of the image if it is available
465 if (EntryPoint
!= NULL
) {
466 *EntryPoint
= Image
->ImageContext
.EntryPoint
;
470 // Print the load address and the PDB file name if it is available
477 CHAR8 EfiFileName
[256];
479 if (Image
->ImageContext
.Machine
!= IMAGE_FILE_MACHINE_IA64
) {
480 DEBUG ((EFI_D_INFO
| EFI_D_LOAD
,
481 "Loading driver at 0x%10p EntryPoint=0x%10p ",
482 (VOID
*)(UINTN
)Image
->ImageContext
.ImageAddress
,
483 (VOID
*)(UINTN
)Image
->ImageContext
.EntryPoint
));
486 // For IPF Image, the real entry point should be print.
488 DEBUG ((EFI_D_INFO
| EFI_D_LOAD
,
489 "Loading driver at 0x%10p EntryPoint=0x%10p ",
490 (VOID
*)(UINTN
)Image
->ImageContext
.ImageAddress
,
491 (VOID
*)(UINTN
)(*(UINT64
*)(UINTN
)Image
->ImageContext
.EntryPoint
)));
495 // Print Module Name by Pdb file path
497 if (Image
->ImageContext
.PdbPointer
!= NULL
) {
499 for (Index
= 0; Image
->ImageContext
.PdbPointer
[Index
] != 0; Index
++) {
500 if (Image
->ImageContext
.PdbPointer
[Index
] == '\\') {
501 StartIndex
= Index
+ 1;
505 // Copy the PDB file name to our temporary string, and replace .pdb with .efi
507 for (Index
= 0; Index
< sizeof (EfiFileName
); Index
++) {
508 EfiFileName
[Index
] = Image
->ImageContext
.PdbPointer
[Index
+ StartIndex
];
509 if (EfiFileName
[Index
] == 0) {
510 EfiFileName
[Index
] = '.';
512 if (EfiFileName
[Index
] == '.') {
513 EfiFileName
[Index
+ 1] = 'e';
514 EfiFileName
[Index
+ 2] = 'f';
515 EfiFileName
[Index
+ 3] = 'i';
516 EfiFileName
[Index
+ 4] = 0;
520 DEBUG ((EFI_D_INFO
| EFI_D_LOAD
, "%a", EfiFileName
)); // &Image->ImageContext.PdbPointer[StartIndex]));
522 DEBUG ((EFI_D_INFO
| EFI_D_LOAD
, "\n"));
534 if (DstBufAlocated
) {
535 CoreFreePages (Image
->ImageContext
.ImageAddress
, Image
->NumberOfPages
);
538 if (Image
->ImageContext
.FixupData
!= NULL
) {
539 CoreFreePool (Image
->ImageContext
.FixupData
);
546 LOADED_IMAGE_PRIVATE_DATA
*
547 CoreLoadedImageInfo (
548 IN EFI_HANDLE ImageHandle
554 Get the image's private data from its handle.
558 ImageHandle - The image handle
562 Return the image private data associated with ImageHandle.
567 EFI_LOADED_IMAGE_PROTOCOL
*LoadedImage
;
568 LOADED_IMAGE_PRIVATE_DATA
*Image
;
570 Status
= CoreHandleProtocol (
572 &gEfiLoadedImageProtocolGuid
,
573 (VOID
**)&LoadedImage
575 if (!EFI_ERROR (Status
)) {
576 Image
= LOADED_IMAGE_PRIVATE_DATA_FROM_THIS (LoadedImage
);
578 DEBUG ((EFI_D_LOAD
, "CoreLoadedImageInfo: Not an ImageHandle %x\n", ImageHandle
));
587 CoreLoadImageCommon (
588 IN BOOLEAN BootPolicy
,
589 IN EFI_HANDLE ParentImageHandle
,
590 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
591 IN VOID
*SourceBuffer OPTIONAL
,
593 IN EFI_PHYSICAL_ADDRESS DstBuffer OPTIONAL
,
594 IN OUT UINTN
*NumberOfPages OPTIONAL
,
595 OUT EFI_HANDLE
*ImageHandle
,
596 OUT EFI_PHYSICAL_ADDRESS
*EntryPoint OPTIONAL
,
603 Loads an EFI image into memory and returns a handle to the image.
607 BootPolicy - If TRUE, indicates that the request originates from the boot manager,
608 and that the boot manager is attempting to load FilePath as a boot selection.
609 ParentImageHandle - The caller's image handle.
610 FilePath - The specific file path from which the image is loaded.
611 SourceBuffer - If not NULL, a pointer to the memory location containing a copy of
612 the image to be loaded.
613 SourceSize - The size in bytes of SourceBuffer.
614 DstBuffer - The buffer to store the image
615 NumberOfPages - If not NULL, a pointer to the image's page number, if this number
616 is not enough, return EFI_BUFFER_TOO_SMALL and this parameter contain
618 ImageHandle - Pointer to the returned image handle that is created when the image
619 is successfully loaded.
620 EntryPoint - A pointer to the entry point
621 Attribute - The bit mask of attributes to set for the load PE image
625 EFI_SUCCESS - The image was loaded into memory.
626 EFI_NOT_FOUND - The FilePath was not found.
627 EFI_INVALID_PARAMETER - One of the parameters has an invalid value.
628 EFI_BUFFER_TOO_SMALL - The buffer is too small
629 EFI_UNSUPPORTED - The image type is not supported, or the device path cannot be
630 parsed to locate the proper protocol for loading the file.
631 EFI_OUT_OF_RESOURCES - Image was not loaded due to insufficient resources.
634 LOADED_IMAGE_PRIVATE_DATA
*Image
;
635 LOADED_IMAGE_PRIVATE_DATA
*ParentImage
;
636 IMAGE_FILE_HANDLE FHand
;
638 EFI_STATUS SecurityStatus
;
639 EFI_HANDLE DeviceHandle
;
640 UINT32 AuthenticationStatus
;
641 EFI_DEVICE_PATH_PROTOCOL
*OriginalFilePath
;
642 EFI_DEVICE_PATH_PROTOCOL
*HandleFilePath
;
645 SecurityStatus
= EFI_SUCCESS
;
647 ASSERT (gEfiCurrentTpl
< TPL_NOTIFY
);
651 // The caller must pass in a valid ParentImageHandle
653 if (ImageHandle
== NULL
|| ParentImageHandle
== NULL
) {
654 return EFI_INVALID_PARAMETER
;
657 ParentImage
= CoreLoadedImageInfo (ParentImageHandle
);
658 if (ParentImage
== NULL
) {
659 DEBUG((EFI_D_LOAD
|EFI_D_ERROR
, "LoadImageEx: Parent handle not an image handle\n"));
660 return EFI_INVALID_PARAMETER
;
664 // Get simple read access to the source file
666 OriginalFilePath
= FilePath
;
667 Status
= CoreOpenImageFile (
674 &AuthenticationStatus
676 if (Status
== EFI_ALREADY_STARTED
) {
679 } else if (EFI_ERROR (Status
)) {
684 // Verify the Authentication Status through the Security Architectural Protocol
686 if ((gSecurity
!= NULL
) && (OriginalFilePath
!= NULL
)) {
687 SecurityStatus
= gSecurity
->FileAuthenticationState (
689 AuthenticationStatus
,
692 if (EFI_ERROR (SecurityStatus
) && SecurityStatus
!= EFI_SECURITY_VIOLATION
) {
693 Status
= SecurityStatus
;
701 // Allocate a new image structure
703 Image
= CoreAllocateZeroBootServicesPool (sizeof(LOADED_IMAGE_PRIVATE_DATA
));
705 return EFI_OUT_OF_RESOURCES
;
709 // Pull out just the file portion of the DevicePath for the LoadedImage FilePath
711 FilePath
= OriginalFilePath
;
712 Status
= CoreHandleProtocol (DeviceHandle
, &gEfiDevicePathProtocolGuid
, (VOID
**)&HandleFilePath
);
713 if (!EFI_ERROR (Status
)) {
714 FilePathSize
= CoreDevicePathSize (HandleFilePath
) - sizeof(EFI_DEVICE_PATH_PROTOCOL
);
715 FilePath
= (EFI_DEVICE_PATH_PROTOCOL
*) ( ((UINT8
*)FilePath
) + FilePathSize
);
719 // Initialize the fields for an internal driver
721 Image
->Signature
= LOADED_IMAGE_PRIVATE_DATA_SIGNATURE
;
722 Image
->Info
.SystemTable
= gDxeCoreST
;
723 Image
->Info
.DeviceHandle
= DeviceHandle
;
724 Image
->Info
.Revision
= EFI_LOADED_IMAGE_INFORMATION_REVISION
;
725 Image
->Info
.FilePath
= CoreDuplicateDevicePath (FilePath
);
726 Image
->Info
.ParentHandle
= ParentImageHandle
;
729 if (NumberOfPages
!= NULL
) {
730 Image
->NumberOfPages
= *NumberOfPages
;
732 Image
->NumberOfPages
= 0 ;
736 // Install the protocol interfaces for this image
737 // don't fire notifications yet
739 Status
= CoreInstallProtocolInterfaceNotify (
741 &gEfiLoadedImageProtocolGuid
,
742 EFI_NATIVE_INTERFACE
,
746 if (EFI_ERROR (Status
)) {
751 // Load the image. If EntryPoint is Null, it will not be set.
753 Status
= CoreLoadPeImage (BootPolicy
, &FHand
, Image
, DstBuffer
, EntryPoint
, Attribute
);
754 if (EFI_ERROR (Status
)) {
755 if ((Status
== EFI_BUFFER_TOO_SMALL
) || (Status
== EFI_OUT_OF_RESOURCES
)) {
756 if (NumberOfPages
!= NULL
) {
757 *NumberOfPages
= Image
->NumberOfPages
;
764 // Register the image in the Debug Image Info Table if the attribute is set
766 if (Attribute
& EFI_LOAD_PE_IMAGE_ATTRIBUTE_DEBUG_IMAGE_INFO_TABLE_REGISTRATION
) {
767 CoreNewDebugImageInfoEntry (EFI_DEBUG_IMAGE_INFO_TYPE_NORMAL
, &Image
->Info
, Image
->Handle
);
771 //Reinstall loaded image protocol to fire any notifications
773 Status
= CoreReinstallProtocolInterface (
775 &gEfiLoadedImageProtocolGuid
,
779 if (EFI_ERROR (Status
)) {
784 // If DevicePath parameter to the LoadImage() is not NULL, then make a copy of DevicePath,
785 // otherwise Loaded Image Device Path Protocol is installed with a NULL interface pointer.
787 if (OriginalFilePath
!= NULL
) {
788 Image
->LoadedImageDevicePath
= CoreDuplicateDevicePath (OriginalFilePath
);
792 // Install Loaded Image Device Path Protocol onto the image handle of a PE/COFE image
794 Status
= CoreInstallProtocolInterface (
796 &gEfiLoadedImageDevicePathProtocolGuid
,
797 EFI_NATIVE_INTERFACE
,
798 Image
->LoadedImageDevicePath
800 if (EFI_ERROR (Status
)) {
805 // Success. Return the image handle
807 *ImageHandle
= Image
->Handle
;
811 // All done accessing the source file
812 // If we allocated the Source buffer, free it
814 if (FHand
.FreeBuffer
) {
815 CoreFreePool (FHand
.Source
);
819 // There was an error. If there's an Image structure, free it
821 if (EFI_ERROR (Status
)) {
823 CoreUnloadAndCloseImage (Image
, (BOOLEAN
)(DstBuffer
== 0));
826 } else if (EFI_ERROR (SecurityStatus
)) {
827 Status
= SecurityStatus
;
838 IN BOOLEAN BootPolicy
,
839 IN EFI_HANDLE ParentImageHandle
,
840 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
841 IN VOID
*SourceBuffer OPTIONAL
,
843 OUT EFI_HANDLE
*ImageHandle
849 Loads an EFI image into memory and returns a handle to the image.
853 BootPolicy - If TRUE, indicates that the request originates from the boot manager,
854 and that the boot manager is attempting to load FilePath as a boot selection.
855 ParentImageHandle - The caller's image handle.
856 FilePath - The specific file path from which the image is loaded.
857 SourceBuffer - If not NULL, a pointer to the memory location containing a copy of
858 the image to be loaded.
859 SourceSize - The size in bytes of SourceBuffer.
860 ImageHandle - Pointer to the returned image handle that is created when the image
861 is successfully loaded.
865 EFI_SUCCESS - The image was loaded into memory.
866 EFI_NOT_FOUND - The FilePath was not found.
867 EFI_INVALID_PARAMETER - One of the parameters has an invalid value.
868 EFI_UNSUPPORTED - The image type is not supported, or the device path cannot be
869 parsed to locate the proper protocol for loading the file.
870 EFI_OUT_OF_RESOURCES - Image was not loaded due to insufficient resources.
875 PERF_START (NULL
, "LoadImage", NULL
, 0);
877 Status
= CoreLoadImageCommon (
883 (EFI_PHYSICAL_ADDRESS
) (UINTN
) NULL
,
887 EFI_LOAD_PE_IMAGE_ATTRIBUTE_RUNTIME_REGISTRATION
| EFI_LOAD_PE_IMAGE_ATTRIBUTE_DEBUG_IMAGE_INFO_TABLE_REGISTRATION
890 PERF_END (NULL
, "LoadImage", NULL
, 0);
899 IN EFI_PE32_IMAGE_PROTOCOL
*This
,
900 IN EFI_HANDLE ParentImageHandle
,
901 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
902 IN VOID
*SourceBuffer OPTIONAL
,
904 IN EFI_PHYSICAL_ADDRESS DstBuffer OPTIONAL
,
905 OUT UINTN
*NumberOfPages OPTIONAL
,
906 OUT EFI_HANDLE
*ImageHandle
,
907 OUT EFI_PHYSICAL_ADDRESS
*EntryPoint OPTIONAL
,
914 Loads an EFI image into memory and returns a handle to the image with extended parameters.
918 This - Calling context
919 ParentImageHandle - The caller's image handle.
920 FilePath - The specific file path from which the image is loaded.
921 SourceBuffer - If not NULL, a pointer to the memory location containing a copy of
922 the image to be loaded.
923 SourceSize - The size in bytes of SourceBuffer.
924 DstBuffer - The buffer to store the image.
925 NumberOfPages - For input, specifies the space size of the image by caller if not NULL.
926 For output, specifies the actual space size needed.
927 ImageHandle - Image handle for output.
928 EntryPoint - Image entry point for output.
929 Attribute - The bit mask of attributes to set for the load PE image.
933 EFI_SUCCESS - The image was loaded into memory.
934 EFI_NOT_FOUND - The FilePath was not found.
935 EFI_INVALID_PARAMETER - One of the parameters has an invalid value.
936 EFI_UNSUPPORTED - The image type is not supported, or the device path cannot be
937 parsed to locate the proper protocol for loading the file.
938 EFI_OUT_OF_RESOURCES - Image was not loaded due to insufficient resources.
941 return CoreLoadImageCommon (
958 IN EFI_HANDLE ImageHandle
,
959 OUT UINTN
*ExitDataSize
,
960 OUT CHAR16
**ExitData OPTIONAL
966 Transfer control to a loaded image's entry point.
970 ImageHandle - Handle of image to be started.
972 ExitDataSize - Pointer of the size to ExitData
974 ExitData - Pointer to a pointer to a data buffer that includes a Null-terminated
975 Unicode string, optionally followed by additional binary data. The string
976 is a description that the caller may use to further indicate the reason for
981 EFI_INVALID_PARAMETER - Invalid parameter
983 EFI_OUT_OF_RESOURCES - No enough buffer to allocate
985 EFI_SUCCESS - Successfully transfer control to the image's entry point.
990 LOADED_IMAGE_PRIVATE_DATA
*Image
;
991 LOADED_IMAGE_PRIVATE_DATA
*LastImage
;
992 UINT64 HandleDatabaseKey
;
995 Image
= CoreLoadedImageInfo (ImageHandle
);
996 if (Image
== NULL_HANDLE
|| Image
->Started
) {
997 return EFI_INVALID_PARAMETER
;
1001 // Don't profile Objects or invalid start requests
1003 PERF_START (ImageHandle
, START_IMAGE_TOK
, NULL
, 0);
1007 // Push the current start image context, and
1008 // link the current image to the head. This is the
1009 // only image that can call Exit()
1011 HandleDatabaseKey
= CoreGetHandleDatabaseKey ();
1012 LastImage
= mCurrentImage
;
1013 mCurrentImage
= Image
;
1014 Image
->Tpl
= gEfiCurrentTpl
;
1017 // Set long jump for Exit() support
1018 // JumpContext must be aligned on a CPU specific boundary.
1019 // Overallocate the buffer and force the required alignment
1021 Image
->JumpBuffer
= CoreAllocateBootServicesPool (sizeof (BASE_LIBRARY_JUMP_BUFFER
) + BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT
);
1022 if (Image
->JumpBuffer
== NULL
) {
1023 PERF_END (ImageHandle
, START_IMAGE_TOK
, NULL
, 0);
1024 return EFI_OUT_OF_RESOURCES
;
1026 Image
->JumpContext
= ALIGN_POINTER (Image
->JumpBuffer
, BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT
);
1028 SetJumpFlag
= SetJump (Image
->JumpContext
);
1030 // The initial call to SetJump() must always return 0.
1031 // Subsequent calls to LongJump() cause a non-zero value to be returned by SetJump().
1035 // Call the image's entry point
1037 Image
->Started
= TRUE
;
1038 Image
->Status
= Image
->EntryPoint (ImageHandle
, Image
->Info
.SystemTable
);
1041 // Add some debug information if the image returned with error.
1042 // This make the user aware and check if the driver image have already released
1043 // all the resource in this situation.
1045 DEBUG_CODE_BEGIN ();
1046 if (EFI_ERROR (Image
->Status
)) {
1047 DEBUG ((EFI_D_ERROR
, "Error: Image at %10p start failed: %r\n", Image
->Info
.ImageBase
, Image
->Status
));
1052 // If the image returns, exit it through Exit()
1054 CoreExit (ImageHandle
, Image
->Status
, 0, NULL
);
1058 // Image has completed. Verify the tpl is the same
1060 ASSERT (Image
->Tpl
== gEfiCurrentTpl
);
1061 CoreRestoreTpl (Image
->Tpl
);
1063 CoreFreePool (Image
->JumpBuffer
);
1066 // Pop the current start image context
1068 mCurrentImage
= LastImage
;
1071 // Go connect any handles that were created or modified while the image executed.
1073 CoreConnectHandlesByKey (HandleDatabaseKey
);
1076 // Handle the image's returned ExitData
1078 DEBUG_CODE_BEGIN ();
1079 if (Image
->ExitDataSize
!= 0 || Image
->ExitData
!= NULL
) {
1083 "StartImage: ExitDataSize %d, ExitData %x",
1084 Image
->ExitDataSize
,
1087 if (Image
->ExitData
!= NULL
) {
1088 DEBUG ((EFI_D_LOAD
, " (%hs)", Image
->ExitData
));
1090 DEBUG ((EFI_D_LOAD
, "\n"));
1095 // Return the exit data to the caller
1097 if (ExitData
!= NULL
&& ExitDataSize
!= NULL
) {
1098 *ExitDataSize
= Image
->ExitDataSize
;
1099 *ExitData
= Image
->ExitData
;
1102 // Caller doesn't want the exit data, free it
1104 CoreFreePool (Image
->ExitData
);
1105 Image
->ExitData
= NULL
;
1109 // Save the Status because Image will get destroyed if it is unloaded.
1111 Status
= Image
->Status
;
1114 // If the image returned an error, or if the image is an application
1117 if (EFI_ERROR (Image
->Status
) || Image
->Type
== EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION
) {
1118 CoreUnloadAndCloseImage (Image
, TRUE
);
1124 PERF_END (ImageHandle
, START_IMAGE_TOK
, NULL
, 0);
1130 CoreUnloadAndCloseImage (
1131 IN LOADED_IMAGE_PRIVATE_DATA
*Image
,
1136 Routine Description:
1138 Unloads EFI image from memory.
1143 FreePage - Free allocated pages
1153 EFI_HANDLE
*HandleBuffer
;
1155 EFI_GUID
**ProtocolGuidArray
;
1157 UINTN ProtocolIndex
;
1158 EFI_OPEN_PROTOCOL_INFORMATION_ENTRY
*OpenInfo
;
1159 UINTN OpenInfoCount
;
1160 UINTN OpenInfoIndex
;
1162 if (Image
->Ebc
!= NULL
) {
1164 // If EBC protocol exists we must perform cleanups for this image.
1166 Image
->Ebc
->UnloadImage (Image
->Ebc
, Image
->Handle
);
1170 // Unload image, free Image->ImageContext->ModHandle
1172 PeCoffLoaderUnloadImage (&Image
->ImageContext
);
1175 // Free our references to the image handle
1177 if (Image
->Handle
!= NULL_HANDLE
) {
1179 Status
= CoreLocateHandleBuffer (
1186 if (!EFI_ERROR (Status
)) {
1187 for (HandleIndex
= 0; HandleIndex
< HandleCount
; HandleIndex
++) {
1188 Status
= CoreProtocolsPerHandle (
1189 HandleBuffer
[HandleIndex
],
1193 if (!EFI_ERROR (Status
)) {
1194 for (ProtocolIndex
= 0; ProtocolIndex
< ArrayCount
; ProtocolIndex
++) {
1195 Status
= CoreOpenProtocolInformation (
1196 HandleBuffer
[HandleIndex
],
1197 ProtocolGuidArray
[ProtocolIndex
],
1201 if (!EFI_ERROR (Status
)) {
1202 for (OpenInfoIndex
= 0; OpenInfoIndex
< OpenInfoCount
; OpenInfoIndex
++) {
1203 if (OpenInfo
[OpenInfoIndex
].AgentHandle
== Image
->Handle
) {
1204 Status
= CoreCloseProtocol (
1205 HandleBuffer
[HandleIndex
],
1206 ProtocolGuidArray
[ProtocolIndex
],
1208 OpenInfo
[OpenInfoIndex
].ControllerHandle
1212 if (OpenInfo
!= NULL
) {
1213 CoreFreePool(OpenInfo
);
1217 if (ProtocolGuidArray
!= NULL
) {
1218 CoreFreePool(ProtocolGuidArray
);
1222 if (HandleBuffer
!= NULL
) {
1223 CoreFreePool (HandleBuffer
);
1227 CoreRemoveDebugImageInfoEntry (Image
->Handle
);
1229 Status
= CoreUninstallProtocolInterface (
1231 &gEfiLoadedImageDevicePathProtocolGuid
,
1232 Image
->LoadedImageDevicePath
1235 Status
= CoreUninstallProtocolInterface (
1237 &gEfiLoadedImageProtocolGuid
,
1243 if (Image
->RuntimeData
!= NULL
) {
1244 if (Image
->RuntimeData
->Link
.ForwardLink
!= NULL
) {
1246 // Remove the Image from the Runtime Image list as we are about to Free it!
1248 RemoveEntryList (&Image
->RuntimeData
->Link
);
1250 CoreFreePool (Image
->RuntimeData
);
1254 // Free the Image from memory
1256 if ((Image
->ImageBasePage
!= 0) && FreePage
) {
1257 CoreFreePages (Image
->ImageBasePage
, Image
->NumberOfPages
);
1261 // Done with the Image structure
1263 if (Image
->Info
.FilePath
!= NULL
) {
1264 CoreFreePool (Image
->Info
.FilePath
);
1267 if (Image
->LoadedImageDevicePath
!= NULL
) {
1268 CoreFreePool (Image
->LoadedImageDevicePath
);
1271 if (Image
->FixupData
!= NULL
) {
1272 CoreFreePool (Image
->FixupData
);
1275 CoreFreePool (Image
);
1283 IN EFI_HANDLE ImageHandle
,
1284 IN EFI_STATUS Status
,
1285 IN UINTN ExitDataSize
,
1286 IN CHAR16
*ExitData OPTIONAL
1290 Routine Description:
1292 Terminates the currently loaded EFI image and returns control to boot services.
1296 ImageHandle - Handle that identifies the image. This parameter is passed to the image
1298 Status - The image's exit code.
1299 ExitDataSize - The size, in bytes, of ExitData. Ignored if ExitStatus is
1301 ExitData - Pointer to a data buffer that includes a Null-terminated Unicode string,
1302 optionally followed by additional binary data. The string is a
1303 description that the caller may use to further indicate the reason for
1308 EFI_INVALID_PARAMETER - Image handle is NULL or it is not current image.
1310 EFI_SUCCESS - Successfully terminates the currently loaded EFI image.
1312 EFI_ACCESS_DENIED - Should never reach there.
1314 EFI_OUT_OF_RESOURCES - Could not allocate pool
1318 LOADED_IMAGE_PRIVATE_DATA
*Image
;
1322 // Prevent possible reentrance to this function
1323 // for the same ImageHandle
1325 OldTpl
= CoreRaiseTpl (TPL_NOTIFY
);
1327 Image
= CoreLoadedImageInfo (ImageHandle
);
1328 if (Image
== NULL_HANDLE
) {
1329 Status
= EFI_INVALID_PARAMETER
;
1333 if (!Image
->Started
) {
1335 // The image has not been started so just free its resources
1337 CoreUnloadAndCloseImage (Image
, TRUE
);
1338 Status
= EFI_SUCCESS
;
1343 // Image has been started, verify this image can exit
1345 if (Image
!= mCurrentImage
) {
1346 DEBUG ((EFI_D_LOAD
|EFI_D_ERROR
, "Exit: Image is not exitable image\n"));
1347 Status
= EFI_INVALID_PARAMETER
;
1354 Image
->Status
= Status
;
1357 // If there's ExitData info, move it
1359 if (ExitData
!= NULL
) {
1360 Image
->ExitDataSize
= ExitDataSize
;
1361 Image
->ExitData
= CoreAllocateBootServicesPool (Image
->ExitDataSize
);
1362 if (Image
->ExitData
== NULL
) {
1363 Status
= EFI_OUT_OF_RESOURCES
;
1366 CopyMem (Image
->ExitData
, ExitData
, Image
->ExitDataSize
);
1369 CoreRestoreTpl (OldTpl
);
1371 // return to StartImage
1373 LongJump (Image
->JumpContext
, (UINTN
)-1);
1376 // If we return from LongJump, then it is an error
1379 Status
= EFI_ACCESS_DENIED
;
1381 CoreRestoreTpl (OldTpl
);
1390 IN EFI_HANDLE ImageHandle
1394 Routine Description:
1400 ImageHandle - Handle that identifies the image to be unloaded.
1404 EFI_SUCCESS - The image has been unloaded.
1405 EFI_UNSUPPORTED - The image has been sarted, and does not support unload.
1406 EFI_INVALID_PARAMPETER - ImageHandle is not a valid image handle.
1411 LOADED_IMAGE_PRIVATE_DATA
*Image
;
1415 // Prevent possible reentrance to this function
1416 // for the same ImageHandle
1418 OldTpl
= CoreRaiseTpl (TPL_NOTIFY
);
1420 Image
= CoreLoadedImageInfo (ImageHandle
);
1421 if (Image
== NULL
) {
1423 // The image handle is not valid
1425 Status
= EFI_INVALID_PARAMETER
;
1429 if (Image
->Started
) {
1431 // The image has been started, request it to unload.
1433 Status
= EFI_UNSUPPORTED
;
1434 if (Image
->Info
.Unload
!= NULL
) {
1435 Status
= Image
->Info
.Unload (ImageHandle
);
1440 // This Image hasn't been started, thus it can be unloaded
1442 Status
= EFI_SUCCESS
;
1446 if (!EFI_ERROR (Status
)) {
1448 // if the Image was not started or Unloaded O.K. then clean up
1450 CoreUnloadAndCloseImage (Image
, TRUE
);
1454 CoreRestoreTpl (OldTpl
);
1462 IN EFI_PE32_IMAGE_PROTOCOL
*This
,
1463 IN EFI_HANDLE ImageHandle
1467 Routine Description:
1469 Unload the specified image.
1473 This - Indicates the calling context.
1475 ImageHandle - The specified image handle.
1479 EFI_INVALID_PARAMETER - Image handle is NULL.
1481 EFI_UNSUPPORTED - Attempt to unload an unsupported image.
1483 EFI_SUCCESS - Image successfully unloaded.
1487 return CoreUnloadImage (ImageHandle
);