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