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