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