]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - MdeModulePkg/Core/Dxe/Image/Image.c
MdeModulePkg/DxeCore: invoke the emulator protocol for foreign images
[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 - 2018, Intel Corporation. All rights reserved.<BR>\r
5SPDX-License-Identifier: BSD-2-Clause-Patent\r
6\r
7**/\r
8\r
9#include "DxeMain.h"\r
10#include "Image.h"\r
11\r
12//\r
13// Module Globals\r
14//\r
15LOADED_IMAGE_PRIVATE_DATA *mCurrentImage = NULL;\r
16\r
17LOAD_PE32_IMAGE_PRIVATE_DATA mLoadPe32PrivateData = {\r
18 LOAD_PE32_IMAGE_PRIVATE_DATA_SIGNATURE,\r
19 NULL,\r
20 {\r
21 CoreLoadImageEx,\r
22 CoreUnloadImageEx\r
23 }\r
24};\r
25\r
26typedef struct {\r
27 LIST_ENTRY Link;\r
28 EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL *Emulator;\r
29 UINT16 MachineType;\r
30} EMULATOR_ENTRY;\r
31\r
32STATIC LIST_ENTRY mAvailableEmulators;\r
33STATIC EFI_EVENT mPeCoffEmuProtocolRegistrationEvent;\r
34STATIC VOID *mPeCoffEmuProtocolNotifyRegistration;\r
35\r
36//\r
37// This code is needed to build the Image handle for the DXE Core\r
38//\r
39LOADED_IMAGE_PRIVATE_DATA mCorePrivateImage = {\r
40 LOADED_IMAGE_PRIVATE_DATA_SIGNATURE, // Signature\r
41 NULL, // Image handle\r
42 EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER, // Image type\r
43 TRUE, // If entrypoint has been called\r
44 NULL, // EntryPoint\r
45 {\r
46 EFI_LOADED_IMAGE_INFORMATION_REVISION, // Revision\r
47 NULL, // Parent handle\r
48 NULL, // System handle\r
49\r
50 NULL, // Device handle\r
51 NULL, // File path\r
52 NULL, // Reserved\r
53\r
54 0, // LoadOptionsSize\r
55 NULL, // LoadOptions\r
56\r
57 NULL, // ImageBase\r
58 0, // ImageSize\r
59 EfiBootServicesCode, // ImageCodeType\r
60 EfiBootServicesData // ImageDataType\r
61 },\r
62 (EFI_PHYSICAL_ADDRESS)0, // ImageBasePage\r
63 0, // NumberOfPages\r
64 NULL, // FixupData\r
65 0, // Tpl\r
66 EFI_SUCCESS, // Status\r
67 0, // ExitDataSize\r
68 NULL, // ExitData\r
69 NULL, // JumpBuffer\r
70 NULL, // JumpContext\r
71 0, // Machine\r
72 NULL, // Ebc\r
73 NULL, // PeCoffEmu\r
74 NULL, // RuntimeData\r
75 NULL // LoadedImageDevicePath\r
76};\r
77//\r
78// The field is define for Loading modules at fixed address feature to tracker the PEI code\r
79// memory range usage. It is a bit mapped array in which every bit indicates the correspoding memory page\r
80// available or not.\r
81//\r
82GLOBAL_REMOVE_IF_UNREFERENCED UINT64 *mDxeCodeMemoryRangeUsageBitMap=NULL;\r
83\r
84typedef struct {\r
85 UINT16 MachineType;\r
86 CHAR16 *MachineTypeName;\r
87} MACHINE_TYPE_INFO;\r
88\r
89//\r
90// EBC machine is not listed in this table, because EBC is in the default supported scopes of other machine type.\r
91//\r
92GLOBAL_REMOVE_IF_UNREFERENCED MACHINE_TYPE_INFO mMachineTypeInfo[] = {\r
93 {EFI_IMAGE_MACHINE_IA32, L"IA32"},\r
94 {EFI_IMAGE_MACHINE_IA64, L"IA64"},\r
95 {EFI_IMAGE_MACHINE_X64, L"X64"},\r
96 {EFI_IMAGE_MACHINE_ARMTHUMB_MIXED, L"ARM"},\r
97 {EFI_IMAGE_MACHINE_AARCH64, L"AARCH64"}\r
98};\r
99\r
100UINT16 mDxeCoreImageMachineType = 0;\r
101\r
102/**\r
103 Return machine type name.\r
104\r
105 @param MachineType The machine type\r
106\r
107 @return machine type name\r
108**/\r
109CHAR16 *\r
110GetMachineTypeName (\r
111 UINT16 MachineType\r
112 )\r
113{\r
114 UINTN Index;\r
115\r
116 for (Index = 0; Index < sizeof(mMachineTypeInfo)/sizeof(mMachineTypeInfo[0]); Index++) {\r
117 if (mMachineTypeInfo[Index].MachineType == MachineType) {\r
118 return mMachineTypeInfo[Index].MachineTypeName;\r
119 }\r
120 }\r
121\r
122 return L"<Unknown>";\r
123}\r
124\r
125/**\r
126 Notification event handler registered by CoreInitializeImageServices () to\r
127 keep track of which PE/COFF image emulators are available.\r
128\r
129 @param Event The Event that is being processed, not used.\r
130 @param Context Event Context, not used.\r
131\r
132**/\r
133STATIC\r
134VOID\r
135EFIAPI\r
136PeCoffEmuProtocolNotify (\r
137 IN EFI_EVENT Event,\r
138 IN VOID *Context\r
139 )\r
140{\r
141 EFI_STATUS Status;\r
142 UINTN BufferSize;\r
143 EFI_HANDLE EmuHandle;\r
144 EMULATOR_ENTRY *Entry;\r
145\r
146 EmuHandle = NULL;\r
147\r
148 while (TRUE) {\r
149 BufferSize = sizeof (EmuHandle);\r
150 Status = CoreLocateHandle (\r
151 ByRegisterNotify,\r
152 NULL,\r
153 mPeCoffEmuProtocolNotifyRegistration,\r
154 &BufferSize,\r
155 &EmuHandle\r
156 );\r
157 if (EFI_ERROR (Status)) {\r
158 //\r
159 // If no more notification events exit\r
160 //\r
161 return;\r
162 }\r
163\r
164 Entry = AllocateZeroPool (sizeof (*Entry));\r
165 ASSERT (Entry != NULL);\r
166\r
167 Status = CoreHandleProtocol (\r
168 EmuHandle,\r
169 &gEdkiiPeCoffImageEmulatorProtocolGuid,\r
170 (VOID **)&Entry->Emulator\r
171 );\r
172 ASSERT_EFI_ERROR (Status);\r
173\r
174 Entry->MachineType = Entry->Emulator->MachineType;\r
175\r
176 InsertTailList (&mAvailableEmulators, &Entry->Link);\r
177 }\r
178}\r
179\r
180/**\r
181 Add the Image Services to EFI Boot Services Table and install the protocol\r
182 interfaces for this image.\r
183\r
184 @param HobStart The HOB to initialize\r
185\r
186 @return Status code.\r
187\r
188**/\r
189EFI_STATUS\r
190CoreInitializeImageServices (\r
191 IN VOID *HobStart\r
192 )\r
193{\r
194 EFI_STATUS Status;\r
195 LOADED_IMAGE_PRIVATE_DATA *Image;\r
196 EFI_PHYSICAL_ADDRESS DxeCoreImageBaseAddress;\r
197 UINT64 DxeCoreImageLength;\r
198 VOID *DxeCoreEntryPoint;\r
199 EFI_PEI_HOB_POINTERS DxeCoreHob;\r
200\r
201 //\r
202 // Searching for image hob\r
203 //\r
204 DxeCoreHob.Raw = HobStart;\r
205 while ((DxeCoreHob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, DxeCoreHob.Raw)) != NULL) {\r
206 if (CompareGuid (&DxeCoreHob.MemoryAllocationModule->MemoryAllocationHeader.Name, &gEfiHobMemoryAllocModuleGuid)) {\r
207 //\r
208 // Find Dxe Core HOB\r
209 //\r
210 break;\r
211 }\r
212 DxeCoreHob.Raw = GET_NEXT_HOB (DxeCoreHob);\r
213 }\r
214 ASSERT (DxeCoreHob.Raw != NULL);\r
215\r
216 DxeCoreImageBaseAddress = DxeCoreHob.MemoryAllocationModule->MemoryAllocationHeader.MemoryBaseAddress;\r
217 DxeCoreImageLength = DxeCoreHob.MemoryAllocationModule->MemoryAllocationHeader.MemoryLength;\r
218 DxeCoreEntryPoint = (VOID *) (UINTN) DxeCoreHob.MemoryAllocationModule->EntryPoint;\r
219 gDxeCoreFileName = &DxeCoreHob.MemoryAllocationModule->ModuleName;\r
220\r
221 //\r
222 // Initialize the fields for an internal driver\r
223 //\r
224 Image = &mCorePrivateImage;\r
225\r
226 Image->EntryPoint = (EFI_IMAGE_ENTRY_POINT)(UINTN)DxeCoreEntryPoint;\r
227 Image->ImageBasePage = DxeCoreImageBaseAddress;\r
228 Image->NumberOfPages = (UINTN)(EFI_SIZE_TO_PAGES((UINTN)(DxeCoreImageLength)));\r
229 Image->Tpl = gEfiCurrentTpl;\r
230 Image->Info.SystemTable = gDxeCoreST;\r
231 Image->Info.ImageBase = (VOID *)(UINTN)DxeCoreImageBaseAddress;\r
232 Image->Info.ImageSize = DxeCoreImageLength;\r
233\r
234 //\r
235 // Install the protocol interfaces for this image\r
236 //\r
237 Status = CoreInstallProtocolInterface (\r
238 &Image->Handle,\r
239 &gEfiLoadedImageProtocolGuid,\r
240 EFI_NATIVE_INTERFACE,\r
241 &Image->Info\r
242 );\r
243 ASSERT_EFI_ERROR (Status);\r
244\r
245 mCurrentImage = Image;\r
246\r
247 //\r
248 // Fill in DXE globals\r
249 //\r
250 mDxeCoreImageMachineType = PeCoffLoaderGetMachineType (Image->Info.ImageBase);\r
251 gDxeCoreImageHandle = Image->Handle;\r
252 gDxeCoreLoadedImage = &Image->Info;\r
253\r
254 //\r
255 // Create the PE/COFF emulator protocol registration event\r
256 //\r
257 Status = CoreCreateEvent (\r
258 EVT_NOTIFY_SIGNAL,\r
259 TPL_CALLBACK,\r
260 PeCoffEmuProtocolNotify,\r
261 NULL,\r
262 &mPeCoffEmuProtocolRegistrationEvent\r
263 );\r
264 ASSERT_EFI_ERROR(Status);\r
265\r
266 //\r
267 // Register for protocol notifications on this event\r
268 //\r
269 Status = CoreRegisterProtocolNotify (\r
270 &gEdkiiPeCoffImageEmulatorProtocolGuid,\r
271 mPeCoffEmuProtocolRegistrationEvent,\r
272 &mPeCoffEmuProtocolNotifyRegistration\r
273 );\r
274 ASSERT_EFI_ERROR(Status);\r
275\r
276 InitializeListHead (&mAvailableEmulators);\r
277\r
278 if (FeaturePcdGet (PcdFrameworkCompatibilitySupport)) {\r
279 //\r
280 // Export DXE Core PE Loader functionality for backward compatibility.\r
281 //\r
282 Status = CoreInstallProtocolInterface (\r
283 &mLoadPe32PrivateData.Handle,\r
284 &gEfiLoadPeImageProtocolGuid,\r
285 EFI_NATIVE_INTERFACE,\r
286 &mLoadPe32PrivateData.Pe32Image\r
287 );\r
288 }\r
289\r
290 ProtectUefiImage (&Image->Info, Image->LoadedImageDevicePath);\r
291\r
292 return Status;\r
293}\r
294\r
295/**\r
296 Read image file (specified by UserHandle) into user specified buffer with specified offset\r
297 and length.\r
298\r
299 @param UserHandle Image file handle\r
300 @param Offset Offset to the source file\r
301 @param ReadSize For input, pointer of size to read; For output,\r
302 pointer of size actually read.\r
303 @param Buffer Buffer to write into\r
304\r
305 @retval EFI_SUCCESS Successfully read the specified part of file\r
306 into buffer.\r
307\r
308**/\r
309EFI_STATUS\r
310EFIAPI\r
311CoreReadImageFile (\r
312 IN VOID *UserHandle,\r
313 IN UINTN Offset,\r
314 IN OUT UINTN *ReadSize,\r
315 OUT VOID *Buffer\r
316 )\r
317{\r
318 UINTN EndPosition;\r
319 IMAGE_FILE_HANDLE *FHand;\r
320\r
321 if (UserHandle == NULL || ReadSize == NULL || Buffer == NULL) {\r
322 return EFI_INVALID_PARAMETER;\r
323 }\r
324\r
325 if (MAX_ADDRESS - Offset < *ReadSize) {\r
326 return EFI_INVALID_PARAMETER;\r
327 }\r
328\r
329 FHand = (IMAGE_FILE_HANDLE *)UserHandle;\r
330 ASSERT (FHand->Signature == IMAGE_FILE_HANDLE_SIGNATURE);\r
331\r
332 //\r
333 // Move data from our local copy of the file\r
334 //\r
335 EndPosition = Offset + *ReadSize;\r
336 if (EndPosition > FHand->SourceSize) {\r
337 *ReadSize = (UINT32)(FHand->SourceSize - Offset);\r
338 }\r
339 if (Offset >= FHand->SourceSize) {\r
340 *ReadSize = 0;\r
341 }\r
342\r
343 CopyMem (Buffer, (CHAR8 *)FHand->Source + Offset, *ReadSize);\r
344 return EFI_SUCCESS;\r
345}\r
346/**\r
347 To check memory usage bit map array to figure out if the memory range the image will be loaded in is available or not. If\r
348 memory range is available, the function will mark the corresponding bits to 1 which indicates the memory range is used.\r
349 The function is only invoked when load modules at fixed address feature is enabled.\r
350\r
351 @param ImageBase The base address the image will be loaded at.\r
352 @param ImageSize The size of the image\r
353\r
354 @retval EFI_SUCCESS The memory range the image will be loaded in is available\r
355 @retval EFI_NOT_FOUND The memory range the image will be loaded in is not available\r
356**/\r
357EFI_STATUS\r
358CheckAndMarkFixLoadingMemoryUsageBitMap (\r
359 IN EFI_PHYSICAL_ADDRESS ImageBase,\r
360 IN UINTN ImageSize\r
361 )\r
362{\r
363 UINT32 DxeCodePageNumber;\r
364 UINT64 DxeCodeSize;\r
365 EFI_PHYSICAL_ADDRESS DxeCodeBase;\r
366 UINTN BaseOffsetPageNumber;\r
367 UINTN TopOffsetPageNumber;\r
368 UINTN Index;\r
369 //\r
370 // The DXE code range includes RuntimeCodePage range and Boot time code range.\r
371 //\r
372 DxeCodePageNumber = PcdGet32(PcdLoadFixAddressRuntimeCodePageNumber);\r
373 DxeCodePageNumber += PcdGet32(PcdLoadFixAddressBootTimeCodePageNumber);\r
374 DxeCodeSize = EFI_PAGES_TO_SIZE(DxeCodePageNumber);\r
375 DxeCodeBase = gLoadModuleAtFixAddressConfigurationTable.DxeCodeTopAddress - DxeCodeSize;\r
376\r
377 //\r
378 // If the memory usage bit map is not initialized, do it. Every bit in the array\r
379 // indicate the status of the corresponding memory page, available or not\r
380 //\r
381 if (mDxeCodeMemoryRangeUsageBitMap == NULL) {\r
382 mDxeCodeMemoryRangeUsageBitMap = AllocateZeroPool(((DxeCodePageNumber/64) + 1)*sizeof(UINT64));\r
383 }\r
384 //\r
385 // If the Dxe code memory range is not allocated or the bit map array allocation failed, return EFI_NOT_FOUND\r
386 //\r
387 if (!gLoadFixedAddressCodeMemoryReady || mDxeCodeMemoryRangeUsageBitMap == NULL) {\r
388 return EFI_NOT_FOUND;\r
389 }\r
390 //\r
391 // Test the memory range for loading the image in the DXE code range.\r
392 //\r
393 if (gLoadModuleAtFixAddressConfigurationTable.DxeCodeTopAddress < ImageBase + ImageSize ||\r
394 DxeCodeBase > ImageBase) {\r
395 return EFI_NOT_FOUND;\r
396 }\r
397 //\r
398 // Test if the memory is avalaible or not.\r
399 //\r
400 BaseOffsetPageNumber = EFI_SIZE_TO_PAGES((UINT32)(ImageBase - DxeCodeBase));\r
401 TopOffsetPageNumber = EFI_SIZE_TO_PAGES((UINT32)(ImageBase + ImageSize - DxeCodeBase));\r
402 for (Index = BaseOffsetPageNumber; Index < TopOffsetPageNumber; Index ++) {\r
403 if ((mDxeCodeMemoryRangeUsageBitMap[Index / 64] & LShiftU64(1, (Index % 64))) != 0) {\r
404 //\r
405 // This page is already used.\r
406 //\r
407 return EFI_NOT_FOUND;\r
408 }\r
409 }\r
410\r
411 //\r
412 // Being here means the memory range is available. So mark the bits for the memory range\r
413 //\r
414 for (Index = BaseOffsetPageNumber; Index < TopOffsetPageNumber; Index ++) {\r
415 mDxeCodeMemoryRangeUsageBitMap[Index / 64] |= LShiftU64(1, (Index % 64));\r
416 }\r
417 return EFI_SUCCESS;\r
418}\r
419/**\r
420\r
421 Get the fixed loading address from image header assigned by build tool. This function only be called\r
422 when Loading module at Fixed address feature enabled.\r
423\r
424 @param ImageContext Pointer to the image context structure that describes the PE/COFF\r
425 image that needs to be examined by this function.\r
426 @retval EFI_SUCCESS An fixed loading address is assigned to this image by build tools .\r
427 @retval EFI_NOT_FOUND The image has no assigned fixed loading address.\r
428\r
429**/\r
430EFI_STATUS\r
431GetPeCoffImageFixLoadingAssignedAddress(\r
432 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext\r
433 )\r
434{\r
435 UINTN SectionHeaderOffset;\r
436 EFI_STATUS Status;\r
437 EFI_IMAGE_SECTION_HEADER SectionHeader;\r
438 EFI_IMAGE_OPTIONAL_HEADER_UNION *ImgHdr;\r
439 UINT16 Index;\r
440 UINTN Size;\r
441 UINT16 NumberOfSections;\r
442 IMAGE_FILE_HANDLE *Handle;\r
443 UINT64 ValueInSectionHeader;\r
444\r
445\r
446 Status = EFI_NOT_FOUND;\r
447\r
448 //\r
449 // Get PeHeader pointer\r
450 //\r
451 Handle = (IMAGE_FILE_HANDLE*)ImageContext->Handle;\r
452 ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((CHAR8* )Handle->Source + ImageContext->PeCoffHeaderOffset);\r
453 SectionHeaderOffset = ImageContext->PeCoffHeaderOffset +\r
454 sizeof (UINT32) +\r
455 sizeof (EFI_IMAGE_FILE_HEADER) +\r
456 ImgHdr->Pe32.FileHeader.SizeOfOptionalHeader;\r
457 NumberOfSections = ImgHdr->Pe32.FileHeader.NumberOfSections;\r
458\r
459 //\r
460 // Get base address from the first section header that doesn't point to code section.\r
461 //\r
462 for (Index = 0; Index < NumberOfSections; Index++) {\r
463 //\r
464 // Read section header from file\r
465 //\r
466 Size = sizeof (EFI_IMAGE_SECTION_HEADER);\r
467 Status = ImageContext->ImageRead (\r
468 ImageContext->Handle,\r
469 SectionHeaderOffset,\r
470 &Size,\r
471 &SectionHeader\r
472 );\r
473 if (EFI_ERROR (Status)) {\r
474 return Status;\r
475 }\r
476 if (Size != sizeof (EFI_IMAGE_SECTION_HEADER)) {\r
477 return EFI_NOT_FOUND;\r
478 }\r
479\r
480 Status = EFI_NOT_FOUND;\r
481\r
482 if ((SectionHeader.Characteristics & EFI_IMAGE_SCN_CNT_CODE) == 0) {\r
483 //\r
484 // Build tool will save the address in PointerToRelocations & PointerToLineNumbers fields in the first section header\r
485 // that doesn't point to code section in image header, as well as ImageBase field of image header. And there is an\r
486 // assumption that when the feature is enabled, if a module is assigned a loading address by tools, PointerToRelocations\r
487 // & PointerToLineNumbers fields should NOT be Zero, or else, these 2 fields should be set to Zero\r
488 //\r
489 ValueInSectionHeader = ReadUnaligned64((UINT64*)&SectionHeader.PointerToRelocations);\r
490 if (ValueInSectionHeader != 0) {\r
491 //\r
492 // When the feature is configured as load module at fixed absolute address, the ImageAddress field of ImageContext\r
493 // hold the spcified address. If the feature is configured as load module at fixed offset, ImageAddress hold an offset\r
494 // relative to top address\r
495 //\r
496 if ((INT64)PcdGet64(PcdLoadModuleAtFixAddressEnable) < 0) {\r
497 ImageContext->ImageAddress = gLoadModuleAtFixAddressConfigurationTable.DxeCodeTopAddress + (INT64)(INTN)ImageContext->ImageAddress;\r
498 }\r
499 //\r
500 // Check if the memory range is available.\r
501 //\r
502 Status = CheckAndMarkFixLoadingMemoryUsageBitMap (ImageContext->ImageAddress, (UINTN)(ImageContext->ImageSize + ImageContext->SectionAlignment));\r
503 }\r
504 break;\r
505 }\r
506 SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);\r
507 }\r
508 DEBUG ((EFI_D_INFO|EFI_D_LOAD, "LOADING MODULE FIXED INFO: Loading module at fixed address 0x%11p. Status = %r \n", (VOID *)(UINTN)(ImageContext->ImageAddress), Status));\r
509 return Status;\r
510}\r
511\r
512/**\r
513 Decides whether a PE/COFF image can execute on this system, either natively\r
514 or via emulation/interpretation. In the latter case, the PeCoffEmu member\r
515 of the LOADED_IMAGE_PRIVATE_DATA struct pointer is populated with a pointer\r
516 to the emulator protocol that supports this image.\r
517\r
518 @param[in, out] Image LOADED_IMAGE_PRIVATE_DATA struct pointer\r
519\r
520 @retval TRUE The image is supported\r
521 @retval FALSE The image is not supported\r
522\r
523**/\r
524STATIC\r
525BOOLEAN\r
526CoreIsImageTypeSupported (\r
527 IN OUT LOADED_IMAGE_PRIVATE_DATA *Image\r
528 )\r
529{\r
530 LIST_ENTRY *Link;\r
531 EMULATOR_ENTRY *Entry;\r
532\r
533 for (Link = GetFirstNode (&mAvailableEmulators);\r
534 !IsNull (&mAvailableEmulators, Link);\r
535 Link = GetNextNode (&mAvailableEmulators, Link)) {\r
536\r
537 Entry = BASE_CR (Link, EMULATOR_ENTRY, Link);\r
538 if (Entry->MachineType != Image->ImageContext.Machine) {\r
539 continue;\r
540 }\r
541\r
542 if (Entry->Emulator->IsImageSupported (Entry->Emulator,\r
543 Image->ImageContext.ImageType,\r
544 Image->Info.FilePath)) {\r
545 Image->PeCoffEmu = Entry->Emulator;\r
546 return TRUE;\r
547 }\r
548 }\r
549\r
550 return EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Image->ImageContext.Machine) ||\r
551 EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED (Image->ImageContext.Machine);\r
552}\r
553\r
554/**\r
555 Loads, relocates, and invokes a PE/COFF image\r
556\r
557 @param BootPolicy If TRUE, indicates that the request originates\r
558 from the boot manager, and that the boot\r
559 manager is attempting to load FilePath as a\r
560 boot selection.\r
561 @param Pe32Handle The handle of PE32 image\r
562 @param Image PE image to be loaded\r
563 @param DstBuffer The buffer to store the image\r
564 @param EntryPoint A pointer to the entry point\r
565 @param Attribute The bit mask of attributes to set for the load\r
566 PE image\r
567\r
568 @retval EFI_SUCCESS The file was loaded, relocated, and invoked\r
569 @retval EFI_OUT_OF_RESOURCES There was not enough memory to load and\r
570 relocate the PE/COFF file\r
571 @retval EFI_INVALID_PARAMETER Invalid parameter\r
572 @retval EFI_BUFFER_TOO_SMALL Buffer for image is too small\r
573\r
574**/\r
575EFI_STATUS\r
576CoreLoadPeImage (\r
577 IN BOOLEAN BootPolicy,\r
578 IN VOID *Pe32Handle,\r
579 IN LOADED_IMAGE_PRIVATE_DATA *Image,\r
580 IN EFI_PHYSICAL_ADDRESS DstBuffer OPTIONAL,\r
581 OUT EFI_PHYSICAL_ADDRESS *EntryPoint OPTIONAL,\r
582 IN UINT32 Attribute\r
583 )\r
584{\r
585 EFI_STATUS Status;\r
586 BOOLEAN DstBufAlocated;\r
587 UINTN Size;\r
588\r
589 ZeroMem (&Image->ImageContext, sizeof (Image->ImageContext));\r
590\r
591 Image->ImageContext.Handle = Pe32Handle;\r
592 Image->ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE)CoreReadImageFile;\r
593\r
594 //\r
595 // Get information about the image being loaded\r
596 //\r
597 Status = PeCoffLoaderGetImageInfo (&Image->ImageContext);\r
598 if (EFI_ERROR (Status)) {\r
599 return Status;\r
600 }\r
601\r
602 if (!CoreIsImageTypeSupported (Image)) {\r
603 //\r
604 // The PE/COFF loader can support loading image types that can be executed.\r
605 // If we loaded an image type that we can not execute return EFI_UNSUPPORTED.\r
606 //\r
607 DEBUG ((DEBUG_ERROR, "Image type %s can't be loaded on %s UEFI system.\n",\r
608 GetMachineTypeName (Image->ImageContext.Machine),\r
609 GetMachineTypeName (mDxeCoreImageMachineType)));\r
610 return EFI_UNSUPPORTED;\r
611 }\r
612\r
613 //\r
614 // Set EFI memory type based on ImageType\r
615 //\r
616 switch (Image->ImageContext.ImageType) {\r
617 case EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION:\r
618 Image->ImageContext.ImageCodeMemoryType = EfiLoaderCode;\r
619 Image->ImageContext.ImageDataMemoryType = EfiLoaderData;\r
620 break;\r
621 case EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER:\r
622 Image->ImageContext.ImageCodeMemoryType = EfiBootServicesCode;\r
623 Image->ImageContext.ImageDataMemoryType = EfiBootServicesData;\r
624 break;\r
625 case EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER:\r
626 case EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER:\r
627 Image->ImageContext.ImageCodeMemoryType = EfiRuntimeServicesCode;\r
628 Image->ImageContext.ImageDataMemoryType = EfiRuntimeServicesData;\r
629 break;\r
630 default:\r
631 Image->ImageContext.ImageError = IMAGE_ERROR_INVALID_SUBSYSTEM;\r
632 return EFI_UNSUPPORTED;\r
633 }\r
634\r
635 //\r
636 // Allocate memory of the correct memory type aligned on the required image boundary\r
637 //\r
638 DstBufAlocated = FALSE;\r
639 if (DstBuffer == 0) {\r
640 //\r
641 // Allocate Destination Buffer as caller did not pass it in\r
642 //\r
643\r
644 if (Image->ImageContext.SectionAlignment > EFI_PAGE_SIZE) {\r
645 Size = (UINTN)Image->ImageContext.ImageSize + Image->ImageContext.SectionAlignment;\r
646 } else {\r
647 Size = (UINTN)Image->ImageContext.ImageSize;\r
648 }\r
649\r
650 Image->NumberOfPages = EFI_SIZE_TO_PAGES (Size);\r
651\r
652 //\r
653 // If the image relocations have not been stripped, then load at any address.\r
654 // Otherwise load at the address at which it was linked.\r
655 //\r
656 // Memory below 1MB should be treated reserved for CSM and there should be\r
657 // no modules whose preferred load addresses are below 1MB.\r
658 //\r
659 Status = EFI_OUT_OF_RESOURCES;\r
660 //\r
661 // If Loading Module At Fixed Address feature is enabled, the module should be loaded to\r
662 // a specified address.\r
663 //\r
664 if (PcdGet64(PcdLoadModuleAtFixAddressEnable) != 0 ) {\r
665 Status = GetPeCoffImageFixLoadingAssignedAddress (&(Image->ImageContext));\r
666\r
667 if (EFI_ERROR (Status)) {\r
668 //\r
669 // If the code memory is not ready, invoke CoreAllocatePage with AllocateAnyPages to load the driver.\r
670 //\r
671 DEBUG ((EFI_D_INFO|EFI_D_LOAD, "LOADING MODULE FIXED ERROR: Loading module at fixed address failed since specified memory is not available.\n"));\r
672\r
673 Status = CoreAllocatePages (\r
674 AllocateAnyPages,\r
675 (EFI_MEMORY_TYPE) (Image->ImageContext.ImageCodeMemoryType),\r
676 Image->NumberOfPages,\r
677 &Image->ImageContext.ImageAddress\r
678 );\r
679 }\r
680 } else {\r
681 if (Image->ImageContext.ImageAddress >= 0x100000 || Image->ImageContext.RelocationsStripped) {\r
682 Status = CoreAllocatePages (\r
683 AllocateAddress,\r
684 (EFI_MEMORY_TYPE) (Image->ImageContext.ImageCodeMemoryType),\r
685 Image->NumberOfPages,\r
686 &Image->ImageContext.ImageAddress\r
687 );\r
688 }\r
689 if (EFI_ERROR (Status) && !Image->ImageContext.RelocationsStripped) {\r
690 Status = CoreAllocatePages (\r
691 AllocateAnyPages,\r
692 (EFI_MEMORY_TYPE) (Image->ImageContext.ImageCodeMemoryType),\r
693 Image->NumberOfPages,\r
694 &Image->ImageContext.ImageAddress\r
695 );\r
696 }\r
697 }\r
698 if (EFI_ERROR (Status)) {\r
699 return Status;\r
700 }\r
701 DstBufAlocated = TRUE;\r
702 } else {\r
703 //\r
704 // Caller provided the destination buffer\r
705 //\r
706\r
707 if (Image->ImageContext.RelocationsStripped && (Image->ImageContext.ImageAddress != DstBuffer)) {\r
708 //\r
709 // If the image relocations were stripped, and the caller provided a\r
710 // destination buffer address that does not match the address that the\r
711 // image is linked at, then the image cannot be loaded.\r
712 //\r
713 return EFI_INVALID_PARAMETER;\r
714 }\r
715\r
716 if (Image->NumberOfPages != 0 &&\r
717 Image->NumberOfPages <\r
718 (EFI_SIZE_TO_PAGES ((UINTN)Image->ImageContext.ImageSize + Image->ImageContext.SectionAlignment))) {\r
719 Image->NumberOfPages = EFI_SIZE_TO_PAGES ((UINTN)Image->ImageContext.ImageSize + Image->ImageContext.SectionAlignment);\r
720 return EFI_BUFFER_TOO_SMALL;\r
721 }\r
722\r
723 Image->NumberOfPages = EFI_SIZE_TO_PAGES ((UINTN)Image->ImageContext.ImageSize + Image->ImageContext.SectionAlignment);\r
724 Image->ImageContext.ImageAddress = DstBuffer;\r
725 }\r
726\r
727 Image->ImageBasePage = Image->ImageContext.ImageAddress;\r
728 if (!Image->ImageContext.IsTeImage) {\r
729 Image->ImageContext.ImageAddress =\r
730 (Image->ImageContext.ImageAddress + Image->ImageContext.SectionAlignment - 1) &\r
731 ~((UINTN)Image->ImageContext.SectionAlignment - 1);\r
732 }\r
733\r
734 //\r
735 // Load the image from the file into the allocated memory\r
736 //\r
737 Status = PeCoffLoaderLoadImage (&Image->ImageContext);\r
738 if (EFI_ERROR (Status)) {\r
739 goto Done;\r
740 }\r
741\r
742 //\r
743 // If this is a Runtime Driver, then allocate memory for the FixupData that\r
744 // is used to relocate the image when SetVirtualAddressMap() is called. The\r
745 // relocation is done by the Runtime AP.\r
746 //\r
747 if ((Attribute & EFI_LOAD_PE_IMAGE_ATTRIBUTE_RUNTIME_REGISTRATION) != 0) {\r
748 if (Image->ImageContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) {\r
749 Image->ImageContext.FixupData = AllocateRuntimePool ((UINTN)(Image->ImageContext.FixupDataSize));\r
750 if (Image->ImageContext.FixupData == NULL) {\r
751 Status = EFI_OUT_OF_RESOURCES;\r
752 goto Done;\r
753 }\r
754 }\r
755 }\r
756\r
757 //\r
758 // Relocate the image in memory\r
759 //\r
760 Status = PeCoffLoaderRelocateImage (&Image->ImageContext);\r
761 if (EFI_ERROR (Status)) {\r
762 goto Done;\r
763 }\r
764\r
765 //\r
766 // Flush the Instruction Cache\r
767 //\r
768 InvalidateInstructionCacheRange ((VOID *)(UINTN)Image->ImageContext.ImageAddress, (UINTN)Image->ImageContext.ImageSize);\r
769\r
770 //\r
771 // Copy the machine type from the context to the image private data. This\r
772 // is needed during image unload to know if we should call an EBC protocol\r
773 // to unload the image.\r
774 //\r
775 Image->Machine = Image->ImageContext.Machine;\r
776\r
777 //\r
778 // Get the image entry point. If it's an EBC image, then call into the\r
779 // interpreter to create a thunk for the entry point and use the returned\r
780 // value for the entry point.\r
781 //\r
782 Image->EntryPoint = (EFI_IMAGE_ENTRY_POINT)(UINTN)Image->ImageContext.EntryPoint;\r
783 if (Image->ImageContext.Machine == EFI_IMAGE_MACHINE_EBC) {\r
784 //\r
785 // Locate the EBC interpreter protocol\r
786 //\r
787 Status = CoreLocateProtocol (&gEfiEbcProtocolGuid, NULL, (VOID **)&Image->Ebc);\r
788 if (EFI_ERROR(Status) || Image->Ebc == NULL) {\r
789 DEBUG ((DEBUG_LOAD | DEBUG_ERROR, "CoreLoadPeImage: There is no EBC interpreter for an EBC image.\n"));\r
790 goto Done;\r
791 }\r
792\r
793 //\r
794 // Register a callback for flushing the instruction cache so that created\r
795 // thunks can be flushed.\r
796 //\r
797 Status = Image->Ebc->RegisterICacheFlush (Image->Ebc, (EBC_ICACHE_FLUSH)InvalidateInstructionCacheRange);\r
798 if (EFI_ERROR(Status)) {\r
799 goto Done;\r
800 }\r
801\r
802 //\r
803 // Create a thunk for the image's entry point. This will be the new\r
804 // entry point for the image.\r
805 //\r
806 Status = Image->Ebc->CreateThunk (\r
807 Image->Ebc,\r
808 Image->Handle,\r
809 (VOID *)(UINTN) Image->ImageContext.EntryPoint,\r
810 (VOID **) &Image->EntryPoint\r
811 );\r
812 if (EFI_ERROR(Status)) {\r
813 goto Done;\r
814 }\r
815 } else if (Image->PeCoffEmu != NULL) {\r
816 Status = Image->PeCoffEmu->RegisterImage (Image->PeCoffEmu,\r
817 Image->ImageBasePage,\r
818 EFI_PAGES_TO_SIZE (Image->NumberOfPages),\r
819 &Image->EntryPoint);\r
820 if (EFI_ERROR (Status)) {\r
821 DEBUG ((DEBUG_LOAD | DEBUG_ERROR,\r
822 "CoreLoadPeImage: Failed to register foreign image with emulator.\n"));\r
823 goto Done;\r
824 }\r
825 }\r
826\r
827 //\r
828 // Fill in the image information for the Loaded Image Protocol\r
829 //\r
830 Image->Type = Image->ImageContext.ImageType;\r
831 Image->Info.ImageBase = (VOID *)(UINTN)Image->ImageContext.ImageAddress;\r
832 Image->Info.ImageSize = Image->ImageContext.ImageSize;\r
833 Image->Info.ImageCodeType = (EFI_MEMORY_TYPE) (Image->ImageContext.ImageCodeMemoryType);\r
834 Image->Info.ImageDataType = (EFI_MEMORY_TYPE) (Image->ImageContext.ImageDataMemoryType);\r
835 if ((Attribute & EFI_LOAD_PE_IMAGE_ATTRIBUTE_RUNTIME_REGISTRATION) != 0) {\r
836 if (Image->ImageContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) {\r
837 //\r
838 // Make a list off all the RT images so we can let the RT AP know about them.\r
839 //\r
840 Image->RuntimeData = AllocateRuntimePool (sizeof(EFI_RUNTIME_IMAGE_ENTRY));\r
841 if (Image->RuntimeData == NULL) {\r
842 goto Done;\r
843 }\r
844 Image->RuntimeData->ImageBase = Image->Info.ImageBase;\r
845 Image->RuntimeData->ImageSize = (UINT64) (Image->Info.ImageSize);\r
846 Image->RuntimeData->RelocationData = Image->ImageContext.FixupData;\r
847 Image->RuntimeData->Handle = Image->Handle;\r
848 InsertTailList (&gRuntime->ImageHead, &Image->RuntimeData->Link);\r
849 InsertImageRecord (Image->RuntimeData);\r
850 }\r
851 }\r
852\r
853 //\r
854 // Fill in the entry point of the image if it is available\r
855 //\r
856 if (EntryPoint != NULL) {\r
857 *EntryPoint = Image->ImageContext.EntryPoint;\r
858 }\r
859\r
860 //\r
861 // Print the load address and the PDB file name if it is available\r
862 //\r
863\r
864 DEBUG_CODE_BEGIN ();\r
865\r
866 UINTN Index;\r
867 UINTN StartIndex;\r
868 CHAR8 EfiFileName[256];\r
869\r
870\r
871 DEBUG ((DEBUG_INFO | DEBUG_LOAD,\r
872 "Loading driver at 0x%11p EntryPoint=0x%11p ",\r
873 (VOID *)(UINTN) Image->ImageContext.ImageAddress,\r
874 FUNCTION_ENTRY_POINT (Image->ImageContext.EntryPoint)));\r
875\r
876\r
877 //\r
878 // Print Module Name by Pdb file path.\r
879 // Windows and Unix style file path are all trimmed correctly.\r
880 //\r
881 if (Image->ImageContext.PdbPointer != NULL) {\r
882 StartIndex = 0;\r
883 for (Index = 0; Image->ImageContext.PdbPointer[Index] != 0; Index++) {\r
884 if ((Image->ImageContext.PdbPointer[Index] == '\\') || (Image->ImageContext.PdbPointer[Index] == '/')) {\r
885 StartIndex = Index + 1;\r
886 }\r
887 }\r
888 //\r
889 // Copy the PDB file name to our temporary string, and replace .pdb with .efi\r
890 // The PDB file name is limited in the range of 0~255.\r
891 // If the length is bigger than 255, trim the redudant characters to avoid overflow in array boundary.\r
892 //\r
893 for (Index = 0; Index < sizeof (EfiFileName) - 4; Index++) {\r
894 EfiFileName[Index] = Image->ImageContext.PdbPointer[Index + StartIndex];\r
895 if (EfiFileName[Index] == 0) {\r
896 EfiFileName[Index] = '.';\r
897 }\r
898 if (EfiFileName[Index] == '.') {\r
899 EfiFileName[Index + 1] = 'e';\r
900 EfiFileName[Index + 2] = 'f';\r
901 EfiFileName[Index + 3] = 'i';\r
902 EfiFileName[Index + 4] = 0;\r
903 break;\r
904 }\r
905 }\r
906\r
907 if (Index == sizeof (EfiFileName) - 4) {\r
908 EfiFileName[Index] = 0;\r
909 }\r
910 DEBUG ((DEBUG_INFO | DEBUG_LOAD, "%a", EfiFileName)); // &Image->ImageContext.PdbPointer[StartIndex]));\r
911 }\r
912 DEBUG ((DEBUG_INFO | DEBUG_LOAD, "\n"));\r
913\r
914 DEBUG_CODE_END ();\r
915\r
916 return EFI_SUCCESS;\r
917\r
918Done:\r
919\r
920 //\r
921 // Free memory.\r
922 //\r
923\r
924 if (DstBufAlocated) {\r
925 CoreFreePages (Image->ImageContext.ImageAddress, Image->NumberOfPages);\r
926 Image->ImageContext.ImageAddress = 0;\r
927 Image->ImageBasePage = 0;\r
928 }\r
929\r
930 if (Image->ImageContext.FixupData != NULL) {\r
931 CoreFreePool (Image->ImageContext.FixupData);\r
932 }\r
933\r
934 return Status;\r
935}\r
936\r
937\r
938\r
939/**\r
940 Get the image's private data from its handle.\r
941\r
942 @param ImageHandle The image handle\r
943\r
944 @return Return the image private data associated with ImageHandle.\r
945\r
946**/\r
947LOADED_IMAGE_PRIVATE_DATA *\r
948CoreLoadedImageInfo (\r
949 IN EFI_HANDLE ImageHandle\r
950 )\r
951{\r
952 EFI_STATUS Status;\r
953 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;\r
954 LOADED_IMAGE_PRIVATE_DATA *Image;\r
955\r
956 Status = CoreHandleProtocol (\r
957 ImageHandle,\r
958 &gEfiLoadedImageProtocolGuid,\r
959 (VOID **)&LoadedImage\r
960 );\r
961 if (!EFI_ERROR (Status)) {\r
962 Image = LOADED_IMAGE_PRIVATE_DATA_FROM_THIS (LoadedImage);\r
963 } else {\r
964 DEBUG ((DEBUG_LOAD, "CoreLoadedImageInfo: Not an ImageHandle %p\n", ImageHandle));\r
965 Image = NULL;\r
966 }\r
967\r
968 return Image;\r
969}\r
970\r
971\r
972/**\r
973 Unloads EFI image from memory.\r
974\r
975 @param Image EFI image\r
976 @param FreePage Free allocated pages\r
977\r
978**/\r
979VOID\r
980CoreUnloadAndCloseImage (\r
981 IN LOADED_IMAGE_PRIVATE_DATA *Image,\r
982 IN BOOLEAN FreePage\r
983 )\r
984{\r
985 EFI_STATUS Status;\r
986 UINTN HandleCount;\r
987 EFI_HANDLE *HandleBuffer;\r
988 UINTN HandleIndex;\r
989 EFI_GUID **ProtocolGuidArray;\r
990 UINTN ArrayCount;\r
991 UINTN ProtocolIndex;\r
992 EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfo;\r
993 UINTN OpenInfoCount;\r
994 UINTN OpenInfoIndex;\r
995\r
996 HandleBuffer = NULL;\r
997 ProtocolGuidArray = NULL;\r
998\r
999 if (Image->Started) {\r
1000 UnregisterMemoryProfileImage (Image);\r
1001 }\r
1002\r
1003 UnprotectUefiImage (&Image->Info, Image->LoadedImageDevicePath);\r
1004\r
1005 if (Image->Ebc != NULL) {\r
1006 //\r
1007 // If EBC protocol exists we must perform cleanups for this image.\r
1008 //\r
1009 Image->Ebc->UnloadImage (Image->Ebc, Image->Handle);\r
1010 }\r
1011\r
1012 if (Image->PeCoffEmu != NULL) {\r
1013 //\r
1014 // If the PE/COFF Emulator protocol exists we must unregister the image.\r
1015 //\r
1016 Image->PeCoffEmu->UnregisterImage (Image->PeCoffEmu, Image->ImageBasePage);\r
1017 }\r
1018\r
1019 //\r
1020 // Unload image, free Image->ImageContext->ModHandle\r
1021 //\r
1022 PeCoffLoaderUnloadImage (&Image->ImageContext);\r
1023\r
1024 //\r
1025 // Free our references to the image handle\r
1026 //\r
1027 if (Image->Handle != NULL) {\r
1028\r
1029 Status = CoreLocateHandleBuffer (\r
1030 AllHandles,\r
1031 NULL,\r
1032 NULL,\r
1033 &HandleCount,\r
1034 &HandleBuffer\r
1035 );\r
1036 if (!EFI_ERROR (Status)) {\r
1037 for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) {\r
1038 Status = CoreProtocolsPerHandle (\r
1039 HandleBuffer[HandleIndex],\r
1040 &ProtocolGuidArray,\r
1041 &ArrayCount\r
1042 );\r
1043 if (!EFI_ERROR (Status)) {\r
1044 for (ProtocolIndex = 0; ProtocolIndex < ArrayCount; ProtocolIndex++) {\r
1045 Status = CoreOpenProtocolInformation (\r
1046 HandleBuffer[HandleIndex],\r
1047 ProtocolGuidArray[ProtocolIndex],\r
1048 &OpenInfo,\r
1049 &OpenInfoCount\r
1050 );\r
1051 if (!EFI_ERROR (Status)) {\r
1052 for (OpenInfoIndex = 0; OpenInfoIndex < OpenInfoCount; OpenInfoIndex++) {\r
1053 if (OpenInfo[OpenInfoIndex].AgentHandle == Image->Handle) {\r
1054 Status = CoreCloseProtocol (\r
1055 HandleBuffer[HandleIndex],\r
1056 ProtocolGuidArray[ProtocolIndex],\r
1057 Image->Handle,\r
1058 OpenInfo[OpenInfoIndex].ControllerHandle\r
1059 );\r
1060 }\r
1061 }\r
1062 if (OpenInfo != NULL) {\r
1063 CoreFreePool(OpenInfo);\r
1064 }\r
1065 }\r
1066 }\r
1067 if (ProtocolGuidArray != NULL) {\r
1068 CoreFreePool(ProtocolGuidArray);\r
1069 }\r
1070 }\r
1071 }\r
1072 if (HandleBuffer != NULL) {\r
1073 CoreFreePool (HandleBuffer);\r
1074 }\r
1075 }\r
1076\r
1077 CoreRemoveDebugImageInfoEntry (Image->Handle);\r
1078\r
1079 Status = CoreUninstallProtocolInterface (\r
1080 Image->Handle,\r
1081 &gEfiLoadedImageDevicePathProtocolGuid,\r
1082 Image->LoadedImageDevicePath\r
1083 );\r
1084\r
1085 Status = CoreUninstallProtocolInterface (\r
1086 Image->Handle,\r
1087 &gEfiLoadedImageProtocolGuid,\r
1088 &Image->Info\r
1089 );\r
1090\r
1091 if (Image->ImageContext.HiiResourceData != 0) {\r
1092 Status = CoreUninstallProtocolInterface (\r
1093 Image->Handle,\r
1094 &gEfiHiiPackageListProtocolGuid,\r
1095 (VOID *) (UINTN) Image->ImageContext.HiiResourceData\r
1096 );\r
1097 }\r
1098\r
1099 }\r
1100\r
1101 if (Image->RuntimeData != NULL) {\r
1102 if (Image->RuntimeData->Link.ForwardLink != NULL) {\r
1103 //\r
1104 // Remove the Image from the Runtime Image list as we are about to Free it!\r
1105 //\r
1106 RemoveEntryList (&Image->RuntimeData->Link);\r
1107 RemoveImageRecord (Image->RuntimeData);\r
1108 }\r
1109 CoreFreePool (Image->RuntimeData);\r
1110 }\r
1111\r
1112 //\r
1113 // Free the Image from memory\r
1114 //\r
1115 if ((Image->ImageBasePage != 0) && FreePage) {\r
1116 CoreFreePages (Image->ImageBasePage, Image->NumberOfPages);\r
1117 }\r
1118\r
1119 //\r
1120 // Done with the Image structure\r
1121 //\r
1122 if (Image->Info.FilePath != NULL) {\r
1123 CoreFreePool (Image->Info.FilePath);\r
1124 }\r
1125\r
1126 if (Image->LoadedImageDevicePath != NULL) {\r
1127 CoreFreePool (Image->LoadedImageDevicePath);\r
1128 }\r
1129\r
1130 if (Image->FixupData != NULL) {\r
1131 CoreFreePool (Image->FixupData);\r
1132 }\r
1133\r
1134 CoreFreePool (Image);\r
1135}\r
1136\r
1137\r
1138/**\r
1139 Loads an EFI image into memory and returns a handle to the image.\r
1140\r
1141 @param BootPolicy If TRUE, indicates that the request originates\r
1142 from the boot manager, and that the boot\r
1143 manager is attempting to load FilePath as a\r
1144 boot selection.\r
1145 @param ParentImageHandle The caller's image handle.\r
1146 @param FilePath The specific file path from which the image is\r
1147 loaded.\r
1148 @param SourceBuffer If not NULL, a pointer to the memory location\r
1149 containing a copy of the image to be loaded.\r
1150 @param SourceSize The size in bytes of SourceBuffer.\r
1151 @param DstBuffer The buffer to store the image\r
1152 @param NumberOfPages If not NULL, it inputs a pointer to the page\r
1153 number of DstBuffer and outputs a pointer to\r
1154 the page number of the image. If this number is\r
1155 not enough, return EFI_BUFFER_TOO_SMALL and\r
1156 this parameter contains the required number.\r
1157 @param ImageHandle Pointer to the returned image handle that is\r
1158 created when the image is successfully loaded.\r
1159 @param EntryPoint A pointer to the entry point\r
1160 @param Attribute The bit mask of attributes to set for the load\r
1161 PE image\r
1162\r
1163 @retval EFI_SUCCESS The image was loaded into memory.\r
1164 @retval EFI_NOT_FOUND The FilePath was not found.\r
1165 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.\r
1166 @retval EFI_BUFFER_TOO_SMALL The buffer is too small\r
1167 @retval EFI_UNSUPPORTED The image type is not supported, or the device\r
1168 path cannot be parsed to locate the proper\r
1169 protocol for loading the file.\r
1170 @retval EFI_OUT_OF_RESOURCES Image was not loaded due to insufficient\r
1171 resources.\r
1172 @retval EFI_LOAD_ERROR Image was not loaded because the image format was corrupt or not\r
1173 understood.\r
1174 @retval EFI_DEVICE_ERROR Image was not loaded because the device returned a read error.\r
1175 @retval EFI_ACCESS_DENIED Image was not loaded because the platform policy prohibits the\r
1176 image from being loaded. NULL is returned in *ImageHandle.\r
1177 @retval EFI_SECURITY_VIOLATION Image was loaded and an ImageHandle was created with a\r
1178 valid EFI_LOADED_IMAGE_PROTOCOL. However, the current\r
1179 platform policy specifies that the image should not be started.\r
1180\r
1181**/\r
1182EFI_STATUS\r
1183CoreLoadImageCommon (\r
1184 IN BOOLEAN BootPolicy,\r
1185 IN EFI_HANDLE ParentImageHandle,\r
1186 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,\r
1187 IN VOID *SourceBuffer OPTIONAL,\r
1188 IN UINTN SourceSize,\r
1189 IN EFI_PHYSICAL_ADDRESS DstBuffer OPTIONAL,\r
1190 IN OUT UINTN *NumberOfPages OPTIONAL,\r
1191 OUT EFI_HANDLE *ImageHandle,\r
1192 OUT EFI_PHYSICAL_ADDRESS *EntryPoint OPTIONAL,\r
1193 IN UINT32 Attribute\r
1194 )\r
1195{\r
1196 LOADED_IMAGE_PRIVATE_DATA *Image;\r
1197 LOADED_IMAGE_PRIVATE_DATA *ParentImage;\r
1198 IMAGE_FILE_HANDLE FHand;\r
1199 EFI_STATUS Status;\r
1200 EFI_STATUS SecurityStatus;\r
1201 EFI_HANDLE DeviceHandle;\r
1202 UINT32 AuthenticationStatus;\r
1203 EFI_DEVICE_PATH_PROTOCOL *OriginalFilePath;\r
1204 EFI_DEVICE_PATH_PROTOCOL *HandleFilePath;\r
1205 EFI_DEVICE_PATH_PROTOCOL *InputFilePath;\r
1206 EFI_DEVICE_PATH_PROTOCOL *Node;\r
1207 UINTN FilePathSize;\r
1208 BOOLEAN ImageIsFromFv;\r
1209 BOOLEAN ImageIsFromLoadFile;\r
1210\r
1211 SecurityStatus = EFI_SUCCESS;\r
1212\r
1213 ASSERT (gEfiCurrentTpl < TPL_NOTIFY);\r
1214 ParentImage = NULL;\r
1215\r
1216 //\r
1217 // The caller must pass in a valid ParentImageHandle\r
1218 //\r
1219 if (ImageHandle == NULL || ParentImageHandle == NULL) {\r
1220 return EFI_INVALID_PARAMETER;\r
1221 }\r
1222\r
1223 ParentImage = CoreLoadedImageInfo (ParentImageHandle);\r
1224 if (ParentImage == NULL) {\r
1225 DEBUG((DEBUG_LOAD|DEBUG_ERROR, "LoadImageEx: Parent handle not an image handle\n"));\r
1226 return EFI_INVALID_PARAMETER;\r
1227 }\r
1228\r
1229 ZeroMem (&FHand, sizeof (IMAGE_FILE_HANDLE));\r
1230 FHand.Signature = IMAGE_FILE_HANDLE_SIGNATURE;\r
1231 OriginalFilePath = FilePath;\r
1232 InputFilePath = FilePath;\r
1233 HandleFilePath = FilePath;\r
1234 DeviceHandle = NULL;\r
1235 Status = EFI_SUCCESS;\r
1236 AuthenticationStatus = 0;\r
1237 ImageIsFromFv = FALSE;\r
1238 ImageIsFromLoadFile = FALSE;\r
1239\r
1240 //\r
1241 // If the caller passed a copy of the file, then just use it\r
1242 //\r
1243 if (SourceBuffer != NULL) {\r
1244 FHand.Source = SourceBuffer;\r
1245 FHand.SourceSize = SourceSize;\r
1246 Status = CoreLocateDevicePath (&gEfiDevicePathProtocolGuid, &HandleFilePath, &DeviceHandle);\r
1247 if (EFI_ERROR (Status)) {\r
1248 DeviceHandle = NULL;\r
1249 }\r
1250 if (SourceSize > 0) {\r
1251 Status = EFI_SUCCESS;\r
1252 } else {\r
1253 Status = EFI_LOAD_ERROR;\r
1254 }\r
1255 } else {\r
1256 if (FilePath == NULL) {\r
1257 return EFI_INVALID_PARAMETER;\r
1258 }\r
1259\r
1260 //\r
1261 // Try to get the image device handle by checking the match protocol.\r
1262 //\r
1263 Node = NULL;\r
1264 Status = CoreLocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &HandleFilePath, &DeviceHandle);\r
1265 if (!EFI_ERROR (Status)) {\r
1266 ImageIsFromFv = TRUE;\r
1267 } else {\r
1268 HandleFilePath = FilePath;\r
1269 Status = CoreLocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &HandleFilePath, &DeviceHandle);\r
1270 if (EFI_ERROR (Status)) {\r
1271 if (!BootPolicy) {\r
1272 HandleFilePath = FilePath;\r
1273 Status = CoreLocateDevicePath (&gEfiLoadFile2ProtocolGuid, &HandleFilePath, &DeviceHandle);\r
1274 }\r
1275 if (EFI_ERROR (Status)) {\r
1276 HandleFilePath = FilePath;\r
1277 Status = CoreLocateDevicePath (&gEfiLoadFileProtocolGuid, &HandleFilePath, &DeviceHandle);\r
1278 if (!EFI_ERROR (Status)) {\r
1279 ImageIsFromLoadFile = TRUE;\r
1280 Node = HandleFilePath;\r
1281 }\r
1282 }\r
1283 }\r
1284 }\r
1285\r
1286 //\r
1287 // Get the source file buffer by its device path.\r
1288 //\r
1289 FHand.Source = GetFileBufferByFilePath (\r
1290 BootPolicy,\r
1291 FilePath,\r
1292 &FHand.SourceSize,\r
1293 &AuthenticationStatus\r
1294 );\r
1295 if (FHand.Source == NULL) {\r
1296 Status = EFI_NOT_FOUND;\r
1297 } else {\r
1298 FHand.FreeBuffer = TRUE;\r
1299 if (ImageIsFromLoadFile) {\r
1300 //\r
1301 // LoadFile () may cause the device path of the Handle be updated.\r
1302 //\r
1303 OriginalFilePath = AppendDevicePath (DevicePathFromHandle (DeviceHandle), Node);\r
1304 }\r
1305 }\r
1306 }\r
1307\r
1308 if (EFI_ERROR (Status)) {\r
1309 Image = NULL;\r
1310 goto Done;\r
1311 }\r
1312\r
1313 if (gSecurity2 != NULL) {\r
1314 //\r
1315 // Verify File Authentication through the Security2 Architectural Protocol\r
1316 //\r
1317 SecurityStatus = gSecurity2->FileAuthentication (\r
1318 gSecurity2,\r
1319 OriginalFilePath,\r
1320 FHand.Source,\r
1321 FHand.SourceSize,\r
1322 BootPolicy\r
1323 );\r
1324 if (!EFI_ERROR (SecurityStatus) && ImageIsFromFv) {\r
1325 //\r
1326 // When Security2 is installed, Security Architectural Protocol must be published.\r
1327 //\r
1328 ASSERT (gSecurity != NULL);\r
1329\r
1330 //\r
1331 // Verify the Authentication Status through the Security Architectural Protocol\r
1332 // Only on images that have been read using Firmware Volume protocol.\r
1333 //\r
1334 SecurityStatus = gSecurity->FileAuthenticationState (\r
1335 gSecurity,\r
1336 AuthenticationStatus,\r
1337 OriginalFilePath\r
1338 );\r
1339 }\r
1340 } else if ((gSecurity != NULL) && (OriginalFilePath != NULL)) {\r
1341 //\r
1342 // Verify the Authentication Status through the Security Architectural Protocol\r
1343 //\r
1344 SecurityStatus = gSecurity->FileAuthenticationState (\r
1345 gSecurity,\r
1346 AuthenticationStatus,\r
1347 OriginalFilePath\r
1348 );\r
1349 }\r
1350\r
1351 //\r
1352 // Check Security Status.\r
1353 //\r
1354 if (EFI_ERROR (SecurityStatus) && SecurityStatus != EFI_SECURITY_VIOLATION) {\r
1355 if (SecurityStatus == EFI_ACCESS_DENIED) {\r
1356 //\r
1357 // Image was not loaded because the platform policy prohibits the image from being loaded.\r
1358 // It's the only place we could meet EFI_ACCESS_DENIED.\r
1359 //\r
1360 *ImageHandle = NULL;\r
1361 }\r
1362 Status = SecurityStatus;\r
1363 Image = NULL;\r
1364 goto Done;\r
1365 }\r
1366\r
1367 //\r
1368 // Allocate a new image structure\r
1369 //\r
1370 Image = AllocateZeroPool (sizeof(LOADED_IMAGE_PRIVATE_DATA));\r
1371 if (Image == NULL) {\r
1372 Status = EFI_OUT_OF_RESOURCES;\r
1373 goto Done;\r
1374 }\r
1375\r
1376 //\r
1377 // Pull out just the file portion of the DevicePath for the LoadedImage FilePath\r
1378 //\r
1379 FilePath = OriginalFilePath;\r
1380 if (DeviceHandle != NULL) {\r
1381 Status = CoreHandleProtocol (DeviceHandle, &gEfiDevicePathProtocolGuid, (VOID **)&HandleFilePath);\r
1382 if (!EFI_ERROR (Status)) {\r
1383 FilePathSize = GetDevicePathSize (HandleFilePath) - sizeof(EFI_DEVICE_PATH_PROTOCOL);\r
1384 FilePath = (EFI_DEVICE_PATH_PROTOCOL *) (((UINT8 *)FilePath) + FilePathSize );\r
1385 }\r
1386 }\r
1387 //\r
1388 // Initialize the fields for an internal driver\r
1389 //\r
1390 Image->Signature = LOADED_IMAGE_PRIVATE_DATA_SIGNATURE;\r
1391 Image->Info.SystemTable = gDxeCoreST;\r
1392 Image->Info.DeviceHandle = DeviceHandle;\r
1393 Image->Info.Revision = EFI_LOADED_IMAGE_PROTOCOL_REVISION;\r
1394 Image->Info.FilePath = DuplicateDevicePath (FilePath);\r
1395 Image->Info.ParentHandle = ParentImageHandle;\r
1396\r
1397\r
1398 if (NumberOfPages != NULL) {\r
1399 Image->NumberOfPages = *NumberOfPages ;\r
1400 } else {\r
1401 Image->NumberOfPages = 0 ;\r
1402 }\r
1403\r
1404 //\r
1405 // Install the protocol interfaces for this image\r
1406 // don't fire notifications yet\r
1407 //\r
1408 Status = CoreInstallProtocolInterfaceNotify (\r
1409 &Image->Handle,\r
1410 &gEfiLoadedImageProtocolGuid,\r
1411 EFI_NATIVE_INTERFACE,\r
1412 &Image->Info,\r
1413 FALSE\r
1414 );\r
1415 if (EFI_ERROR (Status)) {\r
1416 goto Done;\r
1417 }\r
1418\r
1419 //\r
1420 // Load the image. If EntryPoint is Null, it will not be set.\r
1421 //\r
1422 Status = CoreLoadPeImage (BootPolicy, &FHand, Image, DstBuffer, EntryPoint, Attribute);\r
1423 if (EFI_ERROR (Status)) {\r
1424 if ((Status == EFI_BUFFER_TOO_SMALL) || (Status == EFI_OUT_OF_RESOURCES)) {\r
1425 if (NumberOfPages != NULL) {\r
1426 *NumberOfPages = Image->NumberOfPages;\r
1427 }\r
1428 }\r
1429 goto Done;\r
1430 }\r
1431\r
1432 if (NumberOfPages != NULL) {\r
1433 *NumberOfPages = Image->NumberOfPages;\r
1434 }\r
1435\r
1436 //\r
1437 // Register the image in the Debug Image Info Table if the attribute is set\r
1438 //\r
1439 if ((Attribute & EFI_LOAD_PE_IMAGE_ATTRIBUTE_DEBUG_IMAGE_INFO_TABLE_REGISTRATION) != 0) {\r
1440 CoreNewDebugImageInfoEntry (EFI_DEBUG_IMAGE_INFO_TYPE_NORMAL, &Image->Info, Image->Handle);\r
1441 }\r
1442\r
1443 //\r
1444 //Reinstall loaded image protocol to fire any notifications\r
1445 //\r
1446 Status = CoreReinstallProtocolInterface (\r
1447 Image->Handle,\r
1448 &gEfiLoadedImageProtocolGuid,\r
1449 &Image->Info,\r
1450 &Image->Info\r
1451 );\r
1452 if (EFI_ERROR (Status)) {\r
1453 goto Done;\r
1454 }\r
1455\r
1456 //\r
1457 // If DevicePath parameter to the LoadImage() is not NULL, then make a copy of DevicePath,\r
1458 // otherwise Loaded Image Device Path Protocol is installed with a NULL interface pointer.\r
1459 //\r
1460 if (OriginalFilePath != NULL) {\r
1461 Image->LoadedImageDevicePath = DuplicateDevicePath (OriginalFilePath);\r
1462 }\r
1463\r
1464 //\r
1465 // Install Loaded Image Device Path Protocol onto the image handle of a PE/COFE image\r
1466 //\r
1467 Status = CoreInstallProtocolInterface (\r
1468 &Image->Handle,\r
1469 &gEfiLoadedImageDevicePathProtocolGuid,\r
1470 EFI_NATIVE_INTERFACE,\r
1471 Image->LoadedImageDevicePath\r
1472 );\r
1473 if (EFI_ERROR (Status)) {\r
1474 goto Done;\r
1475 }\r
1476\r
1477 //\r
1478 // Install HII Package List Protocol onto the image handle\r
1479 //\r
1480 if (Image->ImageContext.HiiResourceData != 0) {\r
1481 Status = CoreInstallProtocolInterface (\r
1482 &Image->Handle,\r
1483 &gEfiHiiPackageListProtocolGuid,\r
1484 EFI_NATIVE_INTERFACE,\r
1485 (VOID *) (UINTN) Image->ImageContext.HiiResourceData\r
1486 );\r
1487 if (EFI_ERROR (Status)) {\r
1488 goto Done;\r
1489 }\r
1490 }\r
1491 ProtectUefiImage (&Image->Info, Image->LoadedImageDevicePath);\r
1492\r
1493 //\r
1494 // Success. Return the image handle\r
1495 //\r
1496 *ImageHandle = Image->Handle;\r
1497\r
1498Done:\r
1499 //\r
1500 // All done accessing the source file\r
1501 // If we allocated the Source buffer, free it\r
1502 //\r
1503 if (FHand.FreeBuffer) {\r
1504 CoreFreePool (FHand.Source);\r
1505 }\r
1506 if (OriginalFilePath != InputFilePath) {\r
1507 CoreFreePool (OriginalFilePath);\r
1508 }\r
1509\r
1510 //\r
1511 // There was an error. If there's an Image structure, free it\r
1512 //\r
1513 if (EFI_ERROR (Status)) {\r
1514 if (Image != NULL) {\r
1515 CoreUnloadAndCloseImage (Image, (BOOLEAN)(DstBuffer == 0));\r
1516 Image = NULL;\r
1517 }\r
1518 } else if (EFI_ERROR (SecurityStatus)) {\r
1519 Status = SecurityStatus;\r
1520 }\r
1521\r
1522 //\r
1523 // Track the return status from LoadImage.\r
1524 //\r
1525 if (Image != NULL) {\r
1526 Image->LoadImageStatus = Status;\r
1527 }\r
1528\r
1529 return Status;\r
1530}\r
1531\r
1532\r
1533\r
1534\r
1535/**\r
1536 Loads an EFI image into memory and returns a handle to the image.\r
1537\r
1538 @param BootPolicy If TRUE, indicates that the request originates\r
1539 from the boot manager, and that the boot\r
1540 manager is attempting to load FilePath as a\r
1541 boot selection.\r
1542 @param ParentImageHandle The caller's image handle.\r
1543 @param FilePath The specific file path from which the image is\r
1544 loaded.\r
1545 @param SourceBuffer If not NULL, a pointer to the memory location\r
1546 containing a copy of the image to be loaded.\r
1547 @param SourceSize The size in bytes of SourceBuffer.\r
1548 @param ImageHandle Pointer to the returned image handle that is\r
1549 created when the image is successfully loaded.\r
1550\r
1551 @retval EFI_SUCCESS The image was loaded into memory.\r
1552 @retval EFI_NOT_FOUND The FilePath was not found.\r
1553 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.\r
1554 @retval EFI_UNSUPPORTED The image type is not supported, or the device\r
1555 path cannot be parsed to locate the proper\r
1556 protocol for loading the file.\r
1557 @retval EFI_OUT_OF_RESOURCES Image was not loaded due to insufficient\r
1558 resources.\r
1559 @retval EFI_LOAD_ERROR Image was not loaded because the image format was corrupt or not\r
1560 understood.\r
1561 @retval EFI_DEVICE_ERROR Image was not loaded because the device returned a read error.\r
1562 @retval EFI_ACCESS_DENIED Image was not loaded because the platform policy prohibits the\r
1563 image from being loaded. NULL is returned in *ImageHandle.\r
1564 @retval EFI_SECURITY_VIOLATION Image was loaded and an ImageHandle was created with a\r
1565 valid EFI_LOADED_IMAGE_PROTOCOL. However, the current\r
1566 platform policy specifies that the image should not be started.\r
1567\r
1568**/\r
1569EFI_STATUS\r
1570EFIAPI\r
1571CoreLoadImage (\r
1572 IN BOOLEAN BootPolicy,\r
1573 IN EFI_HANDLE ParentImageHandle,\r
1574 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,\r
1575 IN VOID *SourceBuffer OPTIONAL,\r
1576 IN UINTN SourceSize,\r
1577 OUT EFI_HANDLE *ImageHandle\r
1578 )\r
1579{\r
1580 EFI_STATUS Status;\r
1581 EFI_HANDLE Handle;\r
1582\r
1583 PERF_LOAD_IMAGE_BEGIN (NULL);\r
1584\r
1585 Status = CoreLoadImageCommon (\r
1586 BootPolicy,\r
1587 ParentImageHandle,\r
1588 FilePath,\r
1589 SourceBuffer,\r
1590 SourceSize,\r
1591 (EFI_PHYSICAL_ADDRESS) (UINTN) NULL,\r
1592 NULL,\r
1593 ImageHandle,\r
1594 NULL,\r
1595 EFI_LOAD_PE_IMAGE_ATTRIBUTE_RUNTIME_REGISTRATION | EFI_LOAD_PE_IMAGE_ATTRIBUTE_DEBUG_IMAGE_INFO_TABLE_REGISTRATION\r
1596 );\r
1597\r
1598 Handle = NULL;\r
1599 if (!EFI_ERROR (Status)) {\r
1600 //\r
1601 // ImageHandle will be valid only Status is success.\r
1602 //\r
1603 Handle = *ImageHandle;\r
1604 }\r
1605\r
1606 PERF_LOAD_IMAGE_END (Handle);\r
1607\r
1608 return Status;\r
1609}\r
1610\r
1611\r
1612\r
1613/**\r
1614 Loads an EFI image into memory and returns a handle to the image with extended parameters.\r
1615\r
1616 @param This Calling context\r
1617 @param ParentImageHandle The caller's image handle.\r
1618 @param FilePath The specific file path from which the image is\r
1619 loaded.\r
1620 @param SourceBuffer If not NULL, a pointer to the memory location\r
1621 containing a copy of the image to be loaded.\r
1622 @param SourceSize The size in bytes of SourceBuffer.\r
1623 @param DstBuffer The buffer to store the image.\r
1624 @param NumberOfPages For input, specifies the space size of the\r
1625 image by caller if not NULL. For output,\r
1626 specifies the actual space size needed.\r
1627 @param ImageHandle Image handle for output.\r
1628 @param EntryPoint Image entry point for output.\r
1629 @param Attribute The bit mask of attributes to set for the load\r
1630 PE image.\r
1631\r
1632 @retval EFI_SUCCESS The image was loaded into memory.\r
1633 @retval EFI_NOT_FOUND The FilePath was not found.\r
1634 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.\r
1635 @retval EFI_UNSUPPORTED The image type is not supported, or the device\r
1636 path cannot be parsed to locate the proper\r
1637 protocol for loading the file.\r
1638 @retval EFI_OUT_OF_RESOURCES Image was not loaded due to insufficient\r
1639 resources.\r
1640 @retval EFI_LOAD_ERROR Image was not loaded because the image format was corrupt or not\r
1641 understood.\r
1642 @retval EFI_DEVICE_ERROR Image was not loaded because the device returned a read error.\r
1643 @retval EFI_ACCESS_DENIED Image was not loaded because the platform policy prohibits the\r
1644 image from being loaded. NULL is returned in *ImageHandle.\r
1645 @retval EFI_SECURITY_VIOLATION Image was loaded and an ImageHandle was created with a\r
1646 valid EFI_LOADED_IMAGE_PROTOCOL. However, the current\r
1647 platform policy specifies that the image should not be started.\r
1648\r
1649**/\r
1650EFI_STATUS\r
1651EFIAPI\r
1652CoreLoadImageEx (\r
1653 IN EFI_PE32_IMAGE_PROTOCOL *This,\r
1654 IN EFI_HANDLE ParentImageHandle,\r
1655 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,\r
1656 IN VOID *SourceBuffer OPTIONAL,\r
1657 IN UINTN SourceSize,\r
1658 IN EFI_PHYSICAL_ADDRESS DstBuffer OPTIONAL,\r
1659 OUT UINTN *NumberOfPages OPTIONAL,\r
1660 OUT EFI_HANDLE *ImageHandle,\r
1661 OUT EFI_PHYSICAL_ADDRESS *EntryPoint OPTIONAL,\r
1662 IN UINT32 Attribute\r
1663 )\r
1664{\r
1665 EFI_STATUS Status;\r
1666 EFI_HANDLE Handle;\r
1667\r
1668 PERF_LOAD_IMAGE_BEGIN (NULL);\r
1669\r
1670 Status = CoreLoadImageCommon (\r
1671 TRUE,\r
1672 ParentImageHandle,\r
1673 FilePath,\r
1674 SourceBuffer,\r
1675 SourceSize,\r
1676 DstBuffer,\r
1677 NumberOfPages,\r
1678 ImageHandle,\r
1679 EntryPoint,\r
1680 Attribute\r
1681 );\r
1682\r
1683 Handle = NULL;\r
1684 if (!EFI_ERROR (Status)) {\r
1685 //\r
1686 // ImageHandle will be valid only Status is success.\r
1687 //\r
1688 Handle = *ImageHandle;\r
1689 }\r
1690\r
1691 PERF_LOAD_IMAGE_END (Handle);\r
1692\r
1693 return Status;\r
1694}\r
1695\r
1696\r
1697/**\r
1698 Transfer control to a loaded image's entry point.\r
1699\r
1700 @param ImageHandle Handle of image to be started.\r
1701 @param ExitDataSize Pointer of the size to ExitData\r
1702 @param ExitData Pointer to a pointer to a data buffer that\r
1703 includes a Null-terminated string,\r
1704 optionally followed by additional binary data.\r
1705 The string is a description that the caller may\r
1706 use to further indicate the reason for the\r
1707 image's exit.\r
1708\r
1709 @retval EFI_INVALID_PARAMETER Invalid parameter\r
1710 @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate\r
1711 @retval EFI_SECURITY_VIOLATION The current platform policy specifies that the image should not be started.\r
1712 @retval EFI_SUCCESS Successfully transfer control to the image's\r
1713 entry point.\r
1714\r
1715**/\r
1716EFI_STATUS\r
1717EFIAPI\r
1718CoreStartImage (\r
1719 IN EFI_HANDLE ImageHandle,\r
1720 OUT UINTN *ExitDataSize,\r
1721 OUT CHAR16 **ExitData OPTIONAL\r
1722 )\r
1723{\r
1724 EFI_STATUS Status;\r
1725 LOADED_IMAGE_PRIVATE_DATA *Image;\r
1726 LOADED_IMAGE_PRIVATE_DATA *LastImage;\r
1727 UINT64 HandleDatabaseKey;\r
1728 UINTN SetJumpFlag;\r
1729 EFI_HANDLE Handle;\r
1730\r
1731 Handle = ImageHandle;\r
1732\r
1733 Image = CoreLoadedImageInfo (ImageHandle);\r
1734 if (Image == NULL || Image->Started) {\r
1735 return EFI_INVALID_PARAMETER;\r
1736 }\r
1737 if (EFI_ERROR (Image->LoadImageStatus)) {\r
1738 return Image->LoadImageStatus;\r
1739 }\r
1740\r
1741 //\r
1742 // The image to be started must have the machine type supported by DxeCore.\r
1743 //\r
1744 if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Image->Machine) &&\r
1745 Image->PeCoffEmu == NULL) {\r
1746 //\r
1747 // Do not ASSERT here, because image might be loaded via EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED\r
1748 // But it can not be started.\r
1749 //\r
1750 DEBUG ((EFI_D_ERROR, "Image type %s can't be started ", GetMachineTypeName(Image->Machine)));\r
1751 DEBUG ((EFI_D_ERROR, "on %s UEFI system.\n", GetMachineTypeName(mDxeCoreImageMachineType)));\r
1752 return EFI_UNSUPPORTED;\r
1753 }\r
1754\r
1755 PERF_START_IMAGE_BEGIN (Handle);\r
1756\r
1757\r
1758 //\r
1759 // Push the current start image context, and\r
1760 // link the current image to the head. This is the\r
1761 // only image that can call Exit()\r
1762 //\r
1763 HandleDatabaseKey = CoreGetHandleDatabaseKey ();\r
1764 LastImage = mCurrentImage;\r
1765 mCurrentImage = Image;\r
1766 Image->Tpl = gEfiCurrentTpl;\r
1767\r
1768 //\r
1769 // Set long jump for Exit() support\r
1770 // JumpContext must be aligned on a CPU specific boundary.\r
1771 // Overallocate the buffer and force the required alignment\r
1772 //\r
1773 Image->JumpBuffer = AllocatePool (sizeof (BASE_LIBRARY_JUMP_BUFFER) + BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT);\r
1774 if (Image->JumpBuffer == NULL) {\r
1775 //\r
1776 // Image may be unloaded after return with failure,\r
1777 // then ImageHandle may be invalid, so use NULL handle to record perf log.\r
1778 //\r
1779 PERF_START_IMAGE_END (NULL);\r
1780\r
1781 //\r
1782 // Pop the current start image context\r
1783 //\r
1784 mCurrentImage = LastImage;\r
1785\r
1786 return EFI_OUT_OF_RESOURCES;\r
1787 }\r
1788 Image->JumpContext = ALIGN_POINTER (Image->JumpBuffer, BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT);\r
1789\r
1790 SetJumpFlag = SetJump (Image->JumpContext);\r
1791 //\r
1792 // The initial call to SetJump() must always return 0.\r
1793 // Subsequent calls to LongJump() cause a non-zero value to be returned by SetJump().\r
1794 //\r
1795 if (SetJumpFlag == 0) {\r
1796 RegisterMemoryProfileImage (Image, (Image->ImageContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION ? EFI_FV_FILETYPE_APPLICATION : EFI_FV_FILETYPE_DRIVER));\r
1797 //\r
1798 // Call the image's entry point\r
1799 //\r
1800 Image->Started = TRUE;\r
1801 Image->Status = Image->EntryPoint (ImageHandle, Image->Info.SystemTable);\r
1802\r
1803 //\r
1804 // Add some debug information if the image returned with error.\r
1805 // This make the user aware and check if the driver image have already released\r
1806 // all the resource in this situation.\r
1807 //\r
1808 DEBUG_CODE_BEGIN ();\r
1809 if (EFI_ERROR (Image->Status)) {\r
1810 DEBUG ((DEBUG_ERROR, "Error: Image at %11p start failed: %r\n", Image->Info.ImageBase, Image->Status));\r
1811 }\r
1812 DEBUG_CODE_END ();\r
1813\r
1814 //\r
1815 // If the image returns, exit it through Exit()\r
1816 //\r
1817 CoreExit (ImageHandle, Image->Status, 0, NULL);\r
1818 }\r
1819\r
1820 //\r
1821 // Image has completed. Verify the tpl is the same\r
1822 //\r
1823 ASSERT (Image->Tpl == gEfiCurrentTpl);\r
1824 CoreRestoreTpl (Image->Tpl);\r
1825\r
1826 CoreFreePool (Image->JumpBuffer);\r
1827\r
1828 //\r
1829 // Pop the current start image context\r
1830 //\r
1831 mCurrentImage = LastImage;\r
1832\r
1833 //\r
1834 // UEFI Specification - StartImage() - EFI 1.10 Extension\r
1835 // To maintain compatibility with UEFI drivers that are written to the EFI\r
1836 // 1.02 Specification, StartImage() must monitor the handle database before\r
1837 // and after each image is started. If any handles are created or modified\r
1838 // when an image is started, then EFI_BOOT_SERVICES.ConnectController() must\r
1839 // be called with the Recursive parameter set to TRUE for each of the newly\r
1840 // created or modified handles before StartImage() returns.\r
1841 //\r
1842 if (Image->Type != EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) {\r
1843 CoreConnectHandlesByKey (HandleDatabaseKey);\r
1844 }\r
1845\r
1846 //\r
1847 // Handle the image's returned ExitData\r
1848 //\r
1849 DEBUG_CODE_BEGIN ();\r
1850 if (Image->ExitDataSize != 0 || Image->ExitData != NULL) {\r
1851\r
1852 DEBUG ((DEBUG_LOAD, "StartImage: ExitDataSize %d, ExitData %p", (UINT32)Image->ExitDataSize, Image->ExitData));\r
1853 if (Image->ExitData != NULL) {\r
1854 DEBUG ((DEBUG_LOAD, " (%hs)", Image->ExitData));\r
1855 }\r
1856 DEBUG ((DEBUG_LOAD, "\n"));\r
1857 }\r
1858 DEBUG_CODE_END ();\r
1859\r
1860 //\r
1861 // Return the exit data to the caller\r
1862 //\r
1863 if (ExitData != NULL && ExitDataSize != NULL) {\r
1864 *ExitDataSize = Image->ExitDataSize;\r
1865 *ExitData = Image->ExitData;\r
1866 } else {\r
1867 //\r
1868 // Caller doesn't want the exit data, free it\r
1869 //\r
1870 CoreFreePool (Image->ExitData);\r
1871 Image->ExitData = NULL;\r
1872 }\r
1873\r
1874 //\r
1875 // Save the Status because Image will get destroyed if it is unloaded.\r
1876 //\r
1877 Status = Image->Status;\r
1878\r
1879 //\r
1880 // If the image returned an error, or if the image is an application\r
1881 // unload it\r
1882 //\r
1883 if (EFI_ERROR (Image->Status) || Image->Type == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) {\r
1884 CoreUnloadAndCloseImage (Image, TRUE);\r
1885 //\r
1886 // ImageHandle may be invalid after the image is unloaded, so use NULL handle to record perf log.\r
1887 //\r
1888 Handle = NULL;\r
1889 }\r
1890\r
1891 //\r
1892 // Done\r
1893 //\r
1894 PERF_START_IMAGE_END (Handle);\r
1895 return Status;\r
1896}\r
1897\r
1898/**\r
1899 Terminates the currently loaded EFI image and returns control to boot services.\r
1900\r
1901 @param ImageHandle Handle that identifies the image. This\r
1902 parameter is passed to the image on entry.\r
1903 @param Status The image's exit code.\r
1904 @param ExitDataSize The size, in bytes, of ExitData. Ignored if\r
1905 ExitStatus is EFI_SUCCESS.\r
1906 @param ExitData Pointer to a data buffer that includes a\r
1907 Null-terminated Unicode string, optionally\r
1908 followed by additional binary data. The string\r
1909 is a description that the caller may use to\r
1910 further indicate the reason for the image's\r
1911 exit.\r
1912\r
1913 @retval EFI_INVALID_PARAMETER Image handle is NULL or it is not current\r
1914 image.\r
1915 @retval EFI_SUCCESS Successfully terminates the currently loaded\r
1916 EFI image.\r
1917 @retval EFI_ACCESS_DENIED Should never reach there.\r
1918 @retval EFI_OUT_OF_RESOURCES Could not allocate pool\r
1919\r
1920**/\r
1921EFI_STATUS\r
1922EFIAPI\r
1923CoreExit (\r
1924 IN EFI_HANDLE ImageHandle,\r
1925 IN EFI_STATUS Status,\r
1926 IN UINTN ExitDataSize,\r
1927 IN CHAR16 *ExitData OPTIONAL\r
1928 )\r
1929{\r
1930 LOADED_IMAGE_PRIVATE_DATA *Image;\r
1931 EFI_TPL OldTpl;\r
1932\r
1933 //\r
1934 // Prevent possible reentrance to this function\r
1935 // for the same ImageHandle\r
1936 //\r
1937 OldTpl = CoreRaiseTpl (TPL_NOTIFY);\r
1938\r
1939 Image = CoreLoadedImageInfo (ImageHandle);\r
1940 if (Image == NULL) {\r
1941 Status = EFI_INVALID_PARAMETER;\r
1942 goto Done;\r
1943 }\r
1944\r
1945 if (!Image->Started) {\r
1946 //\r
1947 // The image has not been started so just free its resources\r
1948 //\r
1949 CoreUnloadAndCloseImage (Image, TRUE);\r
1950 Status = EFI_SUCCESS;\r
1951 goto Done;\r
1952 }\r
1953\r
1954 //\r
1955 // Image has been started, verify this image can exit\r
1956 //\r
1957 if (Image != mCurrentImage) {\r
1958 DEBUG ((DEBUG_LOAD|DEBUG_ERROR, "Exit: Image is not exitable image\n"));\r
1959 Status = EFI_INVALID_PARAMETER;\r
1960 goto Done;\r
1961 }\r
1962\r
1963 //\r
1964 // Set status\r
1965 //\r
1966 Image->Status = Status;\r
1967\r
1968 //\r
1969 // If there's ExitData info, move it\r
1970 //\r
1971 if (ExitData != NULL) {\r
1972 Image->ExitDataSize = ExitDataSize;\r
1973 Image->ExitData = AllocatePool (Image->ExitDataSize);\r
1974 if (Image->ExitData == NULL) {\r
1975 Status = EFI_OUT_OF_RESOURCES;\r
1976 goto Done;\r
1977 }\r
1978 CopyMem (Image->ExitData, ExitData, Image->ExitDataSize);\r
1979 }\r
1980\r
1981 CoreRestoreTpl (OldTpl);\r
1982 //\r
1983 // return to StartImage\r
1984 //\r
1985 LongJump (Image->JumpContext, (UINTN)-1);\r
1986\r
1987 //\r
1988 // If we return from LongJump, then it is an error\r
1989 //\r
1990 ASSERT (FALSE);\r
1991 Status = EFI_ACCESS_DENIED;\r
1992Done:\r
1993 CoreRestoreTpl (OldTpl);\r
1994 return Status;\r
1995}\r
1996\r
1997\r
1998\r
1999\r
2000/**\r
2001 Unloads an image.\r
2002\r
2003 @param ImageHandle Handle that identifies the image to be\r
2004 unloaded.\r
2005\r
2006 @retval EFI_SUCCESS The image has been unloaded.\r
2007 @retval EFI_UNSUPPORTED The image has been started, and does not support\r
2008 unload.\r
2009 @retval EFI_INVALID_PARAMPETER ImageHandle is not a valid image handle.\r
2010\r
2011**/\r
2012EFI_STATUS\r
2013EFIAPI\r
2014CoreUnloadImage (\r
2015 IN EFI_HANDLE ImageHandle\r
2016 )\r
2017{\r
2018 EFI_STATUS Status;\r
2019 LOADED_IMAGE_PRIVATE_DATA *Image;\r
2020\r
2021 Image = CoreLoadedImageInfo (ImageHandle);\r
2022 if (Image == NULL ) {\r
2023 //\r
2024 // The image handle is not valid\r
2025 //\r
2026 Status = EFI_INVALID_PARAMETER;\r
2027 goto Done;\r
2028 }\r
2029\r
2030 if (Image->Started) {\r
2031 //\r
2032 // The image has been started, request it to unload.\r
2033 //\r
2034 Status = EFI_UNSUPPORTED;\r
2035 if (Image->Info.Unload != NULL) {\r
2036 Status = Image->Info.Unload (ImageHandle);\r
2037 }\r
2038\r
2039 } else {\r
2040 //\r
2041 // This Image hasn't been started, thus it can be unloaded\r
2042 //\r
2043 Status = EFI_SUCCESS;\r
2044 }\r
2045\r
2046\r
2047 if (!EFI_ERROR (Status)) {\r
2048 //\r
2049 // if the Image was not started or Unloaded O.K. then clean up\r
2050 //\r
2051 CoreUnloadAndCloseImage (Image, TRUE);\r
2052 }\r
2053\r
2054Done:\r
2055 return Status;\r
2056}\r
2057\r
2058\r
2059\r
2060/**\r
2061 Unload the specified image.\r
2062\r
2063 @param This Indicates the calling context.\r
2064 @param ImageHandle The specified image handle.\r
2065\r
2066 @retval EFI_INVALID_PARAMETER Image handle is NULL.\r
2067 @retval EFI_UNSUPPORTED Attempt to unload an unsupported image.\r
2068 @retval EFI_SUCCESS Image successfully unloaded.\r
2069\r
2070**/\r
2071EFI_STATUS\r
2072EFIAPI\r
2073CoreUnloadImageEx (\r
2074 IN EFI_PE32_IMAGE_PROTOCOL *This,\r
2075 IN EFI_HANDLE ImageHandle\r
2076 )\r
2077{\r
2078 return CoreUnloadImage (ImageHandle);\r
2079}\r