]> git.proxmox.com Git - mirror_edk2.git/blame - Tools/Source/TianoTools/PeiRebase/PeiRebaseExe.c
Added "synchronized" to getToolChainInfo() to solve synchronization issue.
[mirror_edk2.git] / Tools / Source / TianoTools / PeiRebase / PeiRebaseExe.c
CommitLineData
d25c4bf0 1/*++\r
2\r
ad1f8df0 3Copyright (c) 1999-2006 Intel Corporation. All rights reserved\r
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
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
62 BaseAddress The base address to use for rebasing the FV. The correct \r
63 format is a hex number preceded by 0x.\r
64 InputFileName The name of the input FV file.\r
65 OutputFileName The name of the output FV file.\r
5049fd31 66 MapFileName The name of the map file of relocation info.\r
d25c4bf0 67\r
68 Arguments come in pair in any order.\r
69 -I InputFileName \r
70 -O OutputFileName\r
71 -B BaseAddress \r
5049fd31 72 -M MapFileName \r
d25c4bf0 73\r
74Returns:\r
75\r
76 0 No error conditions detected.\r
77 1 One or more of the input parameters is invalid.\r
78 2 A resource required by the utility was unavailable. \r
79 Most commonly this will be memory allocation or file creation.\r
80 3 PeiRebase.dll could not be loaded.\r
81 4 Error executing the PEI rebase.\r
82\r
83--*/\r
84{\r
85 UINT8 Index;\r
86 CHAR8 InputFileName[_MAX_PATH];\r
87 CHAR8 OutputFileName[_MAX_PATH];\r
5049fd31 88 CHAR8 MapFileName[_MAX_PATH];\r
d25c4bf0 89 EFI_PHYSICAL_ADDRESS BaseAddress;\r
90 BOOLEAN BaseAddressSet;\r
91 EFI_STATUS Status;\r
92 FILE *InputFile;\r
93 FILE *OutputFile;\r
5049fd31 94 FILE *MapFile;\r
d25c4bf0 95 UINT64 FvOffset;\r
96 UINT32 FileCount;\r
97 int BytesRead;\r
98 EFI_FIRMWARE_VOLUME_HEADER *FvImage;\r
99 UINT32 FvSize;\r
100 EFI_FFS_FILE_HEADER *CurrentFile;\r
101 BOOLEAN ErasePolarity;\r
102 EFI_PHYSICAL_ADDRESS CurrentFileBaseAddress;\r
103\r
104 ErasePolarity = FALSE;\r
105 //\r
106 // Set utility name for error/warning reporting purposes.\r
107 //\r
108 SetUtilityName (UTILITY_NAME);\r
109 //\r
110 // Verify the correct number of arguments\r
111 //\r
112 if (argc != MAX_ARGS) {\r
113 PrintUsage ();\r
114 return STATUS_ERROR;\r
115 }\r
5049fd31 116\r
d25c4bf0 117 //\r
118 // Initialize variables\r
119 //\r
120 InputFileName[0] = 0;\r
121 OutputFileName[0] = 0;\r
5049fd31 122 MapFileName[0] = 0;\r
d25c4bf0 123 BaseAddress = 0;\r
124 BaseAddressSet = FALSE;\r
125 FvOffset = 0;\r
126 FileCount = 0;\r
127 ErasePolarity = FALSE;\r
128 InputFile = NULL;\r
129 OutputFile = NULL;\r
5049fd31 130 MapFile = NULL;\r
d25c4bf0 131 FvImage = NULL;\r
5049fd31 132\r
d25c4bf0 133 //\r
134 // Parse the command line arguments\r
135 //\r
136 for (Index = 1; Index < MAX_ARGS; Index += 2) {\r
137 //\r
138 // Make sure argument pair begin with - or /\r
139 //\r
140 if (argv[Index][0] != '-' && argv[Index][0] != '/') {\r
141 PrintUsage ();\r
142 Error (NULL, 0, 0, argv[Index], "unrecognized option");\r
143 return STATUS_ERROR;\r
144 }\r
145 //\r
146 // Make sure argument specifier is only one letter\r
147 //\r
148 if (argv[Index][2] != 0) {\r
149 PrintUsage ();\r
150 Error (NULL, 0, 0, argv[Index], "unrecognized option");\r
151 return STATUS_ERROR;\r
152 } \r
153 //\r
154 // Determine argument to read\r
155 //\r
156 switch (argv[Index][1]) {\r
157 case 'I':\r
158 case 'i':\r
159 if (strlen (InputFileName) == 0) {\r
160 strcpy (InputFileName, argv[Index + 1]);\r
161 } else {\r
162 PrintUsage ();\r
163 Error (NULL, 0, 0, argv[Index + 1], "only one -i InputFileName may be specified");\r
164 return STATUS_ERROR;\r
165 }\r
166 break;\r
167\r
168 case 'O':\r
169 case 'o':\r
170 if (strlen (OutputFileName) == 0) {\r
171 strcpy (OutputFileName, argv[Index + 1]);\r
172 } else {\r
173 PrintUsage ();\r
174 Error (NULL, 0, 0, argv[Index + 1], "only one -o OutputFileName may be specified");\r
175 return STATUS_ERROR;\r
176 }\r
177 break;\r
178\r
179 case 'B':\r
180 case 'b':\r
181 if (!BaseAddressSet) {\r
182 Status = AsciiStringToUint64 (argv[Index + 1], FALSE, &BaseAddress);\r
183 if (EFI_ERROR (Status)) {\r
184 PrintUsage ();\r
185 Error (NULL, 0, 0, argv[Index + 1], "invalid hex digit given for the base address");\r
186 return STATUS_ERROR;\r
187 }\r
188\r
189 BaseAddressSet = TRUE;\r
190 } else {\r
191 PrintUsage ();\r
192 Error (NULL, 0, 0, argv[Index + 1], "-b BaseAddress may only be specified once");\r
193 return STATUS_ERROR;\r
194 }\r
195 break;\r
196\r
5049fd31 197 case 'M':\r
198 case 'm':\r
199 if (strlen (MapFileName) == 0) {\r
200 strcpy (MapFileName, argv[Index + 1]);\r
201 } else {\r
202 PrintUsage ();\r
203 Error (NULL, 0, 0, argv[Index + 1], "only one -m MapFileName may be specified");\r
204 return STATUS_ERROR;\r
205 }\r
206 break;\r
207\r
d25c4bf0 208 default:\r
209 PrintUsage ();\r
210 Error (NULL, 0, 0, argv[Index], "unrecognized argument");\r
211 return STATUS_ERROR;\r
212 break;\r
213 }\r
214 }\r
5049fd31 215\r
216 //\r
217 // Create the Map file if we need it\r
218 //\r
219 if (strlen (MapFileName) != 0) {\r
220 MapFile = fopen (MapFileName, "w");\r
221 if (MapFile == NULL) {\r
222 Error (NULL, 0, 0, MapFileName, "failed to open map file");\r
223 goto Finish;\r
224 }\r
225 } \r
226\r
d25c4bf0 227 //\r
228 // Open the file containing the FV\r
229 //\r
230 InputFile = fopen (InputFileName, "rb");\r
231 if (InputFile == NULL) {\r
232 Error (NULL, 0, 0, InputFileName, "could not open input file for reading");\r
233 return STATUS_ERROR;\r
234 }\r
235 //\r
236 // Determine size of FV\r
237 //\r
238 Status = ReadHeader (InputFile, &FvSize, &ErasePolarity);\r
239 if (EFI_ERROR (Status)) {\r
240 Error (NULL, 0, 0, "could not parse the FV header", NULL);\r
241 goto Finish;\r
242 }\r
243 //\r
244 // Allocate a buffer for the FV image\r
245 //\r
246 FvImage = malloc (FvSize);\r
247 if (FvImage == NULL) {\r
248 Error (NULL, 0, 0, "application error", "memory allocation failed");\r
249 goto Finish;\r
250 }\r
251 //\r
252 // Read the entire FV to the buffer\r
253 //\r
254 BytesRead = fread (FvImage, 1, FvSize, InputFile);\r
255 fclose (InputFile);\r
256 InputFile = NULL;\r
257 if ((unsigned int) BytesRead != FvSize) {\r
258 Error (NULL, 0, 0, InputFileName, "failed to read from file");\r
259 goto Finish;\r
260 }\r
261 //\r
262 // Prepare to walk the FV image\r
263 //\r
264 InitializeFvLib (FvImage, FvSize);\r
265 //\r
266 // Get the first file\r
267 //\r
268 Status = GetNextFile (NULL, &CurrentFile);\r
269 if (EFI_ERROR (Status)) {\r
270 Error (NULL, 0, 0, "cannot find the first file in the FV image", NULL);\r
271 goto Finish;\r
272 }\r
273 //\r
274 // Check if each file should be rebased\r
275 //\r
276 while (CurrentFile != NULL) {\r
277 //\r
278 // Rebase this file\r
279 //\r
280 CurrentFileBaseAddress = BaseAddress + ((UINTN) CurrentFile - (UINTN) FvImage);\r
5049fd31 281 Status = FfsRebase (CurrentFile, CurrentFileBaseAddress, MapFile);\r
d25c4bf0 282\r
283 if (EFI_ERROR (Status)) {\r
284 switch (Status) {\r
285\r
286 case EFI_INVALID_PARAMETER:\r
287 Error (NULL, 0, 0, "invalid parameter passed to FfsRebase", NULL);\r
288 break;\r
289\r
290 case EFI_ABORTED:\r
291 Error (NULL, 0, 0, "error detected while rebasing -- aborted", NULL);\r
292 break;\r
293\r
294 case EFI_OUT_OF_RESOURCES:\r
295 Error (NULL, 0, 0, "FfsRebase could not allocate required resources", NULL);\r
296 break;\r
297\r
298 case EFI_NOT_FOUND:\r
299 Error (NULL, 0, 0, "FfsRebase could not locate a PE32 section", NULL);\r
300 break;\r
301\r
302 default:\r
303 Error (NULL, 0, 0, "FfsRebase returned unknown status", "status=0x%08X", Status);\r
304 break;\r
305 }\r
306\r
307 goto Finish;\r
308 }\r
5049fd31 309\r
d25c4bf0 310 //\r
311 // Get the next file\r
312 //\r
313 Status = GetNextFile (CurrentFile, &CurrentFile);\r
314 if (EFI_ERROR (Status)) {\r
315 Error (NULL, 0, 0, "cannot find the next file in the FV image", NULL);\r
316 goto Finish;\r
317 }\r
318 }\r
319 //\r
320 // Open the output file\r
321 //\r
322 OutputFile = fopen (OutputFileName, "wb");\r
323 if (OutputFile == NULL) {\r
324 Error (NULL, 0, 0, OutputFileName, "failed to open output file");\r
325 goto Finish;\r
326 }\r
327\r
328 if (fwrite (FvImage, 1, FvSize, OutputFile) != FvSize) {\r
329 Error (NULL, 0, 0, "failed to write to output file", 0);\r
330 goto Finish;\r
331 }\r
332\r
333Finish:\r
334 if (InputFile != NULL) {\r
335 fclose (InputFile);\r
336 }\r
337 //\r
338 // If we created an output file, and there was an error, remove it so\r
339 // subsequent builds will rebuild it.\r
340 //\r
341 if (OutputFile != NULL) {\r
342 if (GetUtilityStatus () == STATUS_ERROR) {\r
343 remove (OutputFileName);\r
344 }\r
345\r
346 fclose (OutputFile);\r
347 }\r
348\r
5049fd31 349 if (MapFile != NULL) {\r
350 fclose (MapFile);\r
351 }\r
352\r
d25c4bf0 353 if (FvImage != NULL) {\r
354 free (FvImage);\r
355 }\r
356\r
357 return GetUtilityStatus ();\r
358}\r
359\r
360EFI_STATUS\r
361ReadHeader (\r
362 IN FILE *InputFile,\r
363 OUT UINT32 *FvSize,\r
364 OUT BOOLEAN *ErasePolarity\r
365 )\r
366/*++\r
367\r
368Routine Description:\r
369\r
370 This function determines the size of the FV and the erase polarity. The \r
371 erase polarity is the FALSE value for file state.\r
372\r
373Arguments:\r
374\r
375 InputFile The file that contains the FV image.\r
376 FvSize The size of the FV.\r
377 ErasePolarity The FV erase polarity.\r
378 \r
379Returns:\r
380 \r
381 EFI_SUCCESS Function completed successfully.\r
382 EFI_INVALID_PARAMETER A required parameter was NULL or is out of range.\r
383 EFI_ABORTED The function encountered an error.\r
384\r
385--*/\r
386{\r
387 EFI_FIRMWARE_VOLUME_HEADER VolumeHeader;\r
388 EFI_FV_BLOCK_MAP_ENTRY BlockMap;\r
389 UINTN Signature[2];\r
390 UINTN BytesRead;\r
391 UINT32 Size;\r
392\r
393 BytesRead = 0;\r
394 Size = 0;\r
395 //\r
396 // Check input parameters\r
397 //\r
398 if ((InputFile == NULL) || (FvSize == NULL) || (ErasePolarity == NULL)) {\r
399 Error (NULL, 0, 0, "ReadHeader()", "invalid input parameter");\r
400 return EFI_INVALID_PARAMETER;\r
401 }\r
402 //\r
403 // Read the header\r
404 //\r
405 fread (&VolumeHeader, sizeof (EFI_FIRMWARE_VOLUME_HEADER) - sizeof (EFI_FV_BLOCK_MAP_ENTRY), 1, InputFile);\r
406 BytesRead = sizeof (EFI_FIRMWARE_VOLUME_HEADER) - sizeof (EFI_FV_BLOCK_MAP_ENTRY);\r
407 Signature[0] = VolumeHeader.Signature;\r
408 Signature[1] = 0;\r
409\r
410 //\r
411 // Get erase polarity\r
412 //\r
413 if (VolumeHeader.Attributes & EFI_FVB_ERASE_POLARITY) {\r
414 *ErasePolarity = TRUE;\r
415 }\r
416\r
417 do {\r
418 fread (&BlockMap, sizeof (EFI_FV_BLOCK_MAP_ENTRY), 1, InputFile);\r
419 BytesRead += sizeof (EFI_FV_BLOCK_MAP_ENTRY);\r
420\r
421 if (BlockMap.NumBlocks != 0) {\r
422 Size += BlockMap.NumBlocks * BlockMap.BlockLength;\r
423 }\r
424\r
425 } while (!(BlockMap.NumBlocks == 0 && BlockMap.BlockLength == 0));\r
426\r
427 if (VolumeHeader.FvLength != Size) {\r
428 Error (NULL, 0, 0, "volume size not consistant with block maps", NULL);\r
429 return EFI_ABORTED;\r
430 }\r
431\r
432 *FvSize = Size;\r
433\r
434 rewind (InputFile);\r
435\r
436 return EFI_SUCCESS;\r
437}\r
438\r
439VOID\r
440PrintUtilityInfo (\r
441 VOID\r
442 )\r
443/*++\r
444\r
445Routine Description:\r
446\r
447 Displays the standard utility information to SDTOUT\r
448\r
449Arguments:\r
450\r
451 None\r
452\r
453Returns:\r
454\r
455 None\r
456\r
457--*/\r
458{\r
459 printf (\r
460 "%s, PEI Rebase Utility. Version %i.%i, %s.\n\n",\r
461 UTILITY_NAME,\r
462 UTILITY_MAJOR_VERSION,\r
463 UTILITY_MINOR_VERSION,\r
464 UTILITY_DATE\r
465 );\r
466}\r
467\r
468VOID\r
469PrintUsage (\r
470 VOID\r
471 )\r
472/*++\r
473\r
474Routine Description:\r
475\r
476 Displays the utility usage syntax to STDOUT\r
477\r
478Arguments:\r
479\r
480 None\r
481\r
482Returns:\r
483\r
484 None\r
485\r
486--*/\r
487{\r
488 printf (\r
5049fd31 489 "Usage: %s -I InputFileName -O OutputFileName -B BaseAddress [-M MapFile]\n",\r
d25c4bf0 490 UTILITY_NAME\r
491 );\r
492 printf (" Where:\n");\r
493 printf (" InputFileName is the name of the EFI FV file to rebase.\n");\r
494 printf (" OutputFileName is the desired output file name.\n");\r
495 printf (" BaseAddress is the FV base address to rebase agains.\n");\r
5049fd31 496 printf (" MapFileName is an optional map file of the relocations\n");\r
d25c4bf0 497 printf (" Argument pair may be in any order.\n\n");\r
498}\r
499\r
500EFI_STATUS\r
501FfsRebase (\r
502 IN OUT EFI_FFS_FILE_HEADER *FfsFile,\r
5049fd31 503 IN EFI_PHYSICAL_ADDRESS BaseAddress,\r
504 IN FILE *MapFile OPTIONAL\r
d25c4bf0 505 )\r
506/*++\r
507\r
508Routine Description:\r
509\r
510 This function determines if a file is XIP and should be rebased. It will \r
511 rebase any PE32 sections found in the file using the base address.\r
512 \r
513Arguments:\r
514\r
515 FfsFile A pointer to Ffs file image.\r
516 BaseAddress The base address to use for rebasing the file image.\r
5049fd31 517 MapFile Optional file to dump relocation information into\r
d25c4bf0 518\r
519Returns:\r
520\r
521 EFI_SUCCESS The image was properly rebased.\r
522 EFI_INVALID_PARAMETER An input parameter is invalid.\r
523 EFI_ABORTED An error occurred while rebasing the input file image.\r
524 EFI_OUT_OF_RESOURCES Could not allocate a required resource.\r
525 EFI_NOT_FOUND No compressed sections could be found.\r
526\r
527--*/\r
528{\r
529 EFI_STATUS Status;\r
4df60ea5 530 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;\r
d25c4bf0 531 UINTN MemoryImagePointer;\r
532 UINTN MemoryImagePointerAligned;\r
533 EFI_PHYSICAL_ADDRESS ImageAddress;\r
534 UINT64 ImageSize;\r
535 EFI_PHYSICAL_ADDRESS EntryPoint;\r
536 UINT32 Pe32ImageSize;\r
537 UINT32 NewPe32BaseAddress;\r
538 UINTN Index;\r
539 EFI_FILE_SECTION_POINTER CurrentPe32Section;\r
540 EFI_FFS_FILE_STATE SavedState;\r
541 EFI_IMAGE_NT_HEADERS *PeHdr;\r
542 UINT32 *PeHdrSizeOfImage;\r
543 UINT32 *PeHdrChecksum;\r
544 UINT32 FoundCount;\r
545 EFI_TE_IMAGE_HEADER *TEImageHeader;\r
546 UINT8 *TEBuffer;\r
547 EFI_IMAGE_DOS_HEADER *DosHeader;\r
548 UINT8 FileGuidString[80];\r
549 UINT32 TailSize;\r
550 EFI_FFS_FILE_TAIL TailValue;\r
551\r
552 //\r
553 // Verify input parameters\r
554 //\r
555 if (FfsFile == NULL) {\r
556 return EFI_INVALID_PARAMETER;\r
557 }\r
5049fd31 558 \r
d25c4bf0 559 //\r
560 // Convert the GUID to a string so we can at least report which file\r
561 // if we find an error.\r
562 //\r
563 PrintGuidToBuffer (&FfsFile->Name, FileGuidString, sizeof (FileGuidString), TRUE);\r
564 if (FfsFile->Attributes & FFS_ATTRIB_TAIL_PRESENT) {\r
565 TailSize = sizeof (EFI_FFS_FILE_TAIL);\r
566 } else {\r
567 TailSize = 0;\r
568 }\r
5049fd31 569 \r
d25c4bf0 570 //\r
571 // Do some cursory checks on the FFS file contents\r
572 //\r
573 Status = VerifyFfsFile (FfsFile);\r
574 if (EFI_ERROR (Status)) {\r
575 Error (NULL, 0, 0, "file does not appear to be a valid FFS file, cannot be rebased", FileGuidString);\r
576 return EFI_INVALID_PARAMETER;\r
577 }\r
5049fd31 578\r
579 memset (&ImageContext, 0, sizeof (ImageContext));\r
580\r
d25c4bf0 581 //\r
582 // Check if XIP file type. If not XIP, don't rebase.\r
583 //\r
584 if (FfsFile->Type != EFI_FV_FILETYPE_PEI_CORE &&\r
585 FfsFile->Type != EFI_FV_FILETYPE_PEIM &&\r
586 FfsFile->Type != EFI_FV_FILETYPE_SECURITY_CORE &&\r
587 FfsFile->Type != EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER\r
588 ) {\r
589 return EFI_SUCCESS;\r
590 }\r
5049fd31 591\r
d25c4bf0 592 //\r
593 // Rebase each PE32 section\r
594 //\r
595 Status = EFI_SUCCESS;\r
596 FoundCount = 0;\r
597 for (Index = 1;; Index++) {\r
598 Status = GetSectionByType (FfsFile, EFI_SECTION_PE32, Index, &CurrentPe32Section);\r
599 if (EFI_ERROR (Status)) {\r
600 break;\r
601 }\r
602\r
603 FoundCount++;\r
604\r
605 //\r
606 // Calculate the PE32 base address, the FFS file base plus the offset of the PE32 section\r
607 //\r
608 NewPe32BaseAddress = ((UINT32) BaseAddress) + ((UINTN) CurrentPe32Section.Pe32Section + sizeof (EFI_COMMON_SECTION_HEADER) - (UINTN) FfsFile);\r
609\r
610 //\r
611 // Initialize context\r
612 //\r
613 memset (&ImageContext, 0, sizeof (ImageContext));\r
614 ImageContext.Handle = (VOID *) ((UINTN) CurrentPe32Section.Pe32Section + sizeof (EFI_PE32_SECTION));\r
4df60ea5 615 ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) FfsRebaseImageRead;\r
d25c4bf0 616\r
4df60ea5 617 Status = PeCoffLoaderGetImageInfo (&ImageContext);\r
d25c4bf0 618\r
619 if (EFI_ERROR (Status)) {\r
620 Error (NULL, 0, 0, "GetImageInfo() call failed on rebase", FileGuidString);\r
621 return Status;\r
622 }\r
623 //\r
624 // Allocate a buffer for the image to be loaded into.\r
625 //\r
626 Pe32ImageSize = GetLength (CurrentPe32Section.Pe32Section->CommonHeader.Size) - sizeof (EFI_PE32_SECTION);\r
627 MemoryImagePointer = (UINTN) (malloc (Pe32ImageSize + 0x1000));\r
628 if (MemoryImagePointer == 0) {\r
629 Error (NULL, 0, 0, "memory allocation failure", NULL);\r
630 return EFI_OUT_OF_RESOURCES;\r
631 }\r
632 memset ((void *) MemoryImagePointer, 0, Pe32ImageSize + 0x1000);\r
633 MemoryImagePointerAligned = (MemoryImagePointer + 0x0FFF) & (-1 << 12);\r
634 \r
635\r
636 ImageContext.ImageAddress = MemoryImagePointerAligned;\r
637\r
4df60ea5 638 Status = PeCoffLoaderLoadImage (&ImageContext);\r
d25c4bf0 639 if (EFI_ERROR (Status)) {\r
640 Error (NULL, 0, 0, "LoadImage() call failed on rebase", FileGuidString);\r
641 free ((VOID *) MemoryImagePointer);\r
642 return Status;\r
643 }\r
644\r
645 ImageContext.DestinationAddress = NewPe32BaseAddress;\r
4df60ea5 646 Status = PeCoffLoaderRelocateImage (&ImageContext);\r
d25c4bf0 647 if (EFI_ERROR (Status)) {\r
648 Error (NULL, 0, 0, "RelocateImage() call failed on rebase", FileGuidString);\r
649 free ((VOID *) MemoryImagePointer);\r
650 return Status;\r
651 }\r
652\r
653 ImageAddress = ImageContext.ImageAddress;\r
654 ImageSize = ImageContext.ImageSize;\r
655 EntryPoint = ImageContext.EntryPoint;\r
656\r
657 if (ImageSize > Pe32ImageSize) {\r
658 Error (\r
659 NULL,\r
660 0,\r
661 0,\r
662 "rebased image is larger than original PE32 image",\r
663 "0x%X > 0x%X, file %s",\r
664 ImageSize,\r
665 Pe32ImageSize,\r
666 FileGuidString\r
667 );\r
668 free ((VOID *) MemoryImagePointer);\r
669 return EFI_ABORTED;\r
670 }\r
671 //\r
672 // Since we may have updated the Codeview RVA, we need to insure the PE\r
673 // header indicates the image is large enough to contain the Codeview data\r
674 // so it will be loaded properly later if the PEIM is reloaded into memory...\r
675 //\r
676 PeHdr = (VOID *) ((UINTN) ImageAddress + ImageContext.PeCoffHeaderOffset);\r
677 if (PeHdr->FileHeader.Machine == EFI_IMAGE_MACHINE_IA32) {\r
678 PeHdrSizeOfImage = (UINT32 *) (&(*(EFI_IMAGE_OPTIONAL_HEADER32 *) &PeHdr->OptionalHeader).SizeOfImage);\r
679 PeHdrChecksum = (UINT32 *) (&(*(EFI_IMAGE_OPTIONAL_HEADER32 *) &PeHdr->OptionalHeader).CheckSum);\r
680 } else if (PeHdr->FileHeader.Machine == EFI_IMAGE_MACHINE_IA64) {\r
681 PeHdrSizeOfImage = (UINT32 *) (&(*(EFI_IMAGE_OPTIONAL_HEADER64 *) &PeHdr->OptionalHeader).SizeOfImage);\r
682 PeHdrChecksum = (UINT32 *) (&(*(EFI_IMAGE_OPTIONAL_HEADER64 *) &PeHdr->OptionalHeader).CheckSum);\r
683 } else if (PeHdr->FileHeader.Machine == EFI_IMAGE_MACHINE_X64) {\r
684 PeHdrSizeOfImage = (UINT32 *) (&(*(EFI_IMAGE_OPTIONAL_HEADER64 *) &PeHdr->OptionalHeader).SizeOfImage);\r
685 PeHdrChecksum = (UINT32 *) (&(*(EFI_IMAGE_OPTIONAL_HEADER64 *) &PeHdr->OptionalHeader).CheckSum);\r
686 } else {\r
687 Error (\r
688 NULL,\r
689 0,\r
690 0,\r
691 "unknown machine type in PE32 image",\r
692 "machine type=0x%X, file=%s",\r
693 (UINT32) PeHdr->FileHeader.Machine,\r
694 FileGuidString\r
695 );\r
696 free ((VOID *) MemoryImagePointer);\r
697 return EFI_ABORTED;\r
698 }\r
699\r
700 if (*PeHdrSizeOfImage != ImageContext.ImageSize) {\r
701 *PeHdrSizeOfImage = (UINT32) ImageContext.ImageSize;\r
702 if (*PeHdrChecksum) {\r
703 *PeHdrChecksum = 0;\r
704 }\r
705 }\r
706\r
707 memcpy (CurrentPe32Section.Pe32Section + 1, (VOID *) MemoryImagePointerAligned, (UINT32) ImageSize);\r
708\r
396974d6 709 //\r
710 // If a map file was selected output mapping information for any file that\r
711 // was rebased.\r
712 //\r
713 if (MapFile != NULL) {\r
714 fprintf (MapFile, "PE32 File: %s Base:%08lx", FileGuidString, BaseAddress);\r
715 if (ImageContext.PdbPointer != NULL) {\r
716 fprintf (MapFile, " FileName: %s", ImageContext.PdbPointer);\r
717 }\r
718 fprintf (MapFile, "\n");\r
719 }\r
720\r
d25c4bf0 721 free ((VOID *) MemoryImagePointer);\r
722\r
723 //\r
724 // Now update file checksum\r
725 //\r
726 if (FfsFile->Attributes & FFS_ATTRIB_TAIL_PRESENT) {\r
727 TailSize = sizeof (EFI_FFS_FILE_TAIL);\r
728 } else {\r
729 TailSize = 0;\r
730 }\r
731\r
732 if (FfsFile->Attributes & FFS_ATTRIB_CHECKSUM) {\r
733 SavedState = FfsFile->State;\r
734 FfsFile->IntegrityCheck.Checksum.File = 0;\r
735 FfsFile->State = 0;\r
736 if (FfsFile->Attributes & FFS_ATTRIB_CHECKSUM) {\r
737 FfsFile->IntegrityCheck.Checksum.File = CalculateChecksum8 (\r
738 (UINT8 *) FfsFile,\r
739 GetLength (FfsFile->Size) - TailSize\r
740 );\r
741 } else {\r
742 FfsFile->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;\r
743 }\r
744\r
745 FfsFile->State = SavedState;\r
746 }\r
747 //\r
748 // Update tail if present\r
749 //\r
750 if (FfsFile->Attributes & FFS_ATTRIB_TAIL_PRESENT) {\r
751 TailValue = (EFI_FFS_FILE_TAIL) (~(FfsFile->IntegrityCheck.TailReference));\r
752 *(EFI_FFS_FILE_TAIL *) (((UINTN) FfsFile + GetLength (FfsFile->Size) - sizeof (EFI_FFS_FILE_TAIL))) = TailValue;\r
753 }\r
754 }\r
755 //\r
756 // Now process TE sections\r
757 //\r
758 for (Index = 1;; Index++) {\r
759 Status = GetSectionByType (FfsFile, EFI_SECTION_TE, Index, &CurrentPe32Section);\r
760 if (EFI_ERROR (Status)) {\r
761 break;\r
762 }\r
763\r
764 FoundCount++;\r
765\r
766 //\r
767 // Calculate the TE base address, the FFS file base plus the offset of the TE section less the size stripped off\r
768 // by GenTEImage\r
769 //\r
770 TEImageHeader = (EFI_TE_IMAGE_HEADER *) ((UINT8 *) CurrentPe32Section.Pe32Section + sizeof (EFI_COMMON_SECTION_HEADER));\r
771\r
772 NewPe32BaseAddress = ((UINT32) BaseAddress) +\r
773 (\r
774 (UINTN) CurrentPe32Section.Pe32Section +\r
775 sizeof (EFI_COMMON_SECTION_HEADER) +\r
776 sizeof (EFI_TE_IMAGE_HEADER) -\r
777 TEImageHeader->StrippedSize -\r
778 (UINTN) FfsFile\r
779 );\r
780\r
781 //\r
782 // Allocate a buffer to unshrink the image into.\r
783 //\r
784 Pe32ImageSize = GetLength (CurrentPe32Section.Pe32Section->CommonHeader.Size) - sizeof (EFI_PE32_SECTION) -\r
785 sizeof (EFI_TE_IMAGE_HEADER);\r
786 Pe32ImageSize += TEImageHeader->StrippedSize;\r
787 TEBuffer = (UINT8 *) malloc (Pe32ImageSize);\r
788 if (TEBuffer == NULL) {\r
789 Error (NULL, 0, 0, "failed to allocate memory", NULL);\r
790 return EFI_OUT_OF_RESOURCES;\r
791 }\r
792 //\r
793 // Expand the image into our buffer and fill in critical fields in the DOS header\r
794 // Fill in fields required by the loader.\r
795 // At offset 0x3C is the offset to the PE signature. We'll put it immediately following the offset value\r
796 // itself.\r
797 //\r
798 memset (TEBuffer, 0, Pe32ImageSize);\r
799 DosHeader = (EFI_IMAGE_DOS_HEADER *) TEBuffer;\r
800 DosHeader->e_magic = EFI_IMAGE_DOS_SIGNATURE;\r
801 *(UINT32 *) (TEBuffer + 0x3C) = 0x40;\r
802 PeHdr = (EFI_IMAGE_NT_HEADERS *) (TEBuffer + 0x40);\r
803 PeHdr->Signature = EFI_IMAGE_NT_SIGNATURE;\r
804 PeHdr->FileHeader.Machine = TEImageHeader->Machine;\r
805 PeHdr->FileHeader.NumberOfSections = TEImageHeader->NumberOfSections;\r
806\r
807 //\r
808 // 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
809 // the 0x40 bytes for our DOS header.\r
810 //\r
811 PeHdr->FileHeader.SizeOfOptionalHeader = (UINT16) (TEImageHeader->StrippedSize - 0x40 - sizeof (UINT32) - sizeof (EFI_IMAGE_FILE_HEADER));\r
812 PeHdr->OptionalHeader.ImageBase = (UINTN) (TEImageHeader->ImageBase - TEImageHeader->StrippedSize + sizeof (EFI_TE_IMAGE_HEADER));\r
813 PeHdr->OptionalHeader.SizeOfImage = Pe32ImageSize;\r
814 PeHdr->OptionalHeader.Subsystem = TEImageHeader->Subsystem;\r
815 PeHdr->OptionalHeader.SizeOfImage = Pe32ImageSize;\r
816 PeHdr->OptionalHeader.SizeOfHeaders = TEImageHeader->StrippedSize + TEImageHeader->NumberOfSections *\r
817 sizeof (EFI_IMAGE_SECTION_HEADER) - 12;\r
818\r
819 //\r
820 // Set NumberOfRvaAndSizes in the optional header to what we had available in the original image\r
821 //\r
822 if ((TEImageHeader->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress != 0) ||\r
823 (TEImageHeader->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size != 0)\r
824 ) {\r
825 PeHdr->OptionalHeader.NumberOfRvaAndSizes = EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC + 1;\r
826 PeHdr->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = TEImageHeader->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress;\r
827 PeHdr->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = TEImageHeader->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size;\r
828 }\r
829\r
830 if ((TEImageHeader->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress != 0) ||\r
831 (TEImageHeader->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].Size != 0)\r
832 ) {\r
833 PeHdr->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress = TEImageHeader->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress;\r
834 PeHdr->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].Size = TEImageHeader->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].Size;\r
835 if (PeHdr->OptionalHeader.NumberOfRvaAndSizes < EFI_IMAGE_DIRECTORY_ENTRY_DEBUG + 1) {\r
836 PeHdr->OptionalHeader.NumberOfRvaAndSizes = EFI_IMAGE_DIRECTORY_ENTRY_DEBUG + 1;\r
837 }\r
838 }\r
839 //\r
840 // NOTE: These values are defaults, and should be verified to be correct in the GenTE utility\r
841 //\r
842 PeHdr->OptionalHeader.SectionAlignment = 0x10;\r
843\r
844 //\r
845 // Copy the rest of the image to its original offset\r
846 //\r
847 memcpy (\r
848 TEBuffer + TEImageHeader->StrippedSize,\r
849 (UINT8 *) CurrentPe32Section.Pe32Section + sizeof (EFI_PE32_SECTION) + sizeof (EFI_TE_IMAGE_HEADER),\r
850 GetLength (CurrentPe32Section.Pe32Section->CommonHeader.Size) - sizeof (EFI_PE32_SECTION) -\r
851 sizeof (EFI_TE_IMAGE_HEADER)\r
852 );\r
853\r
854 //\r
855 // Initialize context\r
856 //\r
857 memset (&ImageContext, 0, sizeof (ImageContext));\r
858 ImageContext.Handle = (VOID *) TEBuffer;\r
4df60ea5 859 ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) FfsRebaseImageRead;\r
d25c4bf0 860\r
4df60ea5 861 Status = PeCoffLoaderGetImageInfo (&ImageContext);\r
d25c4bf0 862\r
863 if (EFI_ERROR (Status)) {\r
864 Error (NULL, 0, 0, "GetImageInfo() call failed on rebase of TE image", FileGuidString);\r
865 free (TEBuffer);\r
866 return Status;\r
867 }\r
868 //\r
869 // Allocate a buffer for the image to be loaded into.\r
870 //\r
871 MemoryImagePointer = (UINTN) (malloc (Pe32ImageSize + 0x1000));\r
872 if (MemoryImagePointer == 0) {\r
873 Error (NULL, 0, 0, "memory allocation error on rebase of TE image", FileGuidString);\r
874 free (TEBuffer);\r
875 return EFI_OUT_OF_RESOURCES;\r
876 }\r
877 memset ((void *) MemoryImagePointer, 0, Pe32ImageSize + 0x1000);\r
878 MemoryImagePointerAligned = (MemoryImagePointer + 0x0FFF) & (-1 << 12);\r
879 \r
880\r
881 ImageContext.ImageAddress = MemoryImagePointerAligned;\r
4df60ea5 882 Status = PeCoffLoaderLoadImage (&ImageContext);\r
d25c4bf0 883 if (EFI_ERROR (Status)) {\r
884 Error (NULL, 0, 0, "LoadImage() call failed on rebase of TE image", FileGuidString);\r
885 free (TEBuffer);\r
886 free ((VOID *) MemoryImagePointer);\r
887 return Status;\r
888 }\r
889\r
890 ImageContext.DestinationAddress = NewPe32BaseAddress;\r
4df60ea5 891 Status = PeCoffLoaderRelocateImage (&ImageContext);\r
d25c4bf0 892 if (EFI_ERROR (Status)) {\r
893 Error (NULL, 0, 0, "RelocateImage() call failed on rebase of TE image", FileGuidString);\r
894 free ((VOID *) MemoryImagePointer);\r
895 free (TEBuffer);\r
896 return Status;\r
897 }\r
898\r
899 ImageAddress = ImageContext.ImageAddress;\r
900 ImageSize = ImageContext.ImageSize;\r
901 EntryPoint = ImageContext.EntryPoint;\r
902\r
903 //\r
904 // Since we may have updated the Codeview RVA, we need to insure the PE\r
905 // header indicates the image is large enough to contain the Codeview data\r
906 // so it will be loaded properly later if the PEIM is reloaded into memory...\r
907 //\r
908 PeHdr = (VOID *) ((UINTN) ImageAddress + ImageContext.PeCoffHeaderOffset);\r
909 if (PeHdr->FileHeader.Machine == EFI_IMAGE_MACHINE_IA32) {\r
910 PeHdrSizeOfImage = (UINT32 *) (&(*(EFI_IMAGE_OPTIONAL_HEADER32 *) &PeHdr->OptionalHeader).SizeOfImage);\r
911 PeHdrChecksum = (UINT32 *) (&(*(EFI_IMAGE_OPTIONAL_HEADER32 *) &PeHdr->OptionalHeader).CheckSum);\r
912 } else if (PeHdr->FileHeader.Machine == EFI_IMAGE_MACHINE_IA64) {\r
913 PeHdrSizeOfImage = (UINT32 *) (&(*(EFI_IMAGE_OPTIONAL_HEADER64 *) &PeHdr->OptionalHeader).SizeOfImage);\r
914 PeHdrChecksum = (UINT32 *) (&(*(EFI_IMAGE_OPTIONAL_HEADER64 *) &PeHdr->OptionalHeader).CheckSum);\r
915 } else {\r
916 Error (\r
917 NULL,\r
918 0,\r
919 0,\r
920 "unknown machine type in TE image",\r
921 "machine type=0x%X, file=%s",\r
922 (UINT32) PeHdr->FileHeader.Machine,\r
923 FileGuidString\r
924 );\r
925 free ((VOID *) MemoryImagePointer);\r
926 free (TEBuffer);\r
927 return EFI_ABORTED;\r
928 }\r
929\r
930 if (*PeHdrSizeOfImage != ImageContext.ImageSize) {\r
931 *PeHdrSizeOfImage = (UINT32) ImageContext.ImageSize;\r
932 if (*PeHdrChecksum) {\r
933 *PeHdrChecksum = 0;\r
934 }\r
935 }\r
936\r
937 TEImageHeader->ImageBase = (UINT64) (NewPe32BaseAddress + TEImageHeader->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER));\r
938 memcpy (\r
939 (UINT8 *) (CurrentPe32Section.Pe32Section + 1) + sizeof (EFI_TE_IMAGE_HEADER),\r
940 (VOID *) ((UINT8 *) MemoryImagePointerAligned + TEImageHeader->StrippedSize),\r
941 GetLength (CurrentPe32Section.Pe32Section->CommonHeader.Size) - sizeof (EFI_PE32_SECTION) -\r
942 sizeof (EFI_TE_IMAGE_HEADER)\r
943 );\r
396974d6 944\r
945 //\r
946 // If a map file was selected output mapping information for any file that\r
947 // was rebased.\r
948 //\r
949 if (MapFile != NULL) {\r
950 fprintf (MapFile, "TE File: %s Base:%08lx", FileGuidString, BaseAddress);\r
951 if (ImageContext.PdbPointer != NULL) {\r
952 fprintf (MapFile, " FileName: %s", ImageContext.PdbPointer);\r
953 }\r
954 fprintf (MapFile, "\n");\r
955 }\r
956\r
d25c4bf0 957 free ((VOID *) MemoryImagePointer);\r
958 free (TEBuffer);\r
959 if (FfsFile->Attributes & FFS_ATTRIB_TAIL_PRESENT) {\r
960 TailSize = sizeof (EFI_FFS_FILE_TAIL);\r
961 } else {\r
962 TailSize = 0;\r
963 }\r
964 //\r
965 // Now update file checksum\r
966 //\r
967 if (FfsFile->Attributes & FFS_ATTRIB_CHECKSUM) {\r
968 SavedState = FfsFile->State;\r
969 FfsFile->IntegrityCheck.Checksum.File = 0;\r
970 FfsFile->State = 0;\r
971 if (FfsFile->Attributes & FFS_ATTRIB_CHECKSUM) {\r
972 FfsFile->IntegrityCheck.Checksum.File = CalculateChecksum8 (\r
973 (UINT8 *) FfsFile,\r
974 GetLength (FfsFile->Size) - TailSize\r
975 );\r
976 } else {\r
977 FfsFile->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;\r
978 }\r
979\r
980 FfsFile->State = SavedState;\r
981 }\r
982 //\r
983 // Update tail if present\r
984 //\r
985 if (FfsFile->Attributes & FFS_ATTRIB_TAIL_PRESENT) {\r
986 TailValue = (EFI_FFS_FILE_TAIL) (~(FfsFile->IntegrityCheck.TailReference));\r
987 *(EFI_FFS_FILE_TAIL *) (((UINTN) FfsFile + GetLength (FfsFile->Size) - sizeof (EFI_FFS_FILE_TAIL))) = TailValue;\r
988 }\r
989 }\r
990 //\r
991 // If we found no files, then emit an error if no compressed sections either\r
992 //\r
993 if (FoundCount == 0) {\r
994 Status = GetSectionByType (FfsFile, EFI_SECTION_COMPRESSION, Index, &CurrentPe32Section);\r
995 if (EFI_ERROR (Status)) {\r
996 Error (NULL, 0, 0, "no PE32, TE, nor compressed section found in FV file", FileGuidString);\r
997 return EFI_NOT_FOUND;\r
998 }\r
999 }\r
5049fd31 1000 \r
d25c4bf0 1001 return EFI_SUCCESS;\r
1002}\r
1003\r
1004EFI_STATUS\r
1005FfsRebaseImageRead (\r
1006 IN VOID *FileHandle,\r
1007 IN UINTN FileOffset,\r
1008 IN OUT UINT32 *ReadSize,\r
1009 OUT VOID *Buffer\r
1010 )\r
1011/*++\r
1012\r
1013Routine Description:\r
1014\r
1015 Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file\r
1016\r
1017Arguments:\r
1018\r
1019 FileHandle - The handle to the PE/COFF file\r
1020\r
1021 FileOffset - The offset, in bytes, into the file to read\r
1022\r
1023 ReadSize - The number of bytes to read from the file starting at FileOffset\r
1024\r
1025 Buffer - A pointer to the buffer to read the data into.\r
1026\r
1027Returns:\r
1028\r
1029 EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset\r
1030\r
1031--*/\r
1032{\r
1033 CHAR8 *Destination8;\r
1034 CHAR8 *Source8;\r
1035 UINT32 Length;\r
1036\r
1037 Destination8 = Buffer;\r
1038 Source8 = (CHAR8 *) ((UINTN) FileHandle + FileOffset);\r
1039 Length = *ReadSize;\r
1040 while (Length--) {\r
1041 *(Destination8++) = *(Source8++);\r
1042 }\r
1043\r
1044 return EFI_SUCCESS;\r
1045}\r