]> git.proxmox.com Git - mirror_edk2.git/blame - EdkCompatibilityPkg/Foundation/Library/Pei/PeiLib/PeCoffLoader.c
Sync all bug fixes between EDK1.04 and EDK1.06 into EdkCompatibilityPkg.
[mirror_edk2.git] / EdkCompatibilityPkg / Foundation / Library / Pei / PeiLib / PeCoffLoader.c
CommitLineData
3eb9473e 1/*++\r
2\r
4ac4deb7 3Copyright (c) 2005 - 2010, Intel Corporation. All rights reserved.<BR>\r
4ea9375a 4This program and the accompanying materials \r
3eb9473e 5are licensed and made available under the terms and conditions of the BSD License \r
6which accompanies this distribution. The full text of the license may be found at \r
7http://opensource.org/licenses/bsd-license.php \r
8 \r
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
11\r
12Module Name:\r
13\r
14 PeCoffLoader.c\r
15\r
16Abstract:\r
17\r
18 Tiano PE/COFF loader \r
19\r
20Revision History\r
21\r
22--*/\r
23\r
24#include "Tiano.h"\r
25#include "Pei.h"\r
26#include "PeiLib.h"\r
27#include "PeCoffLoaderEx.h"\r
28\r
29#ifdef EFI_NT_EMULATOR\r
30#include "peilib.h"\r
31#include "EfiHobLib.h"\r
32#include EFI_PPI_DEFINITION (NtLoadAsDll)\r
33#endif\r
34\r
35STATIC\r
36EFI_STATUS\r
37PeCoffLoaderGetPeHeader (\r
38 IN OUT EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,\r
39 OUT EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr\r
40 );\r
41\r
42STATIC\r
43VOID*\r
44PeCoffLoaderImageAddress (\r
45 IN OUT EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,\r
46 IN UINTN Address\r
47 );\r
48\r
49EFI_STATUS\r
50EFIAPI\r
51PeCoffLoaderGetImageInfo (\r
52 IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *This,\r
53 IN OUT EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext\r
54 );\r
55\r
56EFI_STATUS\r
57EFIAPI\r
58PeCoffLoaderRelocateImage (\r
59 IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *This,\r
60 IN OUT EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext\r
61 );\r
62\r
63EFI_STATUS\r
64EFIAPI\r
65PeCoffLoaderLoadImage (\r
66 IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *This,\r
67 IN OUT EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext\r
68 );\r
69\r
70EFI_STATUS\r
71EFIAPI\r
72PeCoffLoaderUnloadImage (\r
3e99020d 73 IN EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext\r
3eb9473e 74 );\r
75\r
76#if defined (EFI_DEBUG_ITP_BREAK) && !defined (_CONSOLE)\r
77VOID\r
78AsmEfiSetBreakSupport (\r
79 IN UINTN LoadAddr\r
80 );\r
81#endif\r
82\r
83EFI_PEI_PE_COFF_LOADER_PROTOCOL mPeCoffLoader = {\r
84 PeCoffLoaderGetImageInfo,\r
85 PeCoffLoaderLoadImage,\r
86 PeCoffLoaderRelocateImage,\r
87 PeCoffLoaderUnloadImage\r
88};\r
89\r
90#ifdef EFI_NT_EMULATOR\r
91EFI_NT_LOAD_AS_DLL_PPI *mPeCoffLoaderWinNtLoadAsDll = NULL;\r
92#endif\r
93\r
94EFI_STATUS\r
95InstallEfiPeiPeCoffLoader (\r
96 IN EFI_PEI_SERVICES **PeiServices,\r
97 IN OUT EFI_PEI_PE_COFF_LOADER_PROTOCOL **This,\r
98 IN EFI_PEI_PPI_DESCRIPTOR *ThisPpi\r
99 )\r
100/*++\r
101\r
102Routine Description:\r
103\r
104 Install PE/COFF loader PPI\r
105 \r
106Arguments:\r
107\r
108 PeiServices - General purpose services available to every PEIM\r
109\r
110 This - Pointer to get Pei PE coff loader protocol as output\r
111 \r
112 ThisPpi - Passed in as EFI_NT_LOAD_AS_DLL_PPI on NT_EMULATOR platform\r
113\r
114Returns:\r
115\r
116 EFI_SUCCESS\r
117\r
118--*/\r
119{\r
120 EFI_STATUS Status;\r
121\r
122 Status = EFI_SUCCESS;\r
123\r
124#ifdef EFI_NT_EMULATOR\r
125 //\r
126 // For use by PEI Core and Modules\r
127 //\r
128 if (NULL != PeiServices) {\r
129 Status = (**PeiServices).LocatePpi (\r
130 PeiServices,\r
131 &gEfiNtLoadAsDllPpiGuid,\r
132 0,\r
133 NULL,\r
134 &mPeCoffLoaderWinNtLoadAsDll\r
135 );\r
136 } else {\r
137 //\r
138 // Now in SecMain or ERM usage, bind appropriately\r
139 //\r
140 PEI_ASSERT (PeiServices, (NULL != ThisPpi));\r
141\r
142 mPeCoffLoaderWinNtLoadAsDll = (EFI_NT_LOAD_AS_DLL_PPI *) ThisPpi;\r
143 PEI_ASSERT (PeiServices, (NULL != mPeCoffLoaderWinNtLoadAsDll));\r
144 }\r
145#endif\r
146\r
147 if (NULL != This) {\r
148 *This = &mPeCoffLoader;\r
149 }\r
150\r
151 return Status;\r
152}\r
153\r
154STATIC\r
155EFI_STATUS\r
156PeCoffLoaderGetPeHeader (\r
157 IN OUT EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,\r
158 OUT EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr\r
159 )\r
160/*++\r
161\r
162Routine Description:\r
163\r
164 Retrieves the PE or TE Header from a PE/COFF or TE image\r
165\r
166Arguments:\r
167\r
168 ImageContext - The context of the image being loaded\r
169\r
170 PeHdr - The buffer in which to return the PE32, PE32+, or TE header\r
171\r
172Returns:\r
173\r
174 EFI_SUCCESS if the PE or TE Header is read, \r
175 Otherwise, the error status from reading the PE/COFF or TE image using the ImageRead function.\r
176\r
177--*/\r
178{\r
179 EFI_STATUS Status;\r
180 EFI_IMAGE_DOS_HEADER DosHdr;\r
181 UINTN Size;\r
182 UINT16 Magic;\r
183\r
184 //\r
185 // Read the DOS image header to check for it's existance\r
186 //\r
187 Size = sizeof (EFI_IMAGE_DOS_HEADER);\r
188 Status = ImageContext->ImageRead (\r
189 ImageContext->Handle,\r
190 0,\r
191 &Size,\r
192 &DosHdr\r
193 );\r
194 if (EFI_ERROR (Status)) {\r
195 ImageContext->ImageError = EFI_IMAGE_ERROR_IMAGE_READ;\r
196 return Status;\r
197 }\r
198\r
199 ImageContext->PeCoffHeaderOffset = 0;\r
200 if (DosHdr.e_magic == EFI_IMAGE_DOS_SIGNATURE) {\r
201 //\r
202 // DOS image header is present, so read the PE header after the DOS image \r
203 // header\r
204 //\r
205 ImageContext->PeCoffHeaderOffset = DosHdr.e_lfanew;\r
206 }\r
207\r
208 //\r
209 // Read the PE/COFF Header. For PE32 (32-bit) this will read in too much \r
210 // data, but that should not hurt anythine. Hdr.Pe32->OptionalHeader.Magic\r
211 // determins if this is a PE32 or PE32+ image. The magic is in the same \r
212 // location in both images.\r
213 //\r
214 Size = sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION);\r
215 Status = ImageContext->ImageRead (\r
216 ImageContext->Handle,\r
217 ImageContext->PeCoffHeaderOffset,\r
218 &Size,\r
219 Hdr.Pe32\r
220 );\r
221 if (EFI_ERROR (Status)) {\r
222 ImageContext->ImageError = EFI_IMAGE_ERROR_IMAGE_READ;\r
223 return Status;\r
224 }\r
225\r
226 //\r
227 // Use Signature to figure out if we understand the image format\r
228 //\r
229 if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {\r
230 ImageContext->IsTeImage = TRUE;\r
231 ImageContext->Machine = Hdr.Te->Machine;\r
232 ImageContext->ImageType = (UINT16)(Hdr.Te->Subsystem);\r
233 ImageContext->ImageSize = 0;\r
234 ImageContext->SectionAlignment = 4096;\r
235 ImageContext->SizeOfHeaders = sizeof (EFI_TE_IMAGE_HEADER) + (UINTN)Hdr.Te->BaseOfCode - (UINTN)Hdr.Te->StrippedSize;\r
236\r
237 } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) {\r
238 ImageContext->IsTeImage = FALSE;\r
239 ImageContext->Machine = Hdr.Pe32->FileHeader.Machine;\r
240 \r
241 //\r
242 // NOTE: We use Machine to identify PE32/PE32+, instead of Magic.\r
243 // It is for backward-compatibility consideration, because\r
244 // some system will generate PE32+ image with PE32 Magic.\r
245 //\r
246 if (Hdr.Pe32->FileHeader.Machine == EFI_IMAGE_MACHINE_IA32) {\r
247 Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC;\r
248 } else if (Hdr.Pe32->FileHeader.Machine == EFI_IMAGE_MACHINE_IA64) {\r
249 Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
250 } else if (Hdr.Pe32->FileHeader.Machine == EFI_IMAGE_MACHINE_X64) {\r
251 Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
252 } else {\r
253 Magic = Hdr.Pe32->OptionalHeader.Magic;\r
254 }\r
255\r
256 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC ||\r
257 Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {\r
258 //\r
259 // PE32 and PE32+ have the same offset for these fields.\r
260 // We use PE32 for both PE32 and PE32+ headers here.\r
261 //\r
262 ImageContext->ImageType = Hdr.Pe32->OptionalHeader.Subsystem;\r
263 ImageContext->ImageSize = (UINT64)Hdr.Pe32->OptionalHeader.SizeOfImage;\r
264 ImageContext->SectionAlignment = Hdr.Pe32->OptionalHeader.SectionAlignment;\r
265 ImageContext->SizeOfHeaders = Hdr.Pe32->OptionalHeader.SizeOfHeaders;\r
266\r
267 } else {\r
268 ImageContext->ImageError = EFI_IMAGE_ERROR_INVALID_MACHINE_TYPE;\r
269 return EFI_UNSUPPORTED; \r
270 }\r
271 } else {\r
272 ImageContext->ImageError = EFI_IMAGE_ERROR_INVALID_MACHINE_TYPE;\r
273 return EFI_UNSUPPORTED;\r
274 }\r
275\r
276 if (!PeCoffLoaderImageFormatSupported (ImageContext->Machine)) {\r
277 //\r
278 // If the PE/COFF loader does not support the image type return\r
279 // unsupported. This library can suport lots of types of images\r
280 // this does not mean the user of this library can call the entry\r
281 // point of the image. \r
282 //\r
283 return EFI_UNSUPPORTED;\r
284 }\r
285\r
286 return EFI_SUCCESS;\r
287}\r
288\r
289STATIC\r
290EFI_STATUS\r
291PeCoffLoaderCheckImageType (\r
292 IN OUT EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext\r
293 )\r
294/*++\r
295\r
296Routine Description:\r
297\r
298 Checks the PE or TE header of a PE/COFF or TE image to determine if it supported\r
299\r
300Arguments:\r
301\r
302 ImageContext - The context of the image being loaded\r
303\r
304Returns:\r
305\r
306 EFI_SUCCESS if the PE/COFF or TE image is supported\r
307 EFI_UNSUPPORTED of the PE/COFF or TE image is not supported.\r
308\r
309--*/\r
310{\r
311 switch (ImageContext->ImageType) {\r
312\r
313 case EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION:\r
314 ImageContext->ImageCodeMemoryType = EfiLoaderCode;\r
315 ImageContext->ImageDataMemoryType = EfiLoaderData;\r
316 break;\r
317\r
318 case EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER:\r
319 ImageContext->ImageCodeMemoryType = EfiBootServicesCode;\r
320 ImageContext->ImageDataMemoryType = EfiBootServicesData;\r
321 break;\r
322\r
323 case EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER:\r
324 case EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER:\r
325 ImageContext->ImageCodeMemoryType = EfiRuntimeServicesCode;\r
326 ImageContext->ImageDataMemoryType = EfiRuntimeServicesData;\r
327 break;\r
328\r
329 default:\r
330 ImageContext->ImageError = EFI_IMAGE_ERROR_INVALID_SUBSYSTEM;\r
331 return EFI_UNSUPPORTED;\r
332 }\r
333\r
334 return EFI_SUCCESS;\r
335}\r
336\r
337EFI_STATUS\r
338EFIAPI\r
339PeCoffLoaderGetImageInfo (\r
340 IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *This,\r
341 IN OUT EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext\r
342 )\r
343/*++\r
344\r
345Routine Description:\r
346\r
347 Retrieves information on a PE/COFF image\r
348\r
349Arguments:\r
350\r
351 This - Calling context\r
352\r
353 ImageContext - The context of the image being loaded\r
354\r
355Returns:\r
356\r
357 EFI_SUCCESS if the information on the PE/COFF image was collected.\r
358 EFI_UNSUPPORTED of the PE/COFF image is not supported.\r
359 Otherwise, the error status from reading the PE/COFF image using the \r
360 ImageContext->ImageRead() function\r
361\r
362 EFI_INVALID_PARAMETER - ImageContext is NULL.\r
363\r
364--*/\r
365{\r
366 EFI_STATUS Status;\r
367 EFI_IMAGE_OPTIONAL_HEADER_UNION HdrData;\r
368 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;\r
369 EFI_IMAGE_DATA_DIRECTORY *DebugDirectoryEntry;\r
370 UINTN Size;\r
371 UINTN Index;\r
372 UINTN DebugDirectoryEntryRva;\r
373 UINTN DebugDirectoryEntryFileOffset;\r
374 UINTN SectionHeaderOffset;\r
375 EFI_IMAGE_SECTION_HEADER SectionHeader;\r
376 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY DebugEntry;\r
377 UINT32 NumberOfRvaAndSizes;\r
378 UINT16 Magic;\r
379\r
380 if (NULL == ImageContext) {\r
381 return EFI_INVALID_PARAMETER;\r
382 }\r
383\r
384 //\r
385 // Assume success\r
386 //\r
387 ImageContext->ImageError = EFI_IMAGE_ERROR_SUCCESS;\r
388\r
389 Hdr.Union = &HdrData;\r
390 Status = PeCoffLoaderGetPeHeader (ImageContext, Hdr);\r
391 if (EFI_ERROR (Status)) {\r
392 return Status;\r
393 }\r
394\r
395 //\r
396 // Verify machine type\r
397 //\r
398 Status = PeCoffLoaderCheckImageType (ImageContext);\r
399 if (EFI_ERROR (Status)) {\r
400 return Status;\r
401 }\r
402\r
403 Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC;\r
404\r
405 //\r
406 // Retrieve the base address of the image\r
407 //\r
408 if (!(ImageContext->IsTeImage)) {\r
409 \r
410 //\r
411 // NOTE: We use Machine to identify PE32/PE32+, instead of Magic.\r
412 // It is for backward-compatibility consideration, because\r
413 // some system will generate PE32+ image with PE32 Magic.\r
414 //\r
415 if (Hdr.Pe32->FileHeader.Machine == EFI_IMAGE_MACHINE_IA32) {\r
416 Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC;\r
417 } else if (Hdr.Pe32->FileHeader.Machine == EFI_IMAGE_MACHINE_IA64) {\r
418 Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
419 } else if (Hdr.Pe32->FileHeader.Machine == EFI_IMAGE_MACHINE_X64) {\r
420 Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
421 } else {\r
422 Magic = Hdr.Pe32->OptionalHeader.Magic;\r
423 }\r
424\r
425 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
426 //\r
427 // Use PE32 offset\r
428 //\r
429 ImageContext->ImageAddress = Hdr.Pe32->OptionalHeader.ImageBase;\r
430 } else {\r
431 //\r
432 // Use PE32+ offset\r
433 //\r
434 ImageContext->ImageAddress = Hdr.Pe32Plus->OptionalHeader.ImageBase;\r
435 }\r
436 } else {\r
c7f33ca4 437 ImageContext->ImageAddress = (EFI_PHYSICAL_ADDRESS)(Hdr.Te->ImageBase + Hdr.Te->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER));\r
3eb9473e 438 }\r
439\r
440 //\r
441 // Initialize the alternate destination address to 0 indicating that it\r
442 // should not be used.\r
443 //\r
444 ImageContext->DestinationAddress = 0;\r
445\r
446 //\r
447 // Initialize the codeview pointer.\r
448 //\r
449 ImageContext->CodeView = NULL;\r
450 ImageContext->PdbPointer = NULL;\r
451\r
452 //\r
453 // Three cases with regards to relocations:\r
454 // - Image has base relocs, RELOCS_STRIPPED==0 => image is relocatable\r
455 // - Image has no base relocs, RELOCS_STRIPPED==1 => Image is not relocatable\r
456 // - Image has no base relocs, RELOCS_STRIPPED==0 => Image is relocatable but\r
457 // has no base relocs to apply\r
458 // Obviously having base relocations with RELOCS_STRIPPED==1 is invalid.\r
459 //\r
460 // Look at the file header to determine if relocations have been stripped, and\r
461 // save this info in the image context for later use.\r
462 //\r
463 if ((!(ImageContext->IsTeImage)) && ((Hdr.Pe32->FileHeader.Characteristics & EFI_IMAGE_FILE_RELOCS_STRIPPED) != 0)) {\r
464 ImageContext->RelocationsStripped = TRUE;\r
465 } else {\r
466 ImageContext->RelocationsStripped = FALSE;\r
467 }\r
468\r
469 if (!(ImageContext->IsTeImage)) {\r
470 //\r
471 // Use PE32 to access fields that have same offset in PE32 and PE32+\r
472 //\r
473 ImageContext->ImageSize = (UINT64) Hdr.Pe32->OptionalHeader.SizeOfImage;\r
474 ImageContext->SectionAlignment = Hdr.Pe32->OptionalHeader.SectionAlignment;\r
475 ImageContext->SizeOfHeaders = Hdr.Pe32->OptionalHeader.SizeOfHeaders;\r
476 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
477 // \r
478 // Use PE32 offset\r
479 //\r
480 NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;\r
481 DebugDirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);\r
482 } else {\r
483 // \r
484 // Use PE32+ offset\r
485 //\r
486 NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;\r
487 DebugDirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);\r
488 } \r
489 \r
490 if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_DEBUG) {\r
491\r
492 DebugDirectoryEntryRva = DebugDirectoryEntry->VirtualAddress;\r
493\r
494 //\r
495 // Determine the file offset of the debug directory... This means we walk\r
496 // the sections to find which section contains the RVA of the debug\r
497 // directory\r
498 //\r
499 DebugDirectoryEntryFileOffset = 0;\r
500\r
501 SectionHeaderOffset = (UINTN)(\r
502 ImageContext->PeCoffHeaderOffset +\r
503 sizeof (UINT32) + \r
504 sizeof (EFI_IMAGE_FILE_HEADER) + \r
505 Hdr.Pe32->FileHeader.SizeOfOptionalHeader\r
506 );\r
507\r
508 for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) {\r
509 //\r
510 // Read section header from file\r
511 //\r
512 Size = sizeof (EFI_IMAGE_SECTION_HEADER);\r
513 Status = ImageContext->ImageRead (\r
514 ImageContext->Handle,\r
515 SectionHeaderOffset,\r
516 &Size,\r
517 &SectionHeader\r
518 );\r
519 if (EFI_ERROR (Status)) {\r
520 ImageContext->ImageError = EFI_IMAGE_ERROR_IMAGE_READ;\r
521 return Status;\r
522 }\r
523\r
524 if (DebugDirectoryEntryRva >= SectionHeader.VirtualAddress &&\r
525 DebugDirectoryEntryRva < SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize) {\r
526\r
527 DebugDirectoryEntryFileOffset = DebugDirectoryEntryRva - SectionHeader.VirtualAddress + SectionHeader.PointerToRawData;\r
528 break;\r
529 }\r
530\r
531 SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);\r
532 }\r
533\r
534 if (DebugDirectoryEntryFileOffset != 0) {\r
535 for (Index = 0; Index < DebugDirectoryEntry->Size; Index++) {\r
536 //\r
537 // Read next debug directory entry\r
538 //\r
539 Size = sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);\r
540 Status = ImageContext->ImageRead (\r
541 ImageContext->Handle,\r
542 DebugDirectoryEntryFileOffset,\r
543 &Size,\r
544 &DebugEntry\r
545 );\r
546 if (EFI_ERROR (Status)) {\r
547 ImageContext->ImageError = EFI_IMAGE_ERROR_IMAGE_READ;\r
548 return Status;\r
549 }\r
550\r
551 if (DebugEntry.Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) {\r
552 ImageContext->DebugDirectoryEntryRva = (UINT32) (DebugDirectoryEntryRva + Index * sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY));\r
553 if (DebugEntry.RVA == 0 && DebugEntry.FileOffset != 0) {\r
554 ImageContext->ImageSize += DebugEntry.SizeOfData;\r
555 }\r
556\r
557 return EFI_SUCCESS;\r
558 }\r
559 }\r
560 }\r
561 }\r
562 } else {\r
563 //\r
564 // Because Te image only extracts base relocations and debug directory entries from\r
565 // Pe image and in Te image header there is not a field to describe the imagesize,\r
566 // we use the largest VirtualAddress plus Size in each directory entry to describe the imagesize\r
567 //\r
3e99020d
LG
568 ImageContext->ImageSize = (UINT64) (Hdr.Te->DataDirectory[0].VirtualAddress + Hdr.Te->DataDirectory[0].Size);\r
569 if(Hdr.Te->DataDirectory[1].VirtualAddress > Hdr.Te->DataDirectory[0].VirtualAddress) {\r
570 ImageContext->ImageSize = (UINT64) (Hdr.Te->DataDirectory[1].VirtualAddress + Hdr.Te->DataDirectory[1].Size);\r
571 }\r
3eb9473e 572 ImageContext->SectionAlignment = 4096;\r
573 ImageContext->SizeOfHeaders = sizeof (EFI_TE_IMAGE_HEADER) + (UINTN) Hdr.Te->BaseOfCode - (UINTN) Hdr.Te->StrippedSize;\r
574\r
575 DebugDirectoryEntry = &Hdr.Te->DataDirectory[1];\r
576 DebugDirectoryEntryRva = DebugDirectoryEntry->VirtualAddress;\r
577 SectionHeaderOffset = (UINTN)(sizeof (EFI_TE_IMAGE_HEADER));\r
578\r
579 DebugDirectoryEntryFileOffset = 0;\r
580\r
581 for (Index = 0; Index < Hdr.Te->NumberOfSections; Index++) {\r
582 //\r
583 // Read section header from file\r
584 //\r
585 Size = sizeof (EFI_IMAGE_SECTION_HEADER);\r
586 Status = ImageContext->ImageRead (\r
587 ImageContext->Handle,\r
588 SectionHeaderOffset,\r
589 &Size,\r
590 &SectionHeader\r
591 );\r
592 if (EFI_ERROR (Status)) {\r
593 ImageContext->ImageError = EFI_IMAGE_ERROR_IMAGE_READ;\r
594 return Status;\r
595 }\r
596\r
597 if (DebugDirectoryEntryRva >= SectionHeader.VirtualAddress &&\r
598 DebugDirectoryEntryRva < SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize) {\r
599 DebugDirectoryEntryFileOffset = DebugDirectoryEntryRva -\r
600 SectionHeader.VirtualAddress +\r
601 SectionHeader.PointerToRawData +\r
602 sizeof (EFI_TE_IMAGE_HEADER) -\r
603 Hdr.Te->StrippedSize;\r
604 break;\r
605 }\r
606\r
607 SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);\r
608 }\r
609\r
610 if (DebugDirectoryEntryFileOffset != 0) {\r
611 for (Index = 0; Index < DebugDirectoryEntry->Size; Index++) {\r
612 //\r
613 // Read next debug directory entry\r
614 //\r
615 Size = sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);\r
616 Status = ImageContext->ImageRead (\r
617 ImageContext->Handle,\r
618 DebugDirectoryEntryFileOffset,\r
619 &Size,\r
620 &DebugEntry\r
621 );\r
622 if (EFI_ERROR (Status)) {\r
623 ImageContext->ImageError = EFI_IMAGE_ERROR_IMAGE_READ;\r
624 return Status;\r
625 }\r
626\r
627 if (DebugEntry.Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) {\r
628 ImageContext->DebugDirectoryEntryRva = (UINT32) (DebugDirectoryEntryRva + Index * sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY));\r
629 return EFI_SUCCESS;\r
630 }\r
631 }\r
632 }\r
633 }\r
634\r
635 return EFI_SUCCESS;\r
636}\r
637\r
638STATIC\r
639VOID *\r
640PeCoffLoaderImageAddress (\r
641 IN OUT EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,\r
642 IN UINTN Address\r
643 )\r
644/*++\r
645\r
646Routine Description:\r
647\r
648 Converts an image address to the loaded address\r
649\r
650Arguments:\r
651\r
652 ImageContext - The context of the image being loaded\r
653\r
654 Address - The address to be converted to the loaded address\r
655\r
656Returns:\r
657\r
658 NULL if the address can not be converted, otherwise, the converted address\r
659\r
660--*/\r
661{\r
662 if (Address >= ImageContext->ImageSize) {\r
663 ImageContext->ImageError = EFI_IMAGE_ERROR_INVALID_IMAGE_ADDRESS;\r
664 return NULL;\r
665 }\r
666\r
667 return (CHAR8 *) ((UINTN) ImageContext->ImageAddress + Address);\r
668}\r
669\r
670EFI_STATUS\r
671EFIAPI\r
672PeCoffLoaderRelocateImage (\r
673 IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *This,\r
674 IN OUT EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext\r
675 )\r
676/*++\r
677\r
678Routine Description:\r
679\r
680 Relocates a PE/COFF image in memory\r
681\r
682Arguments:\r
683\r
684 This - Calling context\r
685\r
686 ImageContext - Contains information on the loaded image to relocate\r
687\r
688Returns:\r
689\r
690 EFI_SUCCESS if the PE/COFF image was relocated\r
691 EFI_LOAD_ERROR if the image is not a valid PE/COFF image\r
692 EFI_UNSUPPORTED not support\r
693\r
694--*/\r
695{\r
696 EFI_STATUS Status;\r
697 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;\r
698 EFI_IMAGE_DATA_DIRECTORY *RelocDir;\r
699 UINT64 Adjust;\r
700 EFI_IMAGE_BASE_RELOCATION *RelocBase;\r
701 EFI_IMAGE_BASE_RELOCATION *RelocBaseEnd;\r
702 UINT16 *Reloc;\r
703 UINT16 *RelocEnd;\r
704 CHAR8 *Fixup;\r
705 CHAR8 *FixupBase;\r
706 UINT16 *F16;\r
707 UINT32 *F32; \r
708 UINT64 *F64;\r
709 CHAR8 *FixupData;\r
710 EFI_PHYSICAL_ADDRESS BaseAddress;\r
711 UINT32 NumberOfRvaAndSizes;\r
712 UINT16 Magic;\r
713#ifdef EFI_NT_EMULATOR\r
714 VOID *DllEntryPoint;\r
715 VOID *ModHandle;\r
716\r
717 ModHandle = NULL;\r
718#endif\r
719\r
720 if (NULL == ImageContext) {\r
721 return EFI_INVALID_PARAMETER;\r
722 }\r
723\r
724 //\r
725 // Assume success\r
726 //\r
727 ImageContext->ImageError = EFI_IMAGE_ERROR_SUCCESS;\r
728\r
729 //\r
730 // If there are no relocation entries, then we are done\r
731 //\r
732 if (ImageContext->RelocationsStripped) {\r
733 return EFI_SUCCESS;\r
734 }\r
735\r
736 //\r
737 // If the destination address is not 0, use that rather than the\r
738 // image address as the relocation target.\r
739 //\r
740 if (ImageContext->DestinationAddress != 0) {\r
741 BaseAddress = ImageContext->DestinationAddress;\r
742 } else {\r
743 BaseAddress = ImageContext->ImageAddress;\r
744 }\r
745\r
746 if (!(ImageContext->IsTeImage)) {\r
747 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN)ImageContext->ImageAddress + ImageContext->PeCoffHeaderOffset);\r
748 \r
749 //\r
750 // NOTE: We use Machine to identify PE32/PE32+, instead of Magic.\r
751 // It is for backward-compatibility consideration, because\r
752 // some system will generate PE32+ image with PE32 Magic.\r
753 //\r
754 if (Hdr.Pe32->FileHeader.Machine == EFI_IMAGE_MACHINE_IA32) {\r
755 Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC;\r
756 } else if (Hdr.Pe32->FileHeader.Machine == EFI_IMAGE_MACHINE_IA64) {\r
757 Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
758 } else if (Hdr.Pe32->FileHeader.Machine == EFI_IMAGE_MACHINE_X64) {\r
759 Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
760 } else {\r
761 Magic = Hdr.Pe32->OptionalHeader.Magic;\r
762 }\r
763\r
764 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
765 //\r
766 // Use PE32 offset\r
767 //\r
768 Adjust = (UINT64)BaseAddress - Hdr.Pe32->OptionalHeader.ImageBase;\r
769 Hdr.Pe32->OptionalHeader.ImageBase = (UINT32)BaseAddress;\r
770 \r
771 NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;\r
772 RelocDir = &Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];\r
773 } else {\r
774 //\r
775 // Use PE32+ offset\r
776 //\r
777 Adjust = (UINT64) BaseAddress - Hdr.Pe32Plus->OptionalHeader.ImageBase;\r
778 Hdr.Pe32Plus->OptionalHeader.ImageBase = (UINT64)BaseAddress;\r
779\r
780 NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;\r
781 RelocDir = &Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];\r
782 }\r
783\r
784 //\r
785 // Find the relocation block\r
786 // Per the PE/COFF spec, you can't assume that a given data directory\r
787 // is present in the image. You have to check the NumberOfRvaAndSizes in\r
788 // the optional header to verify a desired directory entry is there.\r
789 //\r
790\r
4ac4deb7 791 if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC && RelocDir->Size > 0) {\r
3eb9473e 792 RelocBase = PeCoffLoaderImageAddress (ImageContext, RelocDir->VirtualAddress);\r
793 RelocBaseEnd = PeCoffLoaderImageAddress (\r
794 ImageContext,\r
795 RelocDir->VirtualAddress + RelocDir->Size - 1\r
796 );\r
4ac4deb7
LG
797 if ((RelocBase == NULL) || (RelocBaseEnd == NULL)) {\r
798 //\r
799 // If the base start or end address resolved to 0, then fail.\r
800 //\r
801 return EFI_LOAD_ERROR;\r
802 }\r
3eb9473e 803 } else {\r
804 //\r
805 // Set base and end to bypass processing below.\r
806 //\r
807 RelocBase = RelocBaseEnd = 0;\r
808 }\r
809 } else {\r
810 Hdr.Te = (EFI_TE_IMAGE_HEADER *)(UINTN)(ImageContext->ImageAddress);\r
c7f33ca4 811 Adjust = (UINT64) (BaseAddress - Hdr.Te->StrippedSize + sizeof (EFI_TE_IMAGE_HEADER) - Hdr.Te->ImageBase);\r
812 Hdr.Te->ImageBase = (UINT64) (BaseAddress - Hdr.Te->StrippedSize + sizeof (EFI_TE_IMAGE_HEADER));\r
3eb9473e 813\r
814 //\r
815 // Find the relocation block\r
816 //\r
817 RelocDir = &Hdr.Te->DataDirectory[0];\r
4ac4deb7
LG
818 if (RelocDir->Size > 0) {\r
819 RelocBase = (EFI_IMAGE_BASE_RELOCATION *)(UINTN)(\r
820 ImageContext->ImageAddress +\r
821 RelocDir->VirtualAddress +\r
822 sizeof(EFI_TE_IMAGE_HEADER) -\r
823 Hdr.Te->StrippedSize\r
824 );\r
825 RelocBaseEnd = (EFI_IMAGE_BASE_RELOCATION *) ((UINTN) RelocBase + (UINTN) RelocDir->Size - 1);\r
826 } else {\r
827 //\r
828 // Set base and end to bypass processing below.\r
829 //\r
830 RelocBase = NULL;\r
831 RelocBaseEnd = NULL;\r
832 }\r
3eb9473e 833 }\r
834 \r
835 //\r
836 // Run the relocation information and apply the fixups\r
837 //\r
838 FixupData = ImageContext->FixupData;\r
839 while (RelocBase < RelocBaseEnd) {\r
840\r
841 Reloc = (UINT16 *) ((CHAR8 *) RelocBase + sizeof (EFI_IMAGE_BASE_RELOCATION));\r
842 RelocEnd = (UINT16 *) ((CHAR8 *) RelocBase + RelocBase->SizeOfBlock);\r
843 if (!(ImageContext->IsTeImage)) {\r
844 FixupBase = PeCoffLoaderImageAddress (ImageContext, RelocBase->VirtualAddress);\r
4ac4deb7
LG
845\r
846 if (FixupBase == NULL) {\r
847 //\r
848 // If the FixupBase address resolved to 0, then fail.\r
849 //\r
850 return EFI_LOAD_ERROR;\r
851 }\r
3eb9473e 852 } else {\r
853 FixupBase = (CHAR8 *)(UINTN)(ImageContext->ImageAddress +\r
854 RelocBase->VirtualAddress +\r
855 sizeof(EFI_TE_IMAGE_HEADER) - \r
856 Hdr.Te->StrippedSize\r
857 );\r
858 }\r
859\r
860 if ((CHAR8 *) RelocEnd < (CHAR8 *) ((UINTN) ImageContext->ImageAddress) ||\r
861 (CHAR8 *) RelocEnd > (CHAR8 *)((UINTN)ImageContext->ImageAddress + \r
862 (UINTN)ImageContext->ImageSize)) {\r
863 ImageContext->ImageError = EFI_IMAGE_ERROR_FAILED_RELOCATION;\r
864 return EFI_LOAD_ERROR;\r
865 }\r
866\r
867 //\r
868 // Run this relocation record\r
869 //\r
870 while (Reloc < RelocEnd) {\r
871\r
872 Fixup = FixupBase + (*Reloc & 0xFFF);\r
873 switch ((*Reloc) >> 12) {\r
874 case EFI_IMAGE_REL_BASED_ABSOLUTE:\r
875 break;\r
876\r
877 case EFI_IMAGE_REL_BASED_HIGH:\r
878 F16 = (UINT16 *) Fixup;\r
879 *F16 = (UINT16) (*F16 + (UINT16)(((UINT32)Adjust) >> 16));\r
880 if (FixupData != NULL) {\r
881 *(UINT16 *) FixupData = *F16;\r
882 FixupData = FixupData + sizeof (UINT16);\r
883 }\r
884 break;\r
885\r
886 case EFI_IMAGE_REL_BASED_LOW:\r
887 F16 = (UINT16 *) Fixup;\r
888 *F16 = (UINT16) (*F16 + (UINT16) Adjust);\r
889 if (FixupData != NULL) {\r
890 *(UINT16 *) FixupData = *F16;\r
891 FixupData = FixupData + sizeof (UINT16);\r
892 }\r
893 break;\r
894\r
895 case EFI_IMAGE_REL_BASED_HIGHLOW:\r
896 F32 = (UINT32 *) Fixup;\r
897 *F32 = *F32 + (UINT32) Adjust;\r
898 if (FixupData != NULL) {\r
899 FixupData = ALIGN_POINTER (FixupData, sizeof (UINT32));\r
900 *(UINT32 *) FixupData = *F32;\r
901 FixupData = FixupData + sizeof (UINT32);\r
902 }\r
903 break;\r
904\r
905 case EFI_IMAGE_REL_BASED_DIR64:\r
906 //\r
907 // For X64 and IPF\r
908 //\r
909 F64 = (UINT64 *) Fixup;\r
910 *F64 = *F64 + (UINT64) Adjust;\r
911 if (FixupData != NULL) {\r
912 FixupData = ALIGN_POINTER (FixupData, sizeof(UINT64));\r
913 *(UINT64 *)(FixupData) = *F64;\r
914 FixupData = FixupData + sizeof(UINT64);\r
915 }\r
916 break;\r
917\r
918 case EFI_IMAGE_REL_BASED_HIGHADJ:\r
919 //\r
920 // Return the same EFI_UNSUPPORTED return code as\r
921 // PeCoffLoaderRelocateImageEx() returns if it does not recognize\r
922 // the relocation type.\r
923 //\r
924 ImageContext->ImageError = EFI_IMAGE_ERROR_FAILED_RELOCATION;\r
925 return EFI_UNSUPPORTED;\r
926\r
927 default:\r
928 //\r
929 // The common code does not handle some of the stranger IPF relocations\r
930 // PeCoffLoaderRelocateImageEx () addes support for these complex fixups\r
931 // on IPF and is a No-Op on other archtiectures.\r
932 //\r
933 Status = PeCoffLoaderRelocateImageEx (Reloc, Fixup, &FixupData, Adjust);\r
934 if (EFI_ERROR (Status)) {\r
935 ImageContext->ImageError = EFI_IMAGE_ERROR_FAILED_RELOCATION;\r
936 return Status;\r
937 }\r
938 }\r
939\r
940 //\r
941 // Next relocation record\r
942 //\r
943 Reloc += 1;\r
944 }\r
945\r
946 //\r
947 // Next reloc block\r
948 //\r
949 RelocBase = (EFI_IMAGE_BASE_RELOCATION *) RelocEnd;\r
950 }\r
951\r
952#ifdef EFI_NT_EMULATOR\r
953 DllEntryPoint = NULL;\r
954 ImageContext->ModHandle = NULL;\r
955 //\r
956 // Load the DLL if it's not an EBC image.\r
957 //\r
958 if ((ImageContext->PdbPointer != NULL) && \r
959 (ImageContext->Machine != EFI_IMAGE_MACHINE_EBC)) {\r
960 Status = mPeCoffLoaderWinNtLoadAsDll->Entry (\r
961 ImageContext->PdbPointer,\r
962 &DllEntryPoint,\r
963 &ModHandle\r
964 );\r
965\r
966 if (!EFI_ERROR (Status) && DllEntryPoint != NULL) {\r
967 ImageContext->EntryPoint = (EFI_PHYSICAL_ADDRESS) (UINTN) DllEntryPoint;\r
968 ImageContext->ModHandle = ModHandle;\r
969 }\r
970 }\r
971#endif\r
972\r
973 return EFI_SUCCESS;\r
974}\r
975\r
976EFI_STATUS\r
977EFIAPI\r
978PeCoffLoaderLoadImage (\r
979 IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *This,\r
980 IN OUT EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext\r
981 )\r
982/*++\r
983\r
984Routine Description:\r
985\r
986 Loads a PE/COFF image into memory\r
987\r
988Arguments:\r
989\r
990 This - Calling context\r
991\r
992 ImageContext - Contains information on image to load into memory\r
993\r
994Returns:\r
995\r
996 EFI_SUCCESS if the PE/COFF image was loaded\r
997 EFI_BUFFER_TOO_SMALL if the caller did not provide a large enough buffer\r
998 EFI_LOAD_ERROR if the image is a runtime driver with no relocations\r
999 EFI_INVALID_PARAMETER if the image address is invalid\r
1000\r
1001--*/\r
1002{\r
1003 EFI_STATUS Status;\r
1004 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;\r
1005 EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT CheckContext;\r
1006 EFI_IMAGE_SECTION_HEADER *FirstSection;\r
1007 EFI_IMAGE_SECTION_HEADER *Section;\r
1008 UINTN NumberOfSections;\r
1009 UINTN Index;\r
1010 CHAR8 *Base;\r
1011 CHAR8 *End;\r
1012 CHAR8 *MaxEnd;\r
1013 EFI_IMAGE_DATA_DIRECTORY *DirectoryEntry;\r
1014 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *DebugEntry;\r
1015 UINTN Size;\r
1016 UINT32 TempDebugEntryRva;\r
1017 UINT32 NumberOfRvaAndSizes;\r
1018 UINT16 Magic;\r
3e99020d
LG
1019#if (EFI_SPECIFICATION_VERSION >= 0x0002000A)\r
1020 EFI_IMAGE_RESOURCE_DIRECTORY *ResourceDirectory;\r
1021 EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *ResourceDirectoryEntry;\r
1022 EFI_IMAGE_RESOURCE_DIRECTORY_STRING *ResourceDirectoryString;\r
1023 EFI_IMAGE_RESOURCE_DATA_ENTRY *ResourceDataEntry;\r
1024#endif\r
3eb9473e 1025\r
1026 if (NULL == ImageContext) {\r
1027 return EFI_INVALID_PARAMETER;\r
1028 }\r
1029\r
1030 //\r
1031 // Assume success\r
1032 //\r
1033 ImageContext->ImageError = EFI_IMAGE_ERROR_SUCCESS;\r
1034\r
1035 //\r
1036 // Copy the provided context info into our local version, get what we\r
1037 // can from the original image, and then use that to make sure everything\r
1038 // is legit.\r
1039 //\r
1040 CopyMem (&CheckContext, ImageContext, sizeof (EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT));\r
1041\r
1042 Status = PeCoffLoaderGetImageInfo (This, &CheckContext);\r
1043 if (EFI_ERROR (Status)) {\r
1044 return Status;\r
1045 }\r
1046\r
1047 //\r
1048 // Make sure there is enough allocated space for the image being loaded\r
1049 //\r
1050 if (ImageContext->ImageSize < CheckContext.ImageSize) {\r
1051 ImageContext->ImageError = EFI_IMAGE_ERROR_INVALID_IMAGE_SIZE;\r
1052 return EFI_BUFFER_TOO_SMALL;\r
1053 }\r
1054 if (ImageContext->ImageAddress == 0) {\r
1055 //\r
1056 // Image cannot be loaded into 0 address.\r
1057 //\r
1058 ImageContext->ImageError = EFI_IMAGE_ERROR_INVALID_IMAGE_ADDRESS;\r
1059 return EFI_INVALID_PARAMETER;\r
1060 }\r
1061 //\r
1062 // If there's no relocations, then make sure it's not a runtime driver,\r
1063 // and that it's being loaded at the linked address.\r
1064 //\r
1065 if (CheckContext.RelocationsStripped) {\r
1066 //\r
1067 // If the image does not contain relocations and it is a runtime driver\r
1068 // then return an error.\r
1069 //\r
1070 if (CheckContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) {\r
1071 ImageContext->ImageError = EFI_IMAGE_ERROR_INVALID_SUBSYSTEM;\r
1072 return EFI_LOAD_ERROR;\r
1073 }\r
1074 //\r
1075 // If the image does not contain relocations, and the requested load address\r
1076 // is not the linked address, then return an error.\r
1077 //\r
1078 if (CheckContext.ImageAddress != ImageContext->ImageAddress) {\r
1079 ImageContext->ImageError = EFI_IMAGE_ERROR_INVALID_IMAGE_ADDRESS;\r
1080 return EFI_INVALID_PARAMETER;\r
1081 }\r
1082 }\r
1083 //\r
1084 // Make sure the allocated space has the proper section alignment\r
1085 //\r
1086 if (!(ImageContext->IsTeImage)) {\r
1087 if ((ImageContext->ImageAddress & (CheckContext.SectionAlignment - 1)) != 0) {\r
1088 ImageContext->ImageError = EFI_IMAGE_ERROR_INVALID_SECTION_ALIGNMENT;\r
1089 return EFI_INVALID_PARAMETER;\r
1090 }\r
1091 }\r
1092 //\r
1093 // Read the entire PE/COFF or TE header into memory\r
1094 //\r
1095 if (!(ImageContext->IsTeImage)) {\r
1096 Status = ImageContext->ImageRead (\r
1097 ImageContext->Handle,\r
1098 0,\r
1099 &ImageContext->SizeOfHeaders,\r
1100 (VOID *) (UINTN) ImageContext->ImageAddress\r
1101 );\r
1102\r
1103 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN)ImageContext->ImageAddress + ImageContext->PeCoffHeaderOffset);\r
1104\r
1105 FirstSection = (EFI_IMAGE_SECTION_HEADER *) (\r
1106 (UINTN)ImageContext->ImageAddress +\r
1107 ImageContext->PeCoffHeaderOffset +\r
1108 sizeof(UINT32) + \r
1109 sizeof(EFI_IMAGE_FILE_HEADER) + \r
1110 Hdr.Pe32->FileHeader.SizeOfOptionalHeader\r
1111 );\r
1112 NumberOfSections = (UINTN) (Hdr.Pe32->FileHeader.NumberOfSections);\r
1113 } else {\r
1114 Status = ImageContext->ImageRead (\r
1115 ImageContext->Handle,\r
1116 0,\r
1117 &ImageContext->SizeOfHeaders,\r
1118 (VOID *)(UINTN)ImageContext->ImageAddress\r
1119 );\r
1120\r
1121 Hdr.Te = (EFI_TE_IMAGE_HEADER *)(UINTN)(ImageContext->ImageAddress);\r
1122\r
1123 FirstSection = (EFI_IMAGE_SECTION_HEADER *) (\r
1124 (UINTN)ImageContext->ImageAddress +\r
1125 sizeof(EFI_TE_IMAGE_HEADER)\r
1126 );\r
1127 NumberOfSections = (UINTN) (Hdr.Te->NumberOfSections);\r
1128\r
1129 }\r
1130\r
1131 if (EFI_ERROR (Status)) {\r
1132 ImageContext->ImageError = EFI_IMAGE_ERROR_IMAGE_READ;\r
1133 return EFI_LOAD_ERROR;\r
1134 }\r
1135\r
1136 //\r
1137 // Load each section of the image\r
1138 //\r
1139 Section = FirstSection;\r
1140 for (Index = 0, MaxEnd = NULL; Index < NumberOfSections; Index++) {\r
1141\r
1142 //\r
1143 // Compute sections address\r
1144 //\r
1145 Base = PeCoffLoaderImageAddress (ImageContext, Section->VirtualAddress);\r
1146 End = PeCoffLoaderImageAddress (\r
1147 ImageContext,\r
1148 Section->VirtualAddress + Section->Misc.VirtualSize - 1\r
1149 );\r
1150 if (ImageContext->IsTeImage) {\r
1151 Base = (CHAR8 *)((UINTN) Base + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN)Hdr.Te->StrippedSize);\r
1152 End = (CHAR8 *)((UINTN) End + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN)Hdr.Te->StrippedSize);\r
1153 }\r
1154\r
1155 if (End > MaxEnd) {\r
1156 MaxEnd = End;\r
1157 }\r
1158 //\r
1159 // If the base start or end address resolved to 0, then fail.\r
1160 //\r
1161 if ((Base == NULL) || (End == NULL)) {\r
1162 ImageContext->ImageError = EFI_IMAGE_ERROR_SECTION_NOT_LOADED;\r
1163 return EFI_LOAD_ERROR;\r
1164 }\r
1165\r
1166 //\r
1167 // Read the section\r
1168 //\r
1169 Size = (UINTN) Section->Misc.VirtualSize;\r
1170 if ((Size == 0) || (Size > Section->SizeOfRawData)) {\r
1171 Size = (UINTN) Section->SizeOfRawData;\r
1172 }\r
1173\r
1174 if (Section->SizeOfRawData) {\r
1175 if (!(ImageContext->IsTeImage)) {\r
1176 Status = ImageContext->ImageRead (\r
1177 ImageContext->Handle,\r
1178 Section->PointerToRawData,\r
1179 &Size,\r
1180 Base\r
1181 );\r
1182 } else {\r
1183 Status = ImageContext->ImageRead (\r
1184 ImageContext->Handle,\r
1185 Section->PointerToRawData + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN)Hdr.Te->StrippedSize,\r
1186 &Size,\r
1187 Base\r
1188 );\r
1189 }\r
1190\r
1191 if (EFI_ERROR (Status)) {\r
1192 ImageContext->ImageError = EFI_IMAGE_ERROR_IMAGE_READ;\r
1193 return Status;\r
1194 }\r
1195 }\r
1196\r
1197 //\r
1198 // If raw size is less then virt size, zero fill the remaining\r
1199 //\r
1200\r
1201 if (Size < Section->Misc.VirtualSize) {\r
1202 ZeroMem (Base + Size, Section->Misc.VirtualSize - Size);\r
1203 }\r
1204\r
1205 //\r
1206 // Next Section\r
1207 //\r
1208 Section += 1;\r
1209 }\r
1210\r
1211 Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC;\r
1212\r
1213 //\r
1214 // Get image's entry point\r
1215 //\r
1216 if (!(ImageContext->IsTeImage)) {\r
1217\r
1218 //\r
1219 // NOTE: We use Machine to identify PE32/PE32+, instead of Magic.\r
1220 // It is for backward-compatibility consideration, because\r
1221 // some system will generate PE32+ image with PE32 Magic.\r
1222 //\r
1223 if (Hdr.Pe32->FileHeader.Machine == EFI_IMAGE_MACHINE_IA32) {\r
1224 Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC;\r
1225 } else if (Hdr.Pe32->FileHeader.Machine == EFI_IMAGE_MACHINE_IA64) {\r
1226 Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
1227 } else if (Hdr.Pe32->FileHeader.Machine == EFI_IMAGE_MACHINE_X64) {\r
1228 Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
1229 } else {\r
1230 Magic = Hdr.Pe32->OptionalHeader.Magic;\r
1231 }\r
1232\r
1233 //\r
1234 // Sizes of AddressOfEntryPoint are different so we need to do this safely\r
1235 //\r
1236 ImageContext->EntryPoint = (EFI_PHYSICAL_ADDRESS)(UINTN)PeCoffLoaderImageAddress (\r
1237 ImageContext,\r
1238 (UINTN)Hdr.Pe32->OptionalHeader.AddressOfEntryPoint\r
1239 );\r
1240\r
1241 } else {\r
1242 ImageContext->EntryPoint = (EFI_PHYSICAL_ADDRESS) (\r
1243 (UINTN)ImageContext->ImageAddress +\r
1244 (UINTN)Hdr.Te->AddressOfEntryPoint +\r
1245 (UINTN)sizeof(EFI_TE_IMAGE_HEADER) -\r
1246 (UINTN)Hdr.Te->StrippedSize\r
1247 );\r
1248 }\r
1249\r
1250 //\r
1251 // Determine the size of the fixup data\r
1252 //\r
1253 // Per the PE/COFF spec, you can't assume that a given data directory\r
1254 // is present in the image. You have to check the NumberOfRvaAndSizes in\r
1255 // the optional header to verify a desired directory entry is there.\r
1256 //\r
1257 if (!(ImageContext->IsTeImage)) {\r
1258 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
1259 //\r
1260 // Use PE32 offset\r
1261 //\r
1262 NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;\r
1263 DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];\r
1264 } else {\r
1265 //\r
1266 // Use PE32+ offset\r
1267 //\r
1268 NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;\r
1269 DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];\r
1270 }\r
1271 \r
1272 if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {\r
1273 ImageContext->FixupDataSize = DirectoryEntry->Size / sizeof (UINT16) * sizeof (UINTN);\r
1274 } else {\r
1275 ImageContext->FixupDataSize = 0;\r
1276 }\r
1277 } else {\r
1278 DirectoryEntry = &Hdr.Te->DataDirectory[0];\r
1279 ImageContext->FixupDataSize = DirectoryEntry->Size / sizeof (UINT16) * sizeof (UINTN);\r
1280 }\r
1281 //\r
1282 // Consumer must allocate a buffer for the relocation fixup log.\r
1283 // Only used for runtime drivers.\r
1284 //\r
1285 ImageContext->FixupData = NULL;\r
1286\r
1287 //\r
1288 // Load the Codeview info if present\r
1289 //\r
1290 if (ImageContext->DebugDirectoryEntryRva != 0) {\r
1291 if (!(ImageContext->IsTeImage)) {\r
1292 DebugEntry = PeCoffLoaderImageAddress (\r
1293 ImageContext,\r
1294 ImageContext->DebugDirectoryEntryRva\r
1295 );\r
1296 } else {\r
1297 DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *)(UINTN)(\r
1298 ImageContext->ImageAddress +\r
1299 ImageContext->DebugDirectoryEntryRva +\r
1300 sizeof(EFI_TE_IMAGE_HEADER) -\r
1301 Hdr.Te->StrippedSize\r
1302 );\r
1303 }\r
1304\r
1305 if (DebugEntry != NULL) {\r
1306 TempDebugEntryRva = DebugEntry->RVA;\r
1307 if (DebugEntry->RVA == 0 && DebugEntry->FileOffset != 0) {\r
1308 Section--;\r
1309 if ((UINTN)Section->SizeOfRawData < Section->Misc.VirtualSize) {\r
1310 TempDebugEntryRva = Section->VirtualAddress + Section->Misc.VirtualSize;\r
1311 } else {\r
1312 TempDebugEntryRva = Section->VirtualAddress + Section->SizeOfRawData;\r
1313 }\r
1314 }\r
1315\r
1316 if (TempDebugEntryRva != 0) {\r
1317 if (!(ImageContext->IsTeImage)) {\r
1318 ImageContext->CodeView = PeCoffLoaderImageAddress (ImageContext, TempDebugEntryRva);\r
1319 } else {\r
1320 ImageContext->CodeView = (VOID *)(\r
1321 (UINTN)ImageContext->ImageAddress +\r
1322 (UINTN)TempDebugEntryRva +\r
1323 (UINTN)sizeof (EFI_TE_IMAGE_HEADER) -\r
1324 (UINTN) Hdr.Te->StrippedSize\r
1325 );\r
1326 }\r
1327\r
1328 if (ImageContext->CodeView == NULL) {\r
1329 ImageContext->ImageError = EFI_IMAGE_ERROR_IMAGE_READ;\r
1330 return EFI_LOAD_ERROR;\r
1331 }\r
1332\r
1333 if (DebugEntry->RVA == 0) {\r
1334 Size = DebugEntry->SizeOfData;\r
1335 if (!(ImageContext->IsTeImage)) {\r
1336 Status = ImageContext->ImageRead (\r
1337 ImageContext->Handle,\r
1338 DebugEntry->FileOffset,\r
1339 &Size,\r
1340 ImageContext->CodeView\r
1341 );\r
1342 } else {\r
1343 Status = ImageContext->ImageRead (\r
1344 ImageContext->Handle,\r
1345 DebugEntry->FileOffset + sizeof (EFI_TE_IMAGE_HEADER) - Hdr.Te->StrippedSize,\r
1346 &Size,\r
1347 ImageContext->CodeView\r
1348 );\r
1349 //\r
1350 // Should we apply fix up to this field according to the size difference between PE and TE?\r
1351 // Because now we maintain TE header fields unfixed, this field will also remain as they are\r
1352 // in original PE image.\r
1353 //\r
1354 }\r
1355\r
1356 if (EFI_ERROR (Status)) {\r
1357 ImageContext->ImageError = EFI_IMAGE_ERROR_IMAGE_READ;\r
1358 return EFI_LOAD_ERROR;\r
1359 }\r
1360\r
1361 DebugEntry->RVA = TempDebugEntryRva;\r
1362 }\r
1363\r
1364 switch (*(UINT32 *) ImageContext->CodeView) {\r
1365 case CODEVIEW_SIGNATURE_NB10:\r
1366 ImageContext->PdbPointer = (CHAR8 *)ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY);\r
1367 break;\r
1368\r
1369 case CODEVIEW_SIGNATURE_RSDS:\r
1370 ImageContext->PdbPointer = (CHAR8 *)ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY);\r
1371 break;\r
1372\r
1373 default:\r
1374 break;\r
1375 }\r
1376 }\r
1377 }\r
1378 }\r
1379\r
3e99020d
LG
1380#if (EFI_SPECIFICATION_VERSION >= 0x0002000A)\r
1381 //\r
1382 // Get Image's HII resource section\r
1383 //\r
1384 if (!(ImageContext->IsTeImage)) {\r
1385 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
1386 //\r
1387 // Use PE32 offset\r
1388 //\r
1389 DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE];\r
1390 } else {\r
1391 //\r
1392 // Use PE32+ offset\r
1393 //\r
1394 DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE];\r
1395 }\r
1396\r
1397 if (DirectoryEntry->Size != 0) {\r
1398 Base = PeCoffLoaderImageAddress (ImageContext, DirectoryEntry->VirtualAddress);\r
1399\r
1400 ResourceDirectory = (EFI_IMAGE_RESOURCE_DIRECTORY *) Base;\r
1401 ResourceDirectoryEntry = (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *) (ResourceDirectory + 1);\r
1402\r
1403 for (Index = 0; Index < ResourceDirectory->NumberOfNamedEntries; Index++) {\r
1404 if (ResourceDirectoryEntry->u1.s.NameIsString) {\r
1405 ResourceDirectoryString = (EFI_IMAGE_RESOURCE_DIRECTORY_STRING *) (Base + ResourceDirectoryEntry->u1.s.NameOffset);\r
1406\r
1407 if (ResourceDirectoryString->Length == 3 &&\r
1408 ResourceDirectoryString->String[0] == L'H' &&\r
1409 ResourceDirectoryString->String[1] == L'I' &&\r
1410 ResourceDirectoryString->String[2] == L'I') {\r
1411 //\r
1412 // Resource Type "HII" found\r
1413 //\r
1414 if (ResourceDirectoryEntry->u2.s.DataIsDirectory) {\r
1415 //\r
1416 // Move to next level - resource Name\r
1417 //\r
1418 ResourceDirectory = (EFI_IMAGE_RESOURCE_DIRECTORY *) (Base + ResourceDirectoryEntry->u2.s.OffsetToDirectory);\r
1419 ResourceDirectoryEntry = (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *) (ResourceDirectory + 1);\r
1420\r
1421 if (ResourceDirectoryEntry->u2.s.DataIsDirectory) {\r
1422 //\r
1423 // Move to next level - resource Language\r
1424 //\r
1425 ResourceDirectory = (EFI_IMAGE_RESOURCE_DIRECTORY *) (Base + ResourceDirectoryEntry->u2.s.OffsetToDirectory);\r
1426 ResourceDirectoryEntry = (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *) (ResourceDirectory + 1);\r
1427 }\r
1428 }\r
1429\r
1430 //\r
1431 // Now it ought to be resource Data\r
1432 //\r
1433 if (!ResourceDirectoryEntry->u2.s.DataIsDirectory) {\r
1434 ResourceDataEntry = (EFI_IMAGE_RESOURCE_DATA_ENTRY *) (Base + ResourceDirectoryEntry->u2.OffsetToData);\r
1435 ImageContext->HiiResourceData = (EFI_PHYSICAL_ADDRESS) (UINTN) PeCoffLoaderImageAddress (ImageContext, ResourceDataEntry->OffsetToData);\r
1436 break;\r
1437 }\r
1438 }\r
1439 }\r
1440\r
1441 ResourceDirectoryEntry++;\r
1442 }\r
1443 }\r
1444 }\r
1445#endif\r
1446\r
3eb9473e 1447#if defined (EFI_DEBUG_ITP_BREAK) && !defined (_CONSOLE)\r
1448 AsmEfiSetBreakSupport ((UINTN)(ImageContext->ImageAddress));\r
1449#endif\r
1450\r
1451 return Status;\r
1452}\r
1453\r
1454EFI_STATUS\r
1455EFIAPI\r
1456PeCoffLoaderUnloadImage (\r
3e99020d 1457 IN EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext\r
3eb9473e 1458 )\r
1459/*++\r
1460\r
1461Routine Description:\r
1462\r
1463 Unload a PE/COFF image from memory\r
1464\r
1465Arguments:\r
1466\r
1467 ImageContext - Contains information on image to load into memory\r
1468\r
1469Returns:\r
1470\r
1471 EFI_SUCCESS \r
1472\r
1473--*/\r
1474{\r
1475#ifdef EFI_NT_EMULATOR\r
1476 //\r
1477 // Calling Win32 API free library\r
1478 //\r
1479 mPeCoffLoaderWinNtLoadAsDll->FreeLibrary (ImageContext->ModHandle);\r
1480\r
1481#endif\r
1482\r
1483 return EFI_SUCCESS;\r
1484}\r