]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Core/Dxe/Image/Image.c
1. CoreOpenImageFile(): FilePath should be IN OUT.
[mirror_edk2.git] / MdeModulePkg / Core / Dxe / Image / Image.c
1 /*++
2
3 Copyright (c) 2006 - 2007, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11
12 Module Name:
13
14 Image.c
15
16 Abstract:
17
18 Core image handling services
19
20 --*/
21
22 #include <DxeMain.h>
23 //
24 // Module Globals
25 //
26
27 LOADED_IMAGE_PRIVATE_DATA *mCurrentImage = NULL;
28
29 LOAD_PE32_IMAGE_PRIVATE_DATA mLoadPe32PrivateData = {
30 LOAD_PE32_IMAGE_PRIVATE_DATA_SIGNATURE,
31 NULL,
32 {
33 CoreLoadImageEx,
34 CoreUnloadImageEx
35 }
36 };
37
38
39 //
40 // This code is needed to build the Image handle for the DXE Core
41 //
42 LOADED_IMAGE_PRIVATE_DATA mCorePrivateImage = {
43 LOADED_IMAGE_PRIVATE_DATA_SIGNATURE, // Signature
44 NULL, // Image handle
45 EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER, // Image type
46 TRUE, // If entrypoint has been called
47 NULL, // EntryPoint
48 {
49 EFI_LOADED_IMAGE_INFORMATION_REVISION, // Revision
50 NULL, // Parent handle
51 NULL, // System handle
52
53 NULL, // Device handle
54 NULL, // File path
55 NULL, // Reserved
56
57 0, // LoadOptionsSize
58 NULL, // LoadOptions
59
60 NULL, // ImageBase
61 0, // ImageSize
62 EfiBootServicesCode, // ImageCodeType
63 EfiBootServicesData // ImageDataType
64 },
65 (EFI_PHYSICAL_ADDRESS)0, // ImageBasePage
66 0, // NumberOfPages
67 NULL, // FixupData
68 0, // Tpl
69 EFI_SUCCESS, // Status
70 0, // ExitDataSize
71 NULL, // ExitData
72 NULL, // JumpBuffer
73 NULL, // JumpContext
74 0, // Machine
75 NULL, // Ebc
76 NULL, // RuntimeData
77 NULL, // DeviceHandleDevicePath
78 };
79
80
81 EFI_STATUS
82 CoreInitializeImageServices (
83 IN VOID *HobStart
84 )
85 /*++
86
87 Routine Description:
88
89 Add the Image Services to EFI Boot Services Table and install the protocol
90 interfaces for this image.
91
92 Arguments:
93
94 HobStart - The HOB to initialize
95
96 Returns:
97
98 Status code.
99
100 --*/
101 {
102 EFI_STATUS Status;
103 LOADED_IMAGE_PRIVATE_DATA *Image;
104 EFI_PHYSICAL_ADDRESS DxeCoreImageBaseAddress;
105 UINT64 DxeCoreImageLength;
106 VOID *DxeCoreEntryPoint;
107 EFI_PEI_HOB_POINTERS DxeCoreHob;
108 //
109 // Searching for image hob
110 //
111 DxeCoreHob.Raw = HobStart;
112 while ((DxeCoreHob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, DxeCoreHob.Raw)) != NULL) {
113 if (CompareGuid (&DxeCoreHob.MemoryAllocationModule->MemoryAllocationHeader.Name, &gEfiHobMemoryAllocModuleGuid)) {
114 //
115 // Find Dxe Core HOB
116 //
117 break;
118 }
119 DxeCoreHob.Raw = GET_NEXT_HOB (DxeCoreHob);
120 }
121 ASSERT (DxeCoreHob.Raw != NULL);
122
123 DxeCoreImageBaseAddress = DxeCoreHob.MemoryAllocationModule->MemoryAllocationHeader.MemoryBaseAddress;
124 DxeCoreImageLength = DxeCoreHob.MemoryAllocationModule->MemoryAllocationHeader.MemoryLength;
125 DxeCoreEntryPoint = (VOID *) (UINTN) DxeCoreHob.MemoryAllocationModule->EntryPoint;
126 gDxeCoreFileName = &DxeCoreHob.MemoryAllocationModule->ModuleName;
127 //
128 // Initialize the fields for an internal driver
129 //
130 Image = &mCorePrivateImage;
131
132 Image->EntryPoint = (EFI_IMAGE_ENTRY_POINT)(UINTN)DxeCoreEntryPoint;
133 Image->ImageBasePage = DxeCoreImageBaseAddress;
134 Image->NumberOfPages = (UINTN)(EFI_SIZE_TO_PAGES((UINTN)(DxeCoreImageLength)));
135 Image->Tpl = gEfiCurrentTpl;
136 Image->Info.SystemTable = gDxeCoreST;
137 Image->Info.ImageBase = (VOID *)(UINTN)DxeCoreImageBaseAddress;
138 Image->Info.ImageSize = DxeCoreImageLength;
139
140 //
141 // Install the protocol interfaces for this image
142 //
143 Status = CoreInstallProtocolInterface (
144 &Image->Handle,
145 &gEfiLoadedImageProtocolGuid,
146 EFI_NATIVE_INTERFACE,
147 &Image->Info
148 );
149 ASSERT_EFI_ERROR (Status);
150
151 mCurrentImage = Image;
152
153 //
154 // Fill in DXE globals
155 //
156 gDxeCoreImageHandle = Image->Handle;
157 gDxeCoreLoadedImage = &Image->Info;
158
159 //
160 // Export DXE Core PE Loader functionality
161 //
162 return CoreInstallProtocolInterface (
163 &mLoadPe32PrivateData.Handle,
164 &gEfiLoadPeImageProtocolGuid,
165 EFI_NATIVE_INTERFACE,
166 &mLoadPe32PrivateData.Pe32Image
167 );
168 }
169
170 EFI_STATUS
171 CoreLoadPeImage (
172 IN VOID *Pe32Handle,
173 IN LOADED_IMAGE_PRIVATE_DATA *Image,
174 IN EFI_PHYSICAL_ADDRESS DstBuffer OPTIONAL,
175 OUT EFI_PHYSICAL_ADDRESS *EntryPoint OPTIONAL,
176 IN UINT32 Attribute
177 )
178 /*++
179
180 Routine Description:
181
182 Loads, relocates, and invokes a PE/COFF image
183
184 Arguments:
185
186 Pe32Handle - The handle of PE32 image
187 Image - PE image to be loaded
188 DstBuffer - The buffer to store the image
189 EntryPoint - A pointer to the entry point
190 Attribute - The bit mask of attributes to set for the load PE image
191
192 Returns:
193
194 EFI_SUCCESS - The file was loaded, relocated, and invoked
195
196 EFI_OUT_OF_RESOURCES - There was not enough memory to load and relocate the PE/COFF file
197
198 EFI_INVALID_PARAMETER - Invalid parameter
199
200 EFI_BUFFER_TOO_SMALL - Buffer for image is too small
201
202 --*/
203 {
204 EFI_STATUS Status;
205 BOOLEAN DstBufAlocated;
206 UINTN Size;
207
208 ZeroMem (&Image->ImageContext, sizeof (Image->ImageContext));
209
210 Image->ImageContext.Handle = Pe32Handle;
211 Image->ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE)CoreReadImageFile;
212
213 //
214 // Get information about the image being loaded
215 //
216 Status = PeCoffLoaderGetImageInfo (&Image->ImageContext);
217 if (EFI_ERROR (Status)) {
218 return Status;
219 }
220
221 if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Image->ImageContext.Machine)) {
222 //
223 // The PE/COFF loader can support loading image types that can be executed.
224 // If we loaded an image type that we can not execute return EFI_UNSUPORTED.
225 //
226 return EFI_UNSUPPORTED;
227 }
228
229 //
230 // Set EFI memory type based on ImageType
231 //
232 switch (Image->ImageContext.ImageType) {
233 case EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION:
234 Image->ImageContext.ImageCodeMemoryType = EfiLoaderCode;
235 Image->ImageContext.ImageDataMemoryType = EfiLoaderData;
236 break;
237 case EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER:
238 Image->ImageContext.ImageCodeMemoryType = EfiBootServicesCode;
239 Image->ImageContext.ImageDataMemoryType = EfiBootServicesData;
240 break;
241 case EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER:
242 case EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER:
243 Image->ImageContext.ImageCodeMemoryType = EfiRuntimeServicesCode;
244 Image->ImageContext.ImageDataMemoryType = EfiRuntimeServicesData;
245 break;
246 default:
247 Image->ImageContext.ImageError = IMAGE_ERROR_INVALID_SUBSYSTEM;
248 return EFI_UNSUPPORTED;
249 }
250
251 //
252 // Allocate memory of the correct memory type aligned on the required image boundry
253 //
254 DstBufAlocated = FALSE;
255 if (DstBuffer == 0) {
256 //
257 // Allocate Destination Buffer as caller did not pass it in
258 //
259
260 if (Image->ImageContext.SectionAlignment > EFI_PAGE_SIZE) {
261 Size = (UINTN)Image->ImageContext.ImageSize + Image->ImageContext.SectionAlignment;
262 } else {
263 Size = (UINTN)Image->ImageContext.ImageSize;
264 }
265
266 Image->NumberOfPages = EFI_SIZE_TO_PAGES (Size);
267
268 //
269 // If the image relocations have not been stripped, then load at any address.
270 // Otherwise load at the address at which it was linked.
271 //
272 // Memory below 1MB should be treated reserved for CSM and there should be
273 // no modules whose preferred load addresses are below 1MB.
274 //
275 Status = EFI_OUT_OF_RESOURCES;
276 if (Image->ImageContext.ImageAddress >= 0x100000 || Image->ImageContext.RelocationsStripped) {
277 Status = CoreAllocatePages (
278 AllocateAddress,
279 (EFI_MEMORY_TYPE) (Image->ImageContext.ImageCodeMemoryType),
280 Image->NumberOfPages,
281 &Image->ImageContext.ImageAddress
282 );
283 }
284 if (EFI_ERROR (Status) && !Image->ImageContext.RelocationsStripped) {
285 Status = CoreAllocatePages (
286 AllocateAnyPages,
287 (EFI_MEMORY_TYPE) (Image->ImageContext.ImageCodeMemoryType),
288 Image->NumberOfPages,
289 &Image->ImageContext.ImageAddress
290 );
291 }
292 if (EFI_ERROR (Status)) {
293 return Status;
294 }
295 DstBufAlocated = TRUE;
296 } else {
297 //
298 // Caller provided the destination buffer
299 //
300
301 if (Image->ImageContext.RelocationsStripped && (Image->ImageContext.ImageAddress != DstBuffer)) {
302 //
303 // If the image relocations were stripped, and the caller provided a
304 // destination buffer address that does not match the address that the
305 // image is linked at, then the image cannot be loaded.
306 //
307 return EFI_INVALID_PARAMETER;
308 }
309
310 if (Image->NumberOfPages != 0 &&
311 Image->NumberOfPages <
312 (EFI_SIZE_TO_PAGES ((UINTN)Image->ImageContext.ImageSize + Image->ImageContext.SectionAlignment))) {
313 Image->NumberOfPages = EFI_SIZE_TO_PAGES ((UINTN)Image->ImageContext.ImageSize + Image->ImageContext.SectionAlignment);
314 return EFI_BUFFER_TOO_SMALL;
315 }
316
317 Image->NumberOfPages = EFI_SIZE_TO_PAGES ((UINTN)Image->ImageContext.ImageSize + Image->ImageContext.SectionAlignment);
318 Image->ImageContext.ImageAddress = DstBuffer;
319 }
320
321 Image->ImageBasePage = Image->ImageContext.ImageAddress;
322 Image->ImageContext.ImageAddress =
323 (Image->ImageContext.ImageAddress + Image->ImageContext.SectionAlignment - 1) &
324 ~((UINTN)Image->ImageContext.SectionAlignment - 1);
325
326 //
327 // Load the image from the file into the allocated memory
328 //
329 Status = PeCoffLoaderLoadImage (&Image->ImageContext);
330 if (EFI_ERROR (Status)) {
331 goto Done;
332 }
333
334 //
335 // If this is a Runtime Driver, then allocate memory for the FixupData that
336 // is used to relocate the image when SetVirtualAddressMap() is called. The
337 // relocation is done by the Runtime AP.
338 //
339 if (Attribute & EFI_LOAD_PE_IMAGE_ATTRIBUTE_RUNTIME_REGISTRATION) {
340 if (Image->ImageContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) {
341 Image->ImageContext.FixupData = CoreAllocateRuntimePool ((UINTN)(Image->ImageContext.FixupDataSize));
342 if (Image->ImageContext.FixupData == NULL) {
343 Status = EFI_OUT_OF_RESOURCES;
344 goto Done;
345 }
346 }
347 }
348
349 //
350 // Relocate the image in memory
351 //
352 Status = PeCoffLoaderRelocateImage (&Image->ImageContext);
353 if (EFI_ERROR (Status)) {
354 goto Done;
355 }
356
357 //
358 // Flush the Instruction Cache
359 //
360 InvalidateInstructionCacheRange ((VOID *)(UINTN)Image->ImageContext.ImageAddress, (UINTN)Image->ImageContext.ImageSize);
361
362 //
363 // Copy the machine type from the context to the image private data. This
364 // is needed during image unload to know if we should call an EBC protocol
365 // to unload the image.
366 //
367 Image->Machine = Image->ImageContext.Machine;
368
369 //
370 // Get the image entry point. If it's an EBC image, then call into the
371 // interpreter to create a thunk for the entry point and use the returned
372 // value for the entry point.
373 //
374 Image->EntryPoint = (EFI_IMAGE_ENTRY_POINT)(UINTN)Image->ImageContext.EntryPoint;
375 if (Image->ImageContext.Machine == EFI_IMAGE_MACHINE_EBC) {
376 //
377 // Locate the EBC interpreter protocol
378 //
379 Status = CoreLocateProtocol (&gEfiEbcProtocolGuid, NULL, (VOID **)&Image->Ebc);
380 if (EFI_ERROR(Status)) {
381 goto Done;
382 }
383
384 //
385 // Register a callback for flushing the instruction cache so that created
386 // thunks can be flushed.
387 //
388 Status = Image->Ebc->RegisterICacheFlush (Image->Ebc, (EBC_ICACHE_FLUSH)InvalidateInstructionCacheRange);
389 if (EFI_ERROR(Status)) {
390 goto Done;
391 }
392
393 //
394 // Create a thunk for the image's entry point. This will be the new
395 // entry point for the image.
396 //
397 Status = Image->Ebc->CreateThunk (
398 Image->Ebc,
399 Image->Handle,
400 (VOID *)(UINTN)Image->ImageContext.EntryPoint,
401 (VOID **)&Image->EntryPoint
402 );
403 if (EFI_ERROR(Status)) {
404 goto Done;
405 }
406 }
407
408 //
409 // Fill in the image information for the Loaded Image Protocol
410 //
411 Image->Type = Image->ImageContext.ImageType;
412 Image->Info.ImageBase = (VOID *)(UINTN)Image->ImageContext.ImageAddress;
413 Image->Info.ImageSize = Image->ImageContext.ImageSize;
414 Image->Info.ImageCodeType = (EFI_MEMORY_TYPE) (Image->ImageContext.ImageCodeMemoryType);
415 Image->Info.ImageDataType = (EFI_MEMORY_TYPE) (Image->ImageContext.ImageDataMemoryType);
416 if (Attribute & EFI_LOAD_PE_IMAGE_ATTRIBUTE_RUNTIME_REGISTRATION) {
417 if (Image->ImageContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) {
418 //
419 // Make a list off all the RT images so we can let the RT AP know about them.
420 //
421 Image->RuntimeData = CoreAllocateRuntimePool (sizeof(EFI_RUNTIME_IMAGE_ENTRY));
422 if (Image->RuntimeData == NULL) {
423 goto Done;
424 }
425 Image->RuntimeData->ImageBase = Image->Info.ImageBase;
426 Image->RuntimeData->ImageSize = (UINT64) (Image->Info.ImageSize);
427 Image->RuntimeData->RelocationData = Image->ImageContext.FixupData;
428 Image->RuntimeData->Handle = Image->Handle;
429 InsertTailList (&gRuntime->ImageHead, &Image->RuntimeData->Link);
430 }
431 }
432
433 //
434 // Fill in the entry point of the image if it is available
435 //
436 if (EntryPoint != NULL) {
437 *EntryPoint = Image->ImageContext.EntryPoint;
438 }
439
440 //
441 // Print the load address and the PDB file name if it is available
442 //
443
444 DEBUG_CODE_BEGIN ();
445
446 UINTN Index;
447 UINTN StartIndex;
448 CHAR8 EfiFileName[256];
449
450 if (Image->ImageContext.Machine != IMAGE_FILE_MACHINE_IA64) {
451 DEBUG ((EFI_D_INFO | EFI_D_LOAD,
452 "Loading driver at 0x%10p EntryPoint=0x%10p ",
453 (VOID *)(UINTN)Image->ImageContext.ImageAddress,
454 (VOID *)(UINTN)Image->ImageContext.EntryPoint));
455 } else {
456 //
457 // For IPF Image, the real entry point should be print.
458 //
459 DEBUG ((EFI_D_INFO | EFI_D_LOAD,
460 "Loading driver at 0x%10p EntryPoint=0x%10p ",
461 (VOID *)(UINTN)Image->ImageContext.ImageAddress,
462 (VOID *)(UINTN)(*(UINT64 *)(UINTN)Image->ImageContext.EntryPoint)));
463 }
464
465 //
466 // Print Module Name by Pdb file path
467 //
468 if (Image->ImageContext.PdbPointer != NULL) {
469 StartIndex = 0;
470 for (Index = 0; Image->ImageContext.PdbPointer[Index] != 0; Index++) {
471 if (Image->ImageContext.PdbPointer[Index] == '\\') {
472 StartIndex = Index + 1;
473 }
474 }
475 //
476 // Copy the PDB file name to our temporary string, and replace .pdb with .efi
477 //
478 for (Index = 0; Index < sizeof (EfiFileName); Index++) {
479 EfiFileName[Index] = Image->ImageContext.PdbPointer[Index + StartIndex];
480 if (EfiFileName[Index] == 0) {
481 EfiFileName[Index] = '.';
482 }
483 if (EfiFileName[Index] == '.') {
484 EfiFileName[Index + 1] = 'e';
485 EfiFileName[Index + 2] = 'f';
486 EfiFileName[Index + 3] = 'i';
487 EfiFileName[Index + 4] = 0;
488 break;
489 }
490 }
491 DEBUG ((EFI_D_INFO | EFI_D_LOAD, "%a", EfiFileName)); // &Image->ImageContext.PdbPointer[StartIndex]));
492 }
493 DEBUG ((EFI_D_INFO | EFI_D_LOAD, "\n"));
494
495 DEBUG_CODE_END ();
496
497 return EFI_SUCCESS;
498
499 Done:
500
501 //
502 // Free memory.
503 //
504
505 if (DstBufAlocated) {
506 CoreFreePages (Image->ImageContext.ImageAddress, Image->NumberOfPages);
507 }
508
509 if (Image->ImageContext.FixupData != NULL) {
510 CoreFreePool (Image->ImageContext.FixupData);
511 }
512
513 return Status;
514 }
515
516
517 LOADED_IMAGE_PRIVATE_DATA *
518 CoreLoadedImageInfo (
519 IN EFI_HANDLE ImageHandle
520 )
521 /*++
522
523 Routine Description:
524
525 Get the image's private data from its handle.
526
527 Arguments:
528
529 ImageHandle - The image handle
530
531 Returns:
532
533 Return the image private data associated with ImageHandle.
534
535 --*/
536 {
537 EFI_STATUS Status;
538 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
539 LOADED_IMAGE_PRIVATE_DATA *Image;
540
541 Status = CoreHandleProtocol (
542 ImageHandle,
543 &gEfiLoadedImageProtocolGuid,
544 (VOID **)&LoadedImage
545 );
546 if (!EFI_ERROR (Status)) {
547 Image = LOADED_IMAGE_PRIVATE_DATA_FROM_THIS (LoadedImage);
548 } else {
549 DEBUG ((EFI_D_LOAD, "CoreLoadedImageInfo: Not an ImageHandle %x\n", ImageHandle));
550 Image = NULL;
551 }
552
553 return Image;
554 }
555
556 STATIC
557 EFI_STATUS
558 CoreLoadImageCommon (
559 IN BOOLEAN BootPolicy,
560 IN EFI_HANDLE ParentImageHandle,
561 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
562 IN VOID *SourceBuffer OPTIONAL,
563 IN UINTN SourceSize,
564 IN EFI_PHYSICAL_ADDRESS DstBuffer OPTIONAL,
565 IN OUT UINTN *NumberOfPages OPTIONAL,
566 OUT EFI_HANDLE *ImageHandle,
567 OUT EFI_PHYSICAL_ADDRESS *EntryPoint OPTIONAL,
568 IN UINT32 Attribute
569 )
570 /*++
571
572 Routine Description:
573
574 Loads an EFI image into memory and returns a handle to the image.
575
576 Arguments:
577
578 BootPolicy - If TRUE, indicates that the request originates from the boot manager,
579 and that the boot manager is attempting to load FilePath as a boot selection.
580 ParentImageHandle - The caller's image handle.
581 FilePath - The specific file path from which the image is loaded.
582 SourceBuffer - If not NULL, a pointer to the memory location containing a copy of
583 the image to be loaded.
584 SourceSize - The size in bytes of SourceBuffer.
585 DstBuffer - The buffer to store the image
586 NumberOfPages - If not NULL, a pointer to the image's page number, if this number
587 is not enough, return EFI_BUFFER_TOO_SMALL and this parameter contain
588 the required number.
589 ImageHandle - Pointer to the returned image handle that is created when the image
590 is successfully loaded.
591 EntryPoint - A pointer to the entry point
592 Attribute - The bit mask of attributes to set for the load PE image
593
594 Returns:
595
596 EFI_SUCCESS - The image was loaded into memory.
597 EFI_NOT_FOUND - The FilePath was not found.
598 EFI_INVALID_PARAMETER - One of the parameters has an invalid value.
599 EFI_BUFFER_TOO_SMALL - The buffer is too small
600 EFI_UNSUPPORTED - The image type is not supported, or the device path cannot be
601 parsed to locate the proper protocol for loading the file.
602 EFI_OUT_OF_RESOURCES - Image was not loaded due to insufficient resources.
603 --*/
604 {
605 LOADED_IMAGE_PRIVATE_DATA *Image;
606 LOADED_IMAGE_PRIVATE_DATA *ParentImage;
607 IMAGE_FILE_HANDLE FHand;
608 EFI_STATUS Status;
609 EFI_STATUS SecurityStatus;
610 EFI_HANDLE DeviceHandle;
611 UINT32 AuthenticationStatus;
612 EFI_DEVICE_PATH_PROTOCOL *OriginalFilePath;
613 EFI_DEVICE_PATH_PROTOCOL *HandleFilePath;
614 UINTN FilePathSize;
615
616 SecurityStatus = EFI_SUCCESS;
617
618 ASSERT (gEfiCurrentTpl < TPL_NOTIFY);
619 ParentImage = NULL;
620
621 //
622 // The caller must pass in a valid ParentImageHandle
623 //
624 if (ImageHandle == NULL || ParentImageHandle == NULL) {
625 return EFI_INVALID_PARAMETER;
626 }
627
628 ParentImage = CoreLoadedImageInfo (ParentImageHandle);
629 if (ParentImage == NULL) {
630 DEBUG((EFI_D_LOAD|EFI_D_ERROR, "LoadImageEx: Parent handle not an image handle\n"));
631 return EFI_INVALID_PARAMETER;
632 }
633
634 //
635 // Get simple read access to the source file
636 //
637 OriginalFilePath = FilePath;
638 Status = CoreOpenImageFile (
639 BootPolicy,
640 SourceBuffer,
641 SourceSize,
642 &FilePath,
643 &DeviceHandle,
644 &FHand,
645 &AuthenticationStatus
646 );
647 if (Status == EFI_ALREADY_STARTED) {
648 Image = NULL;
649 goto Done;
650 } else if (EFI_ERROR (Status)) {
651 return Status;
652 }
653
654 //
655 // Verify the Authentication Status through the Security Architectural Protocol
656 //
657 if ((gSecurity != NULL) && (OriginalFilePath != NULL)) {
658 SecurityStatus = gSecurity->FileAuthenticationState (
659 gSecurity,
660 AuthenticationStatus,
661 OriginalFilePath
662 );
663 if (EFI_ERROR (SecurityStatus) && SecurityStatus != EFI_SECURITY_VIOLATION) {
664 Status = SecurityStatus;
665 Image = NULL;
666 goto Done;
667 }
668 }
669
670
671 //
672 // Allocate a new image structure
673 //
674 Image = CoreAllocateZeroBootServicesPool (sizeof(LOADED_IMAGE_PRIVATE_DATA));
675 if (Image == NULL) {
676 return EFI_OUT_OF_RESOURCES;
677 }
678
679 //
680 // Pull out just the file portion of the DevicePath for the LoadedImage FilePath
681 //
682 FilePath = OriginalFilePath;
683 Status = CoreHandleProtocol (DeviceHandle, &gEfiDevicePathProtocolGuid, (VOID **)&HandleFilePath);
684 if (!EFI_ERROR (Status)) {
685 FilePathSize = CoreDevicePathSize (HandleFilePath) - sizeof(EFI_DEVICE_PATH_PROTOCOL);
686 FilePath = (EFI_DEVICE_PATH_PROTOCOL *) ( ((UINT8 *)FilePath) + FilePathSize );
687 Image->DeviceHandleDevicePath = CoreDuplicateDevicePath (HandleFilePath);
688 }
689
690 //
691 // Initialize the fields for an internal driver
692 //
693 Image->Signature = LOADED_IMAGE_PRIVATE_DATA_SIGNATURE;
694 Image->Info.SystemTable = gDxeCoreST;
695 Image->Info.DeviceHandle = DeviceHandle;
696 Image->Info.Revision = EFI_LOADED_IMAGE_INFORMATION_REVISION;
697 Image->Info.FilePath = CoreDuplicateDevicePath (FilePath);
698 Image->Info.ParentHandle = ParentImageHandle;
699
700
701 if (NumberOfPages != NULL) {
702 Image->NumberOfPages = *NumberOfPages ;
703 } else {
704 Image->NumberOfPages = 0 ;
705 }
706
707 //
708 // Install the protocol interfaces for this image
709 // don't fire notifications yet
710 //
711 Status = CoreInstallProtocolInterfaceNotify (
712 &Image->Handle,
713 &gEfiLoadedImageProtocolGuid,
714 EFI_NATIVE_INTERFACE,
715 &Image->Info,
716 FALSE
717 );
718 if (EFI_ERROR (Status)) {
719 goto Done;
720 }
721
722 //
723 // Load the image. If EntryPoint is Null, it will not be set.
724 //
725 Status = CoreLoadPeImage (&FHand, Image, DstBuffer, EntryPoint, Attribute);
726 if (EFI_ERROR (Status)) {
727 if ((Status == EFI_BUFFER_TOO_SMALL) || (Status == EFI_OUT_OF_RESOURCES)) {
728 if (NumberOfPages != NULL) {
729 *NumberOfPages = Image->NumberOfPages;
730 }
731 }
732 goto Done;
733 }
734
735 //
736 // Register the image in the Debug Image Info Table if the attribute is set
737 //
738 if (Attribute & EFI_LOAD_PE_IMAGE_ATTRIBUTE_DEBUG_IMAGE_INFO_TABLE_REGISTRATION) {
739 CoreNewDebugImageInfoEntry (EFI_DEBUG_IMAGE_INFO_TYPE_NORMAL, &Image->Info, Image->Handle);
740 }
741
742 //
743 //Reinstall loaded image protocol to fire any notifications
744 //
745 Status = CoreReinstallProtocolInterface (
746 Image->Handle,
747 &gEfiLoadedImageProtocolGuid,
748 &Image->Info,
749 &Image->Info
750 );
751 if (EFI_ERROR (Status)) {
752 goto Done;
753 }
754
755
756 //
757 // Success. Return the image handle
758 //
759 *ImageHandle = Image->Handle;
760
761 Done:
762 //
763 // All done accessing the source file
764 // If we allocated the Source buffer, free it
765 //
766 if (FHand.FreeBuffer) {
767 CoreFreePool (FHand.Source);
768 }
769
770 //
771 // There was an error. If there's an Image structure, free it
772 //
773 if (EFI_ERROR (Status)) {
774 if (Image != NULL) {
775 CoreUnloadAndCloseImage (Image, (BOOLEAN)(DstBuffer == 0));
776 *ImageHandle = NULL;
777 }
778 } else if (EFI_ERROR (SecurityStatus)) {
779 Status = SecurityStatus;
780 }
781
782 return Status;
783 }
784
785
786
787 EFI_STATUS
788 EFIAPI
789 CoreLoadImage (
790 IN BOOLEAN BootPolicy,
791 IN EFI_HANDLE ParentImageHandle,
792 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
793 IN VOID *SourceBuffer OPTIONAL,
794 IN UINTN SourceSize,
795 OUT EFI_HANDLE *ImageHandle
796 )
797 /*++
798
799 Routine Description:
800
801 Loads an EFI image into memory and returns a handle to the image.
802
803 Arguments:
804
805 BootPolicy - If TRUE, indicates that the request originates from the boot manager,
806 and that the boot manager is attempting to load FilePath as a boot selection.
807 ParentImageHandle - The caller's image handle.
808 FilePath - The specific file path from which the image is loaded.
809 SourceBuffer - If not NULL, a pointer to the memory location containing a copy of
810 the image to be loaded.
811 SourceSize - The size in bytes of SourceBuffer.
812 ImageHandle - Pointer to the returned image handle that is created when the image
813 is successfully loaded.
814
815 Returns:
816
817 EFI_SUCCESS - The image was loaded into memory.
818 EFI_NOT_FOUND - The FilePath was not found.
819 EFI_INVALID_PARAMETER - One of the parameters has an invalid value.
820 EFI_UNSUPPORTED - The image type is not supported, or the device path cannot be
821 parsed to locate the proper protocol for loading the file.
822 EFI_OUT_OF_RESOURCES - Image was not loaded due to insufficient resources.
823 --*/
824 {
825 EFI_STATUS Status;
826
827 PERF_START (NULL, "LoadImage", NULL, 0);
828
829 Status = CoreLoadImageCommon (
830 BootPolicy,
831 ParentImageHandle,
832 FilePath,
833 SourceBuffer,
834 SourceSize,
835 (EFI_PHYSICAL_ADDRESS)NULL,
836 NULL,
837 ImageHandle,
838 NULL,
839 EFI_LOAD_PE_IMAGE_ATTRIBUTE_RUNTIME_REGISTRATION | EFI_LOAD_PE_IMAGE_ATTRIBUTE_DEBUG_IMAGE_INFO_TABLE_REGISTRATION
840 );
841
842 PERF_END (NULL, "LoadImage", NULL, 0);
843
844 return Status;
845 }
846
847
848 EFI_STATUS
849 EFIAPI
850 CoreLoadImageEx (
851 IN EFI_PE32_IMAGE_PROTOCOL *This,
852 IN EFI_HANDLE ParentImageHandle,
853 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
854 IN VOID *SourceBuffer OPTIONAL,
855 IN UINTN SourceSize,
856 IN EFI_PHYSICAL_ADDRESS DstBuffer OPTIONAL,
857 OUT UINTN *NumberOfPages OPTIONAL,
858 OUT EFI_HANDLE *ImageHandle,
859 OUT EFI_PHYSICAL_ADDRESS *EntryPoint OPTIONAL,
860 IN UINT32 Attribute
861 )
862 /*++
863
864 Routine Description:
865
866 Loads an EFI image into memory and returns a handle to the image with extended parameters.
867
868 Arguments:
869
870 This - Calling context
871 ParentImageHandle - The caller's image handle.
872 FilePath - The specific file path from which the image is loaded.
873 SourceBuffer - If not NULL, a pointer to the memory location containing a copy of
874 the image to be loaded.
875 SourceSize - The size in bytes of SourceBuffer.
876 DstBuffer - The buffer to store the image.
877 NumberOfPages - For input, specifies the space size of the image by caller if not NULL.
878 For output, specifies the actual space size needed.
879 ImageHandle - Image handle for output.
880 EntryPoint - Image entry point for output.
881 Attribute - The bit mask of attributes to set for the load PE image.
882
883 Returns:
884
885 EFI_SUCCESS - The image was loaded into memory.
886 EFI_NOT_FOUND - The FilePath was not found.
887 EFI_INVALID_PARAMETER - One of the parameters has an invalid value.
888 EFI_UNSUPPORTED - The image type is not supported, or the device path cannot be
889 parsed to locate the proper protocol for loading the file.
890 EFI_OUT_OF_RESOURCES - Image was not loaded due to insufficient resources.
891 --*/
892 {
893 return CoreLoadImageCommon (
894 TRUE,
895 ParentImageHandle,
896 FilePath,
897 SourceBuffer,
898 SourceSize,
899 DstBuffer,
900 NumberOfPages,
901 ImageHandle,
902 EntryPoint,
903 Attribute
904 );
905 }
906
907
908
909
910 EFI_STATUS
911 EFIAPI
912 CoreStartImage (
913 IN EFI_HANDLE ImageHandle,
914 OUT UINTN *ExitDataSize,
915 OUT CHAR16 **ExitData OPTIONAL
916 )
917 /*++
918
919 Routine Description:
920
921 Transfer control to a loaded image's entry point.
922
923 Arguments:
924
925 ImageHandle - Handle of image to be started.
926
927 ExitDataSize - Pointer of the size to ExitData
928
929 ExitData - Pointer to a pointer to a data buffer that includes a Null-terminated
930 Unicode string, optionally followed by additional binary data. The string
931 is a description that the caller may use to further indicate the reason for
932 the image's exit.
933
934 Returns:
935
936 EFI_INVALID_PARAMETER - Invalid parameter
937
938 EFI_OUT_OF_RESOURCES - No enough buffer to allocate
939
940 EFI_SUCCESS - Successfully transfer control to the image's entry point.
941
942 --*/
943 {
944 EFI_STATUS Status;
945 LOADED_IMAGE_PRIVATE_DATA *Image;
946 LOADED_IMAGE_PRIVATE_DATA *LastImage;
947 UINT64 HandleDatabaseKey;
948 UINTN SetJumpFlag;
949
950 Image = CoreLoadedImageInfo (ImageHandle);
951 if (Image == NULL_HANDLE || Image->Started) {
952 return EFI_INVALID_PARAMETER;
953 }
954
955 //
956 // Don't profile Objects or invalid start requests
957 //
958 PERF_START (ImageHandle, START_IMAGE_TOK, NULL, 0);
959
960
961 //
962 // Push the current start image context, and
963 // link the current image to the head. This is the
964 // only image that can call Exit()
965 //
966 HandleDatabaseKey = CoreGetHandleDatabaseKey ();
967 LastImage = mCurrentImage;
968 mCurrentImage = Image;
969 Image->Tpl = gEfiCurrentTpl;
970
971 //
972 // Set long jump for Exit() support
973 // JumpContext must be aligned on a CPU specific boundary.
974 // Overallocate the buffer and force the required alignment
975 //
976 Image->JumpBuffer = CoreAllocateBootServicesPool (sizeof (BASE_LIBRARY_JUMP_BUFFER) + BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT);
977 if (Image->JumpBuffer == NULL) {
978 PERF_END (ImageHandle, START_IMAGE_TOK, NULL, 0);
979 return EFI_OUT_OF_RESOURCES;
980 }
981 Image->JumpContext = ALIGN_POINTER (Image->JumpBuffer, BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT);
982
983 SetJumpFlag = SetJump (Image->JumpContext);
984 //
985 // The initial call to SetJump() must always return 0.
986 // Subsequent calls to LongJump() cause a non-zero value to be returned by SetJump().
987 //
988 if (!SetJumpFlag) {
989 //
990 // Call the image's entry point
991 //
992 Image->Started = TRUE;
993 Image->Status = Image->EntryPoint (ImageHandle, Image->Info.SystemTable);
994
995 //
996 // Add some debug information if the image returned with error.
997 // This make the user aware and check if the driver image have already released
998 // all the resource in this situation.
999 //
1000 DEBUG_CODE_BEGIN ();
1001 if (EFI_ERROR (Image->Status)) {
1002 DEBUG ((EFI_D_ERROR, "Error: Image at %10p start failed: %r\n", Image->Info.ImageBase, Image->Status));
1003 }
1004 DEBUG_CODE_END ();
1005
1006 //
1007 // If the image returns, exit it through Exit()
1008 //
1009 CoreExit (ImageHandle, Image->Status, 0, NULL);
1010 }
1011
1012 //
1013 // Image has completed. Verify the tpl is the same
1014 //
1015 ASSERT (Image->Tpl == gEfiCurrentTpl);
1016 CoreRestoreTpl (Image->Tpl);
1017
1018 CoreFreePool (Image->JumpBuffer);
1019
1020 //
1021 // Pop the current start image context
1022 //
1023 mCurrentImage = LastImage;
1024
1025 //
1026 // Go connect any handles that were created or modified while the image executed.
1027 //
1028 CoreConnectHandlesByKey (HandleDatabaseKey);
1029
1030 //
1031 // Handle the image's returned ExitData
1032 //
1033 DEBUG_CODE_BEGIN ();
1034 if (Image->ExitDataSize != 0 || Image->ExitData != NULL) {
1035
1036 DEBUG (
1037 (EFI_D_LOAD,
1038 "StartImage: ExitDataSize %d, ExitData %x",
1039 Image->ExitDataSize,
1040 Image->ExitData)
1041 );
1042 if (Image->ExitData != NULL) {
1043 DEBUG ((EFI_D_LOAD, " (%hs)", Image->ExitData));
1044 }
1045 DEBUG ((EFI_D_LOAD, "\n"));
1046 }
1047 DEBUG_CODE_END ();
1048
1049 //
1050 // Return the exit data to the caller
1051 //
1052 if (ExitData != NULL && ExitDataSize != NULL) {
1053 *ExitDataSize = Image->ExitDataSize;
1054 *ExitData = Image->ExitData;
1055 } else {
1056 //
1057 // Caller doesn't want the exit data, free it
1058 //
1059 CoreFreePool (Image->ExitData);
1060 Image->ExitData = NULL;
1061 }
1062
1063 //
1064 // Save the Status because Image will get destroyed if it is unloaded.
1065 //
1066 Status = Image->Status;
1067
1068 //
1069 // If the image returned an error, or if the image is an application
1070 // unload it
1071 //
1072 if (EFI_ERROR (Image->Status) || Image->Type == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) {
1073 CoreUnloadAndCloseImage (Image, TRUE);
1074 }
1075
1076 //
1077 // Done
1078 //
1079 PERF_END (ImageHandle, START_IMAGE_TOK, NULL, 0);
1080 return Status;
1081 }
1082
1083
1084 VOID
1085 CoreUnloadAndCloseImage (
1086 IN LOADED_IMAGE_PRIVATE_DATA *Image,
1087 IN BOOLEAN FreePage
1088 )
1089 /*++
1090
1091 Routine Description:
1092
1093 Unloads EFI image from memory.
1094
1095 Arguments:
1096
1097 Image - EFI image
1098 FreePage - Free allocated pages
1099
1100 Returns:
1101
1102 None
1103
1104 --*/
1105 {
1106 EFI_STATUS Status;
1107 UINTN HandleCount;
1108 EFI_HANDLE *HandleBuffer;
1109 UINTN HandleIndex;
1110 EFI_GUID **ProtocolGuidArray;
1111 UINTN ArrayCount;
1112 UINTN ProtocolIndex;
1113 EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfo;
1114 UINTN OpenInfoCount;
1115 UINTN OpenInfoIndex;
1116
1117 if (Image->Ebc != NULL) {
1118 //
1119 // If EBC protocol exists we must perform cleanups for this image.
1120 //
1121 Image->Ebc->UnloadImage (Image->Ebc, Image->Handle);
1122 }
1123
1124 //
1125 // Unload image, free Image->ImageContext->ModHandle
1126 //
1127 PeCoffLoaderUnloadImage (&Image->ImageContext);
1128
1129 //
1130 // Free our references to the image handle
1131 //
1132 if (Image->Handle != NULL_HANDLE) {
1133
1134 Status = CoreLocateHandleBuffer (
1135 AllHandles,
1136 NULL,
1137 NULL,
1138 &HandleCount,
1139 &HandleBuffer
1140 );
1141 if (!EFI_ERROR (Status)) {
1142 for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) {
1143 Status = CoreProtocolsPerHandle (
1144 HandleBuffer[HandleIndex],
1145 &ProtocolGuidArray,
1146 &ArrayCount
1147 );
1148 if (!EFI_ERROR (Status)) {
1149 for (ProtocolIndex = 0; ProtocolIndex < ArrayCount; ProtocolIndex++) {
1150 Status = CoreOpenProtocolInformation (
1151 HandleBuffer[HandleIndex],
1152 ProtocolGuidArray[ProtocolIndex],
1153 &OpenInfo,
1154 &OpenInfoCount
1155 );
1156 if (!EFI_ERROR (Status)) {
1157 for (OpenInfoIndex = 0; OpenInfoIndex < OpenInfoCount; OpenInfoIndex++) {
1158 if (OpenInfo[OpenInfoIndex].AgentHandle == Image->Handle) {
1159 Status = CoreCloseProtocol (
1160 HandleBuffer[HandleIndex],
1161 ProtocolGuidArray[ProtocolIndex],
1162 Image->Handle,
1163 OpenInfo[OpenInfoIndex].ControllerHandle
1164 );
1165 }
1166 }
1167 if (OpenInfo != NULL) {
1168 CoreFreePool(OpenInfo);
1169 }
1170 }
1171 }
1172 if (ProtocolGuidArray != NULL) {
1173 CoreFreePool(ProtocolGuidArray);
1174 }
1175 }
1176 }
1177 if (HandleBuffer != NULL) {
1178 CoreFreePool (HandleBuffer);
1179 }
1180 }
1181
1182 CoreRemoveDebugImageInfoEntry (Image->Handle);
1183
1184 Status = CoreUninstallProtocolInterface (
1185 Image->Handle,
1186 &gEfiLoadedImageProtocolGuid,
1187 &Image->Info
1188 );
1189 }
1190
1191 if (Image->RuntimeData != NULL) {
1192 if (Image->RuntimeData->Link.ForwardLink != NULL) {
1193 //
1194 // Remove the Image from the Runtime Image list as we are about to Free it!
1195 //
1196 RemoveEntryList (&Image->RuntimeData->Link);
1197 }
1198 CoreFreePool (Image->RuntimeData);
1199 }
1200
1201 //
1202 // Free the Image from memory
1203 //
1204 if ((Image->ImageBasePage != 0) && FreePage) {
1205 CoreFreePages (Image->ImageBasePage, Image->NumberOfPages);
1206 }
1207
1208 //
1209 // Done with the Image structure
1210 //
1211 if (Image->Info.FilePath != NULL) {
1212 CoreFreePool (Image->Info.FilePath);
1213 }
1214
1215 if (Image->DeviceHandleDevicePath != NULL) {
1216 CoreFreePool (Image->DeviceHandleDevicePath);
1217 }
1218
1219 if (Image->FixupData != NULL) {
1220 CoreFreePool (Image->FixupData);
1221 }
1222
1223 CoreFreePool (Image);
1224 }
1225
1226
1227
1228 EFI_STATUS
1229 EFIAPI
1230 CoreExit (
1231 IN EFI_HANDLE ImageHandle,
1232 IN EFI_STATUS Status,
1233 IN UINTN ExitDataSize,
1234 IN CHAR16 *ExitData OPTIONAL
1235 )
1236 /*++
1237
1238 Routine Description:
1239
1240 Terminates the currently loaded EFI image and returns control to boot services.
1241
1242 Arguments:
1243
1244 ImageHandle - Handle that identifies the image. This parameter is passed to the image
1245 on entry.
1246 Status - The image's exit code.
1247 ExitDataSize - The size, in bytes, of ExitData. Ignored if ExitStatus is
1248 EFI_SUCCESS.
1249 ExitData - Pointer to a data buffer that includes a Null-terminated Unicode string,
1250 optionally followed by additional binary data. The string is a
1251 description that the caller may use to further indicate the reason for
1252 the image's exit.
1253
1254 Returns:
1255
1256 EFI_INVALID_PARAMETER - Image handle is NULL or it is not current image.
1257
1258 EFI_SUCCESS - Successfully terminates the currently loaded EFI image.
1259
1260 EFI_ACCESS_DENIED - Should never reach there.
1261
1262 EFI_OUT_OF_RESOURCES - Could not allocate pool
1263
1264 --*/
1265 {
1266 LOADED_IMAGE_PRIVATE_DATA *Image;
1267 EFI_TPL OldTpl;
1268
1269 //
1270 // Prevent possible reentrance to this function
1271 // for the same ImageHandle
1272 //
1273 OldTpl = CoreRaiseTpl (TPL_NOTIFY);
1274
1275 Image = CoreLoadedImageInfo (ImageHandle);
1276 if (Image == NULL_HANDLE) {
1277 Status = EFI_INVALID_PARAMETER;
1278 goto Done;
1279 }
1280
1281 if (!Image->Started) {
1282 //
1283 // The image has not been started so just free its resources
1284 //
1285 CoreUnloadAndCloseImage (Image, TRUE);
1286 Status = EFI_SUCCESS;
1287 goto Done;
1288 }
1289
1290 //
1291 // Image has been started, verify this image can exit
1292 //
1293 if (Image != mCurrentImage) {
1294 DEBUG ((EFI_D_LOAD|EFI_D_ERROR, "Exit: Image is not exitable image\n"));
1295 Status = EFI_INVALID_PARAMETER;
1296 goto Done;
1297 }
1298
1299 //
1300 // Set status
1301 //
1302 Image->Status = Status;
1303
1304 //
1305 // If there's ExitData info, move it
1306 //
1307 if (ExitData != NULL) {
1308 Image->ExitDataSize = ExitDataSize;
1309 Image->ExitData = CoreAllocateBootServicesPool (Image->ExitDataSize);
1310 if (Image->ExitData == NULL) {
1311 Status = EFI_OUT_OF_RESOURCES;
1312 goto Done;
1313 }
1314 CopyMem (Image->ExitData, ExitData, Image->ExitDataSize);
1315 }
1316
1317 CoreRestoreTpl (OldTpl);
1318 //
1319 // return to StartImage
1320 //
1321 LongJump (Image->JumpContext, (UINTN)-1);
1322
1323 //
1324 // If we return from LongJump, then it is an error
1325 //
1326 ASSERT (FALSE);
1327 Status = EFI_ACCESS_DENIED;
1328 Done:
1329 CoreRestoreTpl (OldTpl);
1330 return Status;
1331 }
1332
1333
1334
1335 EFI_STATUS
1336 EFIAPI
1337 CoreUnloadImage (
1338 IN EFI_HANDLE ImageHandle
1339 )
1340 /*++
1341
1342 Routine Description:
1343
1344 Unloads an image.
1345
1346 Arguments:
1347
1348 ImageHandle - Handle that identifies the image to be unloaded.
1349
1350 Returns:
1351
1352 EFI_SUCCESS - The image has been unloaded.
1353 EFI_UNSUPPORTED - The image has been sarted, and does not support unload.
1354 EFI_INVALID_PARAMPETER - ImageHandle is not a valid image handle.
1355
1356 --*/
1357 {
1358 EFI_STATUS Status;
1359 LOADED_IMAGE_PRIVATE_DATA *Image;
1360 EFI_TPL OldTpl;
1361
1362 //
1363 // Prevent possible reentrance to this function
1364 // for the same ImageHandle
1365 //
1366 OldTpl = CoreRaiseTpl (TPL_NOTIFY);
1367
1368 Image = CoreLoadedImageInfo (ImageHandle);
1369 if (Image == NULL ) {
1370 //
1371 // The image handle is not valid
1372 //
1373 Status = EFI_INVALID_PARAMETER;
1374 goto Done;
1375 }
1376
1377 if (Image->Started) {
1378 //
1379 // The image has been started, request it to unload.
1380 //
1381 Status = EFI_UNSUPPORTED;
1382 if (Image->Info.Unload != NULL) {
1383 Status = Image->Info.Unload (ImageHandle);
1384 }
1385
1386 } else {
1387 //
1388 // This Image hasn't been started, thus it can be unloaded
1389 //
1390 Status = EFI_SUCCESS;
1391 }
1392
1393
1394 if (!EFI_ERROR (Status)) {
1395 //
1396 // if the Image was not started or Unloaded O.K. then clean up
1397 //
1398 CoreUnloadAndCloseImage (Image, TRUE);
1399 }
1400
1401 Done:
1402 CoreRestoreTpl (OldTpl);
1403 return Status;
1404 }
1405
1406
1407 EFI_STATUS
1408 EFIAPI
1409 CoreUnloadImageEx (
1410 IN EFI_PE32_IMAGE_PROTOCOL *This,
1411 IN EFI_HANDLE ImageHandle
1412 )
1413 /*++
1414
1415 Routine Description:
1416
1417 Unload the specified image.
1418
1419 Arguments:
1420
1421 This - Indicates the calling context.
1422
1423 ImageHandle - The specified image handle.
1424
1425 Returns:
1426
1427 EFI_INVALID_PARAMETER - Image handle is NULL.
1428
1429 EFI_UNSUPPORTED - Attempt to unload an unsupported image.
1430
1431 EFI_SUCCESS - Image successfully unloaded.
1432
1433 --*/
1434 {
1435 return CoreUnloadImage (ImageHandle);
1436 }