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