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