]> git.proxmox.com Git - mirror_edk2.git/blame - Tools/CCode/Source/PeiRebase/PeiRebaseExe.c
Added/modified utility usage and version display.
[mirror_edk2.git] / Tools / CCode / Source / PeiRebase / PeiRebaseExe.c
CommitLineData
d25c4bf0 1/*++\r
2\r
ad1f8df0 3Copyright (c) 1999-2006 Intel Corporation. All rights reserved\r
8733430b 4This program and the accompanying materials are licensed and made available\r
5under the terms and conditions of the BSD License which accompanies this\r
ad1f8df0 6distribution. The full text of the license may be found at\r
7http://opensource.org/licenses/bsd-license.php\r
8\r
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
d25c4bf0 11\r
12\r
13Module Name:\r
14\r
15 PeiRebaseExe.c\r
16\r
17Abstract:\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
d25c4bf0 25#include <stdlib.h>\r
26#include <stdio.h>\r
27#include <string.h>\r
ce53a8c3 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
3ce2b1a8 34#include "CommonLib.h"\r
d25c4bf0 35#include "ParseInf.h"\r
d25c4bf0 36#include "FvLib.h"\r
d25c4bf0 37#include "EfiUtilityMsgs.h"\r
51d48c26 38#include "PeiRebaseExe.h"\r
d25c4bf0 39\r
d25c4bf0 40EFI_STATUS\r
41ReadHeader (\r
42 IN FILE *InputFile,\r
43 OUT UINT32 *FvSize,\r
44 OUT BOOLEAN *ErasePolarity\r
45 );\r
46\r
47int\r
48main (\r
49 int argc,\r
50 char **argv\r
51 )\r
52/*++\r
53\r
54Routine Description:\r
55\r
56 This utility relocates PEI XIP PE32s in a FV.\r
57\r
58Arguments:\r
59\r
60 argc - Number of command line arguments\r
61 argv[]:\r
8733430b 62 BaseAddress The base address to use for rebasing the FV. The correct\r
d25c4bf0 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
8733430b 68 -I InputFileName\r
d25c4bf0 69 -O OutputFileName\r
8733430b 70 -B BaseAddress\r
d25c4bf0 71\r
72Returns:\r
73\r
74 0 No error conditions detected.\r
75 1 One or more of the input parameters is invalid.\r
8733430b 76 2 A resource required by the utility was unavailable.\r
d25c4bf0 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
8733430b 85 CHAR8 *OutputFileName;\r
86 EFI_PHYSICAL_ADDRESS XipBase, BsBase, RtBase;\r
87 UINT32 BaseTypes;\r
d25c4bf0 88 EFI_STATUS Status;\r
89 FILE *InputFile;\r
90 FILE *OutputFile;\r
8733430b 91 FILE *LogFile;\r
d25c4bf0 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
4c50c885 99 MEMORY_FILE InfMemoryFile;\r
8733430b 100 CHAR8 StringBuffer[0x100];\r
d25c4bf0 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
fd23b925 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
d25c4bf0 124 //\r
125 // Verify the correct number of arguments\r
126 //\r
127 if (argc != MAX_ARGS) {\r
fd23b925 128 Usage ();\r
d25c4bf0 129 return STATUS_ERROR;\r
130 }\r
5049fd31 131\r
d25c4bf0 132 //\r
133 // Initialize variables\r
134 //\r
8733430b 135 InputFileName[0] = '\0';\r
136 OutputFileName = NULL;\r
137 XipBase = BsBase = RtBase = 0;\r
138 BaseTypes = 0;\r
d25c4bf0 139 FvOffset = 0;\r
140 FileCount = 0;\r
141 ErasePolarity = FALSE;\r
142 InputFile = NULL;\r
143 OutputFile = NULL;\r
8733430b 144 LogFile = NULL;\r
d25c4bf0 145 FvImage = NULL;\r
5049fd31 146\r
d25c4bf0 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
fd23b925 155 Usage ();\r
d25c4bf0 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
fd23b925 163 Usage ();\r
d25c4bf0 164 Error (NULL, 0, 0, argv[Index], "unrecognized option");\r
165 return STATUS_ERROR;\r
8733430b 166 }\r
d25c4bf0 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
fd23b925 176 Usage ();\r
d25c4bf0 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
8733430b 184 if (OutputFileName == NULL) {\r
185 OutputFileName = argv[Index + 1];\r
d25c4bf0 186 } else {\r
fd23b925 187 Usage ();\r
d25c4bf0 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
8733430b 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
d25c4bf0 221 case 'B':\r
222 case 'b':\r
8733430b 223 if (BaseTypes & 1) {\r
fd23b925 224 Usage ();\r
8733430b 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
d25c4bf0 228\r
8733430b 229 Status = AsciiStringToUint64 (argv[Index + 1], FALSE, &XipBase);\r
230 if (EFI_ERROR (Status)) {\r
fd23b925 231 Usage ();\r
8733430b 232 Error (NULL, 0, 0, argv[Index + 1], "invalid hex digit given for XIP base address");\r
d25c4bf0 233 return STATUS_ERROR;\r
234 }\r
8733430b 235\r
236 BaseTypes |= 1;\r
d25c4bf0 237 break;\r
238\r
8733430b 239 case 'D':\r
240 case 'd':\r
241 if (BaseTypes & 2) {\r
fd23b925 242 Usage ();\r
8733430b 243 Error (NULL, 0, 0, argv[Index + 1], "-d BsBaseAddress may be specified only once");\r
244 return STATUS_ERROR;\r
245 }\r
4c50c885 246\r
8733430b 247 Status = AsciiStringToUint64 (argv[Index + 1], FALSE, &BsBase);\r
248 if (EFI_ERROR (Status)) {\r
fd23b925 249 Usage ();\r
8733430b 250 Error (NULL, 0, 0, argv[Index + 1], "invalid hex digit given for BS_DRIVER base address");\r
4c50c885
LG
251 return STATUS_ERROR;\r
252 }\r
8733430b 253\r
254 BaseTypes |= 2;\r
4c50c885
LG
255 break;\r
256\r
8733430b 257 case 'R':\r
258 case 'r':\r
259 if (BaseTypes & 4) {\r
fd23b925 260 Usage ();\r
8733430b 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
fd23b925 267 Usage ();\r
8733430b 268 Error (NULL, 0, 0, argv[Index + 1], "invalid hex digit given for RT_DRIVER base address");\r
5049fd31 269 return STATUS_ERROR;\r
270 }\r
8733430b 271\r
272 BaseTypes |= 4;\r
5049fd31 273 break;\r
274\r
d25c4bf0 275 default:\r
fd23b925 276 Usage ();\r
d25c4bf0 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
8733430b 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
d25c4bf0 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
8733430b 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
d25c4bf0 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
403Finish:\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
8733430b 419 if (LogFile != NULL) {\r
420 fclose (LogFile);\r
5049fd31 421 }\r
422\r
d25c4bf0 423 if (FvImage != NULL) {\r
424 free (FvImage);\r
425 }\r
426\r
427 return GetUtilityStatus ();\r
428}\r
429\r
430EFI_STATUS\r
431ReadHeader (\r
432 IN FILE *InputFile,\r
433 OUT UINT32 *FvSize,\r
434 OUT BOOLEAN *ErasePolarity\r
435 )\r
436/*++\r
437\r
438Routine Description:\r
439\r
8733430b 440 This function determines the size of the FV and the erase polarity. The\r
d25c4bf0 441 erase polarity is the FALSE value for file state.\r
442\r
443Arguments:\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
8733430b 448\r
d25c4bf0 449Returns:\r
8733430b 450\r
d25c4bf0 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
509VOID\r
fd23b925 510Version (\r
d25c4bf0 511 VOID\r
512 )\r
513/*++\r
514\r
515Routine Description:\r
516\r
517 Displays the standard utility information to SDTOUT\r
518\r
519Arguments:\r
520\r
521 None\r
522\r
523Returns:\r
524\r
525 None\r
526\r
527--*/\r
528{\r
fd23b925 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
d25c4bf0 531}\r
532\r
533VOID\r
fd23b925 534Usage (\r
d25c4bf0 535 VOID\r
536 )\r
537/*++\r
538\r
539Routine Description:\r
540\r
541 Displays the utility usage syntax to STDOUT\r
542\r
543Arguments:\r
544\r
545 None\r
546\r
547Returns:\r
548\r
549 None\r
550\r
551--*/\r
552{\r
fd23b925 553 Version();\r
554 \r
d25c4bf0 555 printf (\r
fd23b925 556 "\nUsage: %s -I InputFileName -O OutputFileName -B BaseAddress\n",\r
d25c4bf0 557 UTILITY_NAME\r
558 );\r
559 printf (" Where:\n");\r
fd23b925 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
d25c4bf0 564}\r
565\r
566EFI_STATUS\r
567FfsRebase (\r
8733430b 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
d25c4bf0 574 )\r
575/*++\r
576\r
577Routine Description:\r
578\r
8733430b 579 This function determines if a file is XIP and should be rebased. It will\r
d25c4bf0 580 rebase any PE32 sections found in the file using the base address.\r
8733430b 581\r
d25c4bf0 582Arguments:\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
587Returns:\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
4df60ea5 598 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;\r
d25c4bf0 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
8733430b 605 EFI_PHYSICAL_ADDRESS NewPe32BaseAddress;\r
d25c4bf0 606 UINTN Index;\r
607 EFI_FILE_SECTION_POINTER CurrentPe32Section;\r
608 EFI_FFS_FILE_STATE SavedState;\r
8733430b 609 EFI_IMAGE_NT_HEADERS32 *PeHdr;\r
610 EFI_IMAGE_NT_HEADERS64 *PePlusHdr;\r
d25c4bf0 611 UINT32 *PeHdrSizeOfImage;\r
612 UINT32 *PeHdrChecksum;\r
d25c4bf0 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
8733430b 619 EFI_PHYSICAL_ADDRESS *BaseToUpdate;\r
d25c4bf0 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
5049fd31 645\r
d25c4bf0 646 //\r
8733430b 647 // We only process files potentially containing PE32 sections.\r
d25c4bf0 648 //\r
8733430b 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
d25c4bf0 659 }\r
5049fd31 660\r
d25c4bf0 661 //\r
662 // Rebase each PE32 section\r
663 //\r
664 Status = EFI_SUCCESS;\r
d25c4bf0 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
d25c4bf0 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
4df60ea5 677 ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) FfsRebaseImageRead;\r
4df60ea5 678 Status = PeCoffLoaderGetImageInfo (&ImageContext);\r
d25c4bf0 679 if (EFI_ERROR (Status)) {\r
680 Error (NULL, 0, 0, "GetImageInfo() call failed on rebase", FileGuidString);\r
681 return Status;\r
682 }\r
8733430b 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
d25c4bf0 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
18a964cf 766 MemoryImagePointer = (UINTN) (malloc (Pe32ImageSize + 0x100000));\r
d25c4bf0 767 if (MemoryImagePointer == 0) {\r
768 Error (NULL, 0, 0, "memory allocation failure", NULL);\r
769 return EFI_OUT_OF_RESOURCES;\r
770 }\r
18a964cf 771 memset ((void *) MemoryImagePointer, 0, Pe32ImageSize + 0x100000);\r
d0b053b7 772 MemoryImagePointerAligned = (MemoryImagePointer + 0x0FFFF) & (-1 << 16);\r
d25c4bf0 773\r
774 ImageContext.ImageAddress = MemoryImagePointerAligned;\r
775\r
4df60ea5 776 Status = PeCoffLoaderLoadImage (&ImageContext);\r
d25c4bf0 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
d0b053b7 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
d25c4bf0 800\r
801 ImageContext.DestinationAddress = NewPe32BaseAddress;\r
4df60ea5 802 Status = PeCoffLoaderRelocateImage (&ImageContext);\r
d25c4bf0 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
8733430b 827\r
828 //\r
829 // Update BASE address\r
830 //\r
831 fprintf (\r
832 LogFile,\r
a3ab2a47 833 "%s %016I64X %s\n",\r
8733430b 834 FileGuidString,\r
a3ab2a47 835 ImageContext.DestinationAddress,\r
836 ImageContext.PdbPointer == NULL ? "*" : ImageContext.PdbPointer\r
8733430b 837 );\r
838 *BaseToUpdate += EFI_SIZE_TO_PAGES (ImageContext.ImageSize) * EFI_PAGE_SIZE;\r
839\r
d25c4bf0 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
8733430b 846 PePlusHdr = (EFI_IMAGE_NT_HEADERS64*)PeHdr;\r
d25c4bf0 847 if (PeHdr->FileHeader.Machine == EFI_IMAGE_MACHINE_IA32) {\r
8733430b 848 PeHdrSizeOfImage = (UINT32 *) (&(PeHdr->OptionalHeader).SizeOfImage);\r
849 PeHdrChecksum = (UINT32 *) (&(PeHdr->OptionalHeader).CheckSum);\r
d25c4bf0 850 } else if (PeHdr->FileHeader.Machine == EFI_IMAGE_MACHINE_IA64) {\r
8733430b 851 PeHdrSizeOfImage = (UINT32 *) (&(PePlusHdr->OptionalHeader).SizeOfImage);\r
852 PeHdrChecksum = (UINT32 *) (&(PePlusHdr->OptionalHeader).CheckSum);\r
d25c4bf0 853 } else if (PeHdr->FileHeader.Machine == EFI_IMAGE_MACHINE_X64) {\r
8733430b 854 PeHdrSizeOfImage = (UINT32 *) (&(PePlusHdr->OptionalHeader).SizeOfImage);\r
855 PeHdrChecksum = (UINT32 *) (&(PePlusHdr->OptionalHeader).CheckSum);\r
d25c4bf0 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
396974d6 878\r
d25c4bf0 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
8733430b 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
d25c4bf0 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
d25c4bf0 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
8733430b 942 NewPe32BaseAddress = ((UINT32) XipBase) +\r
d25c4bf0 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
8733430b 973 PePlusHdr = (EFI_IMAGE_NT_HEADERS64*)PeHdr;\r
d25c4bf0 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
8733430b 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
d25c4bf0 1001 }\r
1002\r
8733430b 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
d25c4bf0 1050 }\r
8733430b 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
d25c4bf0 1065 }\r
d25c4bf0 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
4df60ea5 1082 ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) FfsRebaseImageRead;\r
d25c4bf0 1083\r
4df60ea5 1084 Status = PeCoffLoaderGetImageInfo (&ImageContext);\r
d25c4bf0 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
18a964cf 1094 MemoryImagePointer = (UINTN) (malloc (Pe32ImageSize + 0x100000));\r
d25c4bf0 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
18a964cf 1100 memset ((void *) MemoryImagePointer, 0, Pe32ImageSize + 0x100000);\r
d0b053b7 1101 MemoryImagePointerAligned = (MemoryImagePointer + 0x0FFFF) & (-1 << 16);\r
1102 \r
d25c4bf0 1103\r
1104 ImageContext.ImageAddress = MemoryImagePointerAligned;\r
4df60ea5 1105 Status = PeCoffLoaderLoadImage (&ImageContext);\r
d25c4bf0 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
4df60ea5 1114 Status = PeCoffLoaderRelocateImage (&ImageContext);\r
d25c4bf0 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
8733430b 1132 PePlusHdr = (EFI_IMAGE_NT_HEADERS64*)PeHdr;\r
d25c4bf0 1133 if (PeHdr->FileHeader.Machine == EFI_IMAGE_MACHINE_IA32) {\r
8733430b 1134 PeHdrSizeOfImage = (UINT32 *) (&(PeHdr->OptionalHeader).SizeOfImage);\r
1135 PeHdrChecksum = (UINT32 *) (&(PeHdr->OptionalHeader).CheckSum);\r
d25c4bf0 1136 } else if (PeHdr->FileHeader.Machine == EFI_IMAGE_MACHINE_IA64) {\r
8733430b 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
d25c4bf0 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
d25c4bf0 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
8733430b 1201\r
1202 fprintf (\r
1203 LogFile,\r
a3ab2a47 1204 "%s %016I64X %s\n",\r
8733430b 1205 FileGuidString,\r
a3ab2a47 1206 ImageContext.DestinationAddress,\r
1207 ImageContext.PdbPointer == NULL ? "*" : ImageContext.PdbPointer\r
8733430b 1208 );\r
a3ab2a47 1209\r
1210 //\r
1211 // Free buffers\r
1212 //\r
1213 free ((VOID *) MemoryImagePointer);\r
1214 free (TEBuffer);\r
d25c4bf0 1215 }\r
8733430b 1216\r
d25c4bf0 1217 return EFI_SUCCESS;\r
1218}\r
1219\r
1220EFI_STATUS\r
1221FfsRebaseImageRead (\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
1229Routine Description:\r
1230\r
1231 Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file\r
1232\r
1233Arguments:\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
1243Returns:\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