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