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