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