]> git.proxmox.com Git - mirror_edk2.git/blame - BaseTools/Source/C/Common/BasePeCoff.c
Sync BaseTools Trunk (version r2387) to EDKII main trunk.
[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
9053bc51 5Copyright (c) 2004 - 2010, Intel Corporation. All rights reserved.<BR>\r
40d841f6 6This program and the accompanying materials \r
30fdf114
LG
7are licensed and made available under the terms and conditions of the BSD License \r
8which accompanies this distribution. The full text of the license may be found at \r
9http://opensource.org/licenses/bsd-license.php \r
10 \r
11THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
12WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
13\r
14**/\r
15\r
16#include <Common/UefiBaseTypes.h>\r
17#include <CommonLib.h>\r
18#include <IndustryStandard/PeImage.h>\r
19#include "PeCoffLib.h"\r
20\r
21typedef union {\r
22 VOID *Header; \r
23 EFI_IMAGE_OPTIONAL_HEADER32 *Optional32;\r
24 EFI_IMAGE_OPTIONAL_HEADER64 *Optional64;\r
25} EFI_IMAGE_OPTIONAL_HEADER_POINTER;\r
26\r
27STATIC\r
28RETURN_STATUS\r
29PeCoffLoaderGetPeHeader (\r
30 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,\r
31 OUT EFI_IMAGE_OPTIONAL_HEADER_UNION **PeHdr,\r
32 OUT EFI_TE_IMAGE_HEADER **TeHdr\r
33 );\r
34\r
35STATIC\r
36RETURN_STATUS\r
37PeCoffLoaderCheckImageType (\r
38 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,\r
39 IN EFI_IMAGE_OPTIONAL_HEADER_UNION *PeHdr,\r
40 IN EFI_TE_IMAGE_HEADER *TeHdr\r
41 );\r
42\r
43STATIC\r
44VOID *\r
45PeCoffLoaderImageAddress (\r
46 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,\r
47 IN UINTN Address\r
48 );\r
49\r
50RETURN_STATUS\r
51PeCoffLoaderRelocateIa32Image (\r
52 IN UINT16 *Reloc,\r
53 IN OUT CHAR8 *Fixup,\r
54 IN OUT CHAR8 **FixupData,\r
55 IN UINT64 Adjust\r
56 );\r
57\r
58RETURN_STATUS\r
59PeCoffLoaderRelocateX64Image (\r
60 IN UINT16 *Reloc,\r
61 IN OUT CHAR8 *Fixup,\r
62 IN OUT CHAR8 **FixupData,\r
63 IN UINT64 Adjust\r
64 );\r
65\r
66RETURN_STATUS\r
67PeCoffLoaderRelocateIpfImage (\r
68 IN UINT16 *Reloc,\r
69 IN OUT CHAR8 *Fixup,\r
70 IN OUT CHAR8 **FixupData,\r
71 IN UINT64 Adjust\r
72 );\r
73\r
40d841f6
LG
74RETURN_STATUS\r
75PeCoffLoaderRelocateArmImage (\r
76 IN UINT16 **Reloc,\r
77 IN OUT CHAR8 *Fixup,\r
78 IN OUT CHAR8 **FixupData,\r
79 IN UINT64 Adjust\r
80 );\r
81\r
30fdf114
LG
82STATIC\r
83RETURN_STATUS\r
84PeCoffLoaderGetPeHeader (\r
85 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,\r
86 OUT EFI_IMAGE_OPTIONAL_HEADER_UNION **PeHdr,\r
87 OUT EFI_TE_IMAGE_HEADER **TeHdr\r
88 )\r
89/*++\r
90\r
91Routine Description:\r
92\r
93 Retrieves the PE or TE Header from a PE/COFF or TE image\r
94\r
95Arguments:\r
96\r
97 ImageContext - The context of the image being loaded\r
98\r
99 PeHdr - The buffer in which to return the PE header\r
100 \r
101 TeHdr - The buffer in which to return the TE header\r
102\r
103Returns:\r
104\r
105 RETURN_SUCCESS if the PE or TE Header is read, \r
106 Otherwise, the error status from reading the PE/COFF or TE image using the ImageRead function.\r
107\r
108--*/\r
109{\r
110 RETURN_STATUS Status;\r
111 EFI_IMAGE_DOS_HEADER DosHdr;\r
112 UINTN Size;\r
113\r
114 ImageContext->IsTeImage = FALSE;\r
115 //\r
116 // Read the DOS image headers\r
117 //\r
118 Size = sizeof (EFI_IMAGE_DOS_HEADER);\r
119 Status = ImageContext->ImageRead (\r
120 ImageContext->Handle,\r
121 0,\r
122 &Size,\r
123 &DosHdr\r
124 );\r
125 if (RETURN_ERROR (Status)) {\r
126 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
127 return Status;\r
128 }\r
129\r
130 ImageContext->PeCoffHeaderOffset = 0;\r
131 if (DosHdr.e_magic == EFI_IMAGE_DOS_SIGNATURE) {\r
132 //\r
133 // DOS image header is present, so read the PE header after the DOS image header\r
134 //\r
135 ImageContext->PeCoffHeaderOffset = DosHdr.e_lfanew;\r
136 }\r
137 //\r
138 // Get the PE/COFF Header pointer\r
139 //\r
140 *PeHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *) ((UINTN)ImageContext->Handle + ImageContext->PeCoffHeaderOffset);\r
141 if ((*PeHdr)->Pe32.Signature != EFI_IMAGE_NT_SIGNATURE) {\r
142 //\r
143 // Check the PE/COFF Header Signature. If not, then try to get a TE header\r
144 //\r
145 *TeHdr = (EFI_TE_IMAGE_HEADER *)*PeHdr; \r
146 if ((*TeHdr)->Signature != EFI_TE_IMAGE_HEADER_SIGNATURE) {\r
147 return RETURN_UNSUPPORTED;\r
148 }\r
149 ImageContext->IsTeImage = TRUE;\r
150 }\r
151\r
152 return RETURN_SUCCESS;\r
153}\r
154\r
155STATIC\r
156RETURN_STATUS\r
157PeCoffLoaderCheckImageType (\r
158 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,\r
159 IN EFI_IMAGE_OPTIONAL_HEADER_UNION *PeHdr,\r
160 IN EFI_TE_IMAGE_HEADER *TeHdr\r
161 )\r
162/*++\r
163\r
164Routine Description:\r
165\r
166 Checks the PE or TE header of a PE/COFF or TE image to determine if it supported\r
167\r
168Arguments:\r
169\r
170 ImageContext - The context of the image being loaded\r
171\r
172 PeHdr - The buffer in which to return the PE header\r
173 \r
174 TeHdr - The buffer in which to return the TE header\r
175\r
176Returns:\r
177\r
178 RETURN_SUCCESS if the PE/COFF or TE image is supported\r
179 RETURN_UNSUPPORTED of the PE/COFF or TE image is not supported.\r
180\r
181--*/\r
182{\r
183 //\r
184 // See if the machine type is supported. \r
185 // We support a native machine type (IA-32/Itanium-based)\r
186 //\r
187 if (ImageContext->IsTeImage == FALSE) {\r
188 ImageContext->Machine = PeHdr->Pe32.FileHeader.Machine;\r
189 } else {\r
190 ImageContext->Machine = TeHdr->Machine;\r
191 }\r
192 \r
193 if (ImageContext->Machine != EFI_IMAGE_MACHINE_IA32 && \\r
194 ImageContext->Machine != EFI_IMAGE_MACHINE_IA64 && \\r
195 ImageContext->Machine != EFI_IMAGE_MACHINE_X64 && \\r
196 ImageContext->Machine != EFI_IMAGE_MACHINE_ARMT && \\r
197 ImageContext->Machine != EFI_IMAGE_MACHINE_EBC) {\r
198 if (ImageContext->Machine == IMAGE_FILE_MACHINE_ARM) {\r
199 //\r
200 // There are two types of ARM images. Pure ARM and ARM/Thumb. \r
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
213 // unsupported PeImage machine type \r
214 // \r
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
234 // upsupported PeImage subsystem type \r
235 // \r
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
345 } else if ((ImageContext->IsTeImage) && (TeHdr->DataDirectory[0].Size == 0)) {\r
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
357 \r
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
370 \r
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
380 \r
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
391 sizeof (UINT32) + \r
392 sizeof (EFI_IMAGE_FILE_HEADER) + \r
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
422 if (DebugDirectoryEntryFileOffset != 0) { \r
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
427 Size = sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY); \r
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
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
500 // a mulitple of Section Alignment). Per the PE/COFF specification, the\r
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
612 CHAR8 *FixupData;\r
613 PHYSICAL_ADDRESS BaseAddress;\r
614 UINT16 MachineType;\r
615 EFI_IMAGE_OPTIONAL_HEADER_POINTER OptionHeader;\r
616\r
617 PeHdr = NULL;\r
618 TeHdr = NULL;\r
619 //\r
620 // Assume success\r
621 //\r
622 ImageContext->ImageError = IMAGE_ERROR_SUCCESS;\r
623\r
624 //\r
625 // If there are no relocation entries, then we are done\r
626 //\r
627 if (ImageContext->RelocationsStripped) {\r
628 return RETURN_SUCCESS;\r
629 }\r
630\r
631 //\r
9053bc51 632 // Use DestinationAddress field of ImageContext as the relocation address even if it is 0.\r
30fdf114 633 //\r
9053bc51 634 BaseAddress = ImageContext->DestinationAddress;\r
635 \r
30fdf114
LG
636 if (!(ImageContext->IsTeImage)) {\r
637 PeHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((UINTN)ImageContext->ImageAddress + \r
638 ImageContext->PeCoffHeaderOffset);\r
639 OptionHeader.Header = (VOID *) &(PeHdr->Pe32.OptionalHeader);\r
640 if (PeHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
641 Adjust = (UINT64) BaseAddress - OptionHeader.Optional32->ImageBase;\r
642 OptionHeader.Optional32->ImageBase = (UINT32) BaseAddress;\r
643 MachineType = ImageContext->Machine;\r
644 //\r
645 // Find the relocation block\r
646 //\r
647 // Per the PE/COFF spec, you can't assume that a given data directory\r
648 // is present in the image. You have to check the NumberOfRvaAndSizes in\r
649 // the optional header to verify a desired directory entry is there.\r
650 //\r
651 if (OptionHeader.Optional32->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {\r
652 RelocDir = &OptionHeader.Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];\r
653 RelocBase = PeCoffLoaderImageAddress (ImageContext, RelocDir->VirtualAddress);\r
654 RelocBaseEnd = PeCoffLoaderImageAddress (\r
655 ImageContext,\r
656 RelocDir->VirtualAddress + RelocDir->Size - 1\r
657 );\r
658 } else {\r
659 //\r
660 // Set base and end to bypass processing below.\r
661 //\r
662 RelocBase = RelocBaseEnd = 0;\r
663 }\r
664 } else {\r
665 Adjust = (UINT64) BaseAddress - OptionHeader.Optional64->ImageBase;\r
666 OptionHeader.Optional64->ImageBase = BaseAddress;\r
667 MachineType = ImageContext->Machine;\r
668 //\r
669 // Find the relocation block\r
670 //\r
671 // Per the PE/COFF spec, you can't assume that a given data directory\r
672 // is present in the image. You have to check the NumberOfRvaAndSizes in\r
673 // the optional header to verify a desired directory entry is there.\r
674 //\r
675 if (OptionHeader.Optional64->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {\r
676 RelocDir = &OptionHeader.Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];\r
677 RelocBase = PeCoffLoaderImageAddress (ImageContext, RelocDir->VirtualAddress);\r
678 RelocBaseEnd = PeCoffLoaderImageAddress (\r
679 ImageContext,\r
680 RelocDir->VirtualAddress + RelocDir->Size - 1\r
681 );\r
682 } else {\r
683 //\r
684 // Set base and end to bypass processing below.\r
685 //\r
686 RelocBase = RelocBaseEnd = 0;\r
687 }\r
688 }\r
689 } else {\r
690 TeHdr = (EFI_TE_IMAGE_HEADER *) (UINTN) (ImageContext->ImageAddress);\r
691 Adjust = (UINT64) (BaseAddress - TeHdr->ImageBase);\r
692 TeHdr->ImageBase = (UINT64) (BaseAddress);\r
693 MachineType = TeHdr->Machine;\r
694 \r
695 //\r
696 // Find the relocation block\r
697 //\r
698 RelocDir = &TeHdr->DataDirectory[0];\r
699 RelocBase = (EFI_IMAGE_BASE_RELOCATION *)(UINTN)(\r
700 ImageContext->ImageAddress + \r
701 RelocDir->VirtualAddress +\r
702 sizeof(EFI_TE_IMAGE_HEADER) - \r
703 TeHdr->StrippedSize\r
704 );\r
705 RelocBaseEnd = (EFI_IMAGE_BASE_RELOCATION *) ((UINTN) RelocBase + (UINTN) RelocDir->Size - 1);\r
706 }\r
707 \r
708 //\r
709 // Run the relocation information and apply the fixups\r
710 //\r
711 FixupData = ImageContext->FixupData;\r
712 while (RelocBase < RelocBaseEnd) {\r
713\r
714 Reloc = (UINT16 *) ((CHAR8 *) RelocBase + sizeof (EFI_IMAGE_BASE_RELOCATION));\r
715 RelocEnd = (UINT16 *) ((CHAR8 *) RelocBase + RelocBase->SizeOfBlock);\r
716 if (!(ImageContext->IsTeImage)) {\r
717 FixupBase = PeCoffLoaderImageAddress (ImageContext, RelocBase->VirtualAddress);\r
718 } else {\r
719 FixupBase = (CHAR8 *)(UINTN)(ImageContext->ImageAddress +\r
720 RelocBase->VirtualAddress +\r
721 sizeof(EFI_TE_IMAGE_HEADER) - \r
722 TeHdr->StrippedSize\r
723 );\r
724 }\r
725\r
726 if ((CHAR8 *) RelocEnd < (CHAR8 *) ((UINTN) ImageContext->ImageAddress) ||\r
727 (CHAR8 *) RelocEnd > (CHAR8 *)((UINTN)ImageContext->ImageAddress + \r
728 (UINTN)ImageContext->ImageSize)) {\r
729 ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;\r
730 return RETURN_LOAD_ERROR;\r
731 }\r
732\r
733 //\r
734 // Run this relocation record\r
735 //\r
736 while (Reloc < RelocEnd) {\r
737\r
738 Fixup = FixupBase + (*Reloc & 0xFFF);\r
739 switch ((*Reloc) >> 12) {\r
740 case EFI_IMAGE_REL_BASED_ABSOLUTE:\r
741 break;\r
742\r
743 case EFI_IMAGE_REL_BASED_HIGH:\r
744 F16 = (UINT16 *) Fixup;\r
745 *F16 = (UINT16) (*F16 + ((UINT16) ((UINT32) Adjust >> 16)));\r
746 if (FixupData != NULL) {\r
747 *(UINT16 *) FixupData = *F16;\r
748 FixupData = FixupData + sizeof (UINT16);\r
749 }\r
750 break;\r
751\r
752 case EFI_IMAGE_REL_BASED_LOW:\r
753 F16 = (UINT16 *) Fixup;\r
754 *F16 = (UINT16) (*F16 + (UINT16) Adjust);\r
755 if (FixupData != NULL) {\r
756 *(UINT16 *) FixupData = *F16;\r
757 FixupData = FixupData + sizeof (UINT16);\r
758 }\r
759 break;\r
760\r
761 case EFI_IMAGE_REL_BASED_HIGHLOW:\r
762 F32 = (UINT32 *) Fixup;\r
763 *F32 = *F32 + (UINT32) Adjust;\r
764 if (FixupData != NULL) {\r
765 FixupData = ALIGN_POINTER (FixupData, sizeof (UINT32));\r
766 *(UINT32 *) FixupData = *F32;\r
767 FixupData = FixupData + sizeof (UINT32);\r
768 }\r
769 break;\r
770\r
771 case EFI_IMAGE_REL_BASED_HIGHADJ:\r
772 //\r
773 // Return the same EFI_UNSUPPORTED return code as\r
774 // PeCoffLoaderRelocateImageEx() returns if it does not recognize\r
775 // the relocation type.\r
776 //\r
777 ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;\r
778 return RETURN_UNSUPPORTED;\r
779\r
780 default:\r
781 switch (MachineType) {\r
782 case EFI_IMAGE_MACHINE_IA32:\r
30fdf114
LG
783 Status = PeCoffLoaderRelocateIa32Image (Reloc, Fixup, &FixupData, Adjust);\r
784 break;\r
40d841f6
LG
785 case EFI_IMAGE_MACHINE_ARMT:\r
786 Status = PeCoffLoaderRelocateArmImage (&Reloc, Fixup, &FixupData, Adjust);\r
787 break;\r
30fdf114
LG
788 case EFI_IMAGE_MACHINE_X64:\r
789 Status = PeCoffLoaderRelocateX64Image (Reloc, Fixup, &FixupData, Adjust);\r
790 break;\r
791 case EFI_IMAGE_MACHINE_IA64:\r
792 Status = PeCoffLoaderRelocateIpfImage (Reloc, Fixup, &FixupData, Adjust);\r
793 break;\r
794 default:\r
795 Status = RETURN_UNSUPPORTED;\r
796 break;\r
797 }\r
798 if (RETURN_ERROR (Status)) {\r
799 ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;\r
800 return Status;\r
801 }\r
802 }\r
803\r
804 //\r
805 // Next relocation record\r
806 //\r
807 Reloc += 1;\r
808 }\r
809\r
810 //\r
811 // Next reloc block\r
812 //\r
813 RelocBase = (EFI_IMAGE_BASE_RELOCATION *) RelocEnd;\r
814 }\r
815\r
816 return RETURN_SUCCESS;\r
817}\r
818\r
819RETURN_STATUS\r
820EFIAPI\r
821PeCoffLoaderLoadImage (\r
822 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext\r
823 )\r
824/*++\r
825\r
826Routine Description:\r
827\r
828 Loads a PE/COFF image into memory\r
829\r
830Arguments:\r
831\r
832 This - Calling context\r
833\r
834 ImageContext - Contains information on image to load into memory\r
835\r
836Returns:\r
837\r
838 RETURN_SUCCESS if the PE/COFF image was loaded\r
839 RETURN_BUFFER_TOO_SMALL if the caller did not provide a large enough buffer\r
840 RETURN_LOAD_ERROR if the image is a runtime driver with no relocations\r
841 RETURN_INVALID_PARAMETER if the image address is invalid\r
842\r
843--*/\r
844{\r
845 RETURN_STATUS Status;\r
846 EFI_IMAGE_OPTIONAL_HEADER_UNION *PeHdr;\r
847 EFI_TE_IMAGE_HEADER *TeHdr;\r
848 PE_COFF_LOADER_IMAGE_CONTEXT CheckContext;\r
849 EFI_IMAGE_SECTION_HEADER *FirstSection;\r
850 EFI_IMAGE_SECTION_HEADER *Section;\r
851 UINTN NumberOfSections;\r
852 UINTN Index;\r
853 CHAR8 *Base;\r
854 CHAR8 *End;\r
855 CHAR8 *MaxEnd;\r
856 EFI_IMAGE_DATA_DIRECTORY *DirectoryEntry;\r
857 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *DebugEntry;\r
858 UINTN Size;\r
859 UINT32 TempDebugEntryRva;\r
860 EFI_IMAGE_OPTIONAL_HEADER_POINTER OptionHeader;\r
861\r
862 PeHdr = NULL;\r
863 TeHdr = NULL;\r
fd171542 864 OptionHeader.Header = NULL;\r
30fdf114
LG
865 //\r
866 // Assume success\r
867 //\r
868 ImageContext->ImageError = IMAGE_ERROR_SUCCESS;\r
869\r
870 //\r
871 // Copy the provided context info into our local version, get what we\r
872 // can from the original image, and then use that to make sure everything\r
873 // is legit.\r
874 //\r
875 CopyMem (&CheckContext, ImageContext, sizeof (PE_COFF_LOADER_IMAGE_CONTEXT));\r
876\r
877 Status = PeCoffLoaderGetImageInfo (&CheckContext);\r
878 if (RETURN_ERROR (Status)) {\r
879 return Status;\r
880 }\r
881\r
882 //\r
883 // Make sure there is enough allocated space for the image being loaded\r
884 //\r
885 if (ImageContext->ImageSize < CheckContext.ImageSize) {\r
886 ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_SIZE;\r
887 return RETURN_BUFFER_TOO_SMALL;\r
888 }\r
889\r
890 //\r
891 // If there's no relocations, then make sure it's not a runtime driver,\r
892 // and that it's being loaded at the linked address.\r
893 //\r
894 if (CheckContext.RelocationsStripped) {\r
895 //\r
896 // If the image does not contain relocations and it is a runtime driver\r
897 // then return an error.\r
898 //\r
899 if (CheckContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) {\r
900 ImageContext->ImageError = IMAGE_ERROR_INVALID_SUBSYSTEM;\r
901 return RETURN_LOAD_ERROR;\r
902 }\r
903 //\r
904 // If the image does not contain relocations, and the requested load address\r
905 // is not the linked address, then return an error.\r
906 //\r
907 if (CheckContext.ImageAddress != ImageContext->ImageAddress) {\r
908 ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_ADDRESS;\r
909 return RETURN_INVALID_PARAMETER;\r
910 }\r
911 }\r
912 //\r
913 // Make sure the allocated space has the proper section alignment\r
914 //\r
915 if (!(ImageContext->IsTeImage)) {\r
916 if ((ImageContext->ImageAddress & (CheckContext.SectionAlignment - 1)) != 0) {\r
917 ImageContext->ImageError = IMAGE_ERROR_INVALID_SECTION_ALIGNMENT;\r
918 return RETURN_INVALID_PARAMETER;\r
919 }\r
920 }\r
921 //\r
922 // Read the entire PE/COFF or TE header into memory\r
923 //\r
924 if (!(ImageContext->IsTeImage)) {\r
925 Status = ImageContext->ImageRead (\r
926 ImageContext->Handle,\r
927 0,\r
928 &ImageContext->SizeOfHeaders,\r
929 (VOID *) (UINTN) ImageContext->ImageAddress\r
930 );\r
931\r
932 PeHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)\r
933 ((UINTN)ImageContext->ImageAddress + ImageContext->PeCoffHeaderOffset);\r
934\r
935 OptionHeader.Header = (VOID *) &(PeHdr->Pe32.OptionalHeader);\r
936 \r
937 FirstSection = (EFI_IMAGE_SECTION_HEADER *) (\r
938 (UINTN)ImageContext->ImageAddress +\r
939 ImageContext->PeCoffHeaderOffset +\r
940 sizeof(UINT32) + \r
941 sizeof(EFI_IMAGE_FILE_HEADER) + \r
942 PeHdr->Pe32.FileHeader.SizeOfOptionalHeader\r
943 );\r
944 NumberOfSections = (UINTN) (PeHdr->Pe32.FileHeader.NumberOfSections);\r
945 } else {\r
946 Status = ImageContext->ImageRead (\r
947 ImageContext->Handle,\r
948 0,\r
949 &ImageContext->SizeOfHeaders,\r
950 (VOID *) (UINTN) ImageContext->ImageAddress\r
951 );\r
952\r
953 TeHdr = (EFI_TE_IMAGE_HEADER *) (UINTN) (ImageContext->ImageAddress);\r
954\r
955 FirstSection = (EFI_IMAGE_SECTION_HEADER *) (\r
956 (UINTN)ImageContext->ImageAddress +\r
957 sizeof(EFI_TE_IMAGE_HEADER)\r
958 );\r
959 NumberOfSections = (UINTN) (TeHdr->NumberOfSections);\r
960\r
961 }\r
962\r
963 if (RETURN_ERROR (Status)) {\r
964 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
965 return RETURN_LOAD_ERROR;\r
966 }\r
967\r
968 //\r
969 // Load each section of the image\r
970 //\r
971 Section = FirstSection;\r
972 for (Index = 0, MaxEnd = NULL; Index < NumberOfSections; Index++) {\r
973\r
974 //\r
975 // Compute sections address\r
976 //\r
977 Base = PeCoffLoaderImageAddress (ImageContext, Section->VirtualAddress);\r
978 End = PeCoffLoaderImageAddress (\r
979 ImageContext,\r
980 Section->VirtualAddress + Section->Misc.VirtualSize - 1\r
981 );\r
0d2711a6 982\r
b36d134f
LG
983 //\r
984 // If the base start or end address resolved to 0, then fail.\r
985 //\r
986 if ((Base == NULL) || (End == NULL)) {\r
987 ImageContext->ImageError = IMAGE_ERROR_SECTION_NOT_LOADED;\r
988 return RETURN_LOAD_ERROR;\r
989 }\r
990\r
0d2711a6 991 \r
30fdf114
LG
992 if (ImageContext->IsTeImage) {\r
993 Base = (CHAR8 *) ((UINTN) Base + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN) TeHdr->StrippedSize);\r
994 End = (CHAR8 *) ((UINTN) End + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN) TeHdr->StrippedSize);\r
995 }\r
996\r
997 if (End > MaxEnd) {\r
998 MaxEnd = End;\r
999 }\r
30fdf114
LG
1000\r
1001 //\r
1002 // Read the section\r
1003 //\r
1004 Size = (UINTN) Section->Misc.VirtualSize;\r
1005 if ((Size == 0) || (Size > Section->SizeOfRawData)) {\r
1006 Size = (UINTN) Section->SizeOfRawData;\r
1007 }\r
1008\r
1009 if (Section->SizeOfRawData) {\r
1010 if (!(ImageContext->IsTeImage)) {\r
1011 Status = ImageContext->ImageRead (\r
1012 ImageContext->Handle,\r
1013 Section->PointerToRawData,\r
1014 &Size,\r
1015 Base\r
1016 );\r
1017 } else {\r
1018 Status = ImageContext->ImageRead (\r
1019 ImageContext->Handle,\r
1020 Section->PointerToRawData + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN) TeHdr->StrippedSize,\r
1021 &Size,\r
1022 Base\r
1023 );\r
1024 }\r
1025\r
1026 if (RETURN_ERROR (Status)) {\r
1027 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
1028 return Status;\r
1029 }\r
1030 }\r
1031\r
1032 //\r
1033 // If raw size is less then virt size, zero fill the remaining\r
1034 //\r
1035\r
1036 if (Size < Section->Misc.VirtualSize) {\r
1037 ZeroMem (Base + Size, Section->Misc.VirtualSize - Size);\r
1038 }\r
1039\r
1040 //\r
1041 // Next Section\r
1042 //\r
1043 Section += 1;\r
1044 }\r
1045\r
1046 //\r
1047 // Get image's entry point\r
1048 //\r
1049 if (!(ImageContext->IsTeImage)) {\r
1050 ImageContext->EntryPoint = (PHYSICAL_ADDRESS) (UINTN) PeCoffLoaderImageAddress (\r
1051 ImageContext,\r
1052 PeHdr->Pe32.OptionalHeader.AddressOfEntryPoint\r
1053 );\r
1054 } else {\r
1055 ImageContext->EntryPoint = (PHYSICAL_ADDRESS) (\r
1056 (UINTN)ImageContext->ImageAddress +\r
1057 (UINTN)TeHdr->AddressOfEntryPoint +\r
1058 (UINTN)sizeof(EFI_TE_IMAGE_HEADER) -\r
1059 (UINTN) TeHdr->StrippedSize\r
1060 );\r
1061 }\r
1062\r
1063 //\r
1064 // Determine the size of the fixup data\r
1065 //\r
1066 // Per the PE/COFF spec, you can't assume that a given data directory\r
1067 // is present in the image. You have to check the NumberOfRvaAndSizes in\r
1068 // the optional header to verify a desired directory entry is there.\r
1069 //\r
1070 if (!(ImageContext->IsTeImage)) {\r
1071 if (PeHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
1072 if (OptionHeader.Optional32->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {\r
1073 DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)\r
1074 &OptionHeader.Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];\r
1075 ImageContext->FixupDataSize = DirectoryEntry->Size / sizeof (UINT16) * sizeof (UINTN);\r
1076 } else {\r
1077 ImageContext->FixupDataSize = 0;\r
1078 }\r
1079 } else {\r
1080 if (OptionHeader.Optional64->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {\r
1081 DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)\r
1082 &OptionHeader.Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];\r
1083 ImageContext->FixupDataSize = DirectoryEntry->Size / sizeof (UINT16) * sizeof (UINTN);\r
1084 } else {\r
1085 ImageContext->FixupDataSize = 0;\r
1086 }\r
1087 }\r
1088 } else {\r
1089 DirectoryEntry = &TeHdr->DataDirectory[0];\r
1090 ImageContext->FixupDataSize = DirectoryEntry->Size / sizeof (UINT16) * sizeof (UINTN);\r
1091 }\r
1092 //\r
1093 // Consumer must allocate a buffer for the relocation fixup log.\r
1094 // Only used for runtime drivers.\r
1095 //\r
1096 ImageContext->FixupData = NULL;\r
1097\r
1098 //\r
1099 // Load the Codeview info if present\r
1100 //\r
1101 if (ImageContext->DebugDirectoryEntryRva != 0) {\r
1102 if (!(ImageContext->IsTeImage)) {\r
1103 DebugEntry = PeCoffLoaderImageAddress (\r
1104 ImageContext,\r
1105 ImageContext->DebugDirectoryEntryRva\r
1106 );\r
1107 } else {\r
1108 DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *)(UINTN)(\r
1109 ImageContext->ImageAddress +\r
1110 ImageContext->DebugDirectoryEntryRva +\r
1111 sizeof(EFI_TE_IMAGE_HEADER) -\r
1112 TeHdr->StrippedSize\r
1113 );\r
1114 }\r
1115\r
1116 if (DebugEntry != NULL) {\r
1117 TempDebugEntryRva = DebugEntry->RVA;\r
1118 if (DebugEntry->RVA == 0 && DebugEntry->FileOffset != 0) {\r
1119 Section--;\r
1120 if ((UINTN) Section->SizeOfRawData < Section->Misc.VirtualSize) {\r
1121 TempDebugEntryRva = Section->VirtualAddress + Section->Misc.VirtualSize;\r
1122 } else {\r
1123 TempDebugEntryRva = Section->VirtualAddress + Section->SizeOfRawData;\r
1124 }\r
1125 }\r
1126\r
1127 if (TempDebugEntryRva != 0) {\r
1128 if (!(ImageContext->IsTeImage)) {\r
1129 ImageContext->CodeView = PeCoffLoaderImageAddress (ImageContext, TempDebugEntryRva);\r
1130 } else {\r
1131 ImageContext->CodeView = (VOID *)(\r
1132 (UINTN)ImageContext->ImageAddress +\r
1133 (UINTN)TempDebugEntryRva +\r
1134 (UINTN)sizeof(EFI_TE_IMAGE_HEADER) -\r
1135 (UINTN) TeHdr->StrippedSize\r
1136 );\r
1137 }\r
1138\r
1139 if (ImageContext->CodeView == NULL) {\r
1140 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
1141 return RETURN_LOAD_ERROR;\r
1142 }\r
1143\r
1144 if (DebugEntry->RVA == 0) {\r
1145 Size = DebugEntry->SizeOfData;\r
1146 if (!(ImageContext->IsTeImage)) {\r
1147 Status = ImageContext->ImageRead (\r
1148 ImageContext->Handle,\r
1149 DebugEntry->FileOffset,\r
1150 &Size,\r
1151 ImageContext->CodeView\r
1152 );\r
1153 } else {\r
1154 Status = ImageContext->ImageRead (\r
1155 ImageContext->Handle,\r
1156 DebugEntry->FileOffset + sizeof (EFI_TE_IMAGE_HEADER) - TeHdr->StrippedSize,\r
1157 &Size,\r
1158 ImageContext->CodeView\r
1159 );\r
1160 //\r
1161 // Should we apply fix up to this field according to the size difference between PE and TE?\r
1162 // Because now we maintain TE header fields unfixed, this field will also remain as they are\r
1163 // in original PE image.\r
1164 //\r
1165 }\r
1166\r
1167 if (RETURN_ERROR (Status)) {\r
1168 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
1169 return RETURN_LOAD_ERROR;\r
1170 }\r
1171\r
1172 DebugEntry->RVA = TempDebugEntryRva;\r
1173 }\r
1174\r
1175 switch (*(UINT32 *) ImageContext->CodeView) {\r
1176 case CODEVIEW_SIGNATURE_NB10:\r
1177 ImageContext->PdbPointer = (CHAR8 *) ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY);\r
1178 break;\r
1179\r
1180 case CODEVIEW_SIGNATURE_RSDS:\r
1181 ImageContext->PdbPointer = (CHAR8 *) ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY);\r
1182 break;\r
1183\r
a709adfa
LG
1184 case CODEVIEW_SIGNATURE_MTOC:\r
1185 ImageContext->PdbPointer = (CHAR8 *) ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY);\r
1186\r
30fdf114
LG
1187 default:\r
1188 break;\r
1189 }\r
1190 }\r
1191 }\r
1192 }\r
1193\r
1194 return Status;\r
1195}\r
1196\r
1197/**\r
1198 Returns a pointer to the PDB file name for a raw PE/COFF image that is not\r
1199 loaded into system memory with the PE/COFF Loader Library functions.\r
1200\r
1201 Returns the PDB file name for the PE/COFF image specified by Pe32Data. If\r
1202 the PE/COFF image specified by Pe32Data is not a valid, then NULL is\r
1203 returned. If the PE/COFF image specified by Pe32Data does not contain a\r
1204 debug directory entry, then NULL is returned. If the debug directory entry\r
1205 in the PE/COFF image specified by Pe32Data does not contain a PDB file name,\r
1206 then NULL is returned.\r
1207 If Pe32Data is NULL, then return NULL.\r
1208\r
1209 @param Pe32Data Pointer to the PE/COFF image that is loaded in system\r
1210 memory.\r
1211\r
1212 @return The PDB file name for the PE/COFF image specified by Pe32Data or NULL\r
1213 if it cannot be retrieved.\r
1214\r
1215**/\r
1216VOID *\r
1217EFIAPI\r
1218PeCoffLoaderGetPdbPointer (\r
1219 IN VOID *Pe32Data\r
1220 )\r
1221{\r
1222 EFI_IMAGE_DOS_HEADER *DosHdr;\r
1223 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;\r
1224 EFI_IMAGE_DATA_DIRECTORY *DirectoryEntry;\r
1225 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *DebugEntry;\r
1226 UINTN DirCount;\r
1227 VOID *CodeViewEntryPointer;\r
1228 INTN TEImageAdjust;\r
1229 UINT32 NumberOfRvaAndSizes;\r
1230 UINT16 Magic;\r
1231 EFI_IMAGE_SECTION_HEADER *SectionHeader;\r
1232 UINT32 Index, Index1;\r
1233\r
1234 if (Pe32Data == NULL) {\r
1235 return NULL;\r
1236 }\r
1237\r
1238 TEImageAdjust = 0;\r
1239 DirectoryEntry = NULL;\r
1240 DebugEntry = NULL;\r
1241 NumberOfRvaAndSizes = 0;\r
1242 Index = 0;\r
1243 Index1 = 0;\r
1244 SectionHeader = NULL;\r
1245\r
1246 DosHdr = (EFI_IMAGE_DOS_HEADER *)Pe32Data;\r
1247 if (EFI_IMAGE_DOS_SIGNATURE == DosHdr->e_magic) {\r
1248 //\r
1249 // DOS image header is present, so read the PE header after the DOS image header.\r
1250 //\r
1251 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN) Pe32Data + (UINTN) ((DosHdr->e_lfanew) & 0x0ffff));\r
1252 } else {\r
1253 //\r
1254 // DOS image header is not present, so PE header is at the image base.\r
1255 //\r
1256 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)Pe32Data;\r
1257 }\r
1258\r
1259 if (EFI_TE_IMAGE_HEADER_SIGNATURE == Hdr.Te->Signature) {\r
1260 if (Hdr.Te->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress != 0) {\r
1261 DirectoryEntry = &Hdr.Te->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG];\r
1262 TEImageAdjust = sizeof (EFI_TE_IMAGE_HEADER) - Hdr.Te->StrippedSize;\r
1263 \r
1264 //\r
1265 // Get the DebugEntry offset in the raw data image.\r
1266 //\r
fd171542 1267 SectionHeader = (EFI_IMAGE_SECTION_HEADER *) (Hdr.Te + 1);\r
1268 Index = Hdr.Te->NumberOfSections;\r
30fdf114 1269 for (Index1 = 0; Index1 < Index; Index1 ++) {\r
fd171542 1270 if ((DirectoryEntry->VirtualAddress >= SectionHeader[Index1].VirtualAddress) && \r
1271 (DirectoryEntry->VirtualAddress < (SectionHeader[Index1].VirtualAddress + SectionHeader[Index1].Misc.VirtualSize))) {\r
30fdf114
LG
1272 DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *)((UINTN) Hdr.Te +\r
1273 DirectoryEntry->VirtualAddress - \r
1274 SectionHeader [Index1].VirtualAddress + \r
1275 SectionHeader [Index1].PointerToRawData + \r
1276 TEImageAdjust);\r
1277 break;\r
1278 }\r
1279 }\r
1280 }\r
1281 } else if (EFI_IMAGE_NT_SIGNATURE == Hdr.Pe32->Signature) {\r
1282 //\r
1283 // NOTE: We use Machine field to identify PE32/PE32+, instead of Magic.\r
1284 // It is due to backward-compatibility, for some system might\r
1285 // generate PE32+ image with PE32 Magic.\r
1286 //\r
1287 switch (Hdr.Pe32->FileHeader.Machine) {\r
1288 case EFI_IMAGE_MACHINE_IA32:\r
1289 case EFI_IMAGE_MACHINE_ARMT:\r
1290 //\r
1291 // Assume PE32 image with IA32 Machine field.\r
1292 //\r
1293 Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC;\r
1294 break;\r
1295 case EFI_IMAGE_MACHINE_X64:\r
1296 case EFI_IMAGE_MACHINE_IPF:\r
1297 //\r
1298 // Assume PE32+ image with X64 or IPF Machine field\r
1299 //\r
1300 Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
1301 break;\r
1302 default:\r
1303 //\r
1304 // For unknow Machine field, use Magic in optional Header\r
1305 //\r
1306 Magic = Hdr.Pe32->OptionalHeader.Magic;\r
1307 }\r
1308\r
1309 SectionHeader = (EFI_IMAGE_SECTION_HEADER *) (\r
1310 (UINT8 *) Hdr.Pe32 +\r
1311 sizeof (UINT32) + \r
1312 sizeof (EFI_IMAGE_FILE_HEADER) + \r
1313 Hdr.Pe32->FileHeader.SizeOfOptionalHeader\r
1314 );\r
1315 Index = Hdr.Pe32->FileHeader.NumberOfSections;\r
1316\r
1317 if (EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC == Magic) {\r
1318 //\r
1319 // Use PE32 offset get Debug Directory Entry\r
1320 //\r
1321 NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;\r
1322 DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);\r
1323 } else if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {\r
1324 //\r
1325 // Use PE32+ offset get Debug Directory Entry\r
1326 //\r
1327 NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;\r
1328 DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);\r
1329 }\r
1330\r
1331 if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_DEBUG || DirectoryEntry->VirtualAddress == 0) {\r
1332 DirectoryEntry = NULL;\r
1333 DebugEntry = NULL;\r
1334 } else {\r
1335 //\r
1336 // Get the DebugEntry offset in the raw data image.\r
1337 //\r
1338 for (Index1 = 0; Index1 < Index; Index1 ++) {\r
fd171542 1339 if ((DirectoryEntry->VirtualAddress >= SectionHeader[Index1].VirtualAddress) && \r
1340 (DirectoryEntry->VirtualAddress < (SectionHeader[Index1].VirtualAddress + SectionHeader[Index1].Misc.VirtualSize))) {\r
30fdf114
LG
1341 DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *) (\r
1342 (UINTN) Pe32Data + \r
1343 DirectoryEntry->VirtualAddress - \r
1344 SectionHeader[Index1].VirtualAddress + \r
1345 SectionHeader[Index1].PointerToRawData);\r
1346 break;\r
1347 }\r
1348 }\r
1349 }\r
1350 } else {\r
1351 return NULL;\r
1352 }\r
1353\r
1354 if (NULL == DebugEntry || NULL == DirectoryEntry) {\r
1355 return NULL;\r
1356 }\r
1357\r
1358 //\r
1359 // Scan the directory to find the debug entry.\r
1360 // \r
1361 for (DirCount = 0; DirCount < DirectoryEntry->Size; DirCount += sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY), DebugEntry++) {\r
1362 if (EFI_IMAGE_DEBUG_TYPE_CODEVIEW == DebugEntry->Type) {\r
1363 if (DebugEntry->SizeOfData > 0) {\r
fd171542 1364 //\r
1365 // Get the DebugEntry offset in the raw data image.\r
1366 //\r
1367 CodeViewEntryPointer = NULL;\r
1368 for (Index1 = 0; Index1 < Index; Index1 ++) {\r
1369 if ((DebugEntry->RVA >= SectionHeader[Index1].VirtualAddress) && \r
1370 (DebugEntry->RVA < (SectionHeader[Index1].VirtualAddress + SectionHeader[Index1].Misc.VirtualSize))) {\r
1371 CodeViewEntryPointer = (VOID *) (\r
1372 ((UINTN)Pe32Data) + \r
1373 (UINTN) DebugEntry->RVA - \r
1374 SectionHeader[Index1].VirtualAddress + \r
1375 SectionHeader[Index1].PointerToRawData + \r
1376 (UINTN)TEImageAdjust);\r
1377 break;\r
1378 }\r
1379 }\r
1380 if (Index1 >= Index) {\r
1381 //\r
1382 // Can't find CodeViewEntryPointer in raw PE/COFF image.\r
1383 //\r
1384 continue;\r
1385 }\r
30fdf114
LG
1386 switch (* (UINT32 *) CodeViewEntryPointer) {\r
1387 case CODEVIEW_SIGNATURE_NB10:\r
1388 return (VOID *) ((CHAR8 *)CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY));\r
1389 case CODEVIEW_SIGNATURE_RSDS:\r
1390 return (VOID *) ((CHAR8 *)CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY));\r
a709adfa
LG
1391 case CODEVIEW_SIGNATURE_MTOC:\r
1392 return (VOID *) ((CHAR8 *)CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY));\r
30fdf114
LG
1393 default:\r
1394 break;\r
1395 }\r
1396 }\r
1397 }\r
1398 }\r
1399\r
1400 return NULL;\r
1401}\r
a709adfa
LG
1402\r
1403\r
1404RETURN_STATUS\r
1405EFIAPI\r
1406PeCoffLoaderGetEntryPoint (\r
1407 IN VOID *Pe32Data,\r
1408 OUT VOID **EntryPoint,\r
1409 OUT VOID **BaseOfImage\r
1410 )\r
1411{\r
1412 EFI_IMAGE_DOS_HEADER *DosHdr;\r
1413 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;\r
1414\r
1415 DosHdr = (EFI_IMAGE_DOS_HEADER *)Pe32Data;\r
1416 if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {\r
1417 //\r
1418 // DOS image header is present, so read the PE header after the DOS image header.\r
1419 //\r
1420 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN) Pe32Data + (UINTN) ((DosHdr->e_lfanew) & 0x0ffff));\r
1421 } else {\r
1422 //\r
1423 // DOS image header is not present, so PE header is at the image base.\r
1424 //\r
1425 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)Pe32Data;\r
1426 }\r
1427\r
1428 //\r
1429 // Calculate the entry point relative to the start of the image.\r
1430 // AddressOfEntryPoint is common for PE32 & PE32+\r
1431 //\r
1432 if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {\r
1433 *BaseOfImage = (VOID *)(UINTN)(Hdr.Te->ImageBase + Hdr.Te->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER));\r
1434 *EntryPoint = (VOID *)((UINTN)*BaseOfImage + (Hdr.Te->AddressOfEntryPoint & 0x0ffffffff) + sizeof(EFI_TE_IMAGE_HEADER) - Hdr.Te->StrippedSize);\r
1435 return RETURN_SUCCESS;\r
1436 } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) {\r
1437 *EntryPoint = (VOID *)(UINTN)Hdr.Pe32->OptionalHeader.AddressOfEntryPoint;\r
1438 if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
1439 *BaseOfImage = (VOID *)(UINTN)Hdr.Pe32->OptionalHeader.ImageBase;\r
1440 } else {\r
1441 *BaseOfImage = (VOID *)(UINTN)Hdr.Pe32Plus->OptionalHeader.ImageBase;\r
1442 }\r
1443 *EntryPoint = (VOID *)(UINTN)((UINTN)*EntryPoint + (UINTN)*BaseOfImage);\r
1444 return RETURN_SUCCESS;\r
1445 }\r
1446\r
1447 return RETURN_UNSUPPORTED;\r
1448}\r