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