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