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