]> git.proxmox.com Git - mirror_edk2.git/blame - Tools/CCode/Source/PeiRebase/PeiRebaseExe.c
remove unnecessary check for NULL pointer.
[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
aaed63a9 107\r
fd23b925 108 if ((strcmp(argv[1], "-h") == 0) || (strcmp(argv[1], "--help") == 0) ||\r
109 (strcmp(argv[1], "-?") == 0) || (strcmp(argv[1], "/?") == 0)) {\r
110 Usage();\r
111 return STATUS_ERROR;\r
112 }\r
aaed63a9 113\r
fd23b925 114 if ((strcmp(argv[1], "-V") == 0) || (strcmp(argv[1], "--version") == 0)) {\r
115 Version();\r
116 return STATUS_ERROR;\r
117 }\r
aaed63a9 118\r
d25c4bf0 119 //\r
120 // Verify the correct number of arguments\r
121 //\r
aaed63a9 122 if (argc < MAX_ARGS) {\r
fd23b925 123 Usage ();\r
d25c4bf0 124 return STATUS_ERROR;\r
125 }\r
5049fd31 126\r
d25c4bf0 127 //\r
128 // Initialize variables\r
129 //\r
8733430b 130 InputFileName[0] = '\0';\r
131 OutputFileName = NULL;\r
132 XipBase = BsBase = RtBase = 0;\r
133 BaseTypes = 0;\r
d25c4bf0 134 FvOffset = 0;\r
135 FileCount = 0;\r
136 ErasePolarity = FALSE;\r
137 InputFile = NULL;\r
138 OutputFile = NULL;\r
8733430b 139 LogFile = NULL;\r
d25c4bf0 140 FvImage = NULL;\r
5049fd31 141\r
d25c4bf0 142 //\r
143 // Parse the command line arguments\r
144 //\r
aaed63a9 145 for (Index = 1; Index < argc; Index += 2) {\r
d25c4bf0 146 //\r
147 // Make sure argument pair begin with - or /\r
148 //\r
149 if (argv[Index][0] != '-' && argv[Index][0] != '/') {\r
fd23b925 150 Usage ();\r
d25c4bf0 151 Error (NULL, 0, 0, argv[Index], "unrecognized option");\r
152 return STATUS_ERROR;\r
153 }\r
154 //\r
155 // Make sure argument specifier is only one letter\r
156 //\r
157 if (argv[Index][2] != 0) {\r
fd23b925 158 Usage ();\r
d25c4bf0 159 Error (NULL, 0, 0, argv[Index], "unrecognized option");\r
160 return STATUS_ERROR;\r
8733430b 161 }\r
d25c4bf0 162 //\r
163 // Determine argument to read\r
164 //\r
165 switch (argv[Index][1]) {\r
166 case 'I':\r
167 case 'i':\r
168 if (strlen (InputFileName) == 0) {\r
169 strcpy (InputFileName, argv[Index + 1]);\r
170 } else {\r
fd23b925 171 Usage ();\r
d25c4bf0 172 Error (NULL, 0, 0, argv[Index + 1], "only one -i InputFileName may be specified");\r
173 return STATUS_ERROR;\r
174 }\r
175 break;\r
176\r
177 case 'O':\r
178 case 'o':\r
8733430b 179 if (OutputFileName == NULL) {\r
180 OutputFileName = argv[Index + 1];\r
d25c4bf0 181 } else {\r
fd23b925 182 Usage ();\r
d25c4bf0 183 Error (NULL, 0, 0, argv[Index + 1], "only one -o OutputFileName may be specified");\r
184 return STATUS_ERROR;\r
185 }\r
186 break;\r
187\r
8733430b 188 case 'F':\r
189 case 'f':\r
190 //\r
191 // Load INF file into memory & initialize MEMORY_FILE structure\r
192 //\r
193 Status = GetFileImage (argv[Index + 1], &InfMemoryFile.FileImage, (UINT32*)&InfMemoryFile.Eof);\r
194 InfMemoryFile.Eof = InfMemoryFile.FileImage + (UINT32)(UINTN)InfMemoryFile.Eof;\r
195 InfMemoryFile.CurrentFilePointer = InfMemoryFile.FileImage;\r
196 if (EFI_ERROR (Status)) {\r
197 Error (NULL, 0, 0, argv[Index + 1], "Error opening FvInfFile");\r
198 return STATUS_ERROR;\r
199 }\r
200\r
201 //\r
202 // Read BaseAddress from fv.inf file\r
203 //\r
204 FindToken (&InfMemoryFile, "[options]", "EFI_BASE_ADDRESS", 0, StringBuffer);\r
205\r
206 //\r
207 // Free INF file image\r
208 //\r
209 free (InfMemoryFile.FileImage);\r
210\r
211 //\r
212 // Point argv[Index + 1] to StringBuffer so that it could be processed as "-b"\r
213 //\r
214 argv[Index + 1] = StringBuffer;\r
215\r
d25c4bf0 216 case 'B':\r
217 case 'b':\r
8733430b 218 if (BaseTypes & 1) {\r
fd23b925 219 Usage ();\r
8733430b 220 Error (NULL, 0, 0, argv[Index + 1], "XipBaseAddress may be specified only once by either -b or -f");\r
221 return STATUS_ERROR;\r
222 }\r
d25c4bf0 223\r
8733430b 224 Status = AsciiStringToUint64 (argv[Index + 1], FALSE, &XipBase);\r
225 if (EFI_ERROR (Status)) {\r
fd23b925 226 Usage ();\r
8733430b 227 Error (NULL, 0, 0, argv[Index + 1], "invalid hex digit given for XIP base address");\r
d25c4bf0 228 return STATUS_ERROR;\r
229 }\r
8733430b 230\r
231 BaseTypes |= 1;\r
d25c4bf0 232 break;\r
233\r
8733430b 234 case 'D':\r
235 case 'd':\r
236 if (BaseTypes & 2) {\r
fd23b925 237 Usage ();\r
8733430b 238 Error (NULL, 0, 0, argv[Index + 1], "-d BsBaseAddress may be specified only once");\r
239 return STATUS_ERROR;\r
240 }\r
4c50c885 241\r
8733430b 242 Status = AsciiStringToUint64 (argv[Index + 1], FALSE, &BsBase);\r
243 if (EFI_ERROR (Status)) {\r
fd23b925 244 Usage ();\r
8733430b 245 Error (NULL, 0, 0, argv[Index + 1], "invalid hex digit given for BS_DRIVER base address");\r
4c50c885
LG
246 return STATUS_ERROR;\r
247 }\r
8733430b 248\r
249 BaseTypes |= 2;\r
4c50c885
LG
250 break;\r
251\r
8733430b 252 case 'R':\r
253 case 'r':\r
254 if (BaseTypes & 4) {\r
fd23b925 255 Usage ();\r
8733430b 256 Error (NULL, 0, 0, argv[Index + 1], "-r RtBaseAddress may be specified only once");\r
257 return STATUS_ERROR;\r
258 }\r
259\r
260 Status = AsciiStringToUint64 (argv[Index + 1], FALSE, &RtBase);\r
261 if (EFI_ERROR (Status)) {\r
fd23b925 262 Usage ();\r
8733430b 263 Error (NULL, 0, 0, argv[Index + 1], "invalid hex digit given for RT_DRIVER base address");\r
5049fd31 264 return STATUS_ERROR;\r
265 }\r
8733430b 266\r
267 BaseTypes |= 4;\r
5049fd31 268 break;\r
269\r
d25c4bf0 270 default:\r
fd23b925 271 Usage ();\r
d25c4bf0 272 Error (NULL, 0, 0, argv[Index], "unrecognized argument");\r
273 return STATUS_ERROR;\r
274 break;\r
275 }\r
276 }\r
5b664244 277\r
d25c4bf0 278 //\r
279 // Open the file containing the FV\r
280 //\r
281 InputFile = fopen (InputFileName, "rb");\r
282 if (InputFile == NULL) {\r
283 Error (NULL, 0, 0, InputFileName, "could not open input file for reading");\r
284 return STATUS_ERROR;\r
285 }\r
8733430b 286\r
287 //\r
288 // Open the log file\r
289 //\r
290 strcat (InputFileName, ".log");\r
aaed63a9 291 LogFile = fopen (InputFileName, "w");\r
8733430b 292 if (LogFile == NULL) {\r
293 Error (NULL, 0, 0, InputFileName, "could not append to log file");\r
294 }\r
295\r
d25c4bf0 296 //\r
297 // Determine size of FV\r
298 //\r
299 Status = ReadHeader (InputFile, &FvSize, &ErasePolarity);\r
300 if (EFI_ERROR (Status)) {\r
301 Error (NULL, 0, 0, "could not parse the FV header", NULL);\r
302 goto Finish;\r
303 }\r
304 //\r
305 // Allocate a buffer for the FV image\r
306 //\r
307 FvImage = malloc (FvSize);\r
308 if (FvImage == NULL) {\r
309 Error (NULL, 0, 0, "application error", "memory allocation failed");\r
310 goto Finish;\r
311 }\r
312 //\r
313 // Read the entire FV to the buffer\r
314 //\r
315 BytesRead = fread (FvImage, 1, FvSize, InputFile);\r
316 fclose (InputFile);\r
317 InputFile = NULL;\r
318 if ((unsigned int) BytesRead != FvSize) {\r
319 Error (NULL, 0, 0, InputFileName, "failed to read from file");\r
320 goto Finish;\r
321 }\r
322 //\r
323 // Prepare to walk the FV image\r
324 //\r
325 InitializeFvLib (FvImage, FvSize);\r
326 //\r
327 // Get the first file\r
328 //\r
329 Status = GetNextFile (NULL, &CurrentFile);\r
330 if (EFI_ERROR (Status)) {\r
331 Error (NULL, 0, 0, "cannot find the first file in the FV image", NULL);\r
332 goto Finish;\r
333 }\r
334 //\r
335 // Check if each file should be rebased\r
336 //\r
337 while (CurrentFile != NULL) {\r
338 //\r
339 // Rebase this file\r
340 //\r
8733430b 341 FfsRebase (\r
342 CurrentFile,\r
343 BaseTypes,\r
344 XipBase + (UINTN)CurrentFile - (UINTN)FvImage,\r
345 &BsBase,\r
346 &RtBase,\r
347 LogFile\r
348 );\r
d25c4bf0 349\r
350 if (EFI_ERROR (Status)) {\r
351 switch (Status) {\r
352\r
353 case EFI_INVALID_PARAMETER:\r
354 Error (NULL, 0, 0, "invalid parameter passed to FfsRebase", NULL);\r
355 break;\r
356\r
357 case EFI_ABORTED:\r
358 Error (NULL, 0, 0, "error detected while rebasing -- aborted", NULL);\r
359 break;\r
360\r
361 case EFI_OUT_OF_RESOURCES:\r
362 Error (NULL, 0, 0, "FfsRebase could not allocate required resources", NULL);\r
363 break;\r
364\r
365 case EFI_NOT_FOUND:\r
366 Error (NULL, 0, 0, "FfsRebase could not locate a PE32 section", NULL);\r
367 break;\r
368\r
369 default:\r
370 Error (NULL, 0, 0, "FfsRebase returned unknown status", "status=0x%08X", Status);\r
371 break;\r
372 }\r
373\r
374 goto Finish;\r
375 }\r
376 //\r
377 // Get the next file\r
378 //\r
379 Status = GetNextFile (CurrentFile, &CurrentFile);\r
380 if (EFI_ERROR (Status)) {\r
381 Error (NULL, 0, 0, "cannot find the next file in the FV image", NULL);\r
382 goto Finish;\r
383 }\r
384 }\r
385 //\r
386 // Open the output file\r
387 //\r
388 OutputFile = fopen (OutputFileName, "wb");\r
389 if (OutputFile == NULL) {\r
390 Error (NULL, 0, 0, OutputFileName, "failed to open output file");\r
391 goto Finish;\r
392 }\r
393\r
394 if (fwrite (FvImage, 1, FvSize, OutputFile) != FvSize) {\r
395 Error (NULL, 0, 0, "failed to write to output file", 0);\r
396 goto Finish;\r
397 }\r
398\r
399Finish:\r
400 if (InputFile != NULL) {\r
401 fclose (InputFile);\r
402 }\r
403 //\r
404 // If we created an output file, and there was an error, remove it so\r
405 // subsequent builds will rebuild it.\r
406 //\r
407 if (OutputFile != NULL) {\r
408 if (GetUtilityStatus () == STATUS_ERROR) {\r
409 remove (OutputFileName);\r
410 }\r
411\r
412 fclose (OutputFile);\r
413 }\r
414\r
8733430b 415 if (LogFile != NULL) {\r
416 fclose (LogFile);\r
5049fd31 417 }\r
418\r
d25c4bf0 419 if (FvImage != NULL) {\r
420 free (FvImage);\r
421 }\r
422\r
423 return GetUtilityStatus ();\r
424}\r
425\r
426EFI_STATUS\r
427ReadHeader (\r
428 IN FILE *InputFile,\r
429 OUT UINT32 *FvSize,\r
430 OUT BOOLEAN *ErasePolarity\r
431 )\r
432/*++\r
433\r
434Routine Description:\r
435\r
8733430b 436 This function determines the size of the FV and the erase polarity. The\r
d25c4bf0 437 erase polarity is the FALSE value for file state.\r
438\r
439Arguments:\r
440\r
441 InputFile The file that contains the FV image.\r
442 FvSize The size of the FV.\r
443 ErasePolarity The FV erase polarity.\r
8733430b 444\r
d25c4bf0 445Returns:\r
8733430b 446\r
d25c4bf0 447 EFI_SUCCESS Function completed successfully.\r
448 EFI_INVALID_PARAMETER A required parameter was NULL or is out of range.\r
449 EFI_ABORTED The function encountered an error.\r
450\r
451--*/\r
452{\r
453 EFI_FIRMWARE_VOLUME_HEADER VolumeHeader;\r
454 EFI_FV_BLOCK_MAP_ENTRY BlockMap;\r
455 UINTN Signature[2];\r
456 UINTN BytesRead;\r
457 UINT32 Size;\r
458\r
459 BytesRead = 0;\r
460 Size = 0;\r
461 //\r
462 // Check input parameters\r
463 //\r
464 if ((InputFile == NULL) || (FvSize == NULL) || (ErasePolarity == NULL)) {\r
465 Error (NULL, 0, 0, "ReadHeader()", "invalid input parameter");\r
466 return EFI_INVALID_PARAMETER;\r
467 }\r
468 //\r
469 // Read the header\r
470 //\r
471 fread (&VolumeHeader, sizeof (EFI_FIRMWARE_VOLUME_HEADER) - sizeof (EFI_FV_BLOCK_MAP_ENTRY), 1, InputFile);\r
472 BytesRead = sizeof (EFI_FIRMWARE_VOLUME_HEADER) - sizeof (EFI_FV_BLOCK_MAP_ENTRY);\r
473 Signature[0] = VolumeHeader.Signature;\r
474 Signature[1] = 0;\r
475\r
476 //\r
477 // Get erase polarity\r
478 //\r
479 if (VolumeHeader.Attributes & EFI_FVB_ERASE_POLARITY) {\r
480 *ErasePolarity = TRUE;\r
481 }\r
482\r
483 do {\r
484 fread (&BlockMap, sizeof (EFI_FV_BLOCK_MAP_ENTRY), 1, InputFile);\r
485 BytesRead += sizeof (EFI_FV_BLOCK_MAP_ENTRY);\r
486\r
487 if (BlockMap.NumBlocks != 0) {\r
488 Size += BlockMap.NumBlocks * BlockMap.BlockLength;\r
489 }\r
490\r
491 } while (!(BlockMap.NumBlocks == 0 && BlockMap.BlockLength == 0));\r
492\r
493 if (VolumeHeader.FvLength != Size) {\r
494 Error (NULL, 0, 0, "volume size not consistant with block maps", NULL);\r
495 return EFI_ABORTED;\r
496 }\r
497\r
498 *FvSize = Size;\r
499\r
500 rewind (InputFile);\r
501\r
502 return EFI_SUCCESS;\r
503}\r
504\r
505VOID\r
fd23b925 506Version (\r
d25c4bf0 507 VOID\r
508 )\r
509/*++\r
510\r
511Routine Description:\r
512\r
513 Displays the standard utility information to SDTOUT\r
514\r
515Arguments:\r
516\r
517 None\r
518\r
519Returns:\r
520\r
521 None\r
522\r
523--*/\r
524{\r
fd23b925 525 printf ("%s v%d.%d -PEI Rebase Utility.\n", UTILITY_NAME, UTILITY_MAJOR_VERSION, UTILITY_MINOR_VERSION);\r
526 printf ("Copyright (c) 1999-2007 Intel Corporation. All rights reserved.\n");\r
d25c4bf0 527}\r
528\r
529VOID\r
fd23b925 530Usage (\r
d25c4bf0 531 VOID\r
532 )\r
533/*++\r
534\r
535Routine Description:\r
536\r
537 Displays the utility usage syntax to STDOUT\r
538\r
539Arguments:\r
540\r
541 None\r
542\r
543Returns:\r
544\r
545 None\r
546\r
547--*/\r
548{\r
fd23b925 549 Version();\r
aaed63a9 550\r
d25c4bf0 551 printf (\r
5b664244 552 "Usage: %s -I InputFileName -O OutputFileName -B BaseAddress [-F InputFvInfName]\n",\r
d25c4bf0 553 UTILITY_NAME\r
554 );\r
5b664244 555 printf (" [-D BootDriverBaseAddress] [-R RuntimeDriverBaseAddress]\n");\r
d25c4bf0 556 printf (" Where:\n");\r
5b664244
LG
557 printf (" InputFileName is the name of the EFI FV file to rebase.\n");\r
558 printf (" OutputFileName is the desired output file name.\n");\r
559 printf (" BaseAddress is the rebase address for all drivers run in Flash.\n");\r
560 printf (" InputFvInfName is the Fv.inf file that contains this FV base address to rebase against.\n");\r
561 printf (" BootDriverBaseAddress is the rebase address for all boot drivers in this fv image.\n");\r
562 printf (" RuntimeDriverBaseAddress is the rebase address for all runtime drivers in this fv image.\n");\r
563 printf (" Argument pair may be in any order.\n\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
8733430b 599 EFI_PHYSICAL_ADDRESS NewPe32BaseAddress;\r
d25c4bf0 600 UINTN Index;\r
601 EFI_FILE_SECTION_POINTER CurrentPe32Section;\r
602 EFI_FFS_FILE_STATE SavedState;\r
8733430b 603 EFI_IMAGE_NT_HEADERS32 *PeHdr;\r
d25c4bf0 604 EFI_TE_IMAGE_HEADER *TEImageHeader;\r
d25c4bf0 605 UINT8 FileGuidString[80];\r
606 UINT32 TailSize;\r
607 EFI_FFS_FILE_TAIL TailValue;\r
8733430b 608 EFI_PHYSICAL_ADDRESS *BaseToUpdate;\r
5b664244 609 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *DebugEntry;\r
aaed63a9 610\r
d25c4bf0 611\r
612 //\r
613 // Verify input parameters\r
614 //\r
615 if (FfsFile == NULL) {\r
616 return EFI_INVALID_PARAMETER;\r
617 }\r
618 //\r
619 // Convert the GUID to a string so we can at least report which file\r
620 // if we find an error.\r
621 //\r
622 PrintGuidToBuffer (&FfsFile->Name, FileGuidString, sizeof (FileGuidString), TRUE);\r
623 if (FfsFile->Attributes & FFS_ATTRIB_TAIL_PRESENT) {\r
624 TailSize = sizeof (EFI_FFS_FILE_TAIL);\r
625 } else {\r
626 TailSize = 0;\r
627 }\r
628 //\r
629 // Do some cursory checks on the FFS file contents\r
630 //\r
631 Status = VerifyFfsFile (FfsFile);\r
632 if (EFI_ERROR (Status)) {\r
633 Error (NULL, 0, 0, "file does not appear to be a valid FFS file, cannot be rebased", FileGuidString);\r
634 return EFI_INVALID_PARAMETER;\r
635 }\r
5049fd31 636\r
d25c4bf0 637 //\r
8733430b 638 // We only process files potentially containing PE32 sections.\r
d25c4bf0 639 //\r
8733430b 640 switch (FfsFile->Type) {\r
641 case EFI_FV_FILETYPE_SECURITY_CORE:\r
642 case EFI_FV_FILETYPE_PEI_CORE:\r
643 case EFI_FV_FILETYPE_PEIM:\r
644 case EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER:\r
645 case EFI_FV_FILETYPE_DRIVER:\r
646 case EFI_FV_FILETYPE_DXE_CORE:\r
647 break;\r
648 default:\r
649 return EFI_SUCCESS;\r
d25c4bf0 650 }\r
5049fd31 651\r
d25c4bf0 652 //\r
653 // Rebase each PE32 section\r
654 //\r
655 Status = EFI_SUCCESS;\r
d25c4bf0 656 for (Index = 1;; Index++) {\r
657 Status = GetSectionByType (FfsFile, EFI_SECTION_PE32, Index, &CurrentPe32Section);\r
658 if (EFI_ERROR (Status)) {\r
659 break;\r
660 }\r
661\r
d25c4bf0 662 //\r
663 // Initialize context\r
664 //\r
665 memset (&ImageContext, 0, sizeof (ImageContext));\r
666 ImageContext.Handle = (VOID *) ((UINTN) CurrentPe32Section.Pe32Section + sizeof (EFI_PE32_SECTION));\r
4df60ea5 667 ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) FfsRebaseImageRead;\r
4df60ea5 668 Status = PeCoffLoaderGetImageInfo (&ImageContext);\r
d25c4bf0 669 if (EFI_ERROR (Status)) {\r
670 Error (NULL, 0, 0, "GetImageInfo() call failed on rebase", FileGuidString);\r
671 return Status;\r
672 }\r
8733430b 673\r
5b664244
LG
674 //\r
675 // Don't Load PeImage, only to relocate current image.\r
676 //\r
677 ImageContext.ImageAddress = (UINTN) CurrentPe32Section.Pe32Section + sizeof (EFI_PE32_SECTION);\r
678\r
679 //\r
680 // Check if section-alignment and file-alignment match or not\r
681 //\r
682 PeHdr = (EFI_IMAGE_NT_HEADERS *)((UINTN)ImageContext.ImageAddress + ImageContext.PeCoffHeaderOffset);\r
683 if (PeHdr->OptionalHeader.SectionAlignment != PeHdr->OptionalHeader.FileAlignment) {\r
684 //\r
aaed63a9 685 // Nor XIP module can be ignored.\r
5b664244
LG
686 //\r
687 if ((Flags & 1) == 0) {\r
688 continue;\r
689 }\r
690 Error (NULL, 0, 0, "Section-Alignment and File-Alignment does not match", FileGuidString);\r
691 return EFI_ABORTED;\r
aaed63a9 692 }\r
5b664244
LG
693\r
694 //\r
695 // Update CodeView and PdbPointer in ImageContext\r
696 //\r
697 DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *)(UINTN)(\r
698 ImageContext.ImageAddress +\r
699 ImageContext.DebugDirectoryEntryRva\r
700 );\r
aaed63a9 701 ImageContext.CodeView = (VOID *)(UINTN)(\r
702 ImageContext.ImageAddress +\r
5b664244
LG
703 DebugEntry->RVA\r
704 );\r
705 switch (*(UINT32 *) ImageContext.CodeView) {\r
706 case CODEVIEW_SIGNATURE_NB10:\r
707 ImageContext.PdbPointer = (CHAR8 *) ImageContext.CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY);\r
708 break;\r
709\r
710 case CODEVIEW_SIGNATURE_RSDS:\r
711 ImageContext.PdbPointer = (CHAR8 *) ImageContext.CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY);\r
712 break;\r
713\r
714 default:\r
715 break;\r
716 }\r
717\r
8733430b 718 //\r
719 // Calculate the PE32 base address, based on file type\r
720 //\r
721 switch (FfsFile->Type) {\r
722 case EFI_FV_FILETYPE_SECURITY_CORE:\r
723 case EFI_FV_FILETYPE_PEI_CORE:\r
724 case EFI_FV_FILETYPE_PEIM:\r
725 case EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER:\r
726 if ((Flags & 1) == 0) {\r
727 //\r
728 // We aren't relocating XIP code, so skip it.\r
729 //\r
730 return EFI_SUCCESS;\r
731 }\r
732\r
733 NewPe32BaseAddress =\r
5b664244 734 XipBase + (UINTN)ImageContext.ImageAddress - (UINTN)FfsFile;\r
8733430b 735 BaseToUpdate = &XipBase;\r
736 break;\r
737\r
738 case EFI_FV_FILETYPE_DRIVER:\r
5b664244 739 PeHdr = (EFI_IMAGE_NT_HEADERS32*)(ImageContext.ImageAddress + ImageContext.PeCoffHeaderOffset);\r
8733430b 740 switch (PeHdr->OptionalHeader.Subsystem) {\r
741 case EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER:\r
742 if ((Flags & 4) == 0) {\r
743 //\r
744 // RT drivers aren't supposed to be relocated\r
745 //\r
746 continue;\r
747 }\r
748\r
749 NewPe32BaseAddress = *RtBase;\r
750 BaseToUpdate = RtBase;\r
751 break;\r
752\r
753 default:\r
754 //\r
755 // We treat all other subsystems the same as BS_DRIVER\r
756 //\r
757 if ((Flags & 2) == 0) {\r
758 //\r
759 // Skip all BS_DRIVER's\r
760 //\r
761 continue;\r
762 }\r
763\r
764 NewPe32BaseAddress = *BsBase;\r
765 BaseToUpdate = BsBase;\r
766 break;\r
767 }\r
768 break;\r
769\r
770 case EFI_FV_FILETYPE_DXE_CORE:\r
771 if ((Flags & 2) == 0) {\r
772 //\r
773 // Skip DXE core\r
774 //\r
775 return EFI_SUCCESS;\r
776 }\r
777\r
778 NewPe32BaseAddress = *BsBase;\r
779 BaseToUpdate = BsBase;\r
780 break;\r
781\r
782 default:\r
783 //\r
784 // Not supported file type\r
785 //\r
786 return EFI_SUCCESS;\r
787 }\r
788\r
d25c4bf0 789 ImageContext.DestinationAddress = NewPe32BaseAddress;\r
4df60ea5 790 Status = PeCoffLoaderRelocateImage (&ImageContext);\r
d25c4bf0 791 if (EFI_ERROR (Status)) {\r
792 Error (NULL, 0, 0, "RelocateImage() call failed on rebase", FileGuidString);\r
d25c4bf0 793 return Status;\r
794 }\r
795\r
8733430b 796 //\r
797 // Update BASE address\r
798 //\r
799 fprintf (\r
800 LogFile,\r
aaed63a9 801 "%s %016I64X\n",\r
8733430b 802 FileGuidString,\r
aaed63a9 803 ImageContext.DestinationAddress\r
8733430b 804 );\r
805 *BaseToUpdate += EFI_SIZE_TO_PAGES (ImageContext.ImageSize) * EFI_PAGE_SIZE;\r
806\r
d25c4bf0 807 //\r
808 // Now update file checksum\r
809 //\r
810 if (FfsFile->Attributes & FFS_ATTRIB_TAIL_PRESENT) {\r
811 TailSize = sizeof (EFI_FFS_FILE_TAIL);\r
812 } else {\r
813 TailSize = 0;\r
814 }\r
815\r
816 if (FfsFile->Attributes & FFS_ATTRIB_CHECKSUM) {\r
817 SavedState = FfsFile->State;\r
818 FfsFile->IntegrityCheck.Checksum.File = 0;\r
819 FfsFile->State = 0;\r
820 if (FfsFile->Attributes & FFS_ATTRIB_CHECKSUM) {\r
821 FfsFile->IntegrityCheck.Checksum.File = CalculateChecksum8 (\r
822 (UINT8 *) FfsFile,\r
823 GetLength (FfsFile->Size) - TailSize\r
824 );\r
825 } else {\r
826 FfsFile->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;\r
827 }\r
828\r
829 FfsFile->State = SavedState;\r
830 }\r
831 //\r
832 // Update tail if present\r
833 //\r
834 if (FfsFile->Attributes & FFS_ATTRIB_TAIL_PRESENT) {\r
835 TailValue = (EFI_FFS_FILE_TAIL) (~(FfsFile->IntegrityCheck.TailReference));\r
836 *(EFI_FFS_FILE_TAIL *) (((UINTN) FfsFile + GetLength (FfsFile->Size) - sizeof (EFI_FFS_FILE_TAIL))) = TailValue;\r
837 }\r
838 }\r
8733430b 839\r
840 if ((Flags & 1) == 0 || (\r
841 FfsFile->Type != EFI_FV_FILETYPE_SECURITY_CORE &&\r
842 FfsFile->Type != EFI_FV_FILETYPE_PEI_CORE &&\r
843\r
844 FfsFile->Type != EFI_FV_FILETYPE_PEIM &&\r
845 FfsFile->Type != EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER\r
846 )) {\r
847 //\r
848 // Only XIP code may have a TE section\r
849 //\r
850 return EFI_SUCCESS;\r
851 }\r
aaed63a9 852\r
d25c4bf0 853 //\r
854 // Now process TE sections\r
855 //\r
856 for (Index = 1;; Index++) {\r
857 Status = GetSectionByType (FfsFile, EFI_SECTION_TE, Index, &CurrentPe32Section);\r
858 if (EFI_ERROR (Status)) {\r
859 break;\r
860 }\r
861\r
d25c4bf0 862 //\r
863 // Calculate the TE base address, the FFS file base plus the offset of the TE section less the size stripped off\r
864 // by GenTEImage\r
865 //\r
866 TEImageHeader = (EFI_TE_IMAGE_HEADER *) ((UINT8 *) CurrentPe32Section.Pe32Section + sizeof (EFI_COMMON_SECTION_HEADER));\r
867\r
d25c4bf0 868 //\r
5b664244 869 // Initialize context, load image info.\r
d25c4bf0 870 //\r
871 memset (&ImageContext, 0, sizeof (ImageContext));\r
5b664244 872 ImageContext.Handle = (VOID *) TEImageHeader;\r
4df60ea5 873 ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) FfsRebaseImageRead;\r
d25c4bf0 874\r
4df60ea5 875 Status = PeCoffLoaderGetImageInfo (&ImageContext);\r
d25c4bf0 876\r
877 if (EFI_ERROR (Status)) {\r
878 Error (NULL, 0, 0, "GetImageInfo() call failed on rebase of TE image", FileGuidString);\r
d25c4bf0 879 return Status;\r
880 }\r
881 //\r
5b664244 882 // Don't reload TeImage\r
d25c4bf0 883 //\r
5b664244 884 ImageContext.ImageAddress = (UINTN) TEImageHeader;\r
d25c4bf0 885\r
5b664244
LG
886 //\r
887 // Update CodeView and PdbPointer in ImageContext\r
888 //\r
889 DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *)(UINTN)(\r
890 ImageContext.ImageAddress +\r
891 ImageContext.DebugDirectoryEntryRva +\r
892 sizeof(EFI_TE_IMAGE_HEADER) -\r
893 TEImageHeader->StrippedSize\r
894 );\r
895\r
896 ImageContext.CodeView = (VOID *)(UINTN)(\r
897 ImageContext.ImageAddress +\r
898 DebugEntry->RVA +\r
899 sizeof(EFI_TE_IMAGE_HEADER) -\r
900 TEImageHeader->StrippedSize\r
901 );\r
902\r
903 switch (*(UINT32 *) ImageContext.CodeView) {\r
904 case CODEVIEW_SIGNATURE_NB10:\r
905 ImageContext.PdbPointer = (CHAR8 *) ImageContext.CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY);\r
906 break;\r
907\r
908 case CODEVIEW_SIGNATURE_RSDS:\r
909 ImageContext.PdbPointer = (CHAR8 *) ImageContext.CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY);\r
910 break;\r
911\r
912 default:\r
913 break;\r
d25c4bf0 914 }\r
915\r
5b664244
LG
916 //\r
917 // Reloacate TeImage\r
aaed63a9 918 //\r
5b664244
LG
919 ImageContext.DestinationAddress = XipBase + (UINTN) TEImageHeader + sizeof (EFI_TE_IMAGE_HEADER) \\r
920 - TEImageHeader->StrippedSize - (UINTN) FfsFile;\r
4df60ea5 921 Status = PeCoffLoaderRelocateImage (&ImageContext);\r
d25c4bf0 922 if (EFI_ERROR (Status)) {\r
923 Error (NULL, 0, 0, "RelocateImage() call failed on rebase of TE image", FileGuidString);\r
d25c4bf0 924 return Status;\r
925 }\r
926\r
d25c4bf0 927 if (FfsFile->Attributes & FFS_ATTRIB_TAIL_PRESENT) {\r
928 TailSize = sizeof (EFI_FFS_FILE_TAIL);\r
929 } else {\r
930 TailSize = 0;\r
931 }\r
932 //\r
933 // Now update file checksum\r
934 //\r
935 if (FfsFile->Attributes & FFS_ATTRIB_CHECKSUM) {\r
936 SavedState = FfsFile->State;\r
937 FfsFile->IntegrityCheck.Checksum.File = 0;\r
938 FfsFile->State = 0;\r
939 if (FfsFile->Attributes & FFS_ATTRIB_CHECKSUM) {\r
940 FfsFile->IntegrityCheck.Checksum.File = CalculateChecksum8 (\r
941 (UINT8 *) FfsFile,\r
942 GetLength (FfsFile->Size) - TailSize\r
943 );\r
944 } else {\r
945 FfsFile->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;\r
946 }\r
947\r
948 FfsFile->State = SavedState;\r
949 }\r
950 //\r
951 // Update tail if present\r
952 //\r
953 if (FfsFile->Attributes & FFS_ATTRIB_TAIL_PRESENT) {\r
954 TailValue = (EFI_FFS_FILE_TAIL) (~(FfsFile->IntegrityCheck.TailReference));\r
955 *(EFI_FFS_FILE_TAIL *) (((UINTN) FfsFile + GetLength (FfsFile->Size) - sizeof (EFI_FFS_FILE_TAIL))) = TailValue;\r
956 }\r
8733430b 957\r
958 fprintf (\r
959 LogFile,\r
aaed63a9 960 "%s %016I64X\n",\r
8733430b 961 FileGuidString,\r
aaed63a9 962 ImageContext.DestinationAddress\r
8733430b 963 );\r
d25c4bf0 964 }\r
aaed63a9 965\r
d25c4bf0 966 return EFI_SUCCESS;\r
967}\r
968\r
969EFI_STATUS\r
970FfsRebaseImageRead (\r
971 IN VOID *FileHandle,\r
972 IN UINTN FileOffset,\r
973 IN OUT UINT32 *ReadSize,\r
974 OUT VOID *Buffer\r
975 )\r
976/*++\r
977\r
978Routine Description:\r
979\r
980 Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file\r
981\r
982Arguments:\r
983\r
984 FileHandle - The handle to the PE/COFF file\r
985\r
986 FileOffset - The offset, in bytes, into the file to read\r
987\r
988 ReadSize - The number of bytes to read from the file starting at FileOffset\r
989\r
990 Buffer - A pointer to the buffer to read the data into.\r
991\r
992Returns:\r
993\r
994 EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset\r
995\r
996--*/\r
997{\r
998 CHAR8 *Destination8;\r
999 CHAR8 *Source8;\r
1000 UINT32 Length;\r
1001\r
1002 Destination8 = Buffer;\r
1003 Source8 = (CHAR8 *) ((UINTN) FileHandle + FileOffset);\r
1004 Length = *ReadSize;\r
1005 while (Length--) {\r
1006 *(Destination8++) = *(Source8++);\r
1007 }\r
1008\r
1009 return EFI_SUCCESS;\r
1010}\r