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