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