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