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