]> git.proxmox.com Git - mirror_edk2.git/blame - Tools/CCode/Source/PeiRebase/PeiRebaseExe.c
Correct TeImage file format and Clean up PeiRebase tool to remove unused code and...
[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
5b664244 282\r
d25c4bf0 283 //\r
284 // Open the file containing the FV\r
285 //\r
286 InputFile = fopen (InputFileName, "rb");\r
287 if (InputFile == NULL) {\r
288 Error (NULL, 0, 0, InputFileName, "could not open input file for reading");\r
289 return STATUS_ERROR;\r
290 }\r
8733430b 291\r
292 //\r
293 // Open the log file\r
294 //\r
295 strcat (InputFileName, ".log");\r
296 LogFile = fopen (InputFileName, "a");\r
297 if (LogFile == NULL) {\r
298 Error (NULL, 0, 0, InputFileName, "could not append to log file");\r
299 }\r
300\r
d25c4bf0 301 //\r
302 // Determine size of FV\r
303 //\r
304 Status = ReadHeader (InputFile, &FvSize, &ErasePolarity);\r
305 if (EFI_ERROR (Status)) {\r
306 Error (NULL, 0, 0, "could not parse the FV header", NULL);\r
307 goto Finish;\r
308 }\r
309 //\r
310 // Allocate a buffer for the FV image\r
311 //\r
312 FvImage = malloc (FvSize);\r
313 if (FvImage == NULL) {\r
314 Error (NULL, 0, 0, "application error", "memory allocation failed");\r
315 goto Finish;\r
316 }\r
317 //\r
318 // Read the entire FV to the buffer\r
319 //\r
320 BytesRead = fread (FvImage, 1, FvSize, InputFile);\r
321 fclose (InputFile);\r
322 InputFile = NULL;\r
323 if ((unsigned int) BytesRead != FvSize) {\r
324 Error (NULL, 0, 0, InputFileName, "failed to read from file");\r
325 goto Finish;\r
326 }\r
327 //\r
328 // Prepare to walk the FV image\r
329 //\r
330 InitializeFvLib (FvImage, FvSize);\r
331 //\r
332 // Get the first file\r
333 //\r
334 Status = GetNextFile (NULL, &CurrentFile);\r
335 if (EFI_ERROR (Status)) {\r
336 Error (NULL, 0, 0, "cannot find the first file in the FV image", NULL);\r
337 goto Finish;\r
338 }\r
339 //\r
340 // Check if each file should be rebased\r
341 //\r
342 while (CurrentFile != NULL) {\r
343 //\r
344 // Rebase this file\r
345 //\r
8733430b 346 FfsRebase (\r
347 CurrentFile,\r
348 BaseTypes,\r
349 XipBase + (UINTN)CurrentFile - (UINTN)FvImage,\r
350 &BsBase,\r
351 &RtBase,\r
352 LogFile\r
353 );\r
d25c4bf0 354\r
355 if (EFI_ERROR (Status)) {\r
356 switch (Status) {\r
357\r
358 case EFI_INVALID_PARAMETER:\r
359 Error (NULL, 0, 0, "invalid parameter passed to FfsRebase", NULL);\r
360 break;\r
361\r
362 case EFI_ABORTED:\r
363 Error (NULL, 0, 0, "error detected while rebasing -- aborted", NULL);\r
364 break;\r
365\r
366 case EFI_OUT_OF_RESOURCES:\r
367 Error (NULL, 0, 0, "FfsRebase could not allocate required resources", NULL);\r
368 break;\r
369\r
370 case EFI_NOT_FOUND:\r
371 Error (NULL, 0, 0, "FfsRebase could not locate a PE32 section", NULL);\r
372 break;\r
373\r
374 default:\r
375 Error (NULL, 0, 0, "FfsRebase returned unknown status", "status=0x%08X", Status);\r
376 break;\r
377 }\r
378\r
379 goto Finish;\r
380 }\r
381 //\r
382 // Get the next file\r
383 //\r
384 Status = GetNextFile (CurrentFile, &CurrentFile);\r
385 if (EFI_ERROR (Status)) {\r
386 Error (NULL, 0, 0, "cannot find the next file in the FV image", NULL);\r
387 goto Finish;\r
388 }\r
389 }\r
390 //\r
391 // Open the output file\r
392 //\r
393 OutputFile = fopen (OutputFileName, "wb");\r
394 if (OutputFile == NULL) {\r
395 Error (NULL, 0, 0, OutputFileName, "failed to open output file");\r
396 goto Finish;\r
397 }\r
398\r
399 if (fwrite (FvImage, 1, FvSize, OutputFile) != FvSize) {\r
400 Error (NULL, 0, 0, "failed to write to output file", 0);\r
401 goto Finish;\r
402 }\r
403\r
404Finish:\r
405 if (InputFile != NULL) {\r
406 fclose (InputFile);\r
407 }\r
408 //\r
409 // If we created an output file, and there was an error, remove it so\r
410 // subsequent builds will rebuild it.\r
411 //\r
412 if (OutputFile != NULL) {\r
413 if (GetUtilityStatus () == STATUS_ERROR) {\r
414 remove (OutputFileName);\r
415 }\r
416\r
417 fclose (OutputFile);\r
418 }\r
419\r
8733430b 420 if (LogFile != NULL) {\r
421 fclose (LogFile);\r
5049fd31 422 }\r
423\r
d25c4bf0 424 if (FvImage != NULL) {\r
425 free (FvImage);\r
426 }\r
427\r
428 return GetUtilityStatus ();\r
429}\r
430\r
431EFI_STATUS\r
432ReadHeader (\r
433 IN FILE *InputFile,\r
434 OUT UINT32 *FvSize,\r
435 OUT BOOLEAN *ErasePolarity\r
436 )\r
437/*++\r
438\r
439Routine Description:\r
440\r
8733430b 441 This function determines the size of the FV and the erase polarity. The\r
d25c4bf0 442 erase polarity is the FALSE value for file state.\r
443\r
444Arguments:\r
445\r
446 InputFile The file that contains the FV image.\r
447 FvSize The size of the FV.\r
448 ErasePolarity The FV erase polarity.\r
8733430b 449\r
d25c4bf0 450Returns:\r
8733430b 451\r
d25c4bf0 452 EFI_SUCCESS Function completed successfully.\r
453 EFI_INVALID_PARAMETER A required parameter was NULL or is out of range.\r
454 EFI_ABORTED The function encountered an error.\r
455\r
456--*/\r
457{\r
458 EFI_FIRMWARE_VOLUME_HEADER VolumeHeader;\r
459 EFI_FV_BLOCK_MAP_ENTRY BlockMap;\r
460 UINTN Signature[2];\r
461 UINTN BytesRead;\r
462 UINT32 Size;\r
463\r
464 BytesRead = 0;\r
465 Size = 0;\r
466 //\r
467 // Check input parameters\r
468 //\r
469 if ((InputFile == NULL) || (FvSize == NULL) || (ErasePolarity == NULL)) {\r
470 Error (NULL, 0, 0, "ReadHeader()", "invalid input parameter");\r
471 return EFI_INVALID_PARAMETER;\r
472 }\r
473 //\r
474 // Read the header\r
475 //\r
476 fread (&VolumeHeader, sizeof (EFI_FIRMWARE_VOLUME_HEADER) - sizeof (EFI_FV_BLOCK_MAP_ENTRY), 1, InputFile);\r
477 BytesRead = sizeof (EFI_FIRMWARE_VOLUME_HEADER) - sizeof (EFI_FV_BLOCK_MAP_ENTRY);\r
478 Signature[0] = VolumeHeader.Signature;\r
479 Signature[1] = 0;\r
480\r
481 //\r
482 // Get erase polarity\r
483 //\r
484 if (VolumeHeader.Attributes & EFI_FVB_ERASE_POLARITY) {\r
485 *ErasePolarity = TRUE;\r
486 }\r
487\r
488 do {\r
489 fread (&BlockMap, sizeof (EFI_FV_BLOCK_MAP_ENTRY), 1, InputFile);\r
490 BytesRead += sizeof (EFI_FV_BLOCK_MAP_ENTRY);\r
491\r
492 if (BlockMap.NumBlocks != 0) {\r
493 Size += BlockMap.NumBlocks * BlockMap.BlockLength;\r
494 }\r
495\r
496 } while (!(BlockMap.NumBlocks == 0 && BlockMap.BlockLength == 0));\r
497\r
498 if (VolumeHeader.FvLength != Size) {\r
499 Error (NULL, 0, 0, "volume size not consistant with block maps", NULL);\r
500 return EFI_ABORTED;\r
501 }\r
502\r
503 *FvSize = Size;\r
504\r
505 rewind (InputFile);\r
506\r
507 return EFI_SUCCESS;\r
508}\r
509\r
510VOID\r
fd23b925 511Version (\r
d25c4bf0 512 VOID\r
513 )\r
514/*++\r
515\r
516Routine Description:\r
517\r
518 Displays the standard utility information to SDTOUT\r
519\r
520Arguments:\r
521\r
522 None\r
523\r
524Returns:\r
525\r
526 None\r
527\r
528--*/\r
529{\r
fd23b925 530 printf ("%s v%d.%d -PEI Rebase Utility.\n", UTILITY_NAME, UTILITY_MAJOR_VERSION, UTILITY_MINOR_VERSION);\r
531 printf ("Copyright (c) 1999-2007 Intel Corporation. All rights reserved.\n");\r
d25c4bf0 532}\r
533\r
534VOID\r
fd23b925 535Usage (\r
d25c4bf0 536 VOID\r
537 )\r
538/*++\r
539\r
540Routine Description:\r
541\r
542 Displays the utility usage syntax to STDOUT\r
543\r
544Arguments:\r
545\r
546 None\r
547\r
548Returns:\r
549\r
550 None\r
551\r
552--*/\r
553{\r
fd23b925 554 Version();\r
555 \r
d25c4bf0 556 printf (\r
5b664244 557 "Usage: %s -I InputFileName -O OutputFileName -B BaseAddress [-F InputFvInfName]\n",\r
d25c4bf0 558 UTILITY_NAME\r
559 );\r
5b664244 560 printf (" [-D BootDriverBaseAddress] [-R RuntimeDriverBaseAddress]\n");\r
d25c4bf0 561 printf (" Where:\n");\r
5b664244
LG
562 printf (" InputFileName is the name of the EFI FV file to rebase.\n");\r
563 printf (" OutputFileName is the desired output file name.\n");\r
564 printf (" BaseAddress is the rebase address for all drivers run in Flash.\n");\r
565 printf (" InputFvInfName is the Fv.inf file that contains this FV base address to rebase against.\n");\r
566 printf (" BootDriverBaseAddress is the rebase address for all boot drivers in this fv image.\n");\r
567 printf (" RuntimeDriverBaseAddress is the rebase address for all runtime drivers in this fv image.\n");\r
568 printf (" Argument pair may be in any order.\n\n");\r
d25c4bf0 569}\r
570\r
571EFI_STATUS\r
572FfsRebase (\r
8733430b 573 IN OUT EFI_FFS_FILE_HEADER *FfsFile,\r
574 IN UINT32 Flags,\r
575 IN OUT EFI_PHYSICAL_ADDRESS XipBase,\r
576 IN OUT EFI_PHYSICAL_ADDRESS *BsBase,\r
577 IN OUT EFI_PHYSICAL_ADDRESS *RtBase,\r
578 OUT FILE *LogFile\r
d25c4bf0 579 )\r
580/*++\r
581\r
582Routine Description:\r
583\r
8733430b 584 This function determines if a file is XIP and should be rebased. It will\r
d25c4bf0 585 rebase any PE32 sections found in the file using the base address.\r
8733430b 586\r
d25c4bf0 587Arguments:\r
588\r
589 FfsFile A pointer to Ffs file image.\r
590 BaseAddress The base address to use for rebasing the file image.\r
591\r
592Returns:\r
593\r
594 EFI_SUCCESS The image was properly rebased.\r
595 EFI_INVALID_PARAMETER An input parameter is invalid.\r
596 EFI_ABORTED An error occurred while rebasing the input file image.\r
597 EFI_OUT_OF_RESOURCES Could not allocate a required resource.\r
598 EFI_NOT_FOUND No compressed sections could be found.\r
599\r
600--*/\r
601{\r
602 EFI_STATUS Status;\r
4df60ea5 603 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;\r
8733430b 604 EFI_PHYSICAL_ADDRESS NewPe32BaseAddress;\r
d25c4bf0 605 UINTN Index;\r
606 EFI_FILE_SECTION_POINTER CurrentPe32Section;\r
607 EFI_FFS_FILE_STATE SavedState;\r
8733430b 608 EFI_IMAGE_NT_HEADERS32 *PeHdr;\r
d25c4bf0 609 EFI_TE_IMAGE_HEADER *TEImageHeader;\r
d25c4bf0 610 UINT8 FileGuidString[80];\r
611 UINT32 TailSize;\r
612 EFI_FFS_FILE_TAIL TailValue;\r
8733430b 613 EFI_PHYSICAL_ADDRESS *BaseToUpdate;\r
5b664244
LG
614 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *DebugEntry;\r
615 \r
d25c4bf0 616\r
617 //\r
618 // Verify input parameters\r
619 //\r
620 if (FfsFile == NULL) {\r
621 return EFI_INVALID_PARAMETER;\r
622 }\r
623 //\r
624 // Convert the GUID to a string so we can at least report which file\r
625 // if we find an error.\r
626 //\r
627 PrintGuidToBuffer (&FfsFile->Name, FileGuidString, sizeof (FileGuidString), TRUE);\r
628 if (FfsFile->Attributes & FFS_ATTRIB_TAIL_PRESENT) {\r
629 TailSize = sizeof (EFI_FFS_FILE_TAIL);\r
630 } else {\r
631 TailSize = 0;\r
632 }\r
633 //\r
634 // Do some cursory checks on the FFS file contents\r
635 //\r
636 Status = VerifyFfsFile (FfsFile);\r
637 if (EFI_ERROR (Status)) {\r
638 Error (NULL, 0, 0, "file does not appear to be a valid FFS file, cannot be rebased", FileGuidString);\r
639 return EFI_INVALID_PARAMETER;\r
640 }\r
5049fd31 641\r
d25c4bf0 642 //\r
8733430b 643 // We only process files potentially containing PE32 sections.\r
d25c4bf0 644 //\r
8733430b 645 switch (FfsFile->Type) {\r
646 case EFI_FV_FILETYPE_SECURITY_CORE:\r
647 case EFI_FV_FILETYPE_PEI_CORE:\r
648 case EFI_FV_FILETYPE_PEIM:\r
649 case EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER:\r
650 case EFI_FV_FILETYPE_DRIVER:\r
651 case EFI_FV_FILETYPE_DXE_CORE:\r
652 break;\r
653 default:\r
654 return EFI_SUCCESS;\r
d25c4bf0 655 }\r
5049fd31 656\r
d25c4bf0 657 //\r
658 // Rebase each PE32 section\r
659 //\r
660 Status = EFI_SUCCESS;\r
d25c4bf0 661 for (Index = 1;; Index++) {\r
662 Status = GetSectionByType (FfsFile, EFI_SECTION_PE32, Index, &CurrentPe32Section);\r
663 if (EFI_ERROR (Status)) {\r
664 break;\r
665 }\r
666\r
d25c4bf0 667 //\r
668 // Initialize context\r
669 //\r
670 memset (&ImageContext, 0, sizeof (ImageContext));\r
671 ImageContext.Handle = (VOID *) ((UINTN) CurrentPe32Section.Pe32Section + sizeof (EFI_PE32_SECTION));\r
4df60ea5 672 ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) FfsRebaseImageRead;\r
4df60ea5 673 Status = PeCoffLoaderGetImageInfo (&ImageContext);\r
d25c4bf0 674 if (EFI_ERROR (Status)) {\r
675 Error (NULL, 0, 0, "GetImageInfo() call failed on rebase", FileGuidString);\r
676 return Status;\r
677 }\r
8733430b 678\r
5b664244
LG
679 //\r
680 // Don't Load PeImage, only to relocate current image.\r
681 //\r
682 ImageContext.ImageAddress = (UINTN) CurrentPe32Section.Pe32Section + sizeof (EFI_PE32_SECTION);\r
683\r
684 //\r
685 // Check if section-alignment and file-alignment match or not\r
686 //\r
687 PeHdr = (EFI_IMAGE_NT_HEADERS *)((UINTN)ImageContext.ImageAddress + ImageContext.PeCoffHeaderOffset);\r
688 if (PeHdr->OptionalHeader.SectionAlignment != PeHdr->OptionalHeader.FileAlignment) {\r
689 //\r
690 // Nor XIP module can be ignored. \r
691 //\r
692 if ((Flags & 1) == 0) {\r
693 continue;\r
694 }\r
695 Error (NULL, 0, 0, "Section-Alignment and File-Alignment does not match", FileGuidString);\r
696 return EFI_ABORTED;\r
697 } \r
698\r
699 //\r
700 // Update CodeView and PdbPointer in ImageContext\r
701 //\r
702 DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *)(UINTN)(\r
703 ImageContext.ImageAddress +\r
704 ImageContext.DebugDirectoryEntryRva\r
705 );\r
706 ImageContext.CodeView = (VOID *)(UINTN)( \r
707 ImageContext.ImageAddress + \r
708 DebugEntry->RVA\r
709 );\r
710 switch (*(UINT32 *) ImageContext.CodeView) {\r
711 case CODEVIEW_SIGNATURE_NB10:\r
712 ImageContext.PdbPointer = (CHAR8 *) ImageContext.CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY);\r
713 break;\r
714\r
715 case CODEVIEW_SIGNATURE_RSDS:\r
716 ImageContext.PdbPointer = (CHAR8 *) ImageContext.CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY);\r
717 break;\r
718\r
719 default:\r
720 break;\r
721 }\r
722\r
8733430b 723 //\r
724 // Calculate the PE32 base address, based on file type\r
725 //\r
726 switch (FfsFile->Type) {\r
727 case EFI_FV_FILETYPE_SECURITY_CORE:\r
728 case EFI_FV_FILETYPE_PEI_CORE:\r
729 case EFI_FV_FILETYPE_PEIM:\r
730 case EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER:\r
731 if ((Flags & 1) == 0) {\r
732 //\r
733 // We aren't relocating XIP code, so skip it.\r
734 //\r
735 return EFI_SUCCESS;\r
736 }\r
737\r
738 NewPe32BaseAddress =\r
5b664244 739 XipBase + (UINTN)ImageContext.ImageAddress - (UINTN)FfsFile;\r
8733430b 740 BaseToUpdate = &XipBase;\r
741 break;\r
742\r
743 case EFI_FV_FILETYPE_DRIVER:\r
5b664244 744 PeHdr = (EFI_IMAGE_NT_HEADERS32*)(ImageContext.ImageAddress + ImageContext.PeCoffHeaderOffset);\r
8733430b 745 switch (PeHdr->OptionalHeader.Subsystem) {\r
746 case EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER:\r
747 if ((Flags & 4) == 0) {\r
748 //\r
749 // RT drivers aren't supposed to be relocated\r
750 //\r
751 continue;\r
752 }\r
753\r
754 NewPe32BaseAddress = *RtBase;\r
755 BaseToUpdate = RtBase;\r
756 break;\r
757\r
758 default:\r
759 //\r
760 // We treat all other subsystems the same as BS_DRIVER\r
761 //\r
762 if ((Flags & 2) == 0) {\r
763 //\r
764 // Skip all BS_DRIVER's\r
765 //\r
766 continue;\r
767 }\r
768\r
769 NewPe32BaseAddress = *BsBase;\r
770 BaseToUpdate = BsBase;\r
771 break;\r
772 }\r
773 break;\r
774\r
775 case EFI_FV_FILETYPE_DXE_CORE:\r
776 if ((Flags & 2) == 0) {\r
777 //\r
778 // Skip DXE core\r
779 //\r
780 return EFI_SUCCESS;\r
781 }\r
782\r
783 NewPe32BaseAddress = *BsBase;\r
784 BaseToUpdate = BsBase;\r
785 break;\r
786\r
787 default:\r
788 //\r
789 // Not supported file type\r
790 //\r
791 return EFI_SUCCESS;\r
792 }\r
793\r
d25c4bf0 794 ImageContext.DestinationAddress = NewPe32BaseAddress;\r
4df60ea5 795 Status = PeCoffLoaderRelocateImage (&ImageContext);\r
d25c4bf0 796 if (EFI_ERROR (Status)) {\r
797 Error (NULL, 0, 0, "RelocateImage() call failed on rebase", FileGuidString);\r
d25c4bf0 798 return Status;\r
799 }\r
800\r
8733430b 801 //\r
802 // Update BASE address\r
803 //\r
804 fprintf (\r
805 LogFile,\r
a3ab2a47 806 "%s %016I64X %s\n",\r
8733430b 807 FileGuidString,\r
a3ab2a47 808 ImageContext.DestinationAddress,\r
809 ImageContext.PdbPointer == NULL ? "*" : ImageContext.PdbPointer\r
8733430b 810 );\r
811 *BaseToUpdate += EFI_SIZE_TO_PAGES (ImageContext.ImageSize) * EFI_PAGE_SIZE;\r
812\r
d25c4bf0 813 //\r
814 // Now update file checksum\r
815 //\r
816 if (FfsFile->Attributes & FFS_ATTRIB_TAIL_PRESENT) {\r
817 TailSize = sizeof (EFI_FFS_FILE_TAIL);\r
818 } else {\r
819 TailSize = 0;\r
820 }\r
821\r
822 if (FfsFile->Attributes & FFS_ATTRIB_CHECKSUM) {\r
823 SavedState = FfsFile->State;\r
824 FfsFile->IntegrityCheck.Checksum.File = 0;\r
825 FfsFile->State = 0;\r
826 if (FfsFile->Attributes & FFS_ATTRIB_CHECKSUM) {\r
827 FfsFile->IntegrityCheck.Checksum.File = CalculateChecksum8 (\r
828 (UINT8 *) FfsFile,\r
829 GetLength (FfsFile->Size) - TailSize\r
830 );\r
831 } else {\r
832 FfsFile->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;\r
833 }\r
834\r
835 FfsFile->State = SavedState;\r
836 }\r
837 //\r
838 // Update tail if present\r
839 //\r
840 if (FfsFile->Attributes & FFS_ATTRIB_TAIL_PRESENT) {\r
841 TailValue = (EFI_FFS_FILE_TAIL) (~(FfsFile->IntegrityCheck.TailReference));\r
842 *(EFI_FFS_FILE_TAIL *) (((UINTN) FfsFile + GetLength (FfsFile->Size) - sizeof (EFI_FFS_FILE_TAIL))) = TailValue;\r
843 }\r
844 }\r
8733430b 845\r
846 if ((Flags & 1) == 0 || (\r
847 FfsFile->Type != EFI_FV_FILETYPE_SECURITY_CORE &&\r
848 FfsFile->Type != EFI_FV_FILETYPE_PEI_CORE &&\r
849\r
850 FfsFile->Type != EFI_FV_FILETYPE_PEIM &&\r
851 FfsFile->Type != EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER\r
852 )) {\r
853 //\r
854 // Only XIP code may have a TE section\r
855 //\r
856 return EFI_SUCCESS;\r
857 }\r
5b664244 858 \r
d25c4bf0 859 //\r
860 // Now process TE sections\r
861 //\r
862 for (Index = 1;; Index++) {\r
863 Status = GetSectionByType (FfsFile, EFI_SECTION_TE, Index, &CurrentPe32Section);\r
864 if (EFI_ERROR (Status)) {\r
865 break;\r
866 }\r
867\r
d25c4bf0 868 //\r
869 // Calculate the TE base address, the FFS file base plus the offset of the TE section less the size stripped off\r
870 // by GenTEImage\r
871 //\r
872 TEImageHeader = (EFI_TE_IMAGE_HEADER *) ((UINT8 *) CurrentPe32Section.Pe32Section + sizeof (EFI_COMMON_SECTION_HEADER));\r
873\r
d25c4bf0 874 //\r
5b664244 875 // Initialize context, load image info.\r
d25c4bf0 876 //\r
877 memset (&ImageContext, 0, sizeof (ImageContext));\r
5b664244 878 ImageContext.Handle = (VOID *) TEImageHeader;\r
4df60ea5 879 ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) FfsRebaseImageRead;\r
d25c4bf0 880\r
4df60ea5 881 Status = PeCoffLoaderGetImageInfo (&ImageContext);\r
d25c4bf0 882\r
883 if (EFI_ERROR (Status)) {\r
884 Error (NULL, 0, 0, "GetImageInfo() call failed on rebase of TE image", FileGuidString);\r
d25c4bf0 885 return Status;\r
886 }\r
887 //\r
5b664244 888 // Don't reload TeImage\r
d25c4bf0 889 //\r
5b664244 890 ImageContext.ImageAddress = (UINTN) TEImageHeader;\r
d25c4bf0 891\r
5b664244
LG
892 //\r
893 // Update CodeView and PdbPointer in ImageContext\r
894 //\r
895 DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *)(UINTN)(\r
896 ImageContext.ImageAddress +\r
897 ImageContext.DebugDirectoryEntryRva +\r
898 sizeof(EFI_TE_IMAGE_HEADER) -\r
899 TEImageHeader->StrippedSize\r
900 );\r
901\r
902 ImageContext.CodeView = (VOID *)(UINTN)(\r
903 ImageContext.ImageAddress +\r
904 DebugEntry->RVA +\r
905 sizeof(EFI_TE_IMAGE_HEADER) -\r
906 TEImageHeader->StrippedSize\r
907 );\r
908\r
909 switch (*(UINT32 *) ImageContext.CodeView) {\r
910 case CODEVIEW_SIGNATURE_NB10:\r
911 ImageContext.PdbPointer = (CHAR8 *) ImageContext.CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY);\r
912 break;\r
913\r
914 case CODEVIEW_SIGNATURE_RSDS:\r
915 ImageContext.PdbPointer = (CHAR8 *) ImageContext.CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY);\r
916 break;\r
917\r
918 default:\r
919 break;\r
d25c4bf0 920 }\r
921\r
5b664244
LG
922 //\r
923 // Reloacate TeImage\r
924 // \r
925 ImageContext.DestinationAddress = XipBase + (UINTN) TEImageHeader + sizeof (EFI_TE_IMAGE_HEADER) \\r
926 - TEImageHeader->StrippedSize - (UINTN) FfsFile;\r
4df60ea5 927 Status = PeCoffLoaderRelocateImage (&ImageContext);\r
d25c4bf0 928 if (EFI_ERROR (Status)) {\r
929 Error (NULL, 0, 0, "RelocateImage() call failed on rebase of TE image", FileGuidString);\r
d25c4bf0 930 return Status;\r
931 }\r
932\r
d25c4bf0 933 if (FfsFile->Attributes & FFS_ATTRIB_TAIL_PRESENT) {\r
934 TailSize = sizeof (EFI_FFS_FILE_TAIL);\r
935 } else {\r
936 TailSize = 0;\r
937 }\r
938 //\r
939 // Now update file checksum\r
940 //\r
941 if (FfsFile->Attributes & FFS_ATTRIB_CHECKSUM) {\r
942 SavedState = FfsFile->State;\r
943 FfsFile->IntegrityCheck.Checksum.File = 0;\r
944 FfsFile->State = 0;\r
945 if (FfsFile->Attributes & FFS_ATTRIB_CHECKSUM) {\r
946 FfsFile->IntegrityCheck.Checksum.File = CalculateChecksum8 (\r
947 (UINT8 *) FfsFile,\r
948 GetLength (FfsFile->Size) - TailSize\r
949 );\r
950 } else {\r
951 FfsFile->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;\r
952 }\r
953\r
954 FfsFile->State = SavedState;\r
955 }\r
956 //\r
957 // Update tail if present\r
958 //\r
959 if (FfsFile->Attributes & FFS_ATTRIB_TAIL_PRESENT) {\r
960 TailValue = (EFI_FFS_FILE_TAIL) (~(FfsFile->IntegrityCheck.TailReference));\r
961 *(EFI_FFS_FILE_TAIL *) (((UINTN) FfsFile + GetLength (FfsFile->Size) - sizeof (EFI_FFS_FILE_TAIL))) = TailValue;\r
962 }\r
8733430b 963\r
964 fprintf (\r
965 LogFile,\r
a3ab2a47 966 "%s %016I64X %s\n",\r
8733430b 967 FileGuidString,\r
a3ab2a47 968 ImageContext.DestinationAddress,\r
969 ImageContext.PdbPointer == NULL ? "*" : ImageContext.PdbPointer\r
8733430b 970 );\r
d25c4bf0 971 }\r
5b664244 972 \r
d25c4bf0 973 return EFI_SUCCESS;\r
974}\r
975\r
976EFI_STATUS\r
977FfsRebaseImageRead (\r
978 IN VOID *FileHandle,\r
979 IN UINTN FileOffset,\r
980 IN OUT UINT32 *ReadSize,\r
981 OUT VOID *Buffer\r
982 )\r
983/*++\r
984\r
985Routine Description:\r
986\r
987 Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file\r
988\r
989Arguments:\r
990\r
991 FileHandle - The handle to the PE/COFF file\r
992\r
993 FileOffset - The offset, in bytes, into the file to read\r
994\r
995 ReadSize - The number of bytes to read from the file starting at FileOffset\r
996\r
997 Buffer - A pointer to the buffer to read the data into.\r
998\r
999Returns:\r
1000\r
1001 EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset\r
1002\r
1003--*/\r
1004{\r
1005 CHAR8 *Destination8;\r
1006 CHAR8 *Source8;\r
1007 UINT32 Length;\r
1008\r
1009 Destination8 = Buffer;\r
1010 Source8 = (CHAR8 *) ((UINTN) FileHandle + FileOffset);\r
1011 Length = *ReadSize;\r
1012 while (Length--) {\r
1013 *(Destination8++) = *(Source8++);\r
1014 }\r
1015\r
1016 return EFI_SUCCESS;\r
1017}\r