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