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