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