Updated PeiRebase to produce a map file of the relocations done by this tool
[mirror_edk2.git] / Tools / Source / TianoTools / PeiRebase / PeiRebaseExe.c
1 /*++
2
3 Copyright (c) 1999-2006 Intel Corporation. All rights reserved
4 This program and the accompanying materials are licensed and made available
5 under the terms and conditions of the BSD License which accompanies this
6 distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11
12
13 Module Name:
14
15 PeiRebaseExe.c
16
17 Abstract:
18
19 This contains all code necessary to build the PeiRebase.exe utility.
20 This utility relies heavily on the PeiRebase DLL. Definitions for both
21 can be found in the PEI Rebase Utility Specification, review draft.
22
23 --*/
24
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <string.h>
28
29 #include <Common/UefiBaseTypes.h>
30 #include <Common/FirmwareVolumeImageFormat.h>
31 #include <Common/FirmwareFileSystem.h>
32 #include <Library/PeCoffLib.h>
33
34 #include "CommonLib.h"
35 #include "ParseInf.h"
36 #include "FvLib.h"
37 #include "EfiUtilityMsgs.h"
38 #include "PeiRebaseExe.h"
39
40 EFI_STATUS
41 ReadHeader (
42 IN FILE *InputFile,
43 OUT UINT32 *FvSize,
44 OUT BOOLEAN *ErasePolarity
45 );
46
47 int
48 main (
49 int argc,
50 char **argv
51 )
52 /*++
53
54 Routine Description:
55
56 This utility relocates PEI XIP PE32s in a FV.
57
58 Arguments:
59
60 argc - Number of command line arguments
61 argv[]:
62 BaseAddress The base address to use for rebasing the FV. The correct
63 format is a hex number preceded by 0x.
64 InputFileName The name of the input FV file.
65 OutputFileName The name of the output FV file.
66 MapFileName The name of the map file of relocation info.
67
68 Arguments come in pair in any order.
69 -I InputFileName
70 -O OutputFileName
71 -B BaseAddress
72 -M MapFileName
73
74 Returns:
75
76 0 No error conditions detected.
77 1 One or more of the input parameters is invalid.
78 2 A resource required by the utility was unavailable.
79 Most commonly this will be memory allocation or file creation.
80 3 PeiRebase.dll could not be loaded.
81 4 Error executing the PEI rebase.
82
83 --*/
84 {
85 UINT8 Index;
86 CHAR8 InputFileName[_MAX_PATH];
87 CHAR8 OutputFileName[_MAX_PATH];
88 CHAR8 MapFileName[_MAX_PATH];
89 EFI_PHYSICAL_ADDRESS BaseAddress;
90 BOOLEAN BaseAddressSet;
91 EFI_STATUS Status;
92 FILE *InputFile;
93 FILE *OutputFile;
94 FILE *MapFile;
95 UINT64 FvOffset;
96 UINT32 FileCount;
97 int BytesRead;
98 EFI_FIRMWARE_VOLUME_HEADER *FvImage;
99 UINT32 FvSize;
100 EFI_FFS_FILE_HEADER *CurrentFile;
101 BOOLEAN ErasePolarity;
102 EFI_PHYSICAL_ADDRESS CurrentFileBaseAddress;
103
104 ErasePolarity = FALSE;
105 //
106 // Set utility name for error/warning reporting purposes.
107 //
108 SetUtilityName (UTILITY_NAME);
109 //
110 // Verify the correct number of arguments
111 //
112 if (argc != MAX_ARGS) {
113 PrintUsage ();
114 return STATUS_ERROR;
115 }
116
117 //
118 // Initialize variables
119 //
120 InputFileName[0] = 0;
121 OutputFileName[0] = 0;
122 MapFileName[0] = 0;
123 BaseAddress = 0;
124 BaseAddressSet = FALSE;
125 FvOffset = 0;
126 FileCount = 0;
127 ErasePolarity = FALSE;
128 InputFile = NULL;
129 OutputFile = NULL;
130 MapFile = NULL;
131 FvImage = NULL;
132
133 //
134 // Parse the command line arguments
135 //
136 for (Index = 1; Index < MAX_ARGS; Index += 2) {
137 //
138 // Make sure argument pair begin with - or /
139 //
140 if (argv[Index][0] != '-' && argv[Index][0] != '/') {
141 PrintUsage ();
142 Error (NULL, 0, 0, argv[Index], "unrecognized option");
143 return STATUS_ERROR;
144 }
145 //
146 // Make sure argument specifier is only one letter
147 //
148 if (argv[Index][2] != 0) {
149 PrintUsage ();
150 Error (NULL, 0, 0, argv[Index], "unrecognized option");
151 return STATUS_ERROR;
152 }
153 //
154 // Determine argument to read
155 //
156 switch (argv[Index][1]) {
157 case 'I':
158 case 'i':
159 if (strlen (InputFileName) == 0) {
160 strcpy (InputFileName, argv[Index + 1]);
161 } else {
162 PrintUsage ();
163 Error (NULL, 0, 0, argv[Index + 1], "only one -i InputFileName may be specified");
164 return STATUS_ERROR;
165 }
166 break;
167
168 case 'O':
169 case 'o':
170 if (strlen (OutputFileName) == 0) {
171 strcpy (OutputFileName, argv[Index + 1]);
172 } else {
173 PrintUsage ();
174 Error (NULL, 0, 0, argv[Index + 1], "only one -o OutputFileName may be specified");
175 return STATUS_ERROR;
176 }
177 break;
178
179 case 'B':
180 case 'b':
181 if (!BaseAddressSet) {
182 Status = AsciiStringToUint64 (argv[Index + 1], FALSE, &BaseAddress);
183 if (EFI_ERROR (Status)) {
184 PrintUsage ();
185 Error (NULL, 0, 0, argv[Index + 1], "invalid hex digit given for the base address");
186 return STATUS_ERROR;
187 }
188
189 BaseAddressSet = TRUE;
190 } else {
191 PrintUsage ();
192 Error (NULL, 0, 0, argv[Index + 1], "-b BaseAddress may only be specified once");
193 return STATUS_ERROR;
194 }
195 break;
196
197 case 'M':
198 case 'm':
199 if (strlen (MapFileName) == 0) {
200 strcpy (MapFileName, argv[Index + 1]);
201 } else {
202 PrintUsage ();
203 Error (NULL, 0, 0, argv[Index + 1], "only one -m MapFileName may be specified");
204 return STATUS_ERROR;
205 }
206 break;
207
208 default:
209 PrintUsage ();
210 Error (NULL, 0, 0, argv[Index], "unrecognized argument");
211 return STATUS_ERROR;
212 break;
213 }
214 }
215
216 //
217 // Create the Map file if we need it
218 //
219 if (strlen (MapFileName) != 0) {
220 MapFile = fopen (MapFileName, "w");
221 if (MapFile == NULL) {
222 Error (NULL, 0, 0, MapFileName, "failed to open map file");
223 goto Finish;
224 }
225 }
226
227 //
228 // Open the file containing the FV
229 //
230 InputFile = fopen (InputFileName, "rb");
231 if (InputFile == NULL) {
232 Error (NULL, 0, 0, InputFileName, "could not open input file for reading");
233 return STATUS_ERROR;
234 }
235 //
236 // Determine size of FV
237 //
238 Status = ReadHeader (InputFile, &FvSize, &ErasePolarity);
239 if (EFI_ERROR (Status)) {
240 Error (NULL, 0, 0, "could not parse the FV header", NULL);
241 goto Finish;
242 }
243 //
244 // Allocate a buffer for the FV image
245 //
246 FvImage = malloc (FvSize);
247 if (FvImage == NULL) {
248 Error (NULL, 0, 0, "application error", "memory allocation failed");
249 goto Finish;
250 }
251 //
252 // Read the entire FV to the buffer
253 //
254 BytesRead = fread (FvImage, 1, FvSize, InputFile);
255 fclose (InputFile);
256 InputFile = NULL;
257 if ((unsigned int) BytesRead != FvSize) {
258 Error (NULL, 0, 0, InputFileName, "failed to read from file");
259 goto Finish;
260 }
261 //
262 // Prepare to walk the FV image
263 //
264 InitializeFvLib (FvImage, FvSize);
265 //
266 // Get the first file
267 //
268 Status = GetNextFile (NULL, &CurrentFile);
269 if (EFI_ERROR (Status)) {
270 Error (NULL, 0, 0, "cannot find the first file in the FV image", NULL);
271 goto Finish;
272 }
273 //
274 // Check if each file should be rebased
275 //
276 while (CurrentFile != NULL) {
277 //
278 // Rebase this file
279 //
280 CurrentFileBaseAddress = BaseAddress + ((UINTN) CurrentFile - (UINTN) FvImage);
281 Status = FfsRebase (CurrentFile, CurrentFileBaseAddress, MapFile);
282
283 if (EFI_ERROR (Status)) {
284 switch (Status) {
285
286 case EFI_INVALID_PARAMETER:
287 Error (NULL, 0, 0, "invalid parameter passed to FfsRebase", NULL);
288 break;
289
290 case EFI_ABORTED:
291 Error (NULL, 0, 0, "error detected while rebasing -- aborted", NULL);
292 break;
293
294 case EFI_OUT_OF_RESOURCES:
295 Error (NULL, 0, 0, "FfsRebase could not allocate required resources", NULL);
296 break;
297
298 case EFI_NOT_FOUND:
299 Error (NULL, 0, 0, "FfsRebase could not locate a PE32 section", NULL);
300 break;
301
302 default:
303 Error (NULL, 0, 0, "FfsRebase returned unknown status", "status=0x%08X", Status);
304 break;
305 }
306
307 goto Finish;
308 }
309
310 //
311 // Get the next file
312 //
313 Status = GetNextFile (CurrentFile, &CurrentFile);
314 if (EFI_ERROR (Status)) {
315 Error (NULL, 0, 0, "cannot find the next file in the FV image", NULL);
316 goto Finish;
317 }
318 }
319 //
320 // Open the output file
321 //
322 OutputFile = fopen (OutputFileName, "wb");
323 if (OutputFile == NULL) {
324 Error (NULL, 0, 0, OutputFileName, "failed to open output file");
325 goto Finish;
326 }
327
328 if (fwrite (FvImage, 1, FvSize, OutputFile) != FvSize) {
329 Error (NULL, 0, 0, "failed to write to output file", 0);
330 goto Finish;
331 }
332
333 Finish:
334 if (InputFile != NULL) {
335 fclose (InputFile);
336 }
337 //
338 // If we created an output file, and there was an error, remove it so
339 // subsequent builds will rebuild it.
340 //
341 if (OutputFile != NULL) {
342 if (GetUtilityStatus () == STATUS_ERROR) {
343 remove (OutputFileName);
344 }
345
346 fclose (OutputFile);
347 }
348
349 if (MapFile != NULL) {
350 fclose (MapFile);
351 }
352
353 if (FvImage != NULL) {
354 free (FvImage);
355 }
356
357 return GetUtilityStatus ();
358 }
359
360 EFI_STATUS
361 ReadHeader (
362 IN FILE *InputFile,
363 OUT UINT32 *FvSize,
364 OUT BOOLEAN *ErasePolarity
365 )
366 /*++
367
368 Routine Description:
369
370 This function determines the size of the FV and the erase polarity. The
371 erase polarity is the FALSE value for file state.
372
373 Arguments:
374
375 InputFile The file that contains the FV image.
376 FvSize The size of the FV.
377 ErasePolarity The FV erase polarity.
378
379 Returns:
380
381 EFI_SUCCESS Function completed successfully.
382 EFI_INVALID_PARAMETER A required parameter was NULL or is out of range.
383 EFI_ABORTED The function encountered an error.
384
385 --*/
386 {
387 EFI_FIRMWARE_VOLUME_HEADER VolumeHeader;
388 EFI_FV_BLOCK_MAP_ENTRY BlockMap;
389 UINTN Signature[2];
390 UINTN BytesRead;
391 UINT32 Size;
392
393 BytesRead = 0;
394 Size = 0;
395 //
396 // Check input parameters
397 //
398 if ((InputFile == NULL) || (FvSize == NULL) || (ErasePolarity == NULL)) {
399 Error (NULL, 0, 0, "ReadHeader()", "invalid input parameter");
400 return EFI_INVALID_PARAMETER;
401 }
402 //
403 // Read the header
404 //
405 fread (&VolumeHeader, sizeof (EFI_FIRMWARE_VOLUME_HEADER) - sizeof (EFI_FV_BLOCK_MAP_ENTRY), 1, InputFile);
406 BytesRead = sizeof (EFI_FIRMWARE_VOLUME_HEADER) - sizeof (EFI_FV_BLOCK_MAP_ENTRY);
407 Signature[0] = VolumeHeader.Signature;
408 Signature[1] = 0;
409
410 //
411 // Get erase polarity
412 //
413 if (VolumeHeader.Attributes & EFI_FVB_ERASE_POLARITY) {
414 *ErasePolarity = TRUE;
415 }
416
417 do {
418 fread (&BlockMap, sizeof (EFI_FV_BLOCK_MAP_ENTRY), 1, InputFile);
419 BytesRead += sizeof (EFI_FV_BLOCK_MAP_ENTRY);
420
421 if (BlockMap.NumBlocks != 0) {
422 Size += BlockMap.NumBlocks * BlockMap.BlockLength;
423 }
424
425 } while (!(BlockMap.NumBlocks == 0 && BlockMap.BlockLength == 0));
426
427 if (VolumeHeader.FvLength != Size) {
428 Error (NULL, 0, 0, "volume size not consistant with block maps", NULL);
429 return EFI_ABORTED;
430 }
431
432 *FvSize = Size;
433
434 rewind (InputFile);
435
436 return EFI_SUCCESS;
437 }
438
439 VOID
440 PrintUtilityInfo (
441 VOID
442 )
443 /*++
444
445 Routine Description:
446
447 Displays the standard utility information to SDTOUT
448
449 Arguments:
450
451 None
452
453 Returns:
454
455 None
456
457 --*/
458 {
459 printf (
460 "%s, PEI Rebase Utility. Version %i.%i, %s.\n\n",
461 UTILITY_NAME,
462 UTILITY_MAJOR_VERSION,
463 UTILITY_MINOR_VERSION,
464 UTILITY_DATE
465 );
466 }
467
468 VOID
469 PrintUsage (
470 VOID
471 )
472 /*++
473
474 Routine Description:
475
476 Displays the utility usage syntax to STDOUT
477
478 Arguments:
479
480 None
481
482 Returns:
483
484 None
485
486 --*/
487 {
488 printf (
489 "Usage: %s -I InputFileName -O OutputFileName -B BaseAddress [-M MapFile]\n",
490 UTILITY_NAME
491 );
492 printf (" Where:\n");
493 printf (" InputFileName is the name of the EFI FV file to rebase.\n");
494 printf (" OutputFileName is the desired output file name.\n");
495 printf (" BaseAddress is the FV base address to rebase agains.\n");
496 printf (" MapFileName is an optional map file of the relocations\n");
497 printf (" Argument pair may be in any order.\n\n");
498 }
499
500 EFI_STATUS
501 FfsRebase (
502 IN OUT EFI_FFS_FILE_HEADER *FfsFile,
503 IN EFI_PHYSICAL_ADDRESS BaseAddress,
504 IN FILE *MapFile OPTIONAL
505 )
506 /*++
507
508 Routine Description:
509
510 This function determines if a file is XIP and should be rebased. It will
511 rebase any PE32 sections found in the file using the base address.
512
513 Arguments:
514
515 FfsFile A pointer to Ffs file image.
516 BaseAddress The base address to use for rebasing the file image.
517 MapFile Optional file to dump relocation information into
518
519 Returns:
520
521 EFI_SUCCESS The image was properly rebased.
522 EFI_INVALID_PARAMETER An input parameter is invalid.
523 EFI_ABORTED An error occurred while rebasing the input file image.
524 EFI_OUT_OF_RESOURCES Could not allocate a required resource.
525 EFI_NOT_FOUND No compressed sections could be found.
526
527 --*/
528 {
529 EFI_STATUS Status;
530 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
531 UINTN MemoryImagePointer;
532 UINTN MemoryImagePointerAligned;
533 EFI_PHYSICAL_ADDRESS ImageAddress;
534 UINT64 ImageSize;
535 EFI_PHYSICAL_ADDRESS EntryPoint;
536 UINT32 Pe32ImageSize;
537 UINT32 NewPe32BaseAddress;
538 UINTN Index;
539 EFI_FILE_SECTION_POINTER CurrentPe32Section;
540 EFI_FFS_FILE_STATE SavedState;
541 EFI_IMAGE_NT_HEADERS *PeHdr;
542 UINT32 *PeHdrSizeOfImage;
543 UINT32 *PeHdrChecksum;
544 UINT32 FoundCount;
545 EFI_TE_IMAGE_HEADER *TEImageHeader;
546 UINT8 *TEBuffer;
547 EFI_IMAGE_DOS_HEADER *DosHeader;
548 UINT8 FileGuidString[80];
549 UINT32 TailSize;
550 EFI_FFS_FILE_TAIL TailValue;
551
552 //
553 // Verify input parameters
554 //
555 if (FfsFile == NULL) {
556 return EFI_INVALID_PARAMETER;
557 }
558
559 //
560 // Convert the GUID to a string so we can at least report which file
561 // if we find an error.
562 //
563 PrintGuidToBuffer (&FfsFile->Name, FileGuidString, sizeof (FileGuidString), TRUE);
564 if (FfsFile->Attributes & FFS_ATTRIB_TAIL_PRESENT) {
565 TailSize = sizeof (EFI_FFS_FILE_TAIL);
566 } else {
567 TailSize = 0;
568 }
569
570 //
571 // Do some cursory checks on the FFS file contents
572 //
573 Status = VerifyFfsFile (FfsFile);
574 if (EFI_ERROR (Status)) {
575 Error (NULL, 0, 0, "file does not appear to be a valid FFS file, cannot be rebased", FileGuidString);
576 return EFI_INVALID_PARAMETER;
577 }
578
579 memset (&ImageContext, 0, sizeof (ImageContext));
580
581 //
582 // Check if XIP file type. If not XIP, don't rebase.
583 //
584 if (FfsFile->Type != EFI_FV_FILETYPE_PEI_CORE &&
585 FfsFile->Type != EFI_FV_FILETYPE_PEIM &&
586 FfsFile->Type != EFI_FV_FILETYPE_SECURITY_CORE &&
587 FfsFile->Type != EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER
588 ) {
589 return EFI_SUCCESS;
590 }
591
592 //
593 // Rebase each PE32 section
594 //
595 Status = EFI_SUCCESS;
596 FoundCount = 0;
597 for (Index = 1;; Index++) {
598 Status = GetSectionByType (FfsFile, EFI_SECTION_PE32, Index, &CurrentPe32Section);
599 if (EFI_ERROR (Status)) {
600 break;
601 }
602
603 FoundCount++;
604
605 //
606 // Calculate the PE32 base address, the FFS file base plus the offset of the PE32 section
607 //
608 NewPe32BaseAddress = ((UINT32) BaseAddress) + ((UINTN) CurrentPe32Section.Pe32Section + sizeof (EFI_COMMON_SECTION_HEADER) - (UINTN) FfsFile);
609
610 //
611 // Initialize context
612 //
613 memset (&ImageContext, 0, sizeof (ImageContext));
614 ImageContext.Handle = (VOID *) ((UINTN) CurrentPe32Section.Pe32Section + sizeof (EFI_PE32_SECTION));
615 ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) FfsRebaseImageRead;
616
617 Status = PeCoffLoaderGetImageInfo (&ImageContext);
618
619 if (EFI_ERROR (Status)) {
620 Error (NULL, 0, 0, "GetImageInfo() call failed on rebase", FileGuidString);
621 return Status;
622 }
623 //
624 // Allocate a buffer for the image to be loaded into.
625 //
626 Pe32ImageSize = GetLength (CurrentPe32Section.Pe32Section->CommonHeader.Size) - sizeof (EFI_PE32_SECTION);
627 MemoryImagePointer = (UINTN) (malloc (Pe32ImageSize + 0x1000));
628 if (MemoryImagePointer == 0) {
629 Error (NULL, 0, 0, "memory allocation failure", NULL);
630 return EFI_OUT_OF_RESOURCES;
631 }
632 memset ((void *) MemoryImagePointer, 0, Pe32ImageSize + 0x1000);
633 MemoryImagePointerAligned = (MemoryImagePointer + 0x0FFF) & (-1 << 12);
634
635
636 ImageContext.ImageAddress = MemoryImagePointerAligned;
637
638 Status = PeCoffLoaderLoadImage (&ImageContext);
639 if (EFI_ERROR (Status)) {
640 Error (NULL, 0, 0, "LoadImage() call failed on rebase", FileGuidString);
641 free ((VOID *) MemoryImagePointer);
642 return Status;
643 }
644
645 ImageContext.DestinationAddress = NewPe32BaseAddress;
646 Status = PeCoffLoaderRelocateImage (&ImageContext);
647 if (EFI_ERROR (Status)) {
648 Error (NULL, 0, 0, "RelocateImage() call failed on rebase", FileGuidString);
649 free ((VOID *) MemoryImagePointer);
650 return Status;
651 }
652
653 ImageAddress = ImageContext.ImageAddress;
654 ImageSize = ImageContext.ImageSize;
655 EntryPoint = ImageContext.EntryPoint;
656
657 if (ImageSize > Pe32ImageSize) {
658 Error (
659 NULL,
660 0,
661 0,
662 "rebased image is larger than original PE32 image",
663 "0x%X > 0x%X, file %s",
664 ImageSize,
665 Pe32ImageSize,
666 FileGuidString
667 );
668 free ((VOID *) MemoryImagePointer);
669 return EFI_ABORTED;
670 }
671 //
672 // Since we may have updated the Codeview RVA, we need to insure the PE
673 // header indicates the image is large enough to contain the Codeview data
674 // so it will be loaded properly later if the PEIM is reloaded into memory...
675 //
676 PeHdr = (VOID *) ((UINTN) ImageAddress + ImageContext.PeCoffHeaderOffset);
677 if (PeHdr->FileHeader.Machine == EFI_IMAGE_MACHINE_IA32) {
678 PeHdrSizeOfImage = (UINT32 *) (&(*(EFI_IMAGE_OPTIONAL_HEADER32 *) &PeHdr->OptionalHeader).SizeOfImage);
679 PeHdrChecksum = (UINT32 *) (&(*(EFI_IMAGE_OPTIONAL_HEADER32 *) &PeHdr->OptionalHeader).CheckSum);
680 } else if (PeHdr->FileHeader.Machine == EFI_IMAGE_MACHINE_IA64) {
681 PeHdrSizeOfImage = (UINT32 *) (&(*(EFI_IMAGE_OPTIONAL_HEADER64 *) &PeHdr->OptionalHeader).SizeOfImage);
682 PeHdrChecksum = (UINT32 *) (&(*(EFI_IMAGE_OPTIONAL_HEADER64 *) &PeHdr->OptionalHeader).CheckSum);
683 } else if (PeHdr->FileHeader.Machine == EFI_IMAGE_MACHINE_X64) {
684 PeHdrSizeOfImage = (UINT32 *) (&(*(EFI_IMAGE_OPTIONAL_HEADER64 *) &PeHdr->OptionalHeader).SizeOfImage);
685 PeHdrChecksum = (UINT32 *) (&(*(EFI_IMAGE_OPTIONAL_HEADER64 *) &PeHdr->OptionalHeader).CheckSum);
686 } else {
687 Error (
688 NULL,
689 0,
690 0,
691 "unknown machine type in PE32 image",
692 "machine type=0x%X, file=%s",
693 (UINT32) PeHdr->FileHeader.Machine,
694 FileGuidString
695 );
696 free ((VOID *) MemoryImagePointer);
697 return EFI_ABORTED;
698 }
699
700 if (*PeHdrSizeOfImage != ImageContext.ImageSize) {
701 *PeHdrSizeOfImage = (UINT32) ImageContext.ImageSize;
702 if (*PeHdrChecksum) {
703 *PeHdrChecksum = 0;
704 }
705 }
706
707 memcpy (CurrentPe32Section.Pe32Section + 1, (VOID *) MemoryImagePointerAligned, (UINT32) ImageSize);
708
709 free ((VOID *) MemoryImagePointer);
710
711 //
712 // Now update file checksum
713 //
714 if (FfsFile->Attributes & FFS_ATTRIB_TAIL_PRESENT) {
715 TailSize = sizeof (EFI_FFS_FILE_TAIL);
716 } else {
717 TailSize = 0;
718 }
719
720 if (FfsFile->Attributes & FFS_ATTRIB_CHECKSUM) {
721 SavedState = FfsFile->State;
722 FfsFile->IntegrityCheck.Checksum.File = 0;
723 FfsFile->State = 0;
724 if (FfsFile->Attributes & FFS_ATTRIB_CHECKSUM) {
725 FfsFile->IntegrityCheck.Checksum.File = CalculateChecksum8 (
726 (UINT8 *) FfsFile,
727 GetLength (FfsFile->Size) - TailSize
728 );
729 } else {
730 FfsFile->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;
731 }
732
733 FfsFile->State = SavedState;
734 }
735 //
736 // Update tail if present
737 //
738 if (FfsFile->Attributes & FFS_ATTRIB_TAIL_PRESENT) {
739 TailValue = (EFI_FFS_FILE_TAIL) (~(FfsFile->IntegrityCheck.TailReference));
740 *(EFI_FFS_FILE_TAIL *) (((UINTN) FfsFile + GetLength (FfsFile->Size) - sizeof (EFI_FFS_FILE_TAIL))) = TailValue;
741 }
742 }
743 //
744 // Now process TE sections
745 //
746 for (Index = 1;; Index++) {
747 Status = GetSectionByType (FfsFile, EFI_SECTION_TE, Index, &CurrentPe32Section);
748 if (EFI_ERROR (Status)) {
749 break;
750 }
751
752 FoundCount++;
753
754 //
755 // Calculate the TE base address, the FFS file base plus the offset of the TE section less the size stripped off
756 // by GenTEImage
757 //
758 TEImageHeader = (EFI_TE_IMAGE_HEADER *) ((UINT8 *) CurrentPe32Section.Pe32Section + sizeof (EFI_COMMON_SECTION_HEADER));
759
760 NewPe32BaseAddress = ((UINT32) BaseAddress) +
761 (
762 (UINTN) CurrentPe32Section.Pe32Section +
763 sizeof (EFI_COMMON_SECTION_HEADER) +
764 sizeof (EFI_TE_IMAGE_HEADER) -
765 TEImageHeader->StrippedSize -
766 (UINTN) FfsFile
767 );
768
769 //
770 // Allocate a buffer to unshrink the image into.
771 //
772 Pe32ImageSize = GetLength (CurrentPe32Section.Pe32Section->CommonHeader.Size) - sizeof (EFI_PE32_SECTION) -
773 sizeof (EFI_TE_IMAGE_HEADER);
774 Pe32ImageSize += TEImageHeader->StrippedSize;
775 TEBuffer = (UINT8 *) malloc (Pe32ImageSize);
776 if (TEBuffer == NULL) {
777 Error (NULL, 0, 0, "failed to allocate memory", NULL);
778 return EFI_OUT_OF_RESOURCES;
779 }
780 //
781 // Expand the image into our buffer and fill in critical fields in the DOS header
782 // Fill in fields required by the loader.
783 // At offset 0x3C is the offset to the PE signature. We'll put it immediately following the offset value
784 // itself.
785 //
786 memset (TEBuffer, 0, Pe32ImageSize);
787 DosHeader = (EFI_IMAGE_DOS_HEADER *) TEBuffer;
788 DosHeader->e_magic = EFI_IMAGE_DOS_SIGNATURE;
789 *(UINT32 *) (TEBuffer + 0x3C) = 0x40;
790 PeHdr = (EFI_IMAGE_NT_HEADERS *) (TEBuffer + 0x40);
791 PeHdr->Signature = EFI_IMAGE_NT_SIGNATURE;
792 PeHdr->FileHeader.Machine = TEImageHeader->Machine;
793 PeHdr->FileHeader.NumberOfSections = TEImageHeader->NumberOfSections;
794
795 //
796 // Say the size of the optional header is the total we stripped off less the size of a PE file header and PE signature and
797 // the 0x40 bytes for our DOS header.
798 //
799 PeHdr->FileHeader.SizeOfOptionalHeader = (UINT16) (TEImageHeader->StrippedSize - 0x40 - sizeof (UINT32) - sizeof (EFI_IMAGE_FILE_HEADER));
800 PeHdr->OptionalHeader.ImageBase = (UINTN) (TEImageHeader->ImageBase - TEImageHeader->StrippedSize + sizeof (EFI_TE_IMAGE_HEADER));
801 PeHdr->OptionalHeader.SizeOfImage = Pe32ImageSize;
802 PeHdr->OptionalHeader.Subsystem = TEImageHeader->Subsystem;
803 PeHdr->OptionalHeader.SizeOfImage = Pe32ImageSize;
804 PeHdr->OptionalHeader.SizeOfHeaders = TEImageHeader->StrippedSize + TEImageHeader->NumberOfSections *
805 sizeof (EFI_IMAGE_SECTION_HEADER) - 12;
806
807 //
808 // Set NumberOfRvaAndSizes in the optional header to what we had available in the original image
809 //
810 if ((TEImageHeader->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress != 0) ||
811 (TEImageHeader->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size != 0)
812 ) {
813 PeHdr->OptionalHeader.NumberOfRvaAndSizes = EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC + 1;
814 PeHdr->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = TEImageHeader->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress;
815 PeHdr->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = TEImageHeader->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size;
816 }
817
818 if ((TEImageHeader->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress != 0) ||
819 (TEImageHeader->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].Size != 0)
820 ) {
821 PeHdr->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress = TEImageHeader->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress;
822 PeHdr->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].Size = TEImageHeader->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].Size;
823 if (PeHdr->OptionalHeader.NumberOfRvaAndSizes < EFI_IMAGE_DIRECTORY_ENTRY_DEBUG + 1) {
824 PeHdr->OptionalHeader.NumberOfRvaAndSizes = EFI_IMAGE_DIRECTORY_ENTRY_DEBUG + 1;
825 }
826 }
827 //
828 // NOTE: These values are defaults, and should be verified to be correct in the GenTE utility
829 //
830 PeHdr->OptionalHeader.SectionAlignment = 0x10;
831
832 //
833 // Copy the rest of the image to its original offset
834 //
835 memcpy (
836 TEBuffer + TEImageHeader->StrippedSize,
837 (UINT8 *) CurrentPe32Section.Pe32Section + sizeof (EFI_PE32_SECTION) + sizeof (EFI_TE_IMAGE_HEADER),
838 GetLength (CurrentPe32Section.Pe32Section->CommonHeader.Size) - sizeof (EFI_PE32_SECTION) -
839 sizeof (EFI_TE_IMAGE_HEADER)
840 );
841
842 //
843 // Initialize context
844 //
845 memset (&ImageContext, 0, sizeof (ImageContext));
846 ImageContext.Handle = (VOID *) TEBuffer;
847 ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) FfsRebaseImageRead;
848
849 Status = PeCoffLoaderGetImageInfo (&ImageContext);
850
851 if (EFI_ERROR (Status)) {
852 Error (NULL, 0, 0, "GetImageInfo() call failed on rebase of TE image", FileGuidString);
853 free (TEBuffer);
854 return Status;
855 }
856 //
857 // Allocate a buffer for the image to be loaded into.
858 //
859 MemoryImagePointer = (UINTN) (malloc (Pe32ImageSize + 0x1000));
860 if (MemoryImagePointer == 0) {
861 Error (NULL, 0, 0, "memory allocation error on rebase of TE image", FileGuidString);
862 free (TEBuffer);
863 return EFI_OUT_OF_RESOURCES;
864 }
865 memset ((void *) MemoryImagePointer, 0, Pe32ImageSize + 0x1000);
866 MemoryImagePointerAligned = (MemoryImagePointer + 0x0FFF) & (-1 << 12);
867
868
869 ImageContext.ImageAddress = MemoryImagePointerAligned;
870 Status = PeCoffLoaderLoadImage (&ImageContext);
871 if (EFI_ERROR (Status)) {
872 Error (NULL, 0, 0, "LoadImage() call failed on rebase of TE image", FileGuidString);
873 free (TEBuffer);
874 free ((VOID *) MemoryImagePointer);
875 return Status;
876 }
877
878 ImageContext.DestinationAddress = NewPe32BaseAddress;
879 Status = PeCoffLoaderRelocateImage (&ImageContext);
880 if (EFI_ERROR (Status)) {
881 Error (NULL, 0, 0, "RelocateImage() call failed on rebase of TE image", FileGuidString);
882 free ((VOID *) MemoryImagePointer);
883 free (TEBuffer);
884 return Status;
885 }
886
887 ImageAddress = ImageContext.ImageAddress;
888 ImageSize = ImageContext.ImageSize;
889 EntryPoint = ImageContext.EntryPoint;
890
891 //
892 // Since we may have updated the Codeview RVA, we need to insure the PE
893 // header indicates the image is large enough to contain the Codeview data
894 // so it will be loaded properly later if the PEIM is reloaded into memory...
895 //
896 PeHdr = (VOID *) ((UINTN) ImageAddress + ImageContext.PeCoffHeaderOffset);
897 if (PeHdr->FileHeader.Machine == EFI_IMAGE_MACHINE_IA32) {
898 PeHdrSizeOfImage = (UINT32 *) (&(*(EFI_IMAGE_OPTIONAL_HEADER32 *) &PeHdr->OptionalHeader).SizeOfImage);
899 PeHdrChecksum = (UINT32 *) (&(*(EFI_IMAGE_OPTIONAL_HEADER32 *) &PeHdr->OptionalHeader).CheckSum);
900 } else if (PeHdr->FileHeader.Machine == EFI_IMAGE_MACHINE_IA64) {
901 PeHdrSizeOfImage = (UINT32 *) (&(*(EFI_IMAGE_OPTIONAL_HEADER64 *) &PeHdr->OptionalHeader).SizeOfImage);
902 PeHdrChecksum = (UINT32 *) (&(*(EFI_IMAGE_OPTIONAL_HEADER64 *) &PeHdr->OptionalHeader).CheckSum);
903 } else {
904 Error (
905 NULL,
906 0,
907 0,
908 "unknown machine type in TE image",
909 "machine type=0x%X, file=%s",
910 (UINT32) PeHdr->FileHeader.Machine,
911 FileGuidString
912 );
913 free ((VOID *) MemoryImagePointer);
914 free (TEBuffer);
915 return EFI_ABORTED;
916 }
917
918 if (*PeHdrSizeOfImage != ImageContext.ImageSize) {
919 *PeHdrSizeOfImage = (UINT32) ImageContext.ImageSize;
920 if (*PeHdrChecksum) {
921 *PeHdrChecksum = 0;
922 }
923 }
924
925 TEImageHeader->ImageBase = (UINT64) (NewPe32BaseAddress + TEImageHeader->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER));
926 memcpy (
927 (UINT8 *) (CurrentPe32Section.Pe32Section + 1) + sizeof (EFI_TE_IMAGE_HEADER),
928 (VOID *) ((UINT8 *) MemoryImagePointerAligned + TEImageHeader->StrippedSize),
929 GetLength (CurrentPe32Section.Pe32Section->CommonHeader.Size) - sizeof (EFI_PE32_SECTION) -
930 sizeof (EFI_TE_IMAGE_HEADER)
931 );
932 free ((VOID *) MemoryImagePointer);
933 free (TEBuffer);
934 if (FfsFile->Attributes & FFS_ATTRIB_TAIL_PRESENT) {
935 TailSize = sizeof (EFI_FFS_FILE_TAIL);
936 } else {
937 TailSize = 0;
938 }
939 //
940 // Now update file checksum
941 //
942 if (FfsFile->Attributes & FFS_ATTRIB_CHECKSUM) {
943 SavedState = FfsFile->State;
944 FfsFile->IntegrityCheck.Checksum.File = 0;
945 FfsFile->State = 0;
946 if (FfsFile->Attributes & FFS_ATTRIB_CHECKSUM) {
947 FfsFile->IntegrityCheck.Checksum.File = CalculateChecksum8 (
948 (UINT8 *) FfsFile,
949 GetLength (FfsFile->Size) - TailSize
950 );
951 } else {
952 FfsFile->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;
953 }
954
955 FfsFile->State = SavedState;
956 }
957 //
958 // Update tail if present
959 //
960 if (FfsFile->Attributes & FFS_ATTRIB_TAIL_PRESENT) {
961 TailValue = (EFI_FFS_FILE_TAIL) (~(FfsFile->IntegrityCheck.TailReference));
962 *(EFI_FFS_FILE_TAIL *) (((UINTN) FfsFile + GetLength (FfsFile->Size) - sizeof (EFI_FFS_FILE_TAIL))) = TailValue;
963 }
964 }
965 //
966 // If we found no files, then emit an error if no compressed sections either
967 //
968 if (FoundCount == 0) {
969 Status = GetSectionByType (FfsFile, EFI_SECTION_COMPRESSION, Index, &CurrentPe32Section);
970 if (EFI_ERROR (Status)) {
971 Error (NULL, 0, 0, "no PE32, TE, nor compressed section found in FV file", FileGuidString);
972 return EFI_NOT_FOUND;
973 }
974 }
975
976 //
977 // If a map file was selected output mapping information for any file that
978 // was rebased.
979 //
980 if (MapFile != NULL) {
981 fprintf (MapFile, "File: %s Base:%08lx", FileGuidString, BaseAddress);
982 if (ImageContext.PdbPointer != NULL) {
983 fprintf (MapFile, " FileName: %s", ImageContext.PdbPointer);
984 }
985 fprintf (MapFile, "\n");
986 }
987
988 return EFI_SUCCESS;
989 }
990
991 EFI_STATUS
992 FfsRebaseImageRead (
993 IN VOID *FileHandle,
994 IN UINTN FileOffset,
995 IN OUT UINT32 *ReadSize,
996 OUT VOID *Buffer
997 )
998 /*++
999
1000 Routine Description:
1001
1002 Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file
1003
1004 Arguments:
1005
1006 FileHandle - The handle to the PE/COFF file
1007
1008 FileOffset - The offset, in bytes, into the file to read
1009
1010 ReadSize - The number of bytes to read from the file starting at FileOffset
1011
1012 Buffer - A pointer to the buffer to read the data into.
1013
1014 Returns:
1015
1016 EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset
1017
1018 --*/
1019 {
1020 CHAR8 *Destination8;
1021 CHAR8 *Source8;
1022 UINT32 Length;
1023
1024 Destination8 = Buffer;
1025 Source8 = (CHAR8 *) ((UINTN) FileHandle + FileOffset);
1026 Length = *ReadSize;
1027 while (Length--) {
1028 *(Destination8++) = *(Source8++);
1029 }
1030
1031 return EFI_SUCCESS;
1032 }