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