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