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