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