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