]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Core/Dxe/Image/Image.c
Add comments and DoxyGen format for these files.
[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, a pointer to the image's page number, if this number
616 is not enough, return EFI_BUFFER_TOO_SMALL and this parameter contain
617 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 //
764 // Register the image in the Debug Image Info Table if the attribute is set
765 //
766 if (Attribute & EFI_LOAD_PE_IMAGE_ATTRIBUTE_DEBUG_IMAGE_INFO_TABLE_REGISTRATION) {
767 CoreNewDebugImageInfoEntry (EFI_DEBUG_IMAGE_INFO_TYPE_NORMAL, &Image->Info, Image->Handle);
768 }
769
770 //
771 //Reinstall loaded image protocol to fire any notifications
772 //
773 Status = CoreReinstallProtocolInterface (
774 Image->Handle,
775 &gEfiLoadedImageProtocolGuid,
776 &Image->Info,
777 &Image->Info
778 );
779 if (EFI_ERROR (Status)) {
780 goto Done;
781 }
782
783 //
784 // If DevicePath parameter to the LoadImage() is not NULL, then make a copy of DevicePath,
785 // otherwise Loaded Image Device Path Protocol is installed with a NULL interface pointer.
786 //
787 if (OriginalFilePath != NULL) {
788 Image->LoadedImageDevicePath = CoreDuplicateDevicePath (OriginalFilePath);
789 }
790
791 //
792 // Install Loaded Image Device Path Protocol onto the image handle of a PE/COFE image
793 //
794 Status = CoreInstallProtocolInterface (
795 &Image->Handle,
796 &gEfiLoadedImageDevicePathProtocolGuid,
797 EFI_NATIVE_INTERFACE,
798 Image->LoadedImageDevicePath
799 );
800 if (EFI_ERROR (Status)) {
801 goto Done;
802 }
803
804 //
805 // Success. Return the image handle
806 //
807 *ImageHandle = Image->Handle;
808
809 Done:
810 //
811 // All done accessing the source file
812 // If we allocated the Source buffer, free it
813 //
814 if (FHand.FreeBuffer) {
815 CoreFreePool (FHand.Source);
816 }
817
818 //
819 // There was an error. If there's an Image structure, free it
820 //
821 if (EFI_ERROR (Status)) {
822 if (Image != NULL) {
823 CoreUnloadAndCloseImage (Image, (BOOLEAN)(DstBuffer == 0));
824 *ImageHandle = NULL;
825 }
826 } else if (EFI_ERROR (SecurityStatus)) {
827 Status = SecurityStatus;
828 }
829
830 return Status;
831 }
832
833
834
835 EFI_STATUS
836 EFIAPI
837 CoreLoadImage (
838 IN BOOLEAN BootPolicy,
839 IN EFI_HANDLE ParentImageHandle,
840 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
841 IN VOID *SourceBuffer OPTIONAL,
842 IN UINTN SourceSize,
843 OUT EFI_HANDLE *ImageHandle
844 )
845 /*++
846
847 Routine Description:
848
849 Loads an EFI image into memory and returns a handle to the image.
850
851 Arguments:
852
853 BootPolicy - If TRUE, indicates that the request originates from the boot manager,
854 and that the boot manager is attempting to load FilePath as a boot selection.
855 ParentImageHandle - The caller's image handle.
856 FilePath - The specific file path from which the image is loaded.
857 SourceBuffer - If not NULL, a pointer to the memory location containing a copy of
858 the image to be loaded.
859 SourceSize - The size in bytes of SourceBuffer.
860 ImageHandle - Pointer to the returned image handle that is created when the image
861 is successfully loaded.
862
863 Returns:
864
865 EFI_SUCCESS - The image was loaded into memory.
866 EFI_NOT_FOUND - The FilePath was not found.
867 EFI_INVALID_PARAMETER - One of the parameters has an invalid value.
868 EFI_UNSUPPORTED - The image type is not supported, or the device path cannot be
869 parsed to locate the proper protocol for loading the file.
870 EFI_OUT_OF_RESOURCES - Image was not loaded due to insufficient resources.
871 --*/
872 {
873 EFI_STATUS Status;
874
875 PERF_START (NULL, "LoadImage", NULL, 0);
876
877 Status = CoreLoadImageCommon (
878 BootPolicy,
879 ParentImageHandle,
880 FilePath,
881 SourceBuffer,
882 SourceSize,
883 (EFI_PHYSICAL_ADDRESS) (UINTN) NULL,
884 NULL,
885 ImageHandle,
886 NULL,
887 EFI_LOAD_PE_IMAGE_ATTRIBUTE_RUNTIME_REGISTRATION | EFI_LOAD_PE_IMAGE_ATTRIBUTE_DEBUG_IMAGE_INFO_TABLE_REGISTRATION
888 );
889
890 PERF_END (NULL, "LoadImage", NULL, 0);
891
892 return Status;
893 }
894
895
896 EFI_STATUS
897 EFIAPI
898 CoreLoadImageEx (
899 IN EFI_PE32_IMAGE_PROTOCOL *This,
900 IN EFI_HANDLE ParentImageHandle,
901 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
902 IN VOID *SourceBuffer OPTIONAL,
903 IN UINTN SourceSize,
904 IN EFI_PHYSICAL_ADDRESS DstBuffer OPTIONAL,
905 OUT UINTN *NumberOfPages OPTIONAL,
906 OUT EFI_HANDLE *ImageHandle,
907 OUT EFI_PHYSICAL_ADDRESS *EntryPoint OPTIONAL,
908 IN UINT32 Attribute
909 )
910 /*++
911
912 Routine Description:
913
914 Loads an EFI image into memory and returns a handle to the image with extended parameters.
915
916 Arguments:
917
918 This - Calling context
919 ParentImageHandle - The caller's image handle.
920 FilePath - The specific file path from which the image is loaded.
921 SourceBuffer - If not NULL, a pointer to the memory location containing a copy of
922 the image to be loaded.
923 SourceSize - The size in bytes of SourceBuffer.
924 DstBuffer - The buffer to store the image.
925 NumberOfPages - For input, specifies the space size of the image by caller if not NULL.
926 For output, specifies the actual space size needed.
927 ImageHandle - Image handle for output.
928 EntryPoint - Image entry point for output.
929 Attribute - The bit mask of attributes to set for the load PE image.
930
931 Returns:
932
933 EFI_SUCCESS - The image was loaded into memory.
934 EFI_NOT_FOUND - The FilePath was not found.
935 EFI_INVALID_PARAMETER - One of the parameters has an invalid value.
936 EFI_UNSUPPORTED - The image type is not supported, or the device path cannot be
937 parsed to locate the proper protocol for loading the file.
938 EFI_OUT_OF_RESOURCES - Image was not loaded due to insufficient resources.
939 --*/
940 {
941 return CoreLoadImageCommon (
942 TRUE,
943 ParentImageHandle,
944 FilePath,
945 SourceBuffer,
946 SourceSize,
947 DstBuffer,
948 NumberOfPages,
949 ImageHandle,
950 EntryPoint,
951 Attribute
952 );
953 }
954
955 EFI_STATUS
956 EFIAPI
957 CoreStartImage (
958 IN EFI_HANDLE ImageHandle,
959 OUT UINTN *ExitDataSize,
960 OUT CHAR16 **ExitData OPTIONAL
961 )
962 /*++
963
964 Routine Description:
965
966 Transfer control to a loaded image's entry point.
967
968 Arguments:
969
970 ImageHandle - Handle of image to be started.
971
972 ExitDataSize - Pointer of the size to ExitData
973
974 ExitData - Pointer to a pointer to a data buffer that includes a Null-terminated
975 Unicode string, optionally followed by additional binary data. The string
976 is a description that the caller may use to further indicate the reason for
977 the image's exit.
978
979 Returns:
980
981 EFI_INVALID_PARAMETER - Invalid parameter
982
983 EFI_OUT_OF_RESOURCES - No enough buffer to allocate
984
985 EFI_SUCCESS - Successfully transfer control to the image's entry point.
986
987 --*/
988 {
989 EFI_STATUS Status;
990 LOADED_IMAGE_PRIVATE_DATA *Image;
991 LOADED_IMAGE_PRIVATE_DATA *LastImage;
992 UINT64 HandleDatabaseKey;
993 UINTN SetJumpFlag;
994
995 Image = CoreLoadedImageInfo (ImageHandle);
996 if (Image == NULL_HANDLE || Image->Started) {
997 return EFI_INVALID_PARAMETER;
998 }
999
1000 //
1001 // Don't profile Objects or invalid start requests
1002 //
1003 PERF_START (ImageHandle, START_IMAGE_TOK, NULL, 0);
1004
1005
1006 //
1007 // Push the current start image context, and
1008 // link the current image to the head. This is the
1009 // only image that can call Exit()
1010 //
1011 HandleDatabaseKey = CoreGetHandleDatabaseKey ();
1012 LastImage = mCurrentImage;
1013 mCurrentImage = Image;
1014 Image->Tpl = gEfiCurrentTpl;
1015
1016 //
1017 // Set long jump for Exit() support
1018 // JumpContext must be aligned on a CPU specific boundary.
1019 // Overallocate the buffer and force the required alignment
1020 //
1021 Image->JumpBuffer = CoreAllocateBootServicesPool (sizeof (BASE_LIBRARY_JUMP_BUFFER) + BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT);
1022 if (Image->JumpBuffer == NULL) {
1023 PERF_END (ImageHandle, START_IMAGE_TOK, NULL, 0);
1024 return EFI_OUT_OF_RESOURCES;
1025 }
1026 Image->JumpContext = ALIGN_POINTER (Image->JumpBuffer, BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT);
1027
1028 SetJumpFlag = SetJump (Image->JumpContext);
1029 //
1030 // The initial call to SetJump() must always return 0.
1031 // Subsequent calls to LongJump() cause a non-zero value to be returned by SetJump().
1032 //
1033 if (!SetJumpFlag) {
1034 //
1035 // Call the image's entry point
1036 //
1037 Image->Started = TRUE;
1038 Image->Status = Image->EntryPoint (ImageHandle, Image->Info.SystemTable);
1039
1040 //
1041 // Add some debug information if the image returned with error.
1042 // This make the user aware and check if the driver image have already released
1043 // all the resource in this situation.
1044 //
1045 DEBUG_CODE_BEGIN ();
1046 if (EFI_ERROR (Image->Status)) {
1047 DEBUG ((EFI_D_ERROR, "Error: Image at %10p start failed: %r\n", Image->Info.ImageBase, Image->Status));
1048 }
1049 DEBUG_CODE_END ();
1050
1051 //
1052 // If the image returns, exit it through Exit()
1053 //
1054 CoreExit (ImageHandle, Image->Status, 0, NULL);
1055 }
1056
1057 //
1058 // Image has completed. Verify the tpl is the same
1059 //
1060 ASSERT (Image->Tpl == gEfiCurrentTpl);
1061 CoreRestoreTpl (Image->Tpl);
1062
1063 CoreFreePool (Image->JumpBuffer);
1064
1065 //
1066 // Pop the current start image context
1067 //
1068 mCurrentImage = LastImage;
1069
1070 //
1071 // Go connect any handles that were created or modified while the image executed.
1072 //
1073 CoreConnectHandlesByKey (HandleDatabaseKey);
1074
1075 //
1076 // Handle the image's returned ExitData
1077 //
1078 DEBUG_CODE_BEGIN ();
1079 if (Image->ExitDataSize != 0 || Image->ExitData != NULL) {
1080
1081 DEBUG (
1082 (EFI_D_LOAD,
1083 "StartImage: ExitDataSize %d, ExitData %x",
1084 Image->ExitDataSize,
1085 Image->ExitData)
1086 );
1087 if (Image->ExitData != NULL) {
1088 DEBUG ((EFI_D_LOAD, " (%hs)", Image->ExitData));
1089 }
1090 DEBUG ((EFI_D_LOAD, "\n"));
1091 }
1092 DEBUG_CODE_END ();
1093
1094 //
1095 // Return the exit data to the caller
1096 //
1097 if (ExitData != NULL && ExitDataSize != NULL) {
1098 *ExitDataSize = Image->ExitDataSize;
1099 *ExitData = Image->ExitData;
1100 } else {
1101 //
1102 // Caller doesn't want the exit data, free it
1103 //
1104 CoreFreePool (Image->ExitData);
1105 Image->ExitData = NULL;
1106 }
1107
1108 //
1109 // Save the Status because Image will get destroyed if it is unloaded.
1110 //
1111 Status = Image->Status;
1112
1113 //
1114 // If the image returned an error, or if the image is an application
1115 // unload it
1116 //
1117 if (EFI_ERROR (Image->Status) || Image->Type == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) {
1118 CoreUnloadAndCloseImage (Image, TRUE);
1119 }
1120
1121 //
1122 // Done
1123 //
1124 PERF_END (ImageHandle, START_IMAGE_TOK, NULL, 0);
1125 return Status;
1126 }
1127
1128
1129 VOID
1130 CoreUnloadAndCloseImage (
1131 IN LOADED_IMAGE_PRIVATE_DATA *Image,
1132 IN BOOLEAN FreePage
1133 )
1134 /*++
1135
1136 Routine Description:
1137
1138 Unloads EFI image from memory.
1139
1140 Arguments:
1141
1142 Image - EFI image
1143 FreePage - Free allocated pages
1144
1145 Returns:
1146
1147 None
1148
1149 --*/
1150 {
1151 EFI_STATUS Status;
1152 UINTN HandleCount;
1153 EFI_HANDLE *HandleBuffer;
1154 UINTN HandleIndex;
1155 EFI_GUID **ProtocolGuidArray;
1156 UINTN ArrayCount;
1157 UINTN ProtocolIndex;
1158 EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfo;
1159 UINTN OpenInfoCount;
1160 UINTN OpenInfoIndex;
1161
1162 if (Image->Ebc != NULL) {
1163 //
1164 // If EBC protocol exists we must perform cleanups for this image.
1165 //
1166 Image->Ebc->UnloadImage (Image->Ebc, Image->Handle);
1167 }
1168
1169 //
1170 // Unload image, free Image->ImageContext->ModHandle
1171 //
1172 PeCoffLoaderUnloadImage (&Image->ImageContext);
1173
1174 //
1175 // Free our references to the image handle
1176 //
1177 if (Image->Handle != NULL_HANDLE) {
1178
1179 Status = CoreLocateHandleBuffer (
1180 AllHandles,
1181 NULL,
1182 NULL,
1183 &HandleCount,
1184 &HandleBuffer
1185 );
1186 if (!EFI_ERROR (Status)) {
1187 for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) {
1188 Status = CoreProtocolsPerHandle (
1189 HandleBuffer[HandleIndex],
1190 &ProtocolGuidArray,
1191 &ArrayCount
1192 );
1193 if (!EFI_ERROR (Status)) {
1194 for (ProtocolIndex = 0; ProtocolIndex < ArrayCount; ProtocolIndex++) {
1195 Status = CoreOpenProtocolInformation (
1196 HandleBuffer[HandleIndex],
1197 ProtocolGuidArray[ProtocolIndex],
1198 &OpenInfo,
1199 &OpenInfoCount
1200 );
1201 if (!EFI_ERROR (Status)) {
1202 for (OpenInfoIndex = 0; OpenInfoIndex < OpenInfoCount; OpenInfoIndex++) {
1203 if (OpenInfo[OpenInfoIndex].AgentHandle == Image->Handle) {
1204 Status = CoreCloseProtocol (
1205 HandleBuffer[HandleIndex],
1206 ProtocolGuidArray[ProtocolIndex],
1207 Image->Handle,
1208 OpenInfo[OpenInfoIndex].ControllerHandle
1209 );
1210 }
1211 }
1212 if (OpenInfo != NULL) {
1213 CoreFreePool(OpenInfo);
1214 }
1215 }
1216 }
1217 if (ProtocolGuidArray != NULL) {
1218 CoreFreePool(ProtocolGuidArray);
1219 }
1220 }
1221 }
1222 if (HandleBuffer != NULL) {
1223 CoreFreePool (HandleBuffer);
1224 }
1225 }
1226
1227 CoreRemoveDebugImageInfoEntry (Image->Handle);
1228
1229 Status = CoreUninstallProtocolInterface (
1230 Image->Handle,
1231 &gEfiLoadedImageDevicePathProtocolGuid,
1232 Image->LoadedImageDevicePath
1233 );
1234
1235 Status = CoreUninstallProtocolInterface (
1236 Image->Handle,
1237 &gEfiLoadedImageProtocolGuid,
1238 &Image->Info
1239 );
1240
1241 }
1242
1243 if (Image->RuntimeData != NULL) {
1244 if (Image->RuntimeData->Link.ForwardLink != NULL) {
1245 //
1246 // Remove the Image from the Runtime Image list as we are about to Free it!
1247 //
1248 RemoveEntryList (&Image->RuntimeData->Link);
1249 }
1250 CoreFreePool (Image->RuntimeData);
1251 }
1252
1253 //
1254 // Free the Image from memory
1255 //
1256 if ((Image->ImageBasePage != 0) && FreePage) {
1257 CoreFreePages (Image->ImageBasePage, Image->NumberOfPages);
1258 }
1259
1260 //
1261 // Done with the Image structure
1262 //
1263 if (Image->Info.FilePath != NULL) {
1264 CoreFreePool (Image->Info.FilePath);
1265 }
1266
1267 if (Image->LoadedImageDevicePath != NULL) {
1268 CoreFreePool (Image->LoadedImageDevicePath);
1269 }
1270
1271 if (Image->FixupData != NULL) {
1272 CoreFreePool (Image->FixupData);
1273 }
1274
1275 CoreFreePool (Image);
1276 }
1277
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
1290 Routine Description:
1291
1292 Terminates the currently loaded EFI image and returns control to boot services.
1293
1294 Arguments:
1295
1296 ImageHandle - Handle that identifies the image. This parameter is passed to the image
1297 on entry.
1298 Status - The image's exit code.
1299 ExitDataSize - The size, in bytes, of ExitData. Ignored if ExitStatus is
1300 EFI_SUCCESS.
1301 ExitData - Pointer to a data buffer that includes a Null-terminated Unicode string,
1302 optionally followed by additional binary data. The string is a
1303 description that the caller may use to further indicate the reason for
1304 the image's exit.
1305
1306 Returns:
1307
1308 EFI_INVALID_PARAMETER - Image handle is NULL or it is not current image.
1309
1310 EFI_SUCCESS - Successfully terminates the currently loaded EFI image.
1311
1312 EFI_ACCESS_DENIED - Should never reach there.
1313
1314 EFI_OUT_OF_RESOURCES - Could not allocate pool
1315
1316 --*/
1317 {
1318 LOADED_IMAGE_PRIVATE_DATA *Image;
1319 EFI_TPL OldTpl;
1320
1321 //
1322 // Prevent possible reentrance to this function
1323 // for the same ImageHandle
1324 //
1325 OldTpl = CoreRaiseTpl (TPL_NOTIFY);
1326
1327 Image = CoreLoadedImageInfo (ImageHandle);
1328 if (Image == NULL_HANDLE) {
1329 Status = EFI_INVALID_PARAMETER;
1330 goto Done;
1331 }
1332
1333 if (!Image->Started) {
1334 //
1335 // The image has not been started so just free its resources
1336 //
1337 CoreUnloadAndCloseImage (Image, TRUE);
1338 Status = EFI_SUCCESS;
1339 goto Done;
1340 }
1341
1342 //
1343 // Image has been started, verify this image can exit
1344 //
1345 if (Image != mCurrentImage) {
1346 DEBUG ((EFI_D_LOAD|EFI_D_ERROR, "Exit: Image is not exitable image\n"));
1347 Status = EFI_INVALID_PARAMETER;
1348 goto Done;
1349 }
1350
1351 //
1352 // Set status
1353 //
1354 Image->Status = Status;
1355
1356 //
1357 // If there's ExitData info, move it
1358 //
1359 if (ExitData != NULL) {
1360 Image->ExitDataSize = ExitDataSize;
1361 Image->ExitData = CoreAllocateBootServicesPool (Image->ExitDataSize);
1362 if (Image->ExitData == NULL) {
1363 Status = EFI_OUT_OF_RESOURCES;
1364 goto Done;
1365 }
1366 CopyMem (Image->ExitData, ExitData, Image->ExitDataSize);
1367 }
1368
1369 CoreRestoreTpl (OldTpl);
1370 //
1371 // return to StartImage
1372 //
1373 LongJump (Image->JumpContext, (UINTN)-1);
1374
1375 //
1376 // If we return from LongJump, then it is an error
1377 //
1378 ASSERT (FALSE);
1379 Status = EFI_ACCESS_DENIED;
1380 Done:
1381 CoreRestoreTpl (OldTpl);
1382 return Status;
1383 }
1384
1385
1386
1387 EFI_STATUS
1388 EFIAPI
1389 CoreUnloadImage (
1390 IN EFI_HANDLE ImageHandle
1391 )
1392 /*++
1393
1394 Routine Description:
1395
1396 Unloads an image.
1397
1398 Arguments:
1399
1400 ImageHandle - Handle that identifies the image to be unloaded.
1401
1402 Returns:
1403
1404 EFI_SUCCESS - The image has been unloaded.
1405 EFI_UNSUPPORTED - The image has been sarted, and does not support unload.
1406 EFI_INVALID_PARAMPETER - ImageHandle is not a valid image handle.
1407
1408 --*/
1409 {
1410 EFI_STATUS Status;
1411 LOADED_IMAGE_PRIVATE_DATA *Image;
1412 EFI_TPL OldTpl;
1413
1414 //
1415 // Prevent possible reentrance to this function
1416 // for the same ImageHandle
1417 //
1418 OldTpl = CoreRaiseTpl (TPL_NOTIFY);
1419
1420 Image = CoreLoadedImageInfo (ImageHandle);
1421 if (Image == NULL ) {
1422 //
1423 // The image handle is not valid
1424 //
1425 Status = EFI_INVALID_PARAMETER;
1426 goto Done;
1427 }
1428
1429 if (Image->Started) {
1430 //
1431 // The image has been started, request it to unload.
1432 //
1433 Status = EFI_UNSUPPORTED;
1434 if (Image->Info.Unload != NULL) {
1435 Status = Image->Info.Unload (ImageHandle);
1436 }
1437
1438 } else {
1439 //
1440 // This Image hasn't been started, thus it can be unloaded
1441 //
1442 Status = EFI_SUCCESS;
1443 }
1444
1445
1446 if (!EFI_ERROR (Status)) {
1447 //
1448 // if the Image was not started or Unloaded O.K. then clean up
1449 //
1450 CoreUnloadAndCloseImage (Image, TRUE);
1451 }
1452
1453 Done:
1454 CoreRestoreTpl (OldTpl);
1455 return Status;
1456 }
1457
1458
1459 EFI_STATUS
1460 EFIAPI
1461 CoreUnloadImageEx (
1462 IN EFI_PE32_IMAGE_PROTOCOL *This,
1463 IN EFI_HANDLE ImageHandle
1464 )
1465 /*++
1466
1467 Routine Description:
1468
1469 Unload the specified image.
1470
1471 Arguments:
1472
1473 This - Indicates the calling context.
1474
1475 ImageHandle - The specified image handle.
1476
1477 Returns:
1478
1479 EFI_INVALID_PARAMETER - Image handle is NULL.
1480
1481 EFI_UNSUPPORTED - Attempt to unload an unsupported image.
1482
1483 EFI_SUCCESS - Image successfully unloaded.
1484
1485 --*/
1486 {
1487 return CoreUnloadImage (ImageHandle);
1488 }