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