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