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