]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Core/Dxe/Image/Image.c
Use TmpStr as a backup, as StrCpy in BaseLib does not handle copy of two strings
[mirror_edk2.git] / MdeModulePkg / Core / Dxe / Image / Image.c
CommitLineData
23c98c94 1/** @file\r
504214c4
LG
2 Core image handling services to load and unload PeImage.\r
3\r
23c98c94 4Copyright (c) 2006 - 2008, Intel Corporation. <BR>\r
28a00297 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
504214c4 13**/\r
28a00297 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
ba39e316 70 NULL // LoadedImageDevicePath\r
28a00297 71};\r
72\r
73\r
28a00297 74\r
162ed594 75/**\r
28a00297 76 Add the Image Services to EFI Boot Services Table and install the protocol\r
77 interfaces for this image.\r
78\r
57d6f36d 79 @param HobStart The HOB to initialize\r
28a00297 80\r
162ed594 81 @return Status code.\r
28a00297 82\r
162ed594 83**/\r
84EFI_STATUS\r
85CoreInitializeImageServices (\r
86 IN VOID *HobStart\r
87 )\r
28a00297 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
162ed594 157\r
158/**\r
159 Loads, relocates, and invokes a PE/COFF image\r
160\r
57d6f36d 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
162ed594 176 @retval EFI_BUFFER_TOO_SMALL Buffer for image is too small\r
177\r
178**/\r
28a00297 179EFI_STATUS\r
180CoreLoadPeImage (\r
57d6f36d 181 IN BOOLEAN BootPolicy,\r
28a00297 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
28a00297 188{\r
822360ee
LG
189 EFI_STATUS Status;\r
190 BOOLEAN DstBufAlocated;\r
191 UINTN Size;\r
192 UINTN LinkTimeBase;\r
193 EFI_TCG_PLATFORM_PROTOCOL *TcgPlatformProtocol;\r
6cd7b51e 194 IMAGE_FILE_HANDLE *FHandle;\r
28a00297 195\r
6cd7b51e 196 FHandle = NULL;\r
28a00297 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
3d7b0992 205 Status = PeCoffLoaderGetImageInfo (&Image->ImageContext);\r
28a00297 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
5fed8e34 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
28a00297 218 }\r
57d6f36d 219\r
a0ae8996
LG
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
822360ee
LG
241 //\r
242 // Get the image base address in the original PeImage.\r
243 //\r
244 LinkTimeBase = (UINTN) Image->ImageContext.ImageAddress;\r
28a00297 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
3d7b0992 324 Status = PeCoffLoaderLoadImage (&Image->ImageContext);\r
28a00297 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
71f68914 334 if ((Attribute & EFI_LOAD_PE_IMAGE_ATTRIBUTE_RUNTIME_REGISTRATION) != 0) {\r
28a00297 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
822360ee
LG
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
6cd7b51e
LG
352 if (!EFI_ERROR (Status)) {\r
353 FHandle = (IMAGE_FILE_HANDLE *) Image->ImageContext.Handle;\r
822360ee
LG
354 Status = TcgPlatformProtocol->MeasurePeImage (\r
355 BootPolicy,\r
6cd7b51e
LG
356 (EFI_PHYSICAL_ADDRESS) (UINTN) FHandle->Source,\r
357 FHandle->SourceSize,\r
822360ee
LG
358 LinkTimeBase,\r
359 Image->ImageContext.ImageType,\r
360 Image->Info.DeviceHandle,\r
361 Image->Info.FilePath\r
362 );\r
6cd7b51e 363\r
822360ee
LG
364 ASSERT_EFI_ERROR (Status);\r
365 }\r
366\r
28a00297 367 //\r
368 // Relocate the image in memory\r
369 //\r
3d7b0992 370 Status = PeCoffLoaderRelocateImage (&Image->ImageContext);\r
28a00297 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
57d6f36d 399 DEBUG ((DEBUG_LOAD | DEBUG_ERROR, "CoreLoadPeImage: There is no EBC interpreter for an EBC image.\n"));\r
28a00297 400 goto Done;\r
401 }\r
402\r
403 //\r
404 // Register a callback for flushing the instruction cache so that created\r
405 // thunks can be flushed.\r
406 //\r
407 Status = Image->Ebc->RegisterICacheFlush (Image->Ebc, (EBC_ICACHE_FLUSH)InvalidateInstructionCacheRange);\r
408 if (EFI_ERROR(Status)) {\r
409 goto Done;\r
410 }\r
411\r
412 //\r
413 // Create a thunk for the image's entry point. This will be the new\r
414 // entry point for the image.\r
415 //\r
416 Status = Image->Ebc->CreateThunk (\r
417 Image->Ebc,\r
418 Image->Handle,\r
e94a9ff7 419 (VOID *)(UINTN) Image->ImageContext.EntryPoint,\r
420 (VOID **) &Image->EntryPoint\r
28a00297 421 );\r
422 if (EFI_ERROR(Status)) {\r
423 goto Done;\r
424 }\r
425 }\r
426\r
427 //\r
428 // Fill in the image information for the Loaded Image Protocol\r
429 //\r
430 Image->Type = Image->ImageContext.ImageType;\r
431 Image->Info.ImageBase = (VOID *)(UINTN)Image->ImageContext.ImageAddress;\r
432 Image->Info.ImageSize = Image->ImageContext.ImageSize;\r
433 Image->Info.ImageCodeType = (EFI_MEMORY_TYPE) (Image->ImageContext.ImageCodeMemoryType);\r
434 Image->Info.ImageDataType = (EFI_MEMORY_TYPE) (Image->ImageContext.ImageDataMemoryType);\r
71f68914 435 if ((Attribute & EFI_LOAD_PE_IMAGE_ATTRIBUTE_RUNTIME_REGISTRATION) != 0) {\r
28a00297 436 if (Image->ImageContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) {\r
437 //\r
438 // Make a list off all the RT images so we can let the RT AP know about them.\r
439 //\r
440 Image->RuntimeData = CoreAllocateRuntimePool (sizeof(EFI_RUNTIME_IMAGE_ENTRY));\r
441 if (Image->RuntimeData == NULL) {\r
442 goto Done;\r
443 }\r
444 Image->RuntimeData->ImageBase = Image->Info.ImageBase;\r
445 Image->RuntimeData->ImageSize = (UINT64) (Image->Info.ImageSize);\r
446 Image->RuntimeData->RelocationData = Image->ImageContext.FixupData;\r
447 Image->RuntimeData->Handle = Image->Handle;\r
448 InsertTailList (&gRuntime->ImageHead, &Image->RuntimeData->Link);\r
449 }\r
450 }\r
451\r
452 //\r
453 // Fill in the entry point of the image if it is available\r
454 //\r
455 if (EntryPoint != NULL) {\r
456 *EntryPoint = Image->ImageContext.EntryPoint;\r
457 }\r
458\r
459 //\r
460 // Print the load address and the PDB file name if it is available\r
461 //\r
462\r
463 DEBUG_CODE_BEGIN ();\r
464\r
465 UINTN Index;\r
466 UINTN StartIndex;\r
467 CHAR8 EfiFileName[256];\r
57d6f36d 468\r
e94a9ff7 469 \r
470 DEBUG ((DEBUG_INFO | DEBUG_LOAD,\r
471 "Loading driver at 0x%10p EntryPoint=0x%10p ",\r
472 (VOID *)(UINTN) Image->ImageContext.ImageAddress,\r
473 FUNCTION_ENTRY_POINT ((UINTN) Image->ImageContext.EntryPoint)));\r
474 \r
57d6f36d 475\r
e98cd821
LG
476 //\r
477 // Print Module Name by Pdb file path\r
478 //\r
28a00297 479 if (Image->ImageContext.PdbPointer != NULL) {\r
480 StartIndex = 0;\r
481 for (Index = 0; Image->ImageContext.PdbPointer[Index] != 0; Index++) {\r
482 if (Image->ImageContext.PdbPointer[Index] == '\\') {\r
483 StartIndex = Index + 1;\r
484 }\r
485 }\r
486 //\r
487 // Copy the PDB file name to our temporary string, and replace .pdb with .efi\r
488 //\r
489 for (Index = 0; Index < sizeof (EfiFileName); Index++) {\r
490 EfiFileName[Index] = Image->ImageContext.PdbPointer[Index + StartIndex];\r
491 if (EfiFileName[Index] == 0) {\r
492 EfiFileName[Index] = '.';\r
493 }\r
494 if (EfiFileName[Index] == '.') {\r
495 EfiFileName[Index + 1] = 'e';\r
496 EfiFileName[Index + 2] = 'f';\r
497 EfiFileName[Index + 3] = 'i';\r
498 EfiFileName[Index + 4] = 0;\r
499 break;\r
500 }\r
501 }\r
162ed594 502 DEBUG ((DEBUG_INFO | DEBUG_LOAD, "%a", EfiFileName)); // &Image->ImageContext.PdbPointer[StartIndex]));\r
28a00297 503 }\r
162ed594 504 DEBUG ((DEBUG_INFO | DEBUG_LOAD, "\n"));\r
28a00297 505\r
506 DEBUG_CODE_END ();\r
507\r
508 return EFI_SUCCESS;\r
509\r
510Done:\r
511\r
512 //\r
513 // Free memory.\r
514 //\r
515\r
516 if (DstBufAlocated) {\r
517 CoreFreePages (Image->ImageContext.ImageAddress, Image->NumberOfPages);\r
518 }\r
519\r
520 if (Image->ImageContext.FixupData != NULL) {\r
521 CoreFreePool (Image->ImageContext.FixupData);\r
522 }\r
523\r
524 return Status;\r
525}\r
526\r
527\r
28a00297 528\r
162ed594 529/**\r
28a00297 530 Get the image's private data from its handle.\r
531\r
57d6f36d 532 @param ImageHandle The image handle\r
28a00297 533\r
162ed594 534 @return Return the image private data associated with ImageHandle.\r
28a00297 535\r
162ed594 536**/\r
537LOADED_IMAGE_PRIVATE_DATA *\r
538CoreLoadedImageInfo (\r
539 IN EFI_HANDLE ImageHandle\r
540 )\r
28a00297 541{\r
542 EFI_STATUS Status;\r
543 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;\r
544 LOADED_IMAGE_PRIVATE_DATA *Image;\r
545\r
546 Status = CoreHandleProtocol (\r
547 ImageHandle,\r
548 &gEfiLoadedImageProtocolGuid,\r
549 (VOID **)&LoadedImage\r
550 );\r
551 if (!EFI_ERROR (Status)) {\r
552 Image = LOADED_IMAGE_PRIVATE_DATA_FROM_THIS (LoadedImage);\r
553 } else {\r
e94a9ff7 554 DEBUG ((DEBUG_LOAD, "CoreLoadedImageInfo: Not an ImageHandle %p\n", ImageHandle));\r
28a00297 555 Image = NULL;\r
556 }\r
557\r
558 return Image;\r
559}\r
560\r
162ed594 561\r
562/**\r
563 Loads an EFI image into memory and returns a handle to the image.\r
564\r
57d6f36d 565 @param BootPolicy If TRUE, indicates that the request originates\r
566 from the boot manager, and that the boot\r
567 manager is attempting to load FilePath as a\r
568 boot selection.\r
569 @param ParentImageHandle The caller's image handle.\r
570 @param FilePath The specific file path from which the image is\r
571 loaded.\r
572 @param SourceBuffer If not NULL, a pointer to the memory location\r
573 containing a copy of the image to be loaded.\r
574 @param SourceSize The size in bytes of SourceBuffer.\r
575 @param DstBuffer The buffer to store the image\r
576 @param NumberOfPages If not NULL, it inputs a pointer to the page\r
577 number of DstBuffer and outputs a pointer to\r
578 the page number of the image. If this number is\r
579 not enough, return EFI_BUFFER_TOO_SMALL and\r
580 this parameter contains the required number.\r
581 @param ImageHandle Pointer to the returned image handle that is\r
582 created when the image is successfully loaded.\r
583 @param EntryPoint A pointer to the entry point\r
584 @param Attribute The bit mask of attributes to set for the load\r
585 PE image\r
586\r
587 @retval EFI_SUCCESS The image was loaded into memory.\r
588 @retval EFI_NOT_FOUND The FilePath was not found.\r
589 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.\r
590 @retval EFI_BUFFER_TOO_SMALL The buffer is too small\r
591 @retval EFI_UNSUPPORTED The image type is not supported, or the device\r
592 path cannot be parsed to locate the proper\r
593 protocol for loading the file.\r
594 @retval EFI_OUT_OF_RESOURCES Image was not loaded due to insufficient\r
162ed594 595 resources.\r
596\r
597**/\r
28a00297 598EFI_STATUS\r
599CoreLoadImageCommon (\r
600 IN BOOLEAN BootPolicy,\r
601 IN EFI_HANDLE ParentImageHandle,\r
602 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,\r
603 IN VOID *SourceBuffer OPTIONAL,\r
604 IN UINTN SourceSize,\r
605 IN EFI_PHYSICAL_ADDRESS DstBuffer OPTIONAL,\r
606 IN OUT UINTN *NumberOfPages OPTIONAL,\r
607 OUT EFI_HANDLE *ImageHandle,\r
608 OUT EFI_PHYSICAL_ADDRESS *EntryPoint OPTIONAL,\r
609 IN UINT32 Attribute\r
610 )\r
28a00297 611{\r
612 LOADED_IMAGE_PRIVATE_DATA *Image;\r
613 LOADED_IMAGE_PRIVATE_DATA *ParentImage;\r
614 IMAGE_FILE_HANDLE FHand;\r
615 EFI_STATUS Status;\r
616 EFI_STATUS SecurityStatus;\r
617 EFI_HANDLE DeviceHandle;\r
618 UINT32 AuthenticationStatus;\r
619 EFI_DEVICE_PATH_PROTOCOL *OriginalFilePath;\r
620 EFI_DEVICE_PATH_PROTOCOL *HandleFilePath;\r
621 UINTN FilePathSize;\r
622\r
623 SecurityStatus = EFI_SUCCESS;\r
624\r
625 ASSERT (gEfiCurrentTpl < TPL_NOTIFY);\r
626 ParentImage = NULL;\r
627\r
628 //\r
629 // The caller must pass in a valid ParentImageHandle\r
630 //\r
631 if (ImageHandle == NULL || ParentImageHandle == NULL) {\r
632 return EFI_INVALID_PARAMETER;\r
633 }\r
634\r
635 ParentImage = CoreLoadedImageInfo (ParentImageHandle);\r
636 if (ParentImage == NULL) {\r
162ed594 637 DEBUG((DEBUG_LOAD|DEBUG_ERROR, "LoadImageEx: Parent handle not an image handle\n"));\r
28a00297 638 return EFI_INVALID_PARAMETER;\r
639 }\r
640\r
641 //\r
642 // Get simple read access to the source file\r
643 //\r
644 OriginalFilePath = FilePath;\r
645 Status = CoreOpenImageFile (\r
646 BootPolicy,\r
647 SourceBuffer,\r
648 SourceSize,\r
cfe9de52 649 &FilePath,\r
28a00297 650 &DeviceHandle,\r
651 &FHand,\r
652 &AuthenticationStatus\r
653 );\r
654 if (Status == EFI_ALREADY_STARTED) {\r
655 Image = NULL;\r
656 goto Done;\r
657 } else if (EFI_ERROR (Status)) {\r
658 return Status;\r
659 }\r
660\r
661 //\r
662 // Verify the Authentication Status through the Security Architectural Protocol\r
663 //\r
664 if ((gSecurity != NULL) && (OriginalFilePath != NULL)) {\r
665 SecurityStatus = gSecurity->FileAuthenticationState (\r
666 gSecurity,\r
667 AuthenticationStatus,\r
668 OriginalFilePath\r
669 );\r
670 if (EFI_ERROR (SecurityStatus) && SecurityStatus != EFI_SECURITY_VIOLATION) {\r
671 Status = SecurityStatus;\r
672 Image = NULL;\r
673 goto Done;\r
674 }\r
675 }\r
676\r
677\r
678 //\r
679 // Allocate a new image structure\r
680 //\r
681 Image = CoreAllocateZeroBootServicesPool (sizeof(LOADED_IMAGE_PRIVATE_DATA));\r
682 if (Image == NULL) {\r
683 return EFI_OUT_OF_RESOURCES;\r
684 }\r
685\r
686 //\r
687 // Pull out just the file portion of the DevicePath for the LoadedImage FilePath\r
688 //\r
cfe9de52 689 FilePath = OriginalFilePath;\r
28a00297 690 Status = CoreHandleProtocol (DeviceHandle, &gEfiDevicePathProtocolGuid, (VOID **)&HandleFilePath);\r
691 if (!EFI_ERROR (Status)) {\r
692 FilePathSize = CoreDevicePathSize (HandleFilePath) - sizeof(EFI_DEVICE_PATH_PROTOCOL);\r
e94a9ff7 693 FilePath = (EFI_DEVICE_PATH_PROTOCOL *) (((UINT8 *)FilePath) + FilePathSize );\r
28a00297 694 }\r
695\r
696 //\r
697 // Initialize the fields for an internal driver\r
698 //\r
699 Image->Signature = LOADED_IMAGE_PRIVATE_DATA_SIGNATURE;\r
700 Image->Info.SystemTable = gDxeCoreST;\r
701 Image->Info.DeviceHandle = DeviceHandle;\r
162ed594 702 Image->Info.Revision = EFI_LOADED_IMAGE_PROTOCOL_REVISION;\r
28a00297 703 Image->Info.FilePath = CoreDuplicateDevicePath (FilePath);\r
704 Image->Info.ParentHandle = ParentImageHandle;\r
705\r
85658066 706\r
28a00297 707 if (NumberOfPages != NULL) {\r
708 Image->NumberOfPages = *NumberOfPages ;\r
709 } else {\r
710 Image->NumberOfPages = 0 ;\r
711 }\r
712\r
713 //\r
714 // Install the protocol interfaces for this image\r
715 // don't fire notifications yet\r
716 //\r
717 Status = CoreInstallProtocolInterfaceNotify (\r
718 &Image->Handle,\r
719 &gEfiLoadedImageProtocolGuid,\r
720 EFI_NATIVE_INTERFACE,\r
721 &Image->Info,\r
722 FALSE\r
723 );\r
724 if (EFI_ERROR (Status)) {\r
725 goto Done;\r
726 }\r
727\r
728 //\r
729 // Load the image. If EntryPoint is Null, it will not be set.\r
730 //\r
822360ee 731 Status = CoreLoadPeImage (BootPolicy, &FHand, Image, DstBuffer, EntryPoint, Attribute);\r
28a00297 732 if (EFI_ERROR (Status)) {\r
733 if ((Status == EFI_BUFFER_TOO_SMALL) || (Status == EFI_OUT_OF_RESOURCES)) {\r
734 if (NumberOfPages != NULL) {\r
735 *NumberOfPages = Image->NumberOfPages;\r
736 }\r
737 }\r
738 goto Done;\r
739 }\r
740\r
152af594 741 if (NumberOfPages != NULL) {\r
742 *NumberOfPages = Image->NumberOfPages;\r
57d6f36d 743 }\r
152af594 744\r
28a00297 745 //\r
746 // Register the image in the Debug Image Info Table if the attribute is set\r
747 //\r
71f68914 748 if ((Attribute & EFI_LOAD_PE_IMAGE_ATTRIBUTE_DEBUG_IMAGE_INFO_TABLE_REGISTRATION) != 0) {\r
28a00297 749 CoreNewDebugImageInfoEntry (EFI_DEBUG_IMAGE_INFO_TYPE_NORMAL, &Image->Info, Image->Handle);\r
750 }\r
751\r
752 //\r
753 //Reinstall loaded image protocol to fire any notifications\r
754 //\r
755 Status = CoreReinstallProtocolInterface (\r
756 Image->Handle,\r
757 &gEfiLoadedImageProtocolGuid,\r
758 &Image->Info,\r
759 &Image->Info\r
760 );\r
761 if (EFI_ERROR (Status)) {\r
762 goto Done;\r
763 }\r
764\r
ba39e316 765 //\r
766 // If DevicePath parameter to the LoadImage() is not NULL, then make a copy of DevicePath,\r
767 // otherwise Loaded Image Device Path Protocol is installed with a NULL interface pointer.\r
768 //\r
769 if (OriginalFilePath != NULL) {\r
770 Image->LoadedImageDevicePath = CoreDuplicateDevicePath (OriginalFilePath);\r
771 }\r
772\r
773 //\r
774 // Install Loaded Image Device Path Protocol onto the image handle of a PE/COFE image\r
775 //\r
776 Status = CoreInstallProtocolInterface (\r
777 &Image->Handle,\r
778 &gEfiLoadedImageDevicePathProtocolGuid,\r
779 EFI_NATIVE_INTERFACE,\r
780 Image->LoadedImageDevicePath\r
781 );\r
782 if (EFI_ERROR (Status)) {\r
783 goto Done;\r
784 }\r
28a00297 785\r
786 //\r
787 // Success. Return the image handle\r
788 //\r
789 *ImageHandle = Image->Handle;\r
790\r
791Done:\r
792 //\r
793 // All done accessing the source file\r
794 // If we allocated the Source buffer, free it\r
795 //\r
796 if (FHand.FreeBuffer) {\r
797 CoreFreePool (FHand.Source);\r
798 }\r
799\r
800 //\r
801 // There was an error. If there's an Image structure, free it\r
802 //\r
803 if (EFI_ERROR (Status)) {\r
804 if (Image != NULL) {\r
805 CoreUnloadAndCloseImage (Image, (BOOLEAN)(DstBuffer == 0));\r
806 *ImageHandle = NULL;\r
807 }\r
808 } else if (EFI_ERROR (SecurityStatus)) {\r
809 Status = SecurityStatus;\r
810 }\r
811\r
812 return Status;\r
813}\r
814\r
815\r
816\r
162ed594 817\r
818/**\r
819 Loads an EFI image into memory and returns a handle to the image.\r
820\r
57d6f36d 821 @param BootPolicy If TRUE, indicates that the request originates\r
822 from the boot manager, and that the boot\r
823 manager is attempting to load FilePath as a\r
824 boot selection.\r
825 @param ParentImageHandle The caller's image handle.\r
826 @param FilePath The specific file path from which the image is\r
827 loaded.\r
828 @param SourceBuffer If not NULL, a pointer to the memory location\r
829 containing a copy of the image to be loaded.\r
830 @param SourceSize The size in bytes of SourceBuffer.\r
831 @param ImageHandle Pointer to the returned image handle that is\r
832 created when the image is successfully loaded.\r
833\r
834 @retval EFI_SUCCESS The image was loaded into memory.\r
835 @retval EFI_NOT_FOUND The FilePath was not found.\r
836 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.\r
837 @retval EFI_UNSUPPORTED The image type is not supported, or the device\r
838 path cannot be parsed to locate the proper\r
839 protocol for loading the file.\r
840 @retval EFI_OUT_OF_RESOURCES Image was not loaded due to insufficient\r
162ed594 841 resources.\r
842\r
843**/\r
28a00297 844EFI_STATUS\r
845EFIAPI\r
846CoreLoadImage (\r
847 IN BOOLEAN BootPolicy,\r
848 IN EFI_HANDLE ParentImageHandle,\r
849 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,\r
850 IN VOID *SourceBuffer OPTIONAL,\r
851 IN UINTN SourceSize,\r
852 OUT EFI_HANDLE *ImageHandle\r
853 )\r
28a00297 854{\r
855 EFI_STATUS Status;\r
856\r
857 PERF_START (NULL, "LoadImage", NULL, 0);\r
858\r
859 Status = CoreLoadImageCommon (\r
860 BootPolicy,\r
861 ParentImageHandle,\r
862 FilePath,\r
863 SourceBuffer,\r
864 SourceSize,\r
1be0dda6 865 (EFI_PHYSICAL_ADDRESS) (UINTN) NULL,\r
28a00297 866 NULL,\r
867 ImageHandle,\r
868 NULL,\r
869 EFI_LOAD_PE_IMAGE_ATTRIBUTE_RUNTIME_REGISTRATION | EFI_LOAD_PE_IMAGE_ATTRIBUTE_DEBUG_IMAGE_INFO_TABLE_REGISTRATION\r
870 );\r
871\r
872 PERF_END (NULL, "LoadImage", NULL, 0);\r
873\r
874 return Status;\r
875}\r
876\r
877\r
162ed594 878\r
879/**\r
880 Loads an EFI image into memory and returns a handle to the image with extended parameters.\r
881\r
57d6f36d 882 @param This Calling context\r
883 @param ParentImageHandle The caller's image handle.\r
884 @param FilePath The specific file path from which the image is\r
885 loaded.\r
886 @param SourceBuffer If not NULL, a pointer to the memory location\r
887 containing a copy of the image to be loaded.\r
888 @param SourceSize The size in bytes of SourceBuffer.\r
889 @param DstBuffer The buffer to store the image.\r
890 @param NumberOfPages For input, specifies the space size of the\r
891 image by caller if not NULL. For output,\r
892 specifies the actual space size needed.\r
893 @param ImageHandle Image handle for output.\r
894 @param EntryPoint Image entry point for output.\r
895 @param Attribute The bit mask of attributes to set for the load\r
896 PE image.\r
897\r
898 @retval EFI_SUCCESS The image was loaded into memory.\r
899 @retval EFI_NOT_FOUND The FilePath was not found.\r
900 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.\r
901 @retval EFI_UNSUPPORTED The image type is not supported, or the device\r
902 path cannot be parsed to locate the proper\r
903 protocol for loading the file.\r
904 @retval EFI_OUT_OF_RESOURCES Image was not loaded due to insufficient\r
162ed594 905 resources.\r
906\r
907**/\r
28a00297 908EFI_STATUS\r
909EFIAPI\r
910CoreLoadImageEx (\r
911 IN EFI_PE32_IMAGE_PROTOCOL *This,\r
912 IN EFI_HANDLE ParentImageHandle,\r
913 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,\r
914 IN VOID *SourceBuffer OPTIONAL,\r
915 IN UINTN SourceSize,\r
916 IN EFI_PHYSICAL_ADDRESS DstBuffer OPTIONAL,\r
917 OUT UINTN *NumberOfPages OPTIONAL,\r
918 OUT EFI_HANDLE *ImageHandle,\r
919 OUT EFI_PHYSICAL_ADDRESS *EntryPoint OPTIONAL,\r
920 IN UINT32 Attribute\r
921 )\r
28a00297 922{\r
923 return CoreLoadImageCommon (\r
924 TRUE,\r
925 ParentImageHandle,\r
926 FilePath,\r
927 SourceBuffer,\r
928 SourceSize,\r
929 DstBuffer,\r
930 NumberOfPages,\r
931 ImageHandle,\r
932 EntryPoint,\r
933 Attribute\r
934 );\r
935}\r
936\r
162ed594 937\r
938/**\r
939 Transfer control to a loaded image's entry point.\r
940\r
57d6f36d 941 @param ImageHandle Handle of image to be started.\r
942 @param ExitDataSize Pointer of the size to ExitData\r
943 @param ExitData Pointer to a pointer to a data buffer that\r
944 includes a Null-terminated Unicode string,\r
945 optionally followed by additional binary data.\r
946 The string is a description that the caller may\r
947 use to further indicate the reason for the\r
948 image's exit.\r
949\r
950 @retval EFI_INVALID_PARAMETER Invalid parameter\r
951 @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate\r
952 @retval EFI_SUCCESS Successfully transfer control to the image's\r
162ed594 953 entry point.\r
954\r
955**/\r
28a00297 956EFI_STATUS\r
957EFIAPI\r
958CoreStartImage (\r
959 IN EFI_HANDLE ImageHandle,\r
960 OUT UINTN *ExitDataSize,\r
961 OUT CHAR16 **ExitData OPTIONAL\r
962 )\r
28a00297 963{\r
964 EFI_STATUS Status;\r
965 LOADED_IMAGE_PRIVATE_DATA *Image;\r
966 LOADED_IMAGE_PRIVATE_DATA *LastImage;\r
967 UINT64 HandleDatabaseKey;\r
968 UINTN SetJumpFlag;\r
969\r
970 Image = CoreLoadedImageInfo (ImageHandle);\r
971 if (Image == NULL_HANDLE || Image->Started) {\r
972 return EFI_INVALID_PARAMETER;\r
973 }\r
974\r
975 //\r
976 // Don't profile Objects or invalid start requests\r
977 //\r
978 PERF_START (ImageHandle, START_IMAGE_TOK, NULL, 0);\r
979\r
980\r
981 //\r
982 // Push the current start image context, and\r
983 // link the current image to the head. This is the\r
984 // only image that can call Exit()\r
985 //\r
986 HandleDatabaseKey = CoreGetHandleDatabaseKey ();\r
987 LastImage = mCurrentImage;\r
988 mCurrentImage = Image;\r
989 Image->Tpl = gEfiCurrentTpl;\r
990\r
991 //\r
992 // Set long jump for Exit() support\r
993 // JumpContext must be aligned on a CPU specific boundary.\r
994 // Overallocate the buffer and force the required alignment\r
995 //\r
996 Image->JumpBuffer = CoreAllocateBootServicesPool (sizeof (BASE_LIBRARY_JUMP_BUFFER) + BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT);\r
997 if (Image->JumpBuffer == NULL) {\r
998 PERF_END (ImageHandle, START_IMAGE_TOK, NULL, 0);\r
999 return EFI_OUT_OF_RESOURCES;\r
1000 }\r
1001 Image->JumpContext = ALIGN_POINTER (Image->JumpBuffer, BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT);\r
1002\r
1003 SetJumpFlag = SetJump (Image->JumpContext);\r
1004 //\r
1005 // The initial call to SetJump() must always return 0.\r
1006 // Subsequent calls to LongJump() cause a non-zero value to be returned by SetJump().\r
1007 //\r
71f68914 1008 if (SetJumpFlag == 0) {\r
28a00297 1009 //\r
1010 // Call the image's entry point\r
1011 //\r
1012 Image->Started = TRUE;\r
1013 Image->Status = Image->EntryPoint (ImageHandle, Image->Info.SystemTable);\r
1014\r
1015 //\r
1016 // Add some debug information if the image returned with error.\r
1017 // This make the user aware and check if the driver image have already released\r
1018 // all the resource in this situation.\r
1019 //\r
1020 DEBUG_CODE_BEGIN ();\r
1021 if (EFI_ERROR (Image->Status)) {\r
162ed594 1022 DEBUG ((DEBUG_ERROR, "Error: Image at %10p start failed: %r\n", Image->Info.ImageBase, Image->Status));\r
28a00297 1023 }\r
1024 DEBUG_CODE_END ();\r
1025\r
1026 //\r
1027 // If the image returns, exit it through Exit()\r
1028 //\r
1029 CoreExit (ImageHandle, Image->Status, 0, NULL);\r
1030 }\r
1031\r
1032 //\r
1033 // Image has completed. Verify the tpl is the same\r
1034 //\r
1035 ASSERT (Image->Tpl == gEfiCurrentTpl);\r
1036 CoreRestoreTpl (Image->Tpl);\r
1037\r
1038 CoreFreePool (Image->JumpBuffer);\r
1039\r
1040 //\r
1041 // Pop the current start image context\r
1042 //\r
1043 mCurrentImage = LastImage;\r
1044\r
1045 //\r
1046 // Go connect any handles that were created or modified while the image executed.\r
1047 //\r
1048 CoreConnectHandlesByKey (HandleDatabaseKey);\r
1049\r
1050 //\r
1051 // Handle the image's returned ExitData\r
1052 //\r
1053 DEBUG_CODE_BEGIN ();\r
1054 if (Image->ExitDataSize != 0 || Image->ExitData != NULL) {\r
1055\r
e94a9ff7 1056 DEBUG ((DEBUG_LOAD, "StartImage: ExitDataSize %d, ExitData %x", Image->ExitDataSize, Image->ExitData));\r
28a00297 1057 if (Image->ExitData != NULL) {\r
162ed594 1058 DEBUG ((DEBUG_LOAD, " (%hs)", Image->ExitData));\r
28a00297 1059 }\r
162ed594 1060 DEBUG ((DEBUG_LOAD, "\n"));\r
28a00297 1061 }\r
1062 DEBUG_CODE_END ();\r
1063\r
1064 //\r
1065 // Return the exit data to the caller\r
1066 //\r
1067 if (ExitData != NULL && ExitDataSize != NULL) {\r
1068 *ExitDataSize = Image->ExitDataSize;\r
1069 *ExitData = Image->ExitData;\r
1070 } else {\r
1071 //\r
1072 // Caller doesn't want the exit data, free it\r
1073 //\r
1074 CoreFreePool (Image->ExitData);\r
1075 Image->ExitData = NULL;\r
1076 }\r
1077\r
1078 //\r
1079 // Save the Status because Image will get destroyed if it is unloaded.\r
1080 //\r
1081 Status = Image->Status;\r
1082\r
1083 //\r
1084 // If the image returned an error, or if the image is an application\r
1085 // unload it\r
1086 //\r
1087 if (EFI_ERROR (Image->Status) || Image->Type == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) {\r
1088 CoreUnloadAndCloseImage (Image, TRUE);\r
1089 }\r
1090\r
1091 //\r
1092 // Done\r
1093 //\r
1094 PERF_END (ImageHandle, START_IMAGE_TOK, NULL, 0);\r
1095 return Status;\r
1096}\r
1097\r
1098\r
162ed594 1099\r
1100/**\r
1101 Unloads EFI image from memory.\r
1102\r
57d6f36d 1103 @param Image EFI image\r
162ed594 1104 @param FreePage Free allocated pages\r
1105\r
1106**/\r
28a00297 1107VOID\r
1108CoreUnloadAndCloseImage (\r
1109 IN LOADED_IMAGE_PRIVATE_DATA *Image,\r
1110 IN BOOLEAN FreePage\r
1111 )\r
28a00297 1112{\r
1113 EFI_STATUS Status;\r
1114 UINTN HandleCount;\r
1115 EFI_HANDLE *HandleBuffer;\r
1116 UINTN HandleIndex;\r
1117 EFI_GUID **ProtocolGuidArray;\r
1118 UINTN ArrayCount;\r
1119 UINTN ProtocolIndex;\r
1120 EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfo;\r
1121 UINTN OpenInfoCount;\r
1122 UINTN OpenInfoIndex;\r
1123\r
1124 if (Image->Ebc != NULL) {\r
1125 //\r
1126 // If EBC protocol exists we must perform cleanups for this image.\r
1127 //\r
1128 Image->Ebc->UnloadImage (Image->Ebc, Image->Handle);\r
1129 }\r
1130\r
1131 //\r
1132 // Unload image, free Image->ImageContext->ModHandle\r
1133 //\r
3d7b0992 1134 PeCoffLoaderUnloadImage (&Image->ImageContext);\r
28a00297 1135\r
1136 //\r
1137 // Free our references to the image handle\r
1138 //\r
1139 if (Image->Handle != NULL_HANDLE) {\r
1140\r
1141 Status = CoreLocateHandleBuffer (\r
1142 AllHandles,\r
1143 NULL,\r
1144 NULL,\r
1145 &HandleCount,\r
1146 &HandleBuffer\r
1147 );\r
1148 if (!EFI_ERROR (Status)) {\r
1149 for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) {\r
1150 Status = CoreProtocolsPerHandle (\r
1151 HandleBuffer[HandleIndex],\r
1152 &ProtocolGuidArray,\r
1153 &ArrayCount\r
1154 );\r
1155 if (!EFI_ERROR (Status)) {\r
1156 for (ProtocolIndex = 0; ProtocolIndex < ArrayCount; ProtocolIndex++) {\r
1157 Status = CoreOpenProtocolInformation (\r
1158 HandleBuffer[HandleIndex],\r
1159 ProtocolGuidArray[ProtocolIndex],\r
1160 &OpenInfo,\r
1161 &OpenInfoCount\r
1162 );\r
1163 if (!EFI_ERROR (Status)) {\r
1164 for (OpenInfoIndex = 0; OpenInfoIndex < OpenInfoCount; OpenInfoIndex++) {\r
1165 if (OpenInfo[OpenInfoIndex].AgentHandle == Image->Handle) {\r
1166 Status = CoreCloseProtocol (\r
1167 HandleBuffer[HandleIndex],\r
1168 ProtocolGuidArray[ProtocolIndex],\r
1169 Image->Handle,\r
1170 OpenInfo[OpenInfoIndex].ControllerHandle\r
1171 );\r
1172 }\r
1173 }\r
1174 if (OpenInfo != NULL) {\r
1175 CoreFreePool(OpenInfo);\r
1176 }\r
1177 }\r
1178 }\r
1179 if (ProtocolGuidArray != NULL) {\r
1180 CoreFreePool(ProtocolGuidArray);\r
1181 }\r
1182 }\r
1183 }\r
1184 if (HandleBuffer != NULL) {\r
1185 CoreFreePool (HandleBuffer);\r
1186 }\r
1187 }\r
1188\r
1189 CoreRemoveDebugImageInfoEntry (Image->Handle);\r
1190\r
ba39e316 1191 Status = CoreUninstallProtocolInterface (\r
1192 Image->Handle,\r
1193 &gEfiLoadedImageDevicePathProtocolGuid,\r
1194 Image->LoadedImageDevicePath\r
1195 );\r
1196\r
28a00297 1197 Status = CoreUninstallProtocolInterface (\r
1198 Image->Handle,\r
1199 &gEfiLoadedImageProtocolGuid,\r
1200 &Image->Info\r
1201 );\r
ba39e316 1202\r
28a00297 1203 }\r
1204\r
1205 if (Image->RuntimeData != NULL) {\r
1206 if (Image->RuntimeData->Link.ForwardLink != NULL) {\r
1207 //\r
1208 // Remove the Image from the Runtime Image list as we are about to Free it!\r
1209 //\r
1210 RemoveEntryList (&Image->RuntimeData->Link);\r
1211 }\r
1212 CoreFreePool (Image->RuntimeData);\r
1213 }\r
1214\r
1215 //\r
1216 // Free the Image from memory\r
1217 //\r
1218 if ((Image->ImageBasePage != 0) && FreePage) {\r
1219 CoreFreePages (Image->ImageBasePage, Image->NumberOfPages);\r
1220 }\r
1221\r
1222 //\r
1223 // Done with the Image structure\r
1224 //\r
1225 if (Image->Info.FilePath != NULL) {\r
1226 CoreFreePool (Image->Info.FilePath);\r
1227 }\r
1228\r
ba39e316 1229 if (Image->LoadedImageDevicePath != NULL) {\r
1230 CoreFreePool (Image->LoadedImageDevicePath);\r
85658066 1231 }\r
1232\r
28a00297 1233 if (Image->FixupData != NULL) {\r
1234 CoreFreePool (Image->FixupData);\r
1235 }\r
1236\r
1237 CoreFreePool (Image);\r
1238}\r
1239\r
1240\r
1241\r
162ed594 1242\r
1243/**\r
1244 Terminates the currently loaded EFI image and returns control to boot services.\r
1245\r
57d6f36d 1246 @param ImageHandle Handle that identifies the image. This\r
1247 parameter is passed to the image on entry.\r
1248 @param Status The image's exit code.\r
1249 @param ExitDataSize The size, in bytes, of ExitData. Ignored if\r
1250 ExitStatus is EFI_SUCCESS.\r
1251 @param ExitData Pointer to a data buffer that includes a\r
1252 Null-terminated Unicode string, optionally\r
1253 followed by additional binary data. The string\r
1254 is a description that the caller may use to\r
1255 further indicate the reason for the image's\r
1256 exit.\r
1257\r
1258 @retval EFI_INVALID_PARAMETER Image handle is NULL or it is not current\r
1259 image.\r
1260 @retval EFI_SUCCESS Successfully terminates the currently loaded\r
1261 EFI image.\r
1262 @retval EFI_ACCESS_DENIED Should never reach there.\r
162ed594 1263 @retval EFI_OUT_OF_RESOURCES Could not allocate pool\r
1264\r
1265**/\r
28a00297 1266EFI_STATUS\r
1267EFIAPI\r
1268CoreExit (\r
1269 IN EFI_HANDLE ImageHandle,\r
1270 IN EFI_STATUS Status,\r
1271 IN UINTN ExitDataSize,\r
1272 IN CHAR16 *ExitData OPTIONAL\r
1273 )\r
28a00297 1274{\r
1275 LOADED_IMAGE_PRIVATE_DATA *Image;\r
1276 EFI_TPL OldTpl;\r
1277\r
1278 //\r
1279 // Prevent possible reentrance to this function\r
1280 // for the same ImageHandle\r
57d6f36d 1281 //\r
1282 OldTpl = CoreRaiseTpl (TPL_NOTIFY);\r
1283\r
28a00297 1284 Image = CoreLoadedImageInfo (ImageHandle);\r
1285 if (Image == NULL_HANDLE) {\r
1286 Status = EFI_INVALID_PARAMETER;\r
1287 goto Done;\r
1288 }\r
1289\r
1290 if (!Image->Started) {\r
1291 //\r
1292 // The image has not been started so just free its resources\r
1293 //\r
1294 CoreUnloadAndCloseImage (Image, TRUE);\r
1295 Status = EFI_SUCCESS;\r
1296 goto Done;\r
1297 }\r
1298\r
1299 //\r
1300 // Image has been started, verify this image can exit\r
1301 //\r
1302 if (Image != mCurrentImage) {\r
162ed594 1303 DEBUG ((DEBUG_LOAD|DEBUG_ERROR, "Exit: Image is not exitable image\n"));\r
28a00297 1304 Status = EFI_INVALID_PARAMETER;\r
1305 goto Done;\r
1306 }\r
1307\r
1308 //\r
1309 // Set status\r
1310 //\r
1311 Image->Status = Status;\r
1312\r
1313 //\r
1314 // If there's ExitData info, move it\r
1315 //\r
1316 if (ExitData != NULL) {\r
1317 Image->ExitDataSize = ExitDataSize;\r
1318 Image->ExitData = CoreAllocateBootServicesPool (Image->ExitDataSize);\r
1319 if (Image->ExitData == NULL) {\r
1320 Status = EFI_OUT_OF_RESOURCES;\r
1321 goto Done;\r
1322 }\r
1323 CopyMem (Image->ExitData, ExitData, Image->ExitDataSize);\r
1324 }\r
1325\r
1326 CoreRestoreTpl (OldTpl);\r
1327 //\r
1328 // return to StartImage\r
1329 //\r
1330 LongJump (Image->JumpContext, (UINTN)-1);\r
1331\r
1332 //\r
1333 // If we return from LongJump, then it is an error\r
1334 //\r
1335 ASSERT (FALSE);\r
1336 Status = EFI_ACCESS_DENIED;\r
1337Done:\r
1338 CoreRestoreTpl (OldTpl);\r
1339 return Status;\r
1340}\r
1341\r
1342\r
1343\r
28a00297 1344\r
162ed594 1345/**\r
28a00297 1346 Unloads an image.\r
1347\r
57d6f36d 1348 @param ImageHandle Handle that identifies the image to be\r
1349 unloaded.\r
28a00297 1350\r
57d6f36d 1351 @retval EFI_SUCCESS The image has been unloaded.\r
1352 @retval EFI_UNSUPPORTED The image has been sarted, and does not support\r
1353 unload.\r
162ed594 1354 @retval EFI_INVALID_PARAMPETER ImageHandle is not a valid image handle.\r
28a00297 1355\r
162ed594 1356**/\r
1357EFI_STATUS\r
1358EFIAPI\r
1359CoreUnloadImage (\r
1360 IN EFI_HANDLE ImageHandle\r
1361 )\r
28a00297 1362{\r
1363 EFI_STATUS Status;\r
1364 LOADED_IMAGE_PRIVATE_DATA *Image;\r
1365 EFI_TPL OldTpl;\r
1366\r
1367 //\r
1368 // Prevent possible reentrance to this function\r
1369 // for the same ImageHandle\r
57d6f36d 1370 //\r
28a00297 1371 OldTpl = CoreRaiseTpl (TPL_NOTIFY);\r
57d6f36d 1372\r
28a00297 1373 Image = CoreLoadedImageInfo (ImageHandle);\r
1374 if (Image == NULL ) {\r
1375 //\r
1376 // The image handle is not valid\r
1377 //\r
1378 Status = EFI_INVALID_PARAMETER;\r
1379 goto Done;\r
1380 }\r
1381\r
1382 if (Image->Started) {\r
1383 //\r
1384 // The image has been started, request it to unload.\r
1385 //\r
1386 Status = EFI_UNSUPPORTED;\r
1387 if (Image->Info.Unload != NULL) {\r
1388 Status = Image->Info.Unload (ImageHandle);\r
1389 }\r
1390\r
1391 } else {\r
1392 //\r
1393 // This Image hasn't been started, thus it can be unloaded\r
1394 //\r
1395 Status = EFI_SUCCESS;\r
1396 }\r
1397\r
1398\r
1399 if (!EFI_ERROR (Status)) {\r
1400 //\r
1401 // if the Image was not started or Unloaded O.K. then clean up\r
1402 //\r
1403 CoreUnloadAndCloseImage (Image, TRUE);\r
1404 }\r
1405\r
1406Done:\r
1407 CoreRestoreTpl (OldTpl);\r
1408 return Status;\r
1409}\r
1410\r
1411\r
162ed594 1412\r
1413/**\r
1414 Unload the specified image.\r
1415\r
57d6f36d 1416 @param This Indicates the calling context.\r
1417 @param ImageHandle The specified image handle.\r
162ed594 1418\r
57d6f36d 1419 @retval EFI_INVALID_PARAMETER Image handle is NULL.\r
1420 @retval EFI_UNSUPPORTED Attempt to unload an unsupported image.\r
162ed594 1421 @retval EFI_SUCCESS Image successfully unloaded.\r
1422\r
1423**/\r
28a00297 1424EFI_STATUS\r
1425EFIAPI\r
1426CoreUnloadImageEx (\r
1427 IN EFI_PE32_IMAGE_PROTOCOL *This,\r
1428 IN EFI_HANDLE ImageHandle\r
1429 )\r
28a00297 1430{\r
1431 return CoreUnloadImage (ImageHandle);\r
1432}\r