56c5fe5ea2812ca434eb22513fc30d7d3849dbe7
[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,                       // DeviceHandleDevicePath\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     Image->DeviceHandleDevicePath = CoreDuplicateDevicePath (HandleFilePath);\r
718   }\r
719 \r
720   //\r
721   // Initialize the fields for an internal driver\r
722   //\r
723   Image->Signature         = LOADED_IMAGE_PRIVATE_DATA_SIGNATURE;\r
724   Image->Info.SystemTable  = gDxeCoreST;\r
725   Image->Info.DeviceHandle = DeviceHandle;\r
726   Image->Info.Revision     = EFI_LOADED_IMAGE_INFORMATION_REVISION;\r
727   Image->Info.FilePath     = CoreDuplicateDevicePath (FilePath);\r
728   Image->Info.ParentHandle = ParentImageHandle;\r
729 \r
730 \r
731   if (NumberOfPages != NULL) {\r
732     Image->NumberOfPages = *NumberOfPages ;\r
733   } else {\r
734     Image->NumberOfPages = 0 ;\r
735   }\r
736 \r
737   //\r
738   // Install the protocol interfaces for this image\r
739   // don't fire notifications yet\r
740   //\r
741   Status = CoreInstallProtocolInterfaceNotify (\r
742              &Image->Handle,\r
743              &gEfiLoadedImageProtocolGuid,\r
744              EFI_NATIVE_INTERFACE,\r
745              &Image->Info,\r
746              FALSE\r
747              );\r
748   if (EFI_ERROR (Status)) {\r
749     goto Done;\r
750   }\r
751 \r
752   //\r
753   // Load the image.  If EntryPoint is Null, it will not be set.\r
754   //\r
755   Status = CoreLoadPeImage (BootPolicy, &FHand, Image, DstBuffer, EntryPoint, Attribute);\r
756   if (EFI_ERROR (Status)) {\r
757     if ((Status == EFI_BUFFER_TOO_SMALL) || (Status == EFI_OUT_OF_RESOURCES)) {\r
758       if (NumberOfPages != NULL) {\r
759         *NumberOfPages = Image->NumberOfPages;\r
760       }\r
761     }\r
762     goto Done;\r
763   }\r
764 \r
765   //\r
766   // Register the image in the Debug Image Info Table if the attribute is set\r
767   //\r
768   if (Attribute & EFI_LOAD_PE_IMAGE_ATTRIBUTE_DEBUG_IMAGE_INFO_TABLE_REGISTRATION) {\r
769     CoreNewDebugImageInfoEntry (EFI_DEBUG_IMAGE_INFO_TYPE_NORMAL, &Image->Info, Image->Handle);\r
770   }\r
771 \r
772   //\r
773   //Reinstall loaded image protocol to fire any notifications\r
774   //\r
775   Status = CoreReinstallProtocolInterface (\r
776              Image->Handle,\r
777              &gEfiLoadedImageProtocolGuid,\r
778              &Image->Info,\r
779              &Image->Info\r
780              );\r
781   if (EFI_ERROR (Status)) {\r
782     goto Done;\r
783   }\r
784 \r
785 \r
786   //\r
787   // Success.  Return the image handle\r
788   //\r
789   *ImageHandle = Image->Handle;\r
790 \r
791 Done:\r
792   //\r
793   // All done accessing the source file\r
794   // If we allocated the Source buffer, free it\r
795   //\r
796   if (FHand.FreeBuffer) {\r
797     CoreFreePool (FHand.Source);\r
798   }\r
799 \r
800   //\r
801   // There was an error.  If there's an Image structure, free it\r
802   //\r
803   if (EFI_ERROR (Status)) {\r
804     if (Image != NULL) {\r
805       CoreUnloadAndCloseImage (Image, (BOOLEAN)(DstBuffer == 0));\r
806       *ImageHandle = NULL;\r
807     }\r
808   } else if (EFI_ERROR (SecurityStatus)) {\r
809     Status = SecurityStatus;\r
810   }\r
811 \r
812   return Status;\r
813 }\r
814 \r
815 \r
816 \r
817 EFI_STATUS\r
818 EFIAPI\r
819 CoreLoadImage (\r
820   IN BOOLEAN                    BootPolicy,\r
821   IN EFI_HANDLE                 ParentImageHandle,\r
822   IN EFI_DEVICE_PATH_PROTOCOL   *FilePath,\r
823   IN VOID                       *SourceBuffer   OPTIONAL,\r
824   IN UINTN                      SourceSize,\r
825   OUT EFI_HANDLE                *ImageHandle\r
826   )\r
827 /*++\r
828 \r
829 Routine Description:\r
830 \r
831   Loads an EFI image into memory and returns a handle to the image.\r
832 \r
833 Arguments:\r
834 \r
835   BootPolicy          - If TRUE, indicates that the request originates from the boot manager,\r
836                         and that the boot manager is attempting to load FilePath as a boot selection.\r
837   ParentImageHandle   - The caller's image handle.\r
838   FilePath            - The specific file path from which the image is loaded.\r
839   SourceBuffer        - If not NULL, a pointer to the memory location containing a copy of\r
840                         the image to be loaded.\r
841   SourceSize          - The size in bytes of SourceBuffer.\r
842   ImageHandle         - Pointer to the returned image handle that is created when the image\r
843                         is successfully loaded.\r
844 \r
845 Returns:\r
846 \r
847   EFI_SUCCESS            - The image was loaded into memory.\r
848   EFI_NOT_FOUND          - The FilePath was not found.\r
849   EFI_INVALID_PARAMETER  - One of the parameters has an invalid value.\r
850   EFI_UNSUPPORTED        - The image type is not supported, or the device path cannot be\r
851                            parsed to locate the proper protocol for loading the file.\r
852   EFI_OUT_OF_RESOURCES   - Image was not loaded due to insufficient resources.\r
853 --*/\r
854 {\r
855   EFI_STATUS    Status;\r
856 \r
857   PERF_START (NULL, "LoadImage", NULL, 0);\r
858 \r
859   Status = CoreLoadImageCommon (\r
860              BootPolicy,\r
861              ParentImageHandle,\r
862              FilePath,\r
863              SourceBuffer,\r
864              SourceSize,\r
865              (EFI_PHYSICAL_ADDRESS)NULL,\r
866              NULL,\r
867              ImageHandle,\r
868              NULL,\r
869              EFI_LOAD_PE_IMAGE_ATTRIBUTE_RUNTIME_REGISTRATION | EFI_LOAD_PE_IMAGE_ATTRIBUTE_DEBUG_IMAGE_INFO_TABLE_REGISTRATION\r
870              );\r
871 \r
872   PERF_END (NULL, "LoadImage", NULL, 0);\r
873 \r
874   return Status;\r
875 }\r
876 \r
877 \r
878 EFI_STATUS\r
879 EFIAPI\r
880 CoreLoadImageEx (\r
881   IN  EFI_PE32_IMAGE_PROTOCOL          *This,\r
882   IN  EFI_HANDLE                       ParentImageHandle,\r
883   IN  EFI_DEVICE_PATH_PROTOCOL         *FilePath,\r
884   IN  VOID                             *SourceBuffer       OPTIONAL,\r
885   IN  UINTN                            SourceSize,\r
886   IN  EFI_PHYSICAL_ADDRESS             DstBuffer           OPTIONAL,\r
887   OUT UINTN                            *NumberOfPages      OPTIONAL,\r
888   OUT EFI_HANDLE                       *ImageHandle,\r
889   OUT EFI_PHYSICAL_ADDRESS             *EntryPoint         OPTIONAL,\r
890   IN  UINT32                           Attribute\r
891   )\r
892 /*++\r
893 \r
894 Routine Description:\r
895 \r
896   Loads an EFI image into memory and returns a handle to the image with extended parameters.\r
897 \r
898 Arguments:\r
899 \r
900   This                - Calling context\r
901   ParentImageHandle   - The caller's image handle.\r
902   FilePath            - The specific file path from which the image is loaded.\r
903   SourceBuffer        - If not NULL, a pointer to the memory location containing a copy of\r
904                         the image to be loaded.\r
905   SourceSize          - The size in bytes of SourceBuffer.\r
906   DstBuffer           - The buffer to store the image.\r
907   NumberOfPages       - For input, specifies the space size of the image by caller if not NULL.\r
908                         For output, specifies the actual space size needed.\r
909   ImageHandle         - Image handle for output.\r
910   EntryPoint          - Image entry point for output.\r
911   Attribute           - The bit mask of attributes to set for the load PE image.\r
912 \r
913 Returns:\r
914 \r
915   EFI_SUCCESS            - The image was loaded into memory.\r
916   EFI_NOT_FOUND          - The FilePath was not found.\r
917   EFI_INVALID_PARAMETER  - One of the parameters has an invalid value.\r
918   EFI_UNSUPPORTED        - The image type is not supported, or the device path cannot be\r
919                            parsed to locate the proper protocol for loading the file.\r
920   EFI_OUT_OF_RESOURCES   - Image was not loaded due to insufficient resources.\r
921 --*/\r
922 {\r
923   return CoreLoadImageCommon (\r
924            TRUE,\r
925            ParentImageHandle,\r
926            FilePath,\r
927            SourceBuffer,\r
928            SourceSize,\r
929            DstBuffer,\r
930            NumberOfPages,\r
931            ImageHandle,\r
932            EntryPoint,\r
933            Attribute\r
934            );\r
935 }\r
936 \r
937 EFI_STATUS\r
938 EFIAPI\r
939 CoreStartImage (\r
940   IN EFI_HANDLE  ImageHandle,\r
941   OUT UINTN      *ExitDataSize,\r
942   OUT CHAR16     **ExitData  OPTIONAL\r
943   )\r
944 /*++\r
945 \r
946 Routine Description:\r
947 \r
948   Transfer control to a loaded image's entry point.\r
949 \r
950 Arguments:\r
951 \r
952   ImageHandle     - Handle of image to be started.\r
953 \r
954   ExitDataSize    - Pointer of the size to ExitData\r
955 \r
956   ExitData        - Pointer to a pointer to a data buffer that includes a Null-terminated\r
957                     Unicode string, optionally followed by additional binary data. The string\r
958                     is a description that the caller may use to further indicate the reason for\r
959                     the image's exit.\r
960 \r
961 Returns:\r
962 \r
963   EFI_INVALID_PARAMETER     - Invalid parameter\r
964 \r
965   EFI_OUT_OF_RESOURCES       - No enough buffer to allocate\r
966 \r
967   EFI_SUCCESS               - Successfully transfer control to the image's entry point.\r
968 \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) {\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 ((EFI_D_ERROR, "Error: Image at %10p 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 (\r
1064         (EFI_D_LOAD,\r
1065         "StartImage: ExitDataSize %d, ExitData %x",\r
1066                             Image->ExitDataSize,\r
1067         Image->ExitData)\r
1068         );\r
1069       if (Image->ExitData != NULL) {\r
1070         DEBUG ((EFI_D_LOAD, " (%hs)", Image->ExitData));\r
1071       }\r
1072       DEBUG ((EFI_D_LOAD, "\n"));\r
1073     }\r
1074   DEBUG_CODE_END ();\r
1075 \r
1076   //\r
1077   //  Return the exit data to the caller\r
1078   //\r
1079   if (ExitData != NULL && ExitDataSize != NULL) {\r
1080     *ExitDataSize = Image->ExitDataSize;\r
1081     *ExitData     = Image->ExitData;\r
1082   } else {\r
1083     //\r
1084     // Caller doesn't want the exit data, free it\r
1085     //\r
1086     CoreFreePool (Image->ExitData);\r
1087     Image->ExitData = NULL;\r
1088   }\r
1089 \r
1090   //\r
1091   // Save the Status because Image will get destroyed if it is unloaded.\r
1092   //\r
1093   Status = Image->Status;\r
1094 \r
1095   //\r
1096   // If the image returned an error, or if the image is an application\r
1097   // unload it\r
1098   //\r
1099   if (EFI_ERROR (Image->Status) || Image->Type == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) {\r
1100     CoreUnloadAndCloseImage (Image, TRUE);\r
1101   }\r
1102 \r
1103   //\r
1104   // Done\r
1105   //\r
1106   PERF_END (ImageHandle, START_IMAGE_TOK, NULL, 0);\r
1107   return Status;\r
1108 }\r
1109 \r
1110 \r
1111 VOID\r
1112 CoreUnloadAndCloseImage (\r
1113   IN LOADED_IMAGE_PRIVATE_DATA  *Image,\r
1114   IN BOOLEAN                    FreePage\r
1115   )\r
1116 /*++\r
1117 \r
1118 Routine Description:\r
1119 \r
1120   Unloads EFI image from memory.\r
1121 \r
1122 Arguments:\r
1123 \r
1124   Image      - EFI image\r
1125   FreePage   - Free allocated pages\r
1126 \r
1127 Returns:\r
1128 \r
1129   None\r
1130 \r
1131 --*/\r
1132 {\r
1133   EFI_STATUS                          Status;\r
1134   UINTN                               HandleCount;\r
1135   EFI_HANDLE                          *HandleBuffer;\r
1136   UINTN                               HandleIndex;\r
1137   EFI_GUID                            **ProtocolGuidArray;\r
1138   UINTN                               ArrayCount;\r
1139   UINTN                               ProtocolIndex;\r
1140   EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfo;\r
1141   UINTN                               OpenInfoCount;\r
1142   UINTN                               OpenInfoIndex;\r
1143 \r
1144   if (Image->Ebc != NULL) {\r
1145     //\r
1146     // If EBC protocol exists we must perform cleanups for this image.\r
1147     //\r
1148     Image->Ebc->UnloadImage (Image->Ebc, Image->Handle);\r
1149   }\r
1150 \r
1151   //\r
1152   // Unload image, free Image->ImageContext->ModHandle\r
1153   //\r
1154   PeCoffLoaderUnloadImage (&Image->ImageContext);\r
1155 \r
1156   //\r
1157   // Free our references to the image handle\r
1158   //\r
1159   if (Image->Handle != NULL_HANDLE) {\r
1160 \r
1161     Status = CoreLocateHandleBuffer (\r
1162                AllHandles,\r
1163                NULL,\r
1164                NULL,\r
1165                &HandleCount,\r
1166                &HandleBuffer\r
1167                );\r
1168     if (!EFI_ERROR (Status)) {\r
1169       for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) {\r
1170         Status = CoreProtocolsPerHandle (\r
1171                    HandleBuffer[HandleIndex],\r
1172                    &ProtocolGuidArray,\r
1173                    &ArrayCount\r
1174                    );\r
1175         if (!EFI_ERROR (Status)) {\r
1176           for (ProtocolIndex = 0; ProtocolIndex < ArrayCount; ProtocolIndex++) {\r
1177             Status = CoreOpenProtocolInformation (\r
1178                        HandleBuffer[HandleIndex],\r
1179                        ProtocolGuidArray[ProtocolIndex],\r
1180                        &OpenInfo,\r
1181                        &OpenInfoCount\r
1182                        );\r
1183             if (!EFI_ERROR (Status)) {\r
1184               for (OpenInfoIndex = 0; OpenInfoIndex < OpenInfoCount; OpenInfoIndex++) {\r
1185                 if (OpenInfo[OpenInfoIndex].AgentHandle == Image->Handle) {\r
1186                   Status = CoreCloseProtocol (\r
1187                              HandleBuffer[HandleIndex],\r
1188                              ProtocolGuidArray[ProtocolIndex],\r
1189                              Image->Handle,\r
1190                              OpenInfo[OpenInfoIndex].ControllerHandle\r
1191                              );\r
1192                 }\r
1193               }\r
1194               if (OpenInfo != NULL) {\r
1195                 CoreFreePool(OpenInfo);\r
1196               }\r
1197             }\r
1198           }\r
1199           if (ProtocolGuidArray != NULL) {\r
1200             CoreFreePool(ProtocolGuidArray);\r
1201           }\r
1202         }\r
1203       }\r
1204       if (HandleBuffer != NULL) {\r
1205         CoreFreePool (HandleBuffer);\r
1206       }\r
1207     }\r
1208 \r
1209     CoreRemoveDebugImageInfoEntry (Image->Handle);\r
1210 \r
1211     Status = CoreUninstallProtocolInterface (\r
1212                Image->Handle,\r
1213                &gEfiLoadedImageProtocolGuid,\r
1214                &Image->Info\r
1215                );\r
1216   }\r
1217 \r
1218   if (Image->RuntimeData != NULL) {\r
1219     if (Image->RuntimeData->Link.ForwardLink != NULL) {\r
1220       //\r
1221       // Remove the Image from the Runtime Image list as we are about to Free it!\r
1222       //\r
1223       RemoveEntryList (&Image->RuntimeData->Link);\r
1224     }\r
1225     CoreFreePool (Image->RuntimeData);\r
1226   }\r
1227 \r
1228   //\r
1229   // Free the Image from memory\r
1230   //\r
1231   if ((Image->ImageBasePage != 0) && FreePage) {\r
1232     CoreFreePages (Image->ImageBasePage, Image->NumberOfPages);\r
1233   }\r
1234 \r
1235   //\r
1236   // Done with the Image structure\r
1237   //\r
1238   if (Image->Info.FilePath != NULL) {\r
1239     CoreFreePool (Image->Info.FilePath);\r
1240   }\r
1241 \r
1242   if (Image->DeviceHandleDevicePath != NULL) {\r
1243     CoreFreePool (Image->DeviceHandleDevicePath);\r
1244   }\r
1245 \r
1246   if (Image->FixupData != NULL) {\r
1247     CoreFreePool (Image->FixupData);\r
1248   }\r
1249 \r
1250   CoreFreePool (Image);\r
1251 }\r
1252 \r
1253 \r
1254 \r
1255 EFI_STATUS\r
1256 EFIAPI\r
1257 CoreExit (\r
1258   IN EFI_HANDLE  ImageHandle,\r
1259   IN EFI_STATUS  Status,\r
1260   IN UINTN       ExitDataSize,\r
1261   IN CHAR16      *ExitData  OPTIONAL\r
1262   )\r
1263 /*++\r
1264 \r
1265 Routine Description:\r
1266 \r
1267   Terminates the currently loaded EFI image and returns control to boot services.\r
1268 \r
1269 Arguments:\r
1270 \r
1271   ImageHandle       - Handle that identifies the image. This parameter is passed to the image\r
1272                       on entry.\r
1273   Status            - The image's exit code.\r
1274   ExitDataSize      - The size, in bytes, of ExitData. Ignored if ExitStatus is\r
1275                       EFI_SUCCESS.\r
1276   ExitData          - Pointer to a data buffer that includes a Null-terminated Unicode string,\r
1277                       optionally followed by additional binary data. The string is a\r
1278                       description that the caller may use to further indicate the reason for\r
1279                       the image's exit.\r
1280 \r
1281 Returns:\r
1282 \r
1283   EFI_INVALID_PARAMETER     - Image handle is NULL or it is not current image.\r
1284 \r
1285   EFI_SUCCESS               - Successfully terminates the currently loaded EFI image.\r
1286 \r
1287   EFI_ACCESS_DENIED         - Should never reach there.\r
1288 \r
1289   EFI_OUT_OF_RESOURCES      - Could not allocate pool\r
1290 \r
1291 --*/\r
1292 {\r
1293   LOADED_IMAGE_PRIVATE_DATA  *Image;\r
1294   EFI_TPL                    OldTpl;\r
1295 \r
1296   //\r
1297   // Prevent possible reentrance to this function\r
1298   // for the same ImageHandle\r
1299   // \r
1300   OldTpl = CoreRaiseTpl (TPL_NOTIFY); \r
1301  \r
1302   Image = CoreLoadedImageInfo (ImageHandle);\r
1303   if (Image == NULL_HANDLE) {\r
1304     Status = EFI_INVALID_PARAMETER;\r
1305     goto Done;\r
1306   }\r
1307 \r
1308   if (!Image->Started) {\r
1309     //\r
1310     // The image has not been started so just free its resources\r
1311     //\r
1312     CoreUnloadAndCloseImage (Image, TRUE);\r
1313     Status = EFI_SUCCESS;\r
1314     goto Done;\r
1315   }\r
1316 \r
1317   //\r
1318   // Image has been started, verify this image can exit\r
1319   //\r
1320   if (Image != mCurrentImage) {\r
1321     DEBUG ((EFI_D_LOAD|EFI_D_ERROR, "Exit: Image is not exitable image\n"));\r
1322     Status = EFI_INVALID_PARAMETER;\r
1323     goto Done;\r
1324   }\r
1325 \r
1326   //\r
1327   // Set status\r
1328   //\r
1329   Image->Status = Status;\r
1330 \r
1331   //\r
1332   // If there's ExitData info, move it\r
1333   //\r
1334   if (ExitData != NULL) {\r
1335     Image->ExitDataSize = ExitDataSize;\r
1336     Image->ExitData = CoreAllocateBootServicesPool (Image->ExitDataSize);\r
1337     if (Image->ExitData == NULL) {\r
1338       Status = EFI_OUT_OF_RESOURCES;\r
1339       goto Done;\r
1340     }\r
1341     CopyMem (Image->ExitData, ExitData, Image->ExitDataSize);\r
1342   }\r
1343 \r
1344   CoreRestoreTpl (OldTpl);\r
1345   //\r
1346   // return to StartImage\r
1347   //\r
1348   LongJump (Image->JumpContext, (UINTN)-1);\r
1349 \r
1350   //\r
1351   // If we return from LongJump, then it is an error\r
1352   //\r
1353   ASSERT (FALSE);\r
1354   Status = EFI_ACCESS_DENIED;\r
1355 Done:\r
1356   CoreRestoreTpl (OldTpl);\r
1357   return Status;\r
1358 }\r
1359 \r
1360 \r
1361 \r
1362 EFI_STATUS\r
1363 EFIAPI\r
1364 CoreUnloadImage (\r
1365   IN EFI_HANDLE  ImageHandle\r
1366   )\r
1367 /*++\r
1368 \r
1369 Routine Description:\r
1370 \r
1371   Unloads an image.\r
1372 \r
1373 Arguments:\r
1374 \r
1375   ImageHandle           - Handle that identifies the image to be unloaded.\r
1376 \r
1377 Returns:\r
1378 \r
1379  EFI_SUCCESS            - The image has been unloaded.\r
1380  EFI_UNSUPPORTED        - The image has been sarted, and does not support unload.\r
1381  EFI_INVALID_PARAMPETER - ImageHandle is not a valid image handle.\r
1382 \r
1383 --*/\r
1384 {\r
1385   EFI_STATUS                 Status;\r
1386   LOADED_IMAGE_PRIVATE_DATA  *Image;\r
1387   EFI_TPL                    OldTpl;\r
1388 \r
1389   //\r
1390   // Prevent possible reentrance to this function\r
1391   // for the same ImageHandle\r
1392   // \r
1393   OldTpl = CoreRaiseTpl (TPL_NOTIFY);\r
1394  \r
1395   Image = CoreLoadedImageInfo (ImageHandle);\r
1396   if (Image == NULL ) {\r
1397     //\r
1398     // The image handle is not valid\r
1399     //\r
1400     Status = EFI_INVALID_PARAMETER;\r
1401     goto Done;\r
1402   }\r
1403 \r
1404   if (Image->Started) {\r
1405     //\r
1406     // The image has been started, request it to unload.\r
1407     //\r
1408     Status = EFI_UNSUPPORTED;\r
1409     if (Image->Info.Unload != NULL) {\r
1410       Status = Image->Info.Unload (ImageHandle);\r
1411     }\r
1412 \r
1413   } else {\r
1414     //\r
1415     // This Image hasn't been started, thus it can be unloaded\r
1416     //\r
1417     Status = EFI_SUCCESS;\r
1418   }\r
1419 \r
1420 \r
1421   if (!EFI_ERROR (Status)) {\r
1422     //\r
1423     // if the Image was not started or Unloaded O.K. then clean up\r
1424     //\r
1425     CoreUnloadAndCloseImage (Image, TRUE);\r
1426   }\r
1427 \r
1428 Done:\r
1429   CoreRestoreTpl (OldTpl);\r
1430   return Status;\r
1431 }\r
1432 \r
1433 \r
1434 EFI_STATUS\r
1435 EFIAPI\r
1436 CoreUnloadImageEx (\r
1437   IN EFI_PE32_IMAGE_PROTOCOL  *This,\r
1438   IN EFI_HANDLE                         ImageHandle\r
1439   )\r
1440 /*++\r
1441 \r
1442 Routine Description:\r
1443 \r
1444   Unload the specified image.\r
1445 \r
1446 Arguments:\r
1447 \r
1448   This              - Indicates the calling context.\r
1449 \r
1450   ImageHandle       - The specified image handle.\r
1451 \r
1452 Returns:\r
1453 \r
1454   EFI_INVALID_PARAMETER       - Image handle is NULL.\r
1455 \r
1456   EFI_UNSUPPORTED             - Attempt to unload an unsupported image.\r
1457 \r
1458   EFI_SUCCESS                 - Image successfully unloaded.\r
1459 \r
1460 --*/\r
1461 {\r
1462   return CoreUnloadImage (ImageHandle);\r
1463 }\r