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