]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Core/Dxe/Image/Image.c
Add doxygen style comments for functions in DxeMain.
[mirror_edk2.git] / MdeModulePkg / Core / Dxe / Image / Image.c
1 /** @file
2
3 Core image handling services to load and unload PeImage.
4
5 Copyright (c) 2006 - 2008, Intel Corporation
6 All rights reserved. This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
10
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13
14 **/
15
16 #include <DxeMain.h>
17 //
18 // Module Globals
19 //
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 Image->ImageContext.ImageAddress =
319 (Image->ImageContext.ImageAddress + Image->ImageContext.SectionAlignment - 1) &
320 ~((UINTN)Image->ImageContext.SectionAlignment - 1);
321
322 //
323 // Load the image from the file into the allocated memory
324 //
325 Status = PeCoffLoaderLoadImage (&Image->ImageContext);
326 if (EFI_ERROR (Status)) {
327 goto Done;
328 }
329
330 //
331 // If this is a Runtime Driver, then allocate memory for the FixupData that
332 // is used to relocate the image when SetVirtualAddressMap() is called. The
333 // relocation is done by the Runtime AP.
334 //
335 if (Attribute & EFI_LOAD_PE_IMAGE_ATTRIBUTE_RUNTIME_REGISTRATION) {
336 if (Image->ImageContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) {
337 Image->ImageContext.FixupData = CoreAllocateRuntimePool ((UINTN)(Image->ImageContext.FixupDataSize));
338 if (Image->ImageContext.FixupData == NULL) {
339 Status = EFI_OUT_OF_RESOURCES;
340 goto Done;
341 }
342 }
343 }
344
345 //
346 // Measure the image before applying fixup
347 //
348 Status = CoreLocateProtocol (
349 &gEfiTcgPlatformProtocolGuid,
350 NULL,
351 (VOID **) &TcgPlatformProtocol
352 );
353 if (!EFI_ERROR (Status)) {
354 FHandle = (IMAGE_FILE_HANDLE *) Image->ImageContext.Handle;
355 Status = TcgPlatformProtocol->MeasurePeImage (
356 BootPolicy,
357 (EFI_PHYSICAL_ADDRESS) (UINTN) FHandle->Source,
358 FHandle->SourceSize,
359 LinkTimeBase,
360 Image->ImageContext.ImageType,
361 Image->Info.DeviceHandle,
362 Image->Info.FilePath
363 );
364
365 ASSERT_EFI_ERROR (Status);
366 }
367
368 //
369 // Relocate the image in memory
370 //
371 Status = PeCoffLoaderRelocateImage (&Image->ImageContext);
372 if (EFI_ERROR (Status)) {
373 goto Done;
374 }
375
376 //
377 // Flush the Instruction Cache
378 //
379 InvalidateInstructionCacheRange ((VOID *)(UINTN)Image->ImageContext.ImageAddress, (UINTN)Image->ImageContext.ImageSize);
380
381 //
382 // Copy the machine type from the context to the image private data. This
383 // is needed during image unload to know if we should call an EBC protocol
384 // to unload the image.
385 //
386 Image->Machine = Image->ImageContext.Machine;
387
388 //
389 // Get the image entry point. If it's an EBC image, then call into the
390 // interpreter to create a thunk for the entry point and use the returned
391 // value for the entry point.
392 //
393 Image->EntryPoint = (EFI_IMAGE_ENTRY_POINT)(UINTN)Image->ImageContext.EntryPoint;
394 if (Image->ImageContext.Machine == EFI_IMAGE_MACHINE_EBC) {
395 //
396 // Locate the EBC interpreter protocol
397 //
398 Status = CoreLocateProtocol (&gEfiEbcProtocolGuid, NULL, (VOID **)&Image->Ebc);
399 if (EFI_ERROR(Status)) {
400 goto Done;
401 }
402
403 //
404 // Register a callback for flushing the instruction cache so that created
405 // thunks can be flushed.
406 //
407 Status = Image->Ebc->RegisterICacheFlush (Image->Ebc, (EBC_ICACHE_FLUSH)InvalidateInstructionCacheRange);
408 if (EFI_ERROR(Status)) {
409 goto Done;
410 }
411
412 //
413 // Create a thunk for the image's entry point. This will be the new
414 // entry point for the image.
415 //
416 Status = Image->Ebc->CreateThunk (
417 Image->Ebc,
418 Image->Handle,
419 (VOID *)(UINTN)Image->ImageContext.EntryPoint,
420 (VOID **)&Image->EntryPoint
421 );
422 if (EFI_ERROR(Status)) {
423 goto Done;
424 }
425 }
426
427 //
428 // Fill in the image information for the Loaded Image Protocol
429 //
430 Image->Type = Image->ImageContext.ImageType;
431 Image->Info.ImageBase = (VOID *)(UINTN)Image->ImageContext.ImageAddress;
432 Image->Info.ImageSize = Image->ImageContext.ImageSize;
433 Image->Info.ImageCodeType = (EFI_MEMORY_TYPE) (Image->ImageContext.ImageCodeMemoryType);
434 Image->Info.ImageDataType = (EFI_MEMORY_TYPE) (Image->ImageContext.ImageDataMemoryType);
435 if (Attribute & EFI_LOAD_PE_IMAGE_ATTRIBUTE_RUNTIME_REGISTRATION) {
436 if (Image->ImageContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) {
437 //
438 // Make a list off all the RT images so we can let the RT AP know about them.
439 //
440 Image->RuntimeData = CoreAllocateRuntimePool (sizeof(EFI_RUNTIME_IMAGE_ENTRY));
441 if (Image->RuntimeData == NULL) {
442 goto Done;
443 }
444 Image->RuntimeData->ImageBase = Image->Info.ImageBase;
445 Image->RuntimeData->ImageSize = (UINT64) (Image->Info.ImageSize);
446 Image->RuntimeData->RelocationData = Image->ImageContext.FixupData;
447 Image->RuntimeData->Handle = Image->Handle;
448 InsertTailList (&gRuntime->ImageHead, &Image->RuntimeData->Link);
449 }
450 }
451
452 //
453 // Fill in the entry point of the image if it is available
454 //
455 if (EntryPoint != NULL) {
456 *EntryPoint = Image->ImageContext.EntryPoint;
457 }
458
459 //
460 // Print the load address and the PDB file name if it is available
461 //
462
463 DEBUG_CODE_BEGIN ();
464
465 UINTN Index;
466 UINTN StartIndex;
467 CHAR8 EfiFileName[256];
468
469 if (Image->ImageContext.Machine != IMAGE_FILE_MACHINE_IA64) {
470 DEBUG ((DEBUG_INFO | DEBUG_LOAD,
471 "Loading driver at 0x%10p EntryPoint=0x%10p ",
472 (VOID *)(UINTN)Image->ImageContext.ImageAddress,
473 (VOID *)(UINTN)Image->ImageContext.EntryPoint));
474 } else {
475 //
476 // For IPF Image, the real entry point should be print.
477 //
478 DEBUG ((DEBUG_INFO | DEBUG_LOAD,
479 "Loading driver at 0x%10p EntryPoint=0x%10p ",
480 (VOID *)(UINTN)Image->ImageContext.ImageAddress,
481 (VOID *)(UINTN)(*(UINT64 *)(UINTN)Image->ImageContext.EntryPoint)));
482 }
483
484 //
485 // Print Module Name by Pdb file path
486 //
487 if (Image->ImageContext.PdbPointer != NULL) {
488 StartIndex = 0;
489 for (Index = 0; Image->ImageContext.PdbPointer[Index] != 0; Index++) {
490 if (Image->ImageContext.PdbPointer[Index] == '\\') {
491 StartIndex = Index + 1;
492 }
493 }
494 //
495 // Copy the PDB file name to our temporary string, and replace .pdb with .efi
496 //
497 for (Index = 0; Index < sizeof (EfiFileName); Index++) {
498 EfiFileName[Index] = Image->ImageContext.PdbPointer[Index + StartIndex];
499 if (EfiFileName[Index] == 0) {
500 EfiFileName[Index] = '.';
501 }
502 if (EfiFileName[Index] == '.') {
503 EfiFileName[Index + 1] = 'e';
504 EfiFileName[Index + 2] = 'f';
505 EfiFileName[Index + 3] = 'i';
506 EfiFileName[Index + 4] = 0;
507 break;
508 }
509 }
510 DEBUG ((DEBUG_INFO | DEBUG_LOAD, "%a", EfiFileName)); // &Image->ImageContext.PdbPointer[StartIndex]));
511 }
512 DEBUG ((DEBUG_INFO | DEBUG_LOAD, "\n"));
513
514 DEBUG_CODE_END ();
515
516 return EFI_SUCCESS;
517
518 Done:
519
520 //
521 // Free memory.
522 //
523
524 if (DstBufAlocated) {
525 CoreFreePages (Image->ImageContext.ImageAddress, Image->NumberOfPages);
526 }
527
528 if (Image->ImageContext.FixupData != NULL) {
529 CoreFreePool (Image->ImageContext.FixupData);
530 }
531
532 return Status;
533 }
534
535
536
537 /**
538 Get the image's private data from its handle.
539
540 @param ImageHandle The image handle
541
542 @return Return the image private data associated with ImageHandle.
543
544 **/
545 LOADED_IMAGE_PRIVATE_DATA *
546 CoreLoadedImageInfo (
547 IN EFI_HANDLE ImageHandle
548 )
549 {
550 EFI_STATUS Status;
551 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
552 LOADED_IMAGE_PRIVATE_DATA *Image;
553
554 Status = CoreHandleProtocol (
555 ImageHandle,
556 &gEfiLoadedImageProtocolGuid,
557 (VOID **)&LoadedImage
558 );
559 if (!EFI_ERROR (Status)) {
560 Image = LOADED_IMAGE_PRIVATE_DATA_FROM_THIS (LoadedImage);
561 } else {
562 DEBUG ((DEBUG_LOAD, "CoreLoadedImageInfo: Not an ImageHandle %x\n", ImageHandle));
563 Image = NULL;
564 }
565
566 return Image;
567 }
568
569
570 /**
571 Loads an EFI image into memory and returns a handle to the image.
572
573 @param BootPolicy If TRUE, indicates that the request originates
574 from the boot manager, and that the boot
575 manager is attempting to load FilePath as a
576 boot selection.
577 @param ParentImageHandle The caller's image handle.
578 @param FilePath The specific file path from which the image is
579 loaded.
580 @param SourceBuffer If not NULL, a pointer to the memory location
581 containing a copy of the image to be loaded.
582 @param SourceSize The size in bytes of SourceBuffer.
583 @param DstBuffer The buffer to store the image
584 @param NumberOfPages If not NULL, it inputs a pointer to the page
585 number of DstBuffer and outputs a pointer to
586 the page number of the image. If this number is
587 not enough, return EFI_BUFFER_TOO_SMALL and
588 this parameter contains the required number.
589 @param ImageHandle Pointer to the returned image handle that is
590 created when the image is successfully loaded.
591 @param EntryPoint A pointer to the entry point
592 @param Attribute The bit mask of attributes to set for the load
593 PE image
594
595 @retval EFI_SUCCESS The image was loaded into memory.
596 @retval EFI_NOT_FOUND The FilePath was not found.
597 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
598 @retval EFI_BUFFER_TOO_SMALL The buffer is too small
599 @retval EFI_UNSUPPORTED The image type is not supported, or the device
600 path cannot be parsed to locate the proper
601 protocol for loading the file.
602 @retval EFI_OUT_OF_RESOURCES Image was not loaded due to insufficient
603 resources.
604
605 **/
606 STATIC
607 EFI_STATUS
608 CoreLoadImageCommon (
609 IN BOOLEAN BootPolicy,
610 IN EFI_HANDLE ParentImageHandle,
611 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
612 IN VOID *SourceBuffer OPTIONAL,
613 IN UINTN SourceSize,
614 IN EFI_PHYSICAL_ADDRESS DstBuffer OPTIONAL,
615 IN OUT UINTN *NumberOfPages OPTIONAL,
616 OUT EFI_HANDLE *ImageHandle,
617 OUT EFI_PHYSICAL_ADDRESS *EntryPoint OPTIONAL,
618 IN UINT32 Attribute
619 )
620 {
621 LOADED_IMAGE_PRIVATE_DATA *Image;
622 LOADED_IMAGE_PRIVATE_DATA *ParentImage;
623 IMAGE_FILE_HANDLE FHand;
624 EFI_STATUS Status;
625 EFI_STATUS SecurityStatus;
626 EFI_HANDLE DeviceHandle;
627 UINT32 AuthenticationStatus;
628 EFI_DEVICE_PATH_PROTOCOL *OriginalFilePath;
629 EFI_DEVICE_PATH_PROTOCOL *HandleFilePath;
630 UINTN FilePathSize;
631
632 SecurityStatus = EFI_SUCCESS;
633
634 ASSERT (gEfiCurrentTpl < TPL_NOTIFY);
635 ParentImage = NULL;
636
637 //
638 // The caller must pass in a valid ParentImageHandle
639 //
640 if (ImageHandle == NULL || ParentImageHandle == NULL) {
641 return EFI_INVALID_PARAMETER;
642 }
643
644 ParentImage = CoreLoadedImageInfo (ParentImageHandle);
645 if (ParentImage == NULL) {
646 DEBUG((DEBUG_LOAD|DEBUG_ERROR, "LoadImageEx: Parent handle not an image handle\n"));
647 return EFI_INVALID_PARAMETER;
648 }
649
650 //
651 // Get simple read access to the source file
652 //
653 OriginalFilePath = FilePath;
654 Status = CoreOpenImageFile (
655 BootPolicy,
656 SourceBuffer,
657 SourceSize,
658 &FilePath,
659 &DeviceHandle,
660 &FHand,
661 &AuthenticationStatus
662 );
663 if (Status == EFI_ALREADY_STARTED) {
664 Image = NULL;
665 goto Done;
666 } else if (EFI_ERROR (Status)) {
667 return Status;
668 }
669
670 //
671 // Verify the Authentication Status through the Security Architectural Protocol
672 //
673 if ((gSecurity != NULL) && (OriginalFilePath != NULL)) {
674 SecurityStatus = gSecurity->FileAuthenticationState (
675 gSecurity,
676 AuthenticationStatus,
677 OriginalFilePath
678 );
679 if (EFI_ERROR (SecurityStatus) && SecurityStatus != EFI_SECURITY_VIOLATION) {
680 Status = SecurityStatus;
681 Image = NULL;
682 goto Done;
683 }
684 }
685
686
687 //
688 // Allocate a new image structure
689 //
690 Image = CoreAllocateZeroBootServicesPool (sizeof(LOADED_IMAGE_PRIVATE_DATA));
691 if (Image == NULL) {
692 return EFI_OUT_OF_RESOURCES;
693 }
694
695 //
696 // Pull out just the file portion of the DevicePath for the LoadedImage FilePath
697 //
698 FilePath = OriginalFilePath;
699 Status = CoreHandleProtocol (DeviceHandle, &gEfiDevicePathProtocolGuid, (VOID **)&HandleFilePath);
700 if (!EFI_ERROR (Status)) {
701 FilePathSize = CoreDevicePathSize (HandleFilePath) - sizeof(EFI_DEVICE_PATH_PROTOCOL);
702 FilePath = (EFI_DEVICE_PATH_PROTOCOL *) ( ((UINT8 *)FilePath) + FilePathSize );
703 }
704
705 //
706 // Initialize the fields for an internal driver
707 //
708 Image->Signature = LOADED_IMAGE_PRIVATE_DATA_SIGNATURE;
709 Image->Info.SystemTable = gDxeCoreST;
710 Image->Info.DeviceHandle = DeviceHandle;
711 Image->Info.Revision = EFI_LOADED_IMAGE_PROTOCOL_REVISION;
712 Image->Info.FilePath = CoreDuplicateDevicePath (FilePath);
713 Image->Info.ParentHandle = ParentImageHandle;
714
715
716 if (NumberOfPages != NULL) {
717 Image->NumberOfPages = *NumberOfPages ;
718 } else {
719 Image->NumberOfPages = 0 ;
720 }
721
722 //
723 // Install the protocol interfaces for this image
724 // don't fire notifications yet
725 //
726 Status = CoreInstallProtocolInterfaceNotify (
727 &Image->Handle,
728 &gEfiLoadedImageProtocolGuid,
729 EFI_NATIVE_INTERFACE,
730 &Image->Info,
731 FALSE
732 );
733 if (EFI_ERROR (Status)) {
734 goto Done;
735 }
736
737 //
738 // Load the image. If EntryPoint is Null, it will not be set.
739 //
740 Status = CoreLoadPeImage (BootPolicy, &FHand, Image, DstBuffer, EntryPoint, Attribute);
741 if (EFI_ERROR (Status)) {
742 if ((Status == EFI_BUFFER_TOO_SMALL) || (Status == EFI_OUT_OF_RESOURCES)) {
743 if (NumberOfPages != NULL) {
744 *NumberOfPages = Image->NumberOfPages;
745 }
746 }
747 goto Done;
748 }
749
750 if (NumberOfPages != NULL) {
751 *NumberOfPages = Image->NumberOfPages;
752 }
753
754 //
755 // Register the image in the Debug Image Info Table if the attribute is set
756 //
757 if (Attribute & EFI_LOAD_PE_IMAGE_ATTRIBUTE_DEBUG_IMAGE_INFO_TABLE_REGISTRATION) {
758 CoreNewDebugImageInfoEntry (EFI_DEBUG_IMAGE_INFO_TYPE_NORMAL, &Image->Info, Image->Handle);
759 }
760
761 //
762 //Reinstall loaded image protocol to fire any notifications
763 //
764 Status = CoreReinstallProtocolInterface (
765 Image->Handle,
766 &gEfiLoadedImageProtocolGuid,
767 &Image->Info,
768 &Image->Info
769 );
770 if (EFI_ERROR (Status)) {
771 goto Done;
772 }
773
774 //
775 // If DevicePath parameter to the LoadImage() is not NULL, then make a copy of DevicePath,
776 // otherwise Loaded Image Device Path Protocol is installed with a NULL interface pointer.
777 //
778 if (OriginalFilePath != NULL) {
779 Image->LoadedImageDevicePath = CoreDuplicateDevicePath (OriginalFilePath);
780 }
781
782 //
783 // Install Loaded Image Device Path Protocol onto the image handle of a PE/COFE image
784 //
785 Status = CoreInstallProtocolInterface (
786 &Image->Handle,
787 &gEfiLoadedImageDevicePathProtocolGuid,
788 EFI_NATIVE_INTERFACE,
789 Image->LoadedImageDevicePath
790 );
791 if (EFI_ERROR (Status)) {
792 goto Done;
793 }
794
795 //
796 // Success. Return the image handle
797 //
798 *ImageHandle = Image->Handle;
799
800 Done:
801 //
802 // All done accessing the source file
803 // If we allocated the Source buffer, free it
804 //
805 if (FHand.FreeBuffer) {
806 CoreFreePool (FHand.Source);
807 }
808
809 //
810 // There was an error. If there's an Image structure, free it
811 //
812 if (EFI_ERROR (Status)) {
813 if (Image != NULL) {
814 CoreUnloadAndCloseImage (Image, (BOOLEAN)(DstBuffer == 0));
815 *ImageHandle = NULL;
816 }
817 } else if (EFI_ERROR (SecurityStatus)) {
818 Status = SecurityStatus;
819 }
820
821 return Status;
822 }
823
824
825
826
827 /**
828 Loads an EFI image into memory and returns a handle to the image.
829
830 @param BootPolicy If TRUE, indicates that the request originates
831 from the boot manager, and that the boot
832 manager is attempting to load FilePath as a
833 boot selection.
834 @param ParentImageHandle The caller's image handle.
835 @param FilePath The specific file path from which the image is
836 loaded.
837 @param SourceBuffer If not NULL, a pointer to the memory location
838 containing a copy of the image to be loaded.
839 @param SourceSize The size in bytes of SourceBuffer.
840 @param ImageHandle Pointer to the returned image handle that is
841 created when the image is successfully loaded.
842
843 @retval EFI_SUCCESS The image was loaded into memory.
844 @retval EFI_NOT_FOUND The FilePath was not found.
845 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
846 @retval EFI_UNSUPPORTED The image type is not supported, or the device
847 path cannot be parsed to locate the proper
848 protocol for loading the file.
849 @retval EFI_OUT_OF_RESOURCES Image was not loaded due to insufficient
850 resources.
851
852 **/
853 EFI_STATUS
854 EFIAPI
855 CoreLoadImage (
856 IN BOOLEAN BootPolicy,
857 IN EFI_HANDLE ParentImageHandle,
858 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
859 IN VOID *SourceBuffer OPTIONAL,
860 IN UINTN SourceSize,
861 OUT EFI_HANDLE *ImageHandle
862 )
863 {
864 EFI_STATUS Status;
865
866 PERF_START (NULL, "LoadImage", NULL, 0);
867
868 Status = CoreLoadImageCommon (
869 BootPolicy,
870 ParentImageHandle,
871 FilePath,
872 SourceBuffer,
873 SourceSize,
874 (EFI_PHYSICAL_ADDRESS) (UINTN) NULL,
875 NULL,
876 ImageHandle,
877 NULL,
878 EFI_LOAD_PE_IMAGE_ATTRIBUTE_RUNTIME_REGISTRATION | EFI_LOAD_PE_IMAGE_ATTRIBUTE_DEBUG_IMAGE_INFO_TABLE_REGISTRATION
879 );
880
881 PERF_END (NULL, "LoadImage", NULL, 0);
882
883 return Status;
884 }
885
886
887
888 /**
889 Loads an EFI image into memory and returns a handle to the image with extended parameters.
890
891 @param This Calling context
892 @param ParentImageHandle The caller's image handle.
893 @param FilePath The specific file path from which the image is
894 loaded.
895 @param SourceBuffer If not NULL, a pointer to the memory location
896 containing a copy of the image to be loaded.
897 @param SourceSize The size in bytes of SourceBuffer.
898 @param DstBuffer The buffer to store the image.
899 @param NumberOfPages For input, specifies the space size of the
900 image by caller if not NULL. For output,
901 specifies the actual space size needed.
902 @param ImageHandle Image handle for output.
903 @param EntryPoint Image entry point for output.
904 @param Attribute The bit mask of attributes to set for the load
905 PE image.
906
907 @retval EFI_SUCCESS The image was loaded into memory.
908 @retval EFI_NOT_FOUND The FilePath was not found.
909 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
910 @retval EFI_UNSUPPORTED The image type is not supported, or the device
911 path cannot be parsed to locate the proper
912 protocol for loading the file.
913 @retval EFI_OUT_OF_RESOURCES Image was not loaded due to insufficient
914 resources.
915
916 **/
917 EFI_STATUS
918 EFIAPI
919 CoreLoadImageEx (
920 IN EFI_PE32_IMAGE_PROTOCOL *This,
921 IN EFI_HANDLE ParentImageHandle,
922 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
923 IN VOID *SourceBuffer OPTIONAL,
924 IN UINTN SourceSize,
925 IN EFI_PHYSICAL_ADDRESS DstBuffer OPTIONAL,
926 OUT UINTN *NumberOfPages OPTIONAL,
927 OUT EFI_HANDLE *ImageHandle,
928 OUT EFI_PHYSICAL_ADDRESS *EntryPoint OPTIONAL,
929 IN UINT32 Attribute
930 )
931 {
932 return CoreLoadImageCommon (
933 TRUE,
934 ParentImageHandle,
935 FilePath,
936 SourceBuffer,
937 SourceSize,
938 DstBuffer,
939 NumberOfPages,
940 ImageHandle,
941 EntryPoint,
942 Attribute
943 );
944 }
945
946
947 /**
948 Transfer control to a loaded image's entry point.
949
950 @param ImageHandle Handle of image to be started.
951 @param ExitDataSize Pointer of the size to ExitData
952 @param ExitData Pointer to a pointer to a data buffer that
953 includes a Null-terminated Unicode string,
954 optionally followed by additional binary data.
955 The string is a description that the caller may
956 use to further indicate the reason for the
957 image's exit.
958
959 @retval EFI_INVALID_PARAMETER Invalid parameter
960 @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate
961 @retval EFI_SUCCESS Successfully transfer control to the image's
962 entry point.
963
964 **/
965 EFI_STATUS
966 EFIAPI
967 CoreStartImage (
968 IN EFI_HANDLE ImageHandle,
969 OUT UINTN *ExitDataSize,
970 OUT CHAR16 **ExitData OPTIONAL
971 )
972 {
973 EFI_STATUS Status;
974 LOADED_IMAGE_PRIVATE_DATA *Image;
975 LOADED_IMAGE_PRIVATE_DATA *LastImage;
976 UINT64 HandleDatabaseKey;
977 UINTN SetJumpFlag;
978
979 Image = CoreLoadedImageInfo (ImageHandle);
980 if (Image == NULL_HANDLE || Image->Started) {
981 return EFI_INVALID_PARAMETER;
982 }
983
984 //
985 // Don't profile Objects or invalid start requests
986 //
987 PERF_START (ImageHandle, START_IMAGE_TOK, NULL, 0);
988
989
990 //
991 // Push the current start image context, and
992 // link the current image to the head. This is the
993 // only image that can call Exit()
994 //
995 HandleDatabaseKey = CoreGetHandleDatabaseKey ();
996 LastImage = mCurrentImage;
997 mCurrentImage = Image;
998 Image->Tpl = gEfiCurrentTpl;
999
1000 //
1001 // Set long jump for Exit() support
1002 // JumpContext must be aligned on a CPU specific boundary.
1003 // Overallocate the buffer and force the required alignment
1004 //
1005 Image->JumpBuffer = CoreAllocateBootServicesPool (sizeof (BASE_LIBRARY_JUMP_BUFFER) + BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT);
1006 if (Image->JumpBuffer == NULL) {
1007 PERF_END (ImageHandle, START_IMAGE_TOK, NULL, 0);
1008 return EFI_OUT_OF_RESOURCES;
1009 }
1010 Image->JumpContext = ALIGN_POINTER (Image->JumpBuffer, BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT);
1011
1012 SetJumpFlag = SetJump (Image->JumpContext);
1013 //
1014 // The initial call to SetJump() must always return 0.
1015 // Subsequent calls to LongJump() cause a non-zero value to be returned by SetJump().
1016 //
1017 if (!SetJumpFlag) {
1018 //
1019 // Call the image's entry point
1020 //
1021 Image->Started = TRUE;
1022 Image->Status = Image->EntryPoint (ImageHandle, Image->Info.SystemTable);
1023
1024 //
1025 // Add some debug information if the image returned with error.
1026 // This make the user aware and check if the driver image have already released
1027 // all the resource in this situation.
1028 //
1029 DEBUG_CODE_BEGIN ();
1030 if (EFI_ERROR (Image->Status)) {
1031 DEBUG ((DEBUG_ERROR, "Error: Image at %10p start failed: %r\n", Image->Info.ImageBase, Image->Status));
1032 }
1033 DEBUG_CODE_END ();
1034
1035 //
1036 // If the image returns, exit it through Exit()
1037 //
1038 CoreExit (ImageHandle, Image->Status, 0, NULL);
1039 }
1040
1041 //
1042 // Image has completed. Verify the tpl is the same
1043 //
1044 ASSERT (Image->Tpl == gEfiCurrentTpl);
1045 CoreRestoreTpl (Image->Tpl);
1046
1047 CoreFreePool (Image->JumpBuffer);
1048
1049 //
1050 // Pop the current start image context
1051 //
1052 mCurrentImage = LastImage;
1053
1054 //
1055 // Go connect any handles that were created or modified while the image executed.
1056 //
1057 CoreConnectHandlesByKey (HandleDatabaseKey);
1058
1059 //
1060 // Handle the image's returned ExitData
1061 //
1062 DEBUG_CODE_BEGIN ();
1063 if (Image->ExitDataSize != 0 || Image->ExitData != NULL) {
1064
1065 DEBUG (
1066 (DEBUG_LOAD,
1067 "StartImage: ExitDataSize %d, ExitData %x",
1068 Image->ExitDataSize,
1069 Image->ExitData)
1070 );
1071 if (Image->ExitData != NULL) {
1072 DEBUG ((DEBUG_LOAD, " (%hs)", Image->ExitData));
1073 }
1074 DEBUG ((DEBUG_LOAD, "\n"));
1075 }
1076 DEBUG_CODE_END ();
1077
1078 //
1079 // Return the exit data to the caller
1080 //
1081 if (ExitData != NULL && ExitDataSize != NULL) {
1082 *ExitDataSize = Image->ExitDataSize;
1083 *ExitData = Image->ExitData;
1084 } else {
1085 //
1086 // Caller doesn't want the exit data, free it
1087 //
1088 CoreFreePool (Image->ExitData);
1089 Image->ExitData = NULL;
1090 }
1091
1092 //
1093 // Save the Status because Image will get destroyed if it is unloaded.
1094 //
1095 Status = Image->Status;
1096
1097 //
1098 // If the image returned an error, or if the image is an application
1099 // unload it
1100 //
1101 if (EFI_ERROR (Image->Status) || Image->Type == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) {
1102 CoreUnloadAndCloseImage (Image, TRUE);
1103 }
1104
1105 //
1106 // Done
1107 //
1108 PERF_END (ImageHandle, START_IMAGE_TOK, NULL, 0);
1109 return Status;
1110 }
1111
1112
1113
1114 /**
1115 Unloads EFI image from memory.
1116
1117 @param Image EFI image
1118 @param FreePage Free allocated pages
1119
1120 **/
1121 VOID
1122 CoreUnloadAndCloseImage (
1123 IN LOADED_IMAGE_PRIVATE_DATA *Image,
1124 IN BOOLEAN FreePage
1125 )
1126 {
1127 EFI_STATUS Status;
1128 UINTN HandleCount;
1129 EFI_HANDLE *HandleBuffer;
1130 UINTN HandleIndex;
1131 EFI_GUID **ProtocolGuidArray;
1132 UINTN ArrayCount;
1133 UINTN ProtocolIndex;
1134 EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfo;
1135 UINTN OpenInfoCount;
1136 UINTN OpenInfoIndex;
1137
1138 if (Image->Ebc != NULL) {
1139 //
1140 // If EBC protocol exists we must perform cleanups for this image.
1141 //
1142 Image->Ebc->UnloadImage (Image->Ebc, Image->Handle);
1143 }
1144
1145 //
1146 // Unload image, free Image->ImageContext->ModHandle
1147 //
1148 PeCoffLoaderUnloadImage (&Image->ImageContext);
1149
1150 //
1151 // Free our references to the image handle
1152 //
1153 if (Image->Handle != NULL_HANDLE) {
1154
1155 Status = CoreLocateHandleBuffer (
1156 AllHandles,
1157 NULL,
1158 NULL,
1159 &HandleCount,
1160 &HandleBuffer
1161 );
1162 if (!EFI_ERROR (Status)) {
1163 for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) {
1164 Status = CoreProtocolsPerHandle (
1165 HandleBuffer[HandleIndex],
1166 &ProtocolGuidArray,
1167 &ArrayCount
1168 );
1169 if (!EFI_ERROR (Status)) {
1170 for (ProtocolIndex = 0; ProtocolIndex < ArrayCount; ProtocolIndex++) {
1171 Status = CoreOpenProtocolInformation (
1172 HandleBuffer[HandleIndex],
1173 ProtocolGuidArray[ProtocolIndex],
1174 &OpenInfo,
1175 &OpenInfoCount
1176 );
1177 if (!EFI_ERROR (Status)) {
1178 for (OpenInfoIndex = 0; OpenInfoIndex < OpenInfoCount; OpenInfoIndex++) {
1179 if (OpenInfo[OpenInfoIndex].AgentHandle == Image->Handle) {
1180 Status = CoreCloseProtocol (
1181 HandleBuffer[HandleIndex],
1182 ProtocolGuidArray[ProtocolIndex],
1183 Image->Handle,
1184 OpenInfo[OpenInfoIndex].ControllerHandle
1185 );
1186 }
1187 }
1188 if (OpenInfo != NULL) {
1189 CoreFreePool(OpenInfo);
1190 }
1191 }
1192 }
1193 if (ProtocolGuidArray != NULL) {
1194 CoreFreePool(ProtocolGuidArray);
1195 }
1196 }
1197 }
1198 if (HandleBuffer != NULL) {
1199 CoreFreePool (HandleBuffer);
1200 }
1201 }
1202
1203 CoreRemoveDebugImageInfoEntry (Image->Handle);
1204
1205 Status = CoreUninstallProtocolInterface (
1206 Image->Handle,
1207 &gEfiLoadedImageDevicePathProtocolGuid,
1208 Image->LoadedImageDevicePath
1209 );
1210
1211 Status = CoreUninstallProtocolInterface (
1212 Image->Handle,
1213 &gEfiLoadedImageProtocolGuid,
1214 &Image->Info
1215 );
1216
1217 }
1218
1219 if (Image->RuntimeData != NULL) {
1220 if (Image->RuntimeData->Link.ForwardLink != NULL) {
1221 //
1222 // Remove the Image from the Runtime Image list as we are about to Free it!
1223 //
1224 RemoveEntryList (&Image->RuntimeData->Link);
1225 }
1226 CoreFreePool (Image->RuntimeData);
1227 }
1228
1229 //
1230 // Free the Image from memory
1231 //
1232 if ((Image->ImageBasePage != 0) && FreePage) {
1233 CoreFreePages (Image->ImageBasePage, Image->NumberOfPages);
1234 }
1235
1236 //
1237 // Done with the Image structure
1238 //
1239 if (Image->Info.FilePath != NULL) {
1240 CoreFreePool (Image->Info.FilePath);
1241 }
1242
1243 if (Image->LoadedImageDevicePath != NULL) {
1244 CoreFreePool (Image->LoadedImageDevicePath);
1245 }
1246
1247 if (Image->FixupData != NULL) {
1248 CoreFreePool (Image->FixupData);
1249 }
1250
1251 CoreFreePool (Image);
1252 }
1253
1254
1255
1256
1257 /**
1258 Terminates the currently loaded EFI image and returns control to boot services.
1259
1260 @param ImageHandle Handle that identifies the image. This
1261 parameter is passed to the image on entry.
1262 @param Status The image's exit code.
1263 @param ExitDataSize The size, in bytes, of ExitData. Ignored if
1264 ExitStatus is EFI_SUCCESS.
1265 @param ExitData Pointer to a data buffer that includes a
1266 Null-terminated Unicode string, optionally
1267 followed by additional binary data. The string
1268 is a description that the caller may use to
1269 further indicate the reason for the image's
1270 exit.
1271
1272 @retval EFI_INVALID_PARAMETER Image handle is NULL or it is not current
1273 image.
1274 @retval EFI_SUCCESS Successfully terminates the currently loaded
1275 EFI image.
1276 @retval EFI_ACCESS_DENIED Should never reach there.
1277 @retval EFI_OUT_OF_RESOURCES Could not allocate pool
1278
1279 **/
1280 EFI_STATUS
1281 EFIAPI
1282 CoreExit (
1283 IN EFI_HANDLE ImageHandle,
1284 IN EFI_STATUS Status,
1285 IN UINTN ExitDataSize,
1286 IN CHAR16 *ExitData OPTIONAL
1287 )
1288 {
1289 LOADED_IMAGE_PRIVATE_DATA *Image;
1290 EFI_TPL OldTpl;
1291
1292 //
1293 // Prevent possible reentrance to this function
1294 // for the same ImageHandle
1295 //
1296 OldTpl = CoreRaiseTpl (TPL_NOTIFY);
1297
1298 Image = CoreLoadedImageInfo (ImageHandle);
1299 if (Image == NULL_HANDLE) {
1300 Status = EFI_INVALID_PARAMETER;
1301 goto Done;
1302 }
1303
1304 if (!Image->Started) {
1305 //
1306 // The image has not been started so just free its resources
1307 //
1308 CoreUnloadAndCloseImage (Image, TRUE);
1309 Status = EFI_SUCCESS;
1310 goto Done;
1311 }
1312
1313 //
1314 // Image has been started, verify this image can exit
1315 //
1316 if (Image != mCurrentImage) {
1317 DEBUG ((DEBUG_LOAD|DEBUG_ERROR, "Exit: Image is not exitable image\n"));
1318 Status = EFI_INVALID_PARAMETER;
1319 goto Done;
1320 }
1321
1322 //
1323 // Set status
1324 //
1325 Image->Status = Status;
1326
1327 //
1328 // If there's ExitData info, move it
1329 //
1330 if (ExitData != NULL) {
1331 Image->ExitDataSize = ExitDataSize;
1332 Image->ExitData = CoreAllocateBootServicesPool (Image->ExitDataSize);
1333 if (Image->ExitData == NULL) {
1334 Status = EFI_OUT_OF_RESOURCES;
1335 goto Done;
1336 }
1337 CopyMem (Image->ExitData, ExitData, Image->ExitDataSize);
1338 }
1339
1340 CoreRestoreTpl (OldTpl);
1341 //
1342 // return to StartImage
1343 //
1344 LongJump (Image->JumpContext, (UINTN)-1);
1345
1346 //
1347 // If we return from LongJump, then it is an error
1348 //
1349 ASSERT (FALSE);
1350 Status = EFI_ACCESS_DENIED;
1351 Done:
1352 CoreRestoreTpl (OldTpl);
1353 return Status;
1354 }
1355
1356
1357
1358
1359 /**
1360 Unloads an image.
1361
1362 @param ImageHandle Handle that identifies the image to be
1363 unloaded.
1364
1365 @retval EFI_SUCCESS The image has been unloaded.
1366 @retval EFI_UNSUPPORTED The image has been sarted, and does not support
1367 unload.
1368 @retval EFI_INVALID_PARAMPETER ImageHandle is not a valid image handle.
1369
1370 **/
1371 EFI_STATUS
1372 EFIAPI
1373 CoreUnloadImage (
1374 IN EFI_HANDLE ImageHandle
1375 )
1376 {
1377 EFI_STATUS Status;
1378 LOADED_IMAGE_PRIVATE_DATA *Image;
1379 EFI_TPL OldTpl;
1380
1381 //
1382 // Prevent possible reentrance to this function
1383 // for the same ImageHandle
1384 //
1385 OldTpl = CoreRaiseTpl (TPL_NOTIFY);
1386
1387 Image = CoreLoadedImageInfo (ImageHandle);
1388 if (Image == NULL ) {
1389 //
1390 // The image handle is not valid
1391 //
1392 Status = EFI_INVALID_PARAMETER;
1393 goto Done;
1394 }
1395
1396 if (Image->Started) {
1397 //
1398 // The image has been started, request it to unload.
1399 //
1400 Status = EFI_UNSUPPORTED;
1401 if (Image->Info.Unload != NULL) {
1402 Status = Image->Info.Unload (ImageHandle);
1403 }
1404
1405 } else {
1406 //
1407 // This Image hasn't been started, thus it can be unloaded
1408 //
1409 Status = EFI_SUCCESS;
1410 }
1411
1412
1413 if (!EFI_ERROR (Status)) {
1414 //
1415 // if the Image was not started or Unloaded O.K. then clean up
1416 //
1417 CoreUnloadAndCloseImage (Image, TRUE);
1418 }
1419
1420 Done:
1421 CoreRestoreTpl (OldTpl);
1422 return Status;
1423 }
1424
1425
1426
1427 /**
1428 Unload the specified image.
1429
1430 @param This Indicates the calling context.
1431 @param ImageHandle The specified image handle.
1432
1433 @retval EFI_INVALID_PARAMETER Image handle is NULL.
1434 @retval EFI_UNSUPPORTED Attempt to unload an unsupported image.
1435 @retval EFI_SUCCESS Image successfully unloaded.
1436
1437 **/
1438 EFI_STATUS
1439 EFIAPI
1440 CoreUnloadImageEx (
1441 IN EFI_PE32_IMAGE_PROTOCOL *This,
1442 IN EFI_HANDLE ImageHandle
1443 )
1444 {
1445 return CoreUnloadImage (ImageHandle);
1446 }