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