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