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