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