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