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