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