]> git.proxmox.com Git - mirror_edk2.git/blame - MdePkg/Library/BasePeCoffLib/BasePeCoff.c
1. UINTN & INTN issue for EBC architecture:
[mirror_edk2.git] / MdePkg / Library / BasePeCoffLib / BasePeCoff.c
CommitLineData
878ddf1f 1/** @file\r
2 Tiano PE/COFF loader.\r
3\r
4 Copyright (c) 2006, Intel Corporation\r
5 All rights reserved. This program and the accompanying materials\r
6 are licensed and made available under the terms and conditions of the BSD License\r
7 which accompanies this distribution. The full text of the license may be found at\r
8 http://opensource.org/licenses/bsd-license.php\r
9\r
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
13 Module Name: PeCoffLoader.c\r
14\r
15**/\r
16\r
4ba61e5e 17/**\r
18 Performs an Itanium-based specific relocation fixup.\r
878ddf1f 19\r
4ba61e5e 20 @param Reloc Pointer to the relocation record.\r
21 @param Fixup Pointer to the address to fix up.\r
22 @param FixupData Pointer to a buffer to log the fixups.\r
23 @param Adjust The offset to adjust the fixup.\r
878ddf1f 24\r
4ba61e5e 25 @return Status code.\r
878ddf1f 26\r
4ba61e5e 27**/\r
878ddf1f 28RETURN_STATUS\r
29PeCoffLoaderRelocateImageEx (\r
30 IN UINT16 *Reloc,\r
31 IN OUT CHAR8 *Fixup,\r
32 IN OUT CHAR8 **FixupData,\r
33 IN UINT64 Adjust\r
34 );\r
35\r
36\r
37\r
38/**\r
39 Retrieves the PE or TE Header from a PE/COFF or TE image.\r
40\r
cd14fe3d 41 @param ImageContext The context of the image being loaded.\r
42 @param PeHdr The buffer in which to return the PE header.\r
43 @param TeHdr The buffer in which to return the TE header.\r
878ddf1f 44\r
cd14fe3d 45 @retval RETURN_SUCCESS The PE or TE Header is read.\r
46 @retval Other The error status from reading the PE/COFF or TE image using the ImageRead function.\r
878ddf1f 47\r
48**/\r
49STATIC\r
50RETURN_STATUS\r
51PeCoffLoaderGetPeHeader (\r
52 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,\r
53 OUT EFI_IMAGE_NT_HEADERS *PeHdr,\r
54 OUT EFI_TE_IMAGE_HEADER *TeHdr\r
55 )\r
56{\r
cd14fe3d 57 RETURN_STATUS Status;\r
878ddf1f 58 EFI_IMAGE_DOS_HEADER DosHdr;\r
59 UINTN Size;\r
60\r
61 ImageContext->IsTeImage = FALSE;\r
62 //\r
63 // Read the DOS image headers\r
64 //\r
65 Size = sizeof (EFI_IMAGE_DOS_HEADER);\r
66 Status = ImageContext->ImageRead (\r
cd14fe3d 67 ImageContext->Handle,\r
68 0,\r
69 &Size,\r
70 &DosHdr\r
71 );\r
878ddf1f 72 if (RETURN_ERROR (Status)) {\r
73 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
74 return Status;\r
75 }\r
76\r
77 ImageContext->PeCoffHeaderOffset = 0;\r
78 if (DosHdr.e_magic == EFI_IMAGE_DOS_SIGNATURE) {\r
79 //\r
80 // DOS image header is present, so read the PE header after the DOS image header\r
81 //\r
82 ImageContext->PeCoffHeaderOffset = DosHdr.e_lfanew;\r
83 }\r
84 //\r
85 // Read the PE/COFF Header\r
86 //\r
87 Size = sizeof (EFI_IMAGE_NT_HEADERS);\r
88 Status = ImageContext->ImageRead (\r
cd14fe3d 89 ImageContext->Handle,\r
90 ImageContext->PeCoffHeaderOffset,\r
91 &Size,\r
92 PeHdr\r
93 );\r
878ddf1f 94 if (RETURN_ERROR (Status)) {\r
95 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
96 return Status;\r
97 }\r
98 //\r
99 // Check the PE/COFF Header Signature. If not, then try to read a TE header\r
100 //\r
101 if (PeHdr->Signature != EFI_IMAGE_NT_SIGNATURE) {\r
102 Size = sizeof (EFI_TE_IMAGE_HEADER);\r
103 Status = ImageContext->ImageRead (\r
cd14fe3d 104 ImageContext->Handle,\r
105 0,\r
106 &Size,\r
107 TeHdr\r
108 );\r
878ddf1f 109 if (TeHdr->Signature != EFI_TE_IMAGE_HEADER_SIGNATURE) {\r
110 return RETURN_UNSUPPORTED;\r
111 }\r
112\r
113 ImageContext->IsTeImage = TRUE;\r
114 }\r
115\r
116 return RETURN_SUCCESS;\r
117}\r
118\r
119/**\r
120 Checks the PE or TE header of a PE/COFF or TE image to determine if it supported.\r
121\r
cd14fe3d 122 @param ImageContext The context of the image being loaded.\r
123 @param PeHdr The buffer in which to return the PE header.\r
124 @param TeHdr The buffer in which to return the TE header.\r
878ddf1f 125\r
cd14fe3d 126 @retval RETURN_SUCCESS The PE/COFF or TE image is supported.\r
127 @retval RETURN_UNSUPPORTED The PE/COFF or TE image is not supported.\r
878ddf1f 128\r
129**/\r
130STATIC\r
131RETURN_STATUS\r
132PeCoffLoaderCheckImageType (\r
133 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,\r
134 IN EFI_IMAGE_NT_HEADERS *PeHdr,\r
135 IN EFI_TE_IMAGE_HEADER *TeHdr\r
136 )\r
137{\r
138 //\r
139 // See if the machine type is supported. We support a native machine type (IA-32/Itanium-based)\r
140 // and the machine type for the Virtual Machine.\r
141 //\r
142 if (ImageContext->IsTeImage == FALSE) {\r
143 ImageContext->Machine = PeHdr->FileHeader.Machine;\r
144 } else {\r
145 ImageContext->Machine = TeHdr->Machine;\r
146 }\r
147\r
148 if (!(EFI_IMAGE_MACHINE_TYPE_SUPPORTED (ImageContext->Machine))) {\r
149 ImageContext->ImageError = IMAGE_ERROR_INVALID_MACHINE_TYPE;\r
150 return RETURN_UNSUPPORTED;\r
151 }\r
152\r
153 //\r
154 // See if the image type is supported. We support EFI Applications,\r
155 // EFI Boot Service Drivers, and EFI Runtime Drivers.\r
156 //\r
157 if (ImageContext->IsTeImage == FALSE) {\r
158 ImageContext->ImageType = PeHdr->OptionalHeader.Subsystem;\r
159 } else {\r
160 ImageContext->ImageType = (UINT16) (TeHdr->Subsystem);\r
161 }\r
162\r
163\r
164 return RETURN_SUCCESS;\r
165}\r
166\r
167/**\r
cd14fe3d 168 Retrieves information about a PE/COFF image.\r
169\r
170 Computes the PeCoffHeaderOffset, ImageAddress, ImageSize, DestinationAddress, CodeView,\r
171 PdbPointer, RelocationsStripped, SectionAlignment, SizeOfHeaders, and DebugDirectoryEntryRva\r
172 fields of the ImageContext structure. If ImageContext is NULL, then return RETURN_INVALID_PARAMETER.\r
173 If the PE/COFF image accessed through the ImageRead service in the ImageContext structure is not\r
174 a supported PE/COFF image type, then return RETURN_UNSUPPORTED. If any errors occur while\r
175 computing the fields of ImageContext, then the error status is returned in the ImageError field of\r
176 ImageContext. \r
878ddf1f 177\r
cd14fe3d 178 @param ImageContext Pointer to the image context structure that describes the PE/COFF\r
179 image that needs to be examined by this function.\r
878ddf1f 180\r
4ba61e5e 181 @retval RETURN_SUCCESS The information on the PE/COFF image was collected.\r
182 @retval RETURN_INVALID_PARAMETER ImageContext is NULL.\r
183 @retval RETURN_UNSUPPORTED The PE/COFF image is not supported.\r
878ddf1f 184\r
185**/\r
186RETURN_STATUS\r
187EFIAPI\r
188PeCoffLoaderGetImageInfo (\r
189 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext\r
190 )\r
191{\r
cd14fe3d 192 RETURN_STATUS Status;\r
878ddf1f 193 EFI_IMAGE_NT_HEADERS PeHdr;\r
194 EFI_TE_IMAGE_HEADER TeHdr;\r
195 EFI_IMAGE_DATA_DIRECTORY *DebugDirectoryEntry;\r
196 UINTN Size;\r
197 UINTN Index;\r
198 UINTN DebugDirectoryEntryRva;\r
199 UINTN DebugDirectoryEntryFileOffset;\r
200 UINTN SectionHeaderOffset;\r
201 EFI_IMAGE_SECTION_HEADER SectionHeader;\r
202 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY DebugEntry;\r
203\r
204 if (NULL == ImageContext) {\r
205 return RETURN_INVALID_PARAMETER;\r
206 }\r
207 //\r
208 // Assume success\r
209 //\r
210 ImageContext->ImageError = IMAGE_ERROR_SUCCESS;\r
211\r
212 Status = PeCoffLoaderGetPeHeader (ImageContext, &PeHdr, &TeHdr);\r
213 if (RETURN_ERROR (Status)) {\r
214 return Status;\r
215 }\r
216 //\r
217 // Verify machine type\r
218 //\r
219 Status = PeCoffLoaderCheckImageType (ImageContext, &PeHdr, &TeHdr);\r
220 if (RETURN_ERROR (Status)) {\r
221 return Status;\r
222 }\r
223 //\r
224 // Retrieve the base address of the image\r
225 //\r
226 if (!(ImageContext->IsTeImage)) {\r
227 ImageContext->ImageAddress = PeHdr.OptionalHeader.ImageBase;\r
228 } else {\r
229 ImageContext->ImageAddress = (PHYSICAL_ADDRESS) (TeHdr.ImageBase);\r
230 }\r
231 //\r
232 // Initialize the alternate destination address to 0 indicating that it\r
233 // should not be used.\r
234 //\r
235 ImageContext->DestinationAddress = 0;\r
236\r
237 //\r
238 // Initialize the codeview pointer.\r
239 //\r
240 ImageContext->CodeView = NULL;\r
241 ImageContext->PdbPointer = NULL;\r
242\r
243 //\r
244 // Three cases with regards to relocations:\r
245 // - Image has base relocs, RELOCS_STRIPPED==0 => image is relocatable\r
246 // - Image has no base relocs, RELOCS_STRIPPED==1 => Image is not relocatable\r
247 // - Image has no base relocs, RELOCS_STRIPPED==0 => Image is relocatable but\r
248 // has no base relocs to apply\r
249 // Obviously having base relocations with RELOCS_STRIPPED==1 is invalid.\r
250 //\r
251 // Look at the file header to determine if relocations have been stripped, and\r
252 // save this info in the image context for later use.\r
253 //\r
254 if ((!(ImageContext->IsTeImage)) && ((PeHdr.FileHeader.Characteristics & EFI_IMAGE_FILE_RELOCS_STRIPPED) != 0)) {\r
255 ImageContext->RelocationsStripped = TRUE;\r
256 } else {\r
257 ImageContext->RelocationsStripped = FALSE;\r
258 }\r
259\r
260 if (!(ImageContext->IsTeImage)) {\r
261 ImageContext->ImageSize = (UINT64) PeHdr.OptionalHeader.SizeOfImage;\r
262 ImageContext->SectionAlignment = PeHdr.OptionalHeader.SectionAlignment;\r
263 ImageContext->SizeOfHeaders = PeHdr.OptionalHeader.SizeOfHeaders;\r
264\r
265 //\r
266 // Modify ImageSize to contain .PDB file name if required and initialize\r
267 // PdbRVA field...\r
268 //\r
269 if (PeHdr.OptionalHeader.NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_DEBUG) {\r
270 DebugDirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *) &(PeHdr.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);\r
271\r
272 DebugDirectoryEntryRva = DebugDirectoryEntry->VirtualAddress;\r
273\r
274 //\r
275 // Determine the file offset of the debug directory... This means we walk\r
276 // the sections to find which section contains the RVA of the debug\r
277 // directory\r
278 //\r
279 DebugDirectoryEntryFileOffset = 0;\r
280\r
281 SectionHeaderOffset = (UINTN)(\r
282 ImageContext->PeCoffHeaderOffset +\r
283 sizeof (UINT32) + \r
284 sizeof (EFI_IMAGE_FILE_HEADER) + \r
285 PeHdr.FileHeader.SizeOfOptionalHeader\r
286 );\r
287\r
288 for (Index = 0; Index < PeHdr.FileHeader.NumberOfSections; Index++) {\r
289 //\r
290 // Read section header from file\r
291 //\r
292 Size = sizeof (EFI_IMAGE_SECTION_HEADER);\r
293 Status = ImageContext->ImageRead (\r
294 ImageContext->Handle,\r
295 SectionHeaderOffset,\r
296 &Size,\r
297 &SectionHeader\r
298 );\r
299 if (RETURN_ERROR (Status)) {\r
300 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
301 return Status;\r
302 }\r
303\r
304 if (DebugDirectoryEntryRva >= SectionHeader.VirtualAddress &&\r
305 DebugDirectoryEntryRva < SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize) {\r
306 DebugDirectoryEntryFileOffset =\r
307 DebugDirectoryEntryRva - SectionHeader.VirtualAddress + SectionHeader.PointerToRawData;\r
308 break;\r
309 }\r
310\r
311 SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);\r
312 }\r
313\r
314 if (DebugDirectoryEntryFileOffset != 0) {\r
315 for (Index = 0; Index < DebugDirectoryEntry->Size; Index++) {\r
316 //\r
317 // Read next debug directory entry\r
318 //\r
319 Size = sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);\r
320 Status = ImageContext->ImageRead (\r
321 ImageContext->Handle,\r
322 DebugDirectoryEntryFileOffset,\r
323 &Size,\r
324 &DebugEntry\r
325 );\r
326 if (RETURN_ERROR (Status)) {\r
327 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
328 return Status;\r
329 }\r
330\r
331 if (DebugEntry.Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) {\r
332 ImageContext->DebugDirectoryEntryRva = (UINT32) (DebugDirectoryEntryRva + Index * sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY));\r
333 if (DebugEntry.RVA == 0 && DebugEntry.FileOffset != 0) {\r
334 ImageContext->ImageSize += DebugEntry.SizeOfData;\r
335 }\r
336\r
337 return RETURN_SUCCESS;\r
338 }\r
339 }\r
340 }\r
341 }\r
342 } else {\r
343 ImageContext->ImageSize = 0;\r
344 ImageContext->SectionAlignment = 4096;\r
345 ImageContext->SizeOfHeaders = sizeof (EFI_TE_IMAGE_HEADER) + (UINTN) TeHdr.BaseOfCode - (UINTN) TeHdr.StrippedSize;\r
346\r
347 DebugDirectoryEntry = &TeHdr.DataDirectory[1];\r
348 DebugDirectoryEntryRva = DebugDirectoryEntry->VirtualAddress;\r
349 SectionHeaderOffset = (UINTN) (sizeof (EFI_TE_IMAGE_HEADER));\r
350\r
351 DebugDirectoryEntryFileOffset = 0;\r
352\r
353 for (Index = 0; Index < TeHdr.NumberOfSections;) {\r
354 //\r
355 // Read section header from file\r
356 //\r
cd14fe3d 357 Size = sizeof (EFI_IMAGE_SECTION_HEADER);\r
878ddf1f 358 Status = ImageContext->ImageRead (\r
359 ImageContext->Handle,\r
360 SectionHeaderOffset,\r
361 &Size,\r
362 &SectionHeader\r
363 );\r
364 if (RETURN_ERROR (Status)) {\r
365 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
366 return Status;\r
367 }\r
368\r
369 if (DebugDirectoryEntryRva >= SectionHeader.VirtualAddress &&\r
370 DebugDirectoryEntryRva < SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize) {\r
371 DebugDirectoryEntryFileOffset = DebugDirectoryEntryRva -\r
cd14fe3d 372 SectionHeader.VirtualAddress +\r
373 SectionHeader.PointerToRawData +\r
374 sizeof (EFI_TE_IMAGE_HEADER) -\r
375 TeHdr.StrippedSize;\r
878ddf1f 376\r
377 //\r
378 // File offset of the debug directory was found, if this is not the last\r
379 // section, then skip to the last section for calculating the image size.\r
380 //\r
381 if (Index < (UINTN) TeHdr.NumberOfSections - 1) {\r
382 SectionHeaderOffset += (TeHdr.NumberOfSections - 1 - Index) * sizeof (EFI_IMAGE_SECTION_HEADER);\r
383 Index = TeHdr.NumberOfSections - 1;\r
384 continue;\r
385 }\r
386 }\r
387\r
388 //\r
389 // In Te image header there is not a field to describe the ImageSize.\r
390 // Actually, the ImageSize equals the RVA plus the VirtualSize of \r
391 // the last section mapped into memory (Must be rounded up to \r
392 // a mulitple of Section Alignment). Per the PE/COFF specification, the\r
393 // section headers in the Section Table must appear in order of the RVA\r
394 // values for the corresponding sections. So the ImageSize can be determined\r
395 // by the RVA and the VirtualSize of the last section header in the\r
396 // Section Table.\r
397 //\r
398 if ((++Index) == (UINTN) TeHdr.NumberOfSections) {\r
399 ImageContext->ImageSize = (SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize +\r
400 ImageContext->SectionAlignment - 1) & ~(ImageContext->SectionAlignment - 1);\r
401 }\r
402\r
403 SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);\r
404 }\r
405\r
406 if (DebugDirectoryEntryFileOffset != 0) {\r
407 for (Index = 0; Index < DebugDirectoryEntry->Size; Index++) {\r
408 //\r
409 // Read next debug directory entry\r
410 //\r
411 Size = sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);\r
412 Status = ImageContext->ImageRead (\r
413 ImageContext->Handle,\r
414 DebugDirectoryEntryFileOffset,\r
415 &Size,\r
416 &DebugEntry\r
417 );\r
418 if (RETURN_ERROR (Status)) {\r
419 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
420 return Status;\r
421 }\r
422\r
423 if (DebugEntry.Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) {\r
424 ImageContext->DebugDirectoryEntryRva = (UINT32) (DebugDirectoryEntryRva + Index * sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY));\r
425 return RETURN_SUCCESS;\r
426 }\r
427 }\r
428 }\r
429 }\r
430\r
431 return RETURN_SUCCESS;\r
432}\r
433\r
434/**\r
435 Converts an image address to the loaded address.\r
436\r
cd14fe3d 437 @param ImageContext The context of the image being loaded.\r
438 @param Address The address to be converted to the loaded address.\r
878ddf1f 439\r
cd14fe3d 440 @return The converted address or NULL if the address can not be converted.\r
878ddf1f 441\r
442**/\r
443STATIC\r
444VOID *\r
445PeCoffLoaderImageAddress (\r
446 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,\r
447 IN UINTN Address\r
448 )\r
449{\r
450 if (Address >= ImageContext->ImageSize) {\r
451 ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_ADDRESS;\r
452 return NULL;\r
453 }\r
454\r
455 return (CHAR8 *) ((UINTN) ImageContext->ImageAddress + Address);\r
456}\r
457\r
458/**\r
cd14fe3d 459 Applies relocation fixups to a PE/COFF image that was loaded with PeCoffLoaderLoadImage().\r
878ddf1f 460\r
cd14fe3d 461 If the DestinationAddress field of ImageContext is 0, then use the ImageAddress field of\r
462 ImageContext as the relocation base address. Otherwise, use the DestinationAddress field\r
463 of ImageContext as the relocation base address. The caller must allocate the relocation\r
464 fixup log buffer and fill in the FixupData field of ImageContext prior to calling this function. \r
465 If ImageContext is NULL, then ASSERT().\r
466\r
467 @param ImageContext Pointer to the image context structure that describes the PE/COFF\r
468 image that is being relocated.\r
878ddf1f 469\r
cd14fe3d 470 @retval RETURN_SUCCESS The PE/COFF image was relocated.\r
471 Extended status information is in the ImageError field of ImageContext.\r
472 @retval RETURN_LOAD_ERROR The image in not a valid PE/COFF image.\r
473 Extended status information is in the ImageError field of ImageContext.\r
474 @retval RETURN_UNSUPPORTED A relocation record type is not supported.\r
475 Extended status information is in the ImageError field of ImageContext.\r
878ddf1f 476\r
477**/\r
478RETURN_STATUS\r
479EFIAPI\r
480PeCoffLoaderRelocateImage (\r
481 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext\r
482 )\r
483{\r
484 RETURN_STATUS Status;\r
485 EFI_IMAGE_NT_HEADERS *PeHdr;\r
486 EFI_TE_IMAGE_HEADER *TeHdr;\r
487 EFI_IMAGE_DATA_DIRECTORY *RelocDir;\r
488 UINT64 Adjust;\r
489 EFI_IMAGE_BASE_RELOCATION *RelocBase;\r
490 EFI_IMAGE_BASE_RELOCATION *RelocBaseEnd;\r
491 UINT16 *Reloc;\r
492 UINT16 *RelocEnd;\r
493 CHAR8 *Fixup;\r
494 CHAR8 *FixupBase;\r
495 UINT16 *F16;\r
496 UINT32 *F32;\r
497 CHAR8 *FixupData;\r
498 PHYSICAL_ADDRESS BaseAddress;\r
499\r
cd14fe3d 500 ASSERT (ImageContext != NULL);\r
501\r
878ddf1f 502 PeHdr = NULL;\r
503 TeHdr = NULL;\r
504 //\r
505 // Assume success\r
506 //\r
507 ImageContext->ImageError = IMAGE_ERROR_SUCCESS;\r
508\r
509 //\r
510 // If there are no relocation entries, then we are done\r
511 //\r
512 if (ImageContext->RelocationsStripped) {\r
513 return RETURN_SUCCESS;\r
514 }\r
515\r
516 //\r
517 // If the destination address is not 0, use that rather than the\r
518 // image address as the relocation target.\r
519 //\r
cd14fe3d 520 if (ImageContext->DestinationAddress != 0) {\r
878ddf1f 521 BaseAddress = ImageContext->DestinationAddress;\r
522 } else {\r
523 BaseAddress = ImageContext->ImageAddress;\r
524 }\r
525\r
526 if (!(ImageContext->IsTeImage)) {\r
527 PeHdr = (EFI_IMAGE_NT_HEADERS *)((UINTN)ImageContext->ImageAddress + \r
528 ImageContext->PeCoffHeaderOffset);\r
cd14fe3d 529 \r
878ddf1f 530 Adjust = (UINT64) BaseAddress - PeHdr->OptionalHeader.ImageBase;\r
531 PeHdr->OptionalHeader.ImageBase = (UINTN)BaseAddress;\r
532\r
533 //\r
534 // Find the relocation block\r
535 //\r
536 // Per the PE/COFF spec, you can't assume that a given data directory\r
537 // is present in the image. You have to check the NumberOfRvaAndSizes in\r
538 // the optional header to verify a desired directory entry is there.\r
539 //\r
540 if (PeHdr->OptionalHeader.NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {\r
541 RelocDir = &PeHdr->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];\r
542 RelocBase = PeCoffLoaderImageAddress (ImageContext, RelocDir->VirtualAddress);\r
543 RelocBaseEnd = PeCoffLoaderImageAddress (\r
544 ImageContext,\r
545 RelocDir->VirtualAddress + RelocDir->Size - 1\r
546 );\r
547 } else {\r
548 //\r
549 // Set base and end to bypass processing below.\r
550 //\r
551 RelocBase = RelocBaseEnd = 0;\r
552 }\r
553 } else {\r
554 TeHdr = (EFI_TE_IMAGE_HEADER *) (UINTN) (ImageContext->ImageAddress);\r
555 Adjust = (UINT64) (BaseAddress - TeHdr->ImageBase);\r
556 TeHdr->ImageBase = (UINT64) (BaseAddress);\r
557\r
558 //\r
559 // Find the relocation block\r
560 //\r
561 RelocDir = &TeHdr->DataDirectory[0];\r
562 RelocBase = (EFI_IMAGE_BASE_RELOCATION *)(UINTN)(\r
563 ImageContext->ImageAddress + \r
564 RelocDir->VirtualAddress +\r
565 sizeof(EFI_TE_IMAGE_HEADER) - \r
566 TeHdr->StrippedSize\r
567 );\r
568 RelocBaseEnd = (EFI_IMAGE_BASE_RELOCATION *) ((UINTN) RelocBase + (UINTN) RelocDir->Size - 1);\r
569 }\r
570 \r
571 //\r
572 // Run the relocation information and apply the fixups\r
573 //\r
574 FixupData = ImageContext->FixupData;\r
575 while (RelocBase < RelocBaseEnd) {\r
576\r
577 Reloc = (UINT16 *) ((CHAR8 *) RelocBase + sizeof (EFI_IMAGE_BASE_RELOCATION));\r
578 RelocEnd = (UINT16 *) ((CHAR8 *) RelocBase + RelocBase->SizeOfBlock);\r
579 if (!(ImageContext->IsTeImage)) {\r
580 FixupBase = PeCoffLoaderImageAddress (ImageContext, RelocBase->VirtualAddress);\r
581 } else {\r
582 FixupBase = (CHAR8 *)(UINTN)(ImageContext->ImageAddress +\r
583 RelocBase->VirtualAddress +\r
584 sizeof(EFI_TE_IMAGE_HEADER) - \r
585 TeHdr->StrippedSize\r
586 );\r
587 }\r
588\r
589 if ((CHAR8 *) RelocEnd < (CHAR8 *) ((UINTN) ImageContext->ImageAddress) ||\r
590 (CHAR8 *) RelocEnd > (CHAR8 *)((UINTN)ImageContext->ImageAddress + \r
591 (UINTN)ImageContext->ImageSize)) {\r
592 ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;\r
593 return RETURN_LOAD_ERROR;\r
594 }\r
595\r
596 //\r
597 // Run this relocation record\r
598 //\r
599 while (Reloc < RelocEnd) {\r
600\r
601 Fixup = FixupBase + (*Reloc & 0xFFF);\r
602 switch ((*Reloc) >> 12) {\r
603 case EFI_IMAGE_REL_BASED_ABSOLUTE:\r
604 break;\r
605\r
606 case EFI_IMAGE_REL_BASED_HIGH:\r
607 F16 = (UINT16 *) Fixup;\r
608 *F16 = (UINT16) ((*F16 << 16) + (UINT16) Adjust);\r
609 if (FixupData != NULL) {\r
610 *(UINT16 *) FixupData = *F16;\r
611 FixupData = FixupData + sizeof (UINT16);\r
612 }\r
613 break;\r
614\r
615 case EFI_IMAGE_REL_BASED_LOW:\r
616 F16 = (UINT16 *) Fixup;\r
617 *F16 = (UINT16) (*F16 + (UINT16) Adjust);\r
618 if (FixupData != NULL) {\r
619 *(UINT16 *) FixupData = *F16;\r
620 FixupData = FixupData + sizeof (UINT16);\r
621 }\r
622 break;\r
623\r
624 case EFI_IMAGE_REL_BASED_HIGHLOW:\r
625 F32 = (UINT32 *) Fixup;\r
626 *F32 = *F32 + (UINT32) Adjust;\r
627 if (FixupData != NULL) {\r
628 FixupData = ALIGN_POINTER (FixupData, sizeof (UINT32));\r
629 *(UINT32 *) FixupData = *F32;\r
630 FixupData = FixupData + sizeof (UINT32);\r
631 }\r
632 break;\r
633\r
634 case EFI_IMAGE_REL_BASED_HIGHADJ:\r
635 //\r
636 // Return the same EFI_UNSUPPORTED return code as\r
637 // PeCoffLoaderRelocateImageEx() returns if it does not recognize\r
638 // the relocation type.\r
639 //\r
640 ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;\r
641 return RETURN_UNSUPPORTED;\r
642\r
643 default:\r
644 Status = PeCoffLoaderRelocateImageEx (Reloc, Fixup, &FixupData, Adjust);\r
645 if (RETURN_ERROR (Status)) {\r
646 ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;\r
647 return Status;\r
648 }\r
649 }\r
650\r
651 //\r
652 // Next relocation record\r
653 //\r
654 Reloc += 1;\r
655 }\r
656\r
657 //\r
658 // Next reloc block\r
659 //\r
660 RelocBase = (EFI_IMAGE_BASE_RELOCATION *) RelocEnd;\r
661 }\r
662\r
663 return RETURN_SUCCESS;\r
664}\r
665\r
666/**\r
667 Loads a PE/COFF image into memory.\r
668\r
cd14fe3d 669 Loads the PE/COFF image accessed through the ImageRead service of ImageContext into the buffer\r
670 specified by the ImageAddress and ImageSize fields of ImageContext. The caller must allocate\r
671 the load buffer and fill in the ImageAddress and ImageSize fields prior to calling this function.\r
672 The EntryPoint, FixupDataSize, CodeView, and PdbPointer fields of ImageContext are computed.\r
4ba61e5e 673 If ImageContext is NULL, then ASSERT().\r
cd14fe3d 674\r
675 @param ImageContext Pointer to the image context structure that describes the PE/COFF\r
676 image that is being loaded.\r
878ddf1f 677\r
cd14fe3d 678 @retval RETURN_SUCCESS The PE/COFF image was loaded into the buffer specified by\r
679 the ImageAddress and ImageSize fields of ImageContext.\r
680 Extended status information is in the ImageError field of ImageContext.\r
681 @retval RETURN_BUFFER_TOO_SMALL The caller did not provide a large enough buffer.\r
682 Extended status information is in the ImageError field of ImageContext.\r
683 @retval RETURN_LOAD_ERROR The PE/COFF image is an EFI Runtime image with no relocations.\r
684 Extended status information is in the ImageError field of ImageContext.\r
685 @retval RETURN_INVALID_PARAMETER The image address is invalid.\r
686 Extended status information is in the ImageError field of ImageContext.\r
878ddf1f 687\r
688**/\r
689RETURN_STATUS\r
690EFIAPI\r
691PeCoffLoaderLoadImage (\r
692 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext\r
693 )\r
694{\r
cd14fe3d 695 RETURN_STATUS Status;\r
878ddf1f 696 EFI_IMAGE_NT_HEADERS *PeHdr;\r
697 EFI_TE_IMAGE_HEADER *TeHdr;\r
cd14fe3d 698 PE_COFF_LOADER_IMAGE_CONTEXT CheckContext;\r
878ddf1f 699 EFI_IMAGE_SECTION_HEADER *FirstSection;\r
700 EFI_IMAGE_SECTION_HEADER *Section;\r
701 UINTN NumberOfSections;\r
702 UINTN Index;\r
703 CHAR8 *Base;\r
704 CHAR8 *End;\r
705 CHAR8 *MaxEnd;\r
706 EFI_IMAGE_DATA_DIRECTORY *DirectoryEntry;\r
707 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *DebugEntry;\r
708 UINTN Size;\r
709 UINT32 TempDebugEntryRva;\r
710\r
4ba61e5e 711 ASSERT (ImageContext != NULL);\r
712\r
878ddf1f 713 PeHdr = NULL;\r
714 TeHdr = NULL;\r
4ba61e5e 715\r
878ddf1f 716 //\r
717 // Assume success\r
718 //\r
719 ImageContext->ImageError = IMAGE_ERROR_SUCCESS;\r
720\r
721 //\r
722 // Copy the provided context info into our local version, get what we\r
723 // can from the original image, and then use that to make sure everything\r
724 // is legit.\r
725 //\r
726 CopyMem (&CheckContext, ImageContext, sizeof (PE_COFF_LOADER_IMAGE_CONTEXT));\r
727\r
728 Status = PeCoffLoaderGetImageInfo (&CheckContext);\r
729 if (RETURN_ERROR (Status)) {\r
730 return Status;\r
731 }\r
732\r
733 //\r
734 // Make sure there is enough allocated space for the image being loaded\r
735 //\r
736 if (ImageContext->ImageSize < CheckContext.ImageSize) {\r
737 ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_SIZE;\r
738 return RETURN_BUFFER_TOO_SMALL;\r
739 }\r
4ba61e5e 740 if (ImageContext->ImageAddress == 0) {\r
741 //\r
742 // Image cannot be loaded into 0 address.\r
743 //\r
744 ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_ADDRESS;\r
745 return RETURN_INVALID_PARAMETER;\r
746 }\r
878ddf1f 747 //\r
748 // If there's no relocations, then make sure it's not a runtime driver,\r
749 // and that it's being loaded at the linked address.\r
750 //\r
751 if (CheckContext.RelocationsStripped) {\r
752 //\r
753 // If the image does not contain relocations and it is a runtime driver\r
754 // then return an error.\r
755 //\r
756 if (CheckContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) {\r
757 ImageContext->ImageError = IMAGE_ERROR_INVALID_SUBSYSTEM;\r
758 return RETURN_LOAD_ERROR;\r
759 }\r
760 //\r
761 // If the image does not contain relocations, and the requested load address\r
762 // is not the linked address, then return an error.\r
763 //\r
764 if (CheckContext.ImageAddress != ImageContext->ImageAddress) {\r
765 ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_ADDRESS;\r
766 return RETURN_INVALID_PARAMETER;\r
767 }\r
768 }\r
769 //\r
770 // Make sure the allocated space has the proper section alignment\r
771 //\r
772 if (!(ImageContext->IsTeImage)) {\r
773 if ((ImageContext->ImageAddress & (CheckContext.SectionAlignment - 1)) != 0) {\r
774 ImageContext->ImageError = IMAGE_ERROR_INVALID_SECTION_ALIGNMENT;\r
775 return RETURN_INVALID_PARAMETER;\r
776 }\r
777 }\r
778 //\r
779 // Read the entire PE/COFF or TE header into memory\r
780 //\r
781 if (!(ImageContext->IsTeImage)) {\r
782 Status = ImageContext->ImageRead (\r
783 ImageContext->Handle,\r
784 0,\r
785 &ImageContext->SizeOfHeaders,\r
786 (VOID *) (UINTN) ImageContext->ImageAddress\r
787 );\r
788\r
789 PeHdr = (EFI_IMAGE_NT_HEADERS *)\r
790 ((UINTN)ImageContext->ImageAddress + ImageContext->PeCoffHeaderOffset);\r
791\r
792 FirstSection = (EFI_IMAGE_SECTION_HEADER *) (\r
793 (UINTN)ImageContext->ImageAddress +\r
794 ImageContext->PeCoffHeaderOffset +\r
795 sizeof(UINT32) + \r
796 sizeof(EFI_IMAGE_FILE_HEADER) + \r
797 PeHdr->FileHeader.SizeOfOptionalHeader\r
798 );\r
799 NumberOfSections = (UINTN) (PeHdr->FileHeader.NumberOfSections);\r
800 } else {\r
801 Status = ImageContext->ImageRead (\r
802 ImageContext->Handle,\r
803 0,\r
804 &ImageContext->SizeOfHeaders,\r
805 (void *) (UINTN) ImageContext->ImageAddress\r
806 );\r
807\r
808 TeHdr = (EFI_TE_IMAGE_HEADER *) (UINTN) (ImageContext->ImageAddress);\r
809\r
810 FirstSection = (EFI_IMAGE_SECTION_HEADER *) (\r
811 (UINTN)ImageContext->ImageAddress +\r
812 sizeof(EFI_TE_IMAGE_HEADER)\r
813 );\r
814 NumberOfSections = (UINTN) (TeHdr->NumberOfSections);\r
815\r
816 }\r
817\r
818 if (RETURN_ERROR (Status)) {\r
819 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
820 return RETURN_LOAD_ERROR;\r
821 }\r
822\r
823 //\r
824 // Load each section of the image\r
825 //\r
826 Section = FirstSection;\r
827 for (Index = 0, MaxEnd = NULL; Index < NumberOfSections; Index++) {\r
828\r
829 //\r
830 // Compute sections address\r
831 //\r
832 Base = PeCoffLoaderImageAddress (ImageContext, Section->VirtualAddress);\r
833 End = PeCoffLoaderImageAddress (\r
834 ImageContext,\r
835 Section->VirtualAddress + Section->Misc.VirtualSize - 1\r
836 );\r
837 if (ImageContext->IsTeImage) {\r
838 Base = (CHAR8 *) ((UINTN) Base + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN) TeHdr->StrippedSize);\r
839 End = (CHAR8 *) ((UINTN) End + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN) TeHdr->StrippedSize);\r
840 }\r
841\r
842 if (End > MaxEnd) {\r
843 MaxEnd = End;\r
844 }\r
845 //\r
846 // If the base start or end address resolved to 0, then fail.\r
847 //\r
848 if ((Base == NULL) || (End == NULL)) {\r
849 ImageContext->ImageError = IMAGE_ERROR_SECTION_NOT_LOADED;\r
850 return RETURN_LOAD_ERROR;\r
851 }\r
852\r
853 //\r
854 // Read the section\r
855 //\r
856 Size = (UINTN) Section->Misc.VirtualSize;\r
857 if ((Size == 0) || (Size > Section->SizeOfRawData)) {\r
858 Size = (UINTN) Section->SizeOfRawData;\r
859 }\r
860\r
861 if (Section->SizeOfRawData) {\r
862 if (!(ImageContext->IsTeImage)) {\r
863 Status = ImageContext->ImageRead (\r
864 ImageContext->Handle,\r
865 Section->PointerToRawData,\r
866 &Size,\r
867 Base\r
868 );\r
869 } else {\r
870 Status = ImageContext->ImageRead (\r
871 ImageContext->Handle,\r
872 Section->PointerToRawData + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN) TeHdr->StrippedSize,\r
873 &Size,\r
874 Base\r
875 );\r
876 }\r
877\r
878 if (RETURN_ERROR (Status)) {\r
879 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
880 return Status;\r
881 }\r
882 }\r
883\r
884 //\r
885 // If raw size is less then virt size, zero fill the remaining\r
886 //\r
887\r
888 if (Size < Section->Misc.VirtualSize) {\r
889 ZeroMem (Base + Size, Section->Misc.VirtualSize - Size);\r
890 }\r
891\r
892 //\r
893 // Next Section\r
894 //\r
895 Section += 1;\r
896 }\r
897\r
898 //\r
899 // Get image's entry point\r
900 //\r
901 if (!(ImageContext->IsTeImage)) {\r
902 ImageContext->EntryPoint = (PHYSICAL_ADDRESS) (UINTN) PeCoffLoaderImageAddress (\r
903 ImageContext,\r
904 PeHdr->OptionalHeader.AddressOfEntryPoint\r
905 );\r
906 } else {\r
907 ImageContext->EntryPoint = (PHYSICAL_ADDRESS) (\r
908 (UINTN)ImageContext->ImageAddress +\r
909 (UINTN)TeHdr->AddressOfEntryPoint +\r
910 (UINTN)sizeof(EFI_TE_IMAGE_HEADER) -\r
911 (UINTN) TeHdr->StrippedSize\r
912 );\r
913 }\r
914\r
915 //\r
916 // Determine the size of the fixup data\r
917 //\r
918 // Per the PE/COFF spec, you can't assume that a given data directory\r
919 // is present in the image. You have to check the NumberOfRvaAndSizes in\r
920 // the optional header to verify a desired directory entry is there.\r
921 //\r
922 if (!(ImageContext->IsTeImage)) {\r
923 if (PeHdr->OptionalHeader.NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {\r
924 DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)\r
925 &PeHdr->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];\r
926 ImageContext->FixupDataSize = DirectoryEntry->Size / sizeof (UINT16) * sizeof (UINTN);\r
927 } else {\r
928 ImageContext->FixupDataSize = 0;\r
929 }\r
930 } else {\r
931 DirectoryEntry = &TeHdr->DataDirectory[0];\r
932 ImageContext->FixupDataSize = DirectoryEntry->Size / sizeof (UINT16) * sizeof (UINTN);\r
933 }\r
934 //\r
935 // Consumer must allocate a buffer for the relocation fixup log.\r
936 // Only used for runtime drivers.\r
937 //\r
938 ImageContext->FixupData = NULL;\r
939\r
940 //\r
941 // Load the Codeview info if present\r
942 //\r
943 if (ImageContext->DebugDirectoryEntryRva != 0) {\r
944 if (!(ImageContext->IsTeImage)) {\r
945 DebugEntry = PeCoffLoaderImageAddress (\r
946 ImageContext,\r
947 ImageContext->DebugDirectoryEntryRva\r
948 );\r
949 } else {\r
950 DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *)(UINTN)(\r
951 ImageContext->ImageAddress +\r
952 ImageContext->DebugDirectoryEntryRva +\r
953 sizeof(EFI_TE_IMAGE_HEADER) -\r
954 TeHdr->StrippedSize\r
955 );\r
956 }\r
957\r
958 if (DebugEntry != NULL) {\r
959 TempDebugEntryRva = DebugEntry->RVA;\r
960 if (DebugEntry->RVA == 0 && DebugEntry->FileOffset != 0) {\r
961 Section--;\r
962 if ((UINTN) Section->SizeOfRawData < Section->Misc.VirtualSize) {\r
963 TempDebugEntryRva = Section->VirtualAddress + Section->Misc.VirtualSize;\r
964 } else {\r
965 TempDebugEntryRva = Section->VirtualAddress + Section->SizeOfRawData;\r
966 }\r
967 }\r
968\r
969 if (TempDebugEntryRva != 0) {\r
970 if (!(ImageContext->IsTeImage)) {\r
971 ImageContext->CodeView = PeCoffLoaderImageAddress (ImageContext, TempDebugEntryRva);\r
972 } else {\r
973 ImageContext->CodeView = (VOID *)(\r
974 (UINTN)ImageContext->ImageAddress +\r
975 (UINTN)TempDebugEntryRva +\r
976 (UINTN)sizeof(EFI_TE_IMAGE_HEADER) -\r
977 (UINTN) TeHdr->StrippedSize\r
978 );\r
979 }\r
980\r
981 if (ImageContext->CodeView == NULL) {\r
982 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
983 return RETURN_LOAD_ERROR;\r
984 }\r
985\r
986 if (DebugEntry->RVA == 0) {\r
987 Size = DebugEntry->SizeOfData;\r
988 if (!(ImageContext->IsTeImage)) {\r
989 Status = ImageContext->ImageRead (\r
990 ImageContext->Handle,\r
991 DebugEntry->FileOffset,\r
992 &Size,\r
993 ImageContext->CodeView\r
994 );\r
995 } else {\r
996 Status = ImageContext->ImageRead (\r
997 ImageContext->Handle,\r
998 DebugEntry->FileOffset + sizeof (EFI_TE_IMAGE_HEADER) - TeHdr->StrippedSize,\r
999 &Size,\r
1000 ImageContext->CodeView\r
1001 );\r
1002 //\r
1003 // Should we apply fix up to this field according to the size difference between PE and TE?\r
1004 // Because now we maintain TE header fields unfixed, this field will also remain as they are\r
1005 // in original PE image.\r
1006 //\r
1007 }\r
1008\r
1009 if (RETURN_ERROR (Status)) {\r
1010 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
1011 return RETURN_LOAD_ERROR;\r
1012 }\r
1013\r
1014 DebugEntry->RVA = TempDebugEntryRva;\r
1015 }\r
1016\r
1017 switch (*(UINT32 *) ImageContext->CodeView) {\r
1018 case CODEVIEW_SIGNATURE_NB10:\r
1019 ImageContext->PdbPointer = (CHAR8 *) ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY);\r
1020 break;\r
1021\r
1022 case CODEVIEW_SIGNATURE_RSDS:\r
1023 ImageContext->PdbPointer = (CHAR8 *) ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY);\r
1024 break;\r
1025\r
1026 default:\r
1027 break;\r
1028 }\r
1029 }\r
1030 }\r
1031 }\r
1032\r
1033 return Status;\r
1034}\r