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