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