Sync basetools' source and binary files with r1707 of the basetools project.
[edk2.git] / BaseTools / Source / C / GenFv / GenFvInternalLib.c
blob917baa11e83d775d115c96235e869a8f34939166
1 /** @file
3 Copyright (c) 2004 - 2009, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12 Module Name:
14 GenFvInternalLib.c
16 Abstract:
18 This file contains the internal functions required to generate a Firmware Volume.
20 **/
23 // Include files
25 #ifdef __GNUC__
26 #include <uuid/uuid.h>
27 #include <sys/stat.h>
28 #endif
29 #include <string.h>
30 #ifndef __GNUC__
31 #include <io.h>
32 #endif
33 #include <assert.h>
35 #include "GenFvInternalLib.h"
36 #include "FvLib.h"
37 #include "PeCoffLib.h"
38 #include "WinNtInclude.h"
40 BOOLEAN mArm = FALSE;
41 STATIC UINT32 MaxFfsAlignment = 0;
43 EFI_GUID mEfiFirmwareVolumeTopFileGuid = EFI_FFS_VOLUME_TOP_FILE_GUID;
44 EFI_GUID mFileGuidArray [MAX_NUMBER_OF_FILES_IN_FV];
45 EFI_GUID mZeroGuid = {0x0, 0x0, 0x0, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}};
46 EFI_GUID mDefaultCapsuleGuid = {0x3B6686BD, 0x0D76, 0x4030, { 0xB7, 0x0E, 0xB5, 0x51, 0x9E, 0x2F, 0xC5, 0xA0 }};
48 CHAR8 *mFvbAttributeName[] = {
49 EFI_FVB2_READ_DISABLED_CAP_STRING,
50 EFI_FVB2_READ_ENABLED_CAP_STRING,
51 EFI_FVB2_READ_STATUS_STRING,
52 EFI_FVB2_WRITE_DISABLED_CAP_STRING,
53 EFI_FVB2_WRITE_ENABLED_CAP_STRING,
54 EFI_FVB2_WRITE_STATUS_STRING,
55 EFI_FVB2_LOCK_CAP_STRING,
56 EFI_FVB2_LOCK_STATUS_STRING,
57 NULL,
58 EFI_FVB2_STICKY_WRITE_STRING,
59 EFI_FVB2_MEMORY_MAPPED_STRING,
60 EFI_FVB2_ERASE_POLARITY_STRING,
61 EFI_FVB2_READ_LOCK_CAP_STRING,
62 EFI_FVB2_READ_LOCK_STATUS_STRING,
63 EFI_FVB2_WRITE_LOCK_CAP_STRING,
64 EFI_FVB2_WRITE_LOCK_STATUS_STRING
67 CHAR8 *mFvbAlignmentName[] = {
68 EFI_FVB2_ALIGNMENT_1_STRING,
69 EFI_FVB2_ALIGNMENT_2_STRING,
70 EFI_FVB2_ALIGNMENT_4_STRING,
71 EFI_FVB2_ALIGNMENT_8_STRING,
72 EFI_FVB2_ALIGNMENT_16_STRING,
73 EFI_FVB2_ALIGNMENT_32_STRING,
74 EFI_FVB2_ALIGNMENT_64_STRING,
75 EFI_FVB2_ALIGNMENT_128_STRING,
76 EFI_FVB2_ALIGNMENT_256_STRING,
77 EFI_FVB2_ALIGNMENT_512_STRING,
78 EFI_FVB2_ALIGNMENT_1K_STRING,
79 EFI_FVB2_ALIGNMENT_2K_STRING,
80 EFI_FVB2_ALIGNMENT_4K_STRING,
81 EFI_FVB2_ALIGNMENT_8K_STRING,
82 EFI_FVB2_ALIGNMENT_16K_STRING,
83 EFI_FVB2_ALIGNMENT_32K_STRING,
84 EFI_FVB2_ALIGNMENT_64K_STRING,
85 EFI_FVB2_ALIGNMENT_128K_STRING,
86 EFI_FVB2_ALIGNMENT_256K_STRING,
87 EFI_FVB2_ALIGNMNET_512K_STRING,
88 EFI_FVB2_ALIGNMENT_1M_STRING,
89 EFI_FVB2_ALIGNMENT_2M_STRING,
90 EFI_FVB2_ALIGNMENT_4M_STRING,
91 EFI_FVB2_ALIGNMENT_8M_STRING,
92 EFI_FVB2_ALIGNMENT_16M_STRING,
93 EFI_FVB2_ALIGNMENT_32M_STRING,
94 EFI_FVB2_ALIGNMENT_64M_STRING,
95 EFI_FVB2_ALIGNMENT_128M_STRING,
96 EFI_FVB2_ALIGNMENT_256M_STRING,
97 EFI_FVB2_ALIGNMENT_512M_STRING,
98 EFI_FVB2_ALIGNMENT_1G_STRING,
99 EFI_FVB2_ALIGNMENT_2G_STRING
103 // This data array will be located at the base of the Firmware Volume Header (FVH)
104 // in the boot block. It must not exceed 14 bytes of code. The last 2 bytes
105 // will be used to keep the FVH checksum consistent.
106 // This code will be run in response to a starutp IPI for HT-enabled systems.
108 #define SIZEOF_STARTUP_DATA_ARRAY 0x10
110 UINT8 m128kRecoveryStartupApDataArray[SIZEOF_STARTUP_DATA_ARRAY] = {
112 // EA D0 FF 00 F0 ; far jmp F000:FFD0
113 // 0, 0, 0, 0, 0, 0, 0, 0, 0, ; Reserved bytes
114 // 0, 0 ; Checksum Padding
116 0xEA,
117 0xD0,
118 0xFF,
119 0x0,
120 0xF0,
121 0x00,
122 0x00,
123 0x00,
124 0x00,
125 0x00,
126 0x00,
127 0x00,
128 0x00,
129 0x00,
130 0x00,
131 0x00
134 UINT8 m64kRecoveryStartupApDataArray[SIZEOF_STARTUP_DATA_ARRAY] = {
136 // EB CE ; jmp short ($-0x30)
137 // ; (from offset 0x0 to offset 0xFFD0)
138 // 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ; Reserved bytes
139 // 0, 0 ; Checksum Padding
141 0xEB,
142 0xCE,
143 0x00,
144 0x00,
145 0x00,
146 0x00,
147 0x00,
148 0x00,
149 0x00,
150 0x00,
151 0x00,
152 0x00,
153 0x00,
154 0x00,
155 0x00,
156 0x00
159 FV_INFO mFvDataInfo;
160 CAP_INFO mCapDataInfo;
162 EFI_STATUS
163 ParseFvInf (
164 IN MEMORY_FILE *InfFile,
165 OUT FV_INFO *FvInfo
167 /*++
169 Routine Description:
171 This function parses a FV.INF file and copies info into a FV_INFO structure.
173 Arguments:
175 InfFile Memory file image.
176 FvInfo Information read from INF file.
178 Returns:
180 EFI_SUCCESS INF file information successfully retrieved.
181 EFI_ABORTED INF file has an invalid format.
182 EFI_NOT_FOUND A required string was not found in the INF file.
183 --*/
185 CHAR8 Value[_MAX_PATH];
186 UINT64 Value64;
187 UINTN Index;
188 UINTN Number;
189 EFI_STATUS Status;
190 EFI_GUID GuidValue;
193 // Read the FV base address
195 if (!mFvDataInfo.BaseAddressSet) {
196 Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_FV_BASE_ADDRESS_STRING, 0, Value);
197 if (Status == EFI_SUCCESS) {
199 // Get the base address
201 Status = AsciiStringToUint64 (Value, FALSE, &Value64);
202 if (EFI_ERROR (Status)) {
203 Error (NULL, 0, 2000, "Invalid parameter", "%s = %s", EFI_FV_BASE_ADDRESS_STRING, Value);
204 return EFI_ABORTED;
206 DebugMsg (NULL, 0, 9, "rebase address", "%s = %s", EFI_FV_BASE_ADDRESS_STRING, Value);
208 FvInfo->BaseAddress = Value64;
213 // Read the FV File System Guid
215 if (!FvInfo->FvFileSystemGuidSet) {
216 Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_FV_FILESYSTEMGUID_STRING, 0, Value);
217 if (Status == EFI_SUCCESS) {
219 // Get the guid value
221 Status = StringToGuid (Value, &GuidValue);
222 if (EFI_ERROR (Status)) {
223 Error (NULL, 0, 2000, "Invalid parameter", "%s = %s", EFI_FV_FILESYSTEMGUID_STRING, Value);
224 return EFI_ABORTED;
226 memcpy (&FvInfo->FvFileSystemGuid, &GuidValue, sizeof (EFI_GUID));
227 FvInfo->FvFileSystemGuidSet = TRUE;
232 // Read the FV Name Guid
234 if (!FvInfo->FvNameGuidSet) {
235 Status = FindToken (InfFile, ATTRIBUTES_SECTION_STRING, EFI_FV_NAMEGUID_STRING, 0, Value);
236 if (Status == EFI_SUCCESS) {
238 // Get the guid value
240 Status = StringToGuid (Value, &GuidValue);
241 if (EFI_ERROR (Status)) {
242 Error (NULL, 0, 2000, "Invalid parameter", "%s = %s", EFI_FV_NAMEGUID_STRING, Value);
243 return EFI_ABORTED;
245 memcpy (&FvInfo->FvNameGuid, &GuidValue, sizeof (EFI_GUID));
246 FvInfo->FvNameGuidSet = TRUE;
251 // Read the FV file name
253 Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_FV_FILE_NAME_STRING, 0, Value);
254 if (Status == EFI_SUCCESS) {
256 // copy the file name
258 strcpy (FvInfo->FvName, Value);
262 // Read Fv Attribute
264 for (Index = 0; Index < sizeof (mFvbAttributeName)/sizeof (CHAR8 *); Index ++) {
265 if ((mFvbAttributeName [Index] != NULL) && \
266 (FindToken (InfFile, ATTRIBUTES_SECTION_STRING, mFvbAttributeName [Index], 0, Value) == EFI_SUCCESS)) {
267 if ((strcmp (Value, TRUE_STRING) == 0) || (strcmp (Value, ONE_STRING) == 0)) {
268 FvInfo->FvAttributes |= 1 << Index;
269 } else if ((strcmp (Value, FALSE_STRING) != 0) && (strcmp (Value, ZERO_STRING) != 0)) {
270 Error (NULL, 0, 2000, "Invalid parameter", "%s expected %s | %s", mFvbAttributeName [Index], TRUE_STRING, FALSE_STRING);
271 return EFI_ABORTED;
277 // Read Fv Alignment
279 for (Index = 0; Index < sizeof (mFvbAlignmentName)/sizeof (CHAR8 *); Index ++) {
280 if (FindToken (InfFile, ATTRIBUTES_SECTION_STRING, mFvbAlignmentName [Index], 0, Value) == EFI_SUCCESS) {
281 if (strcmp (Value, TRUE_STRING) == 0) {
282 FvInfo->FvAttributes |= Index << 16;
283 DebugMsg (NULL, 0, 9, "FV file alignment", "Align = %s", mFvbAlignmentName [Index]);
284 break;
290 // Read block maps
292 for (Index = 0; Index < MAX_NUMBER_OF_FV_BLOCKS; Index++) {
293 if (FvInfo->FvBlocks[Index].Length == 0) {
295 // Read block size
297 Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_BLOCK_SIZE_STRING, Index, Value);
299 if (Status == EFI_SUCCESS) {
301 // Update the size of block
303 Status = AsciiStringToUint64 (Value, FALSE, &Value64);
304 if (EFI_ERROR (Status)) {
305 Error (NULL, 0, 2000, "Invalid parameter", "%s = %s", EFI_BLOCK_SIZE_STRING, Value);
306 return EFI_ABORTED;
309 FvInfo->FvBlocks[Index].Length = (UINT32) Value64;
310 DebugMsg (NULL, 0, 9, "FV Block Size", "%s = %s", EFI_BLOCK_SIZE_STRING, Value);
311 } else {
313 // If there is no blocks size, but there is the number of block, then we have a mismatched pair
314 // and should return an error.
316 Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_NUM_BLOCKS_STRING, Index, Value);
317 if (!EFI_ERROR (Status)) {
318 Error (NULL, 0, 2000, "Invalid parameter", "both %s and %s must be specified.", EFI_NUM_BLOCKS_STRING, EFI_BLOCK_SIZE_STRING);
319 return EFI_ABORTED;
320 } else {
322 // We are done
324 break;
329 // Read blocks number
331 Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_NUM_BLOCKS_STRING, Index, Value);
333 if (Status == EFI_SUCCESS) {
335 // Update the number of blocks
337 Status = AsciiStringToUint64 (Value, FALSE, &Value64);
338 if (EFI_ERROR (Status)) {
339 Error (NULL, 0, 2000, "Invalid parameter", "%s = %s", EFI_NUM_BLOCKS_STRING, Value);
340 return EFI_ABORTED;
343 FvInfo->FvBlocks[Index].NumBlocks = (UINT32) Value64;
344 DebugMsg (NULL, 0, 9, "FV Block Number", "%s = %s", EFI_NUM_BLOCKS_STRING, Value);
349 if (Index == 0) {
350 Error (NULL, 0, 2001, "Missing required argument", "block size.");
351 return EFI_ABORTED;
355 // Read files
357 Number = 0;
358 for (Number = 0; Number < MAX_NUMBER_OF_FILES_IN_FV; Number ++) {
359 if (FvInfo->FvFiles[Number][0] == '\0') {
360 break;
364 for (Index = 0; Index < MAX_NUMBER_OF_FILES_IN_FV; Index++) {
366 // Read the FFS file list
368 Status = FindToken (InfFile, FILES_SECTION_STRING, EFI_FILE_NAME_STRING, Index, Value);
370 if (Status == EFI_SUCCESS) {
372 // Add the file
374 strcpy (FvInfo->FvFiles[Number + Index], Value);
375 DebugMsg (NULL, 0, 9, "FV component file", "the %uth name is %s", (unsigned) Index, Value);
376 } else {
377 break;
381 if ((Index + Number) == 0) {
382 Warning (NULL, 0, 0, "FV components are not specified.", NULL);
385 return EFI_SUCCESS;
388 VOID
389 UpdateFfsFileState (
390 IN EFI_FFS_FILE_HEADER *FfsFile,
391 IN EFI_FIRMWARE_VOLUME_HEADER *FvHeader
393 /*++
395 Routine Description:
397 This function changes the FFS file attributes based on the erase polarity
398 of the FV. Update the reserved bits of State to EFI_FVB2_ERASE_POLARITY.
400 Arguments:
402 FfsFile File header.
403 FvHeader FV header.
405 Returns:
407 None
409 --*/
411 if (FvHeader->Attributes & EFI_FVB2_ERASE_POLARITY) {
412 FfsFile->State = (UINT8)~(FfsFile->State);
413 // FfsFile->State |= ~(UINT8) EFI_FILE_ALL_STATE_BITS;
417 EFI_STATUS
418 ReadFfsAlignment (
419 IN EFI_FFS_FILE_HEADER *FfsFile,
420 IN OUT UINT32 *Alignment
422 /*++
424 Routine Description:
426 This function determines the alignment of the FFS input file from the file
427 attributes.
429 Arguments:
431 FfsFile FFS file to parse
432 Alignment The minimum required alignment offset of the FFS file
434 Returns:
436 EFI_SUCCESS The function completed successfully.
437 EFI_INVALID_PARAMETER One of the input parameters was invalid.
438 EFI_ABORTED An error occurred.
440 --*/
443 // Verify input parameters.
445 if (FfsFile == NULL || Alignment == NULL) {
446 return EFI_INVALID_PARAMETER;
449 switch ((FfsFile->Attributes >> 3) & 0x07) {
451 case 0:
453 // 8 byte alignment, mini alignment requirement for FFS file.
455 *Alignment = 3;
456 break;
458 case 1:
460 // 16 byte alignment
462 *Alignment = 4;
463 break;
465 case 2:
467 // 128 byte alignment
469 *Alignment = 7;
470 break;
472 case 3:
474 // 512 byte alignment
476 *Alignment = 9;
477 break;
479 case 4:
481 // 1K byte alignment
483 *Alignment = 10;
484 break;
486 case 5:
488 // 4K byte alignment
490 *Alignment = 12;
491 break;
493 case 6:
495 // 32K byte alignment
497 *Alignment = 15;
498 break;
500 case 7:
502 // 64K byte alignment
504 *Alignment = 16;
505 break;
507 default:
508 break;
511 return EFI_SUCCESS;
514 EFI_STATUS
515 AddPadFile (
516 IN OUT MEMORY_FILE *FvImage,
517 IN UINT32 DataAlignment,
518 IN VOID *FvEnd,
519 IN EFI_FIRMWARE_VOLUME_EXT_HEADER *ExtHeader
521 /*++
523 Routine Description:
525 This function adds a pad file to the FV image if it required to align the
526 data of the next file.
528 Arguments:
530 FvImage The memory image of the FV to add it to.
531 The current offset must be valid.
532 DataAlignment The data alignment of the next FFS file.
533 FvEnd End of the empty data in FvImage.
534 ExtHeader PI FvExtHeader Optional
536 Returns:
538 EFI_SUCCESS The function completed successfully.
539 EFI_INVALID_PARAMETER One of the input parameters was invalid.
540 EFI_OUT_OF_RESOURCES Insufficient resources exist in the FV to complete
541 the pad file add.
543 --*/
545 EFI_FFS_FILE_HEADER *PadFile;
546 UINTN PadFileSize;
549 // Verify input parameters.
551 if (FvImage == NULL) {
552 return EFI_INVALID_PARAMETER;
556 // Check if a pad file is necessary
558 if ((ExtHeader == NULL) && (((UINTN) FvImage->CurrentFilePointer - (UINTN) FvImage->FileImage + sizeof (EFI_FFS_FILE_HEADER)) % DataAlignment == 0)) {
559 return EFI_SUCCESS;
563 // Calculate the pad file size
566 // This is the earliest possible valid offset (current plus pad file header
567 // plus the next file header)
569 PadFileSize = (UINTN) FvImage->CurrentFilePointer - (UINTN) FvImage->FileImage + (sizeof (EFI_FFS_FILE_HEADER) * 2);
572 // Add whatever it takes to get to the next aligned address
574 while ((PadFileSize % DataAlignment) != 0) {
575 PadFileSize++;
578 // Subtract the next file header size
580 PadFileSize -= sizeof (EFI_FFS_FILE_HEADER);
583 // Subtract the starting offset to get size
585 PadFileSize -= (UINTN) FvImage->CurrentFilePointer - (UINTN) FvImage->FileImage;
588 // Append extension header size
590 if (ExtHeader != NULL) {
591 PadFileSize = PadFileSize + ExtHeader->ExtHeaderSize;
595 // Verify that we have enough space for the file header
597 if (((UINTN) FvImage->CurrentFilePointer + PadFileSize) > (UINTN) FvEnd) {
598 return EFI_OUT_OF_RESOURCES;
602 // Write pad file header
604 PadFile = (EFI_FFS_FILE_HEADER *) FvImage->CurrentFilePointer;
607 // Write PadFile FFS header with PadType, don't need to set PAD file guid in its header.
609 PadFile->Type = EFI_FV_FILETYPE_FFS_PAD;
610 PadFile->Attributes = 0;
613 // Write pad file size (calculated size minus next file header size)
615 PadFile->Size[0] = (UINT8) (PadFileSize & 0xFF);
616 PadFile->Size[1] = (UINT8) ((PadFileSize >> 8) & 0xFF);
617 PadFile->Size[2] = (UINT8) ((PadFileSize >> 16) & 0xFF);
620 // Fill in checksums and state, they must be 0 for checksumming.
622 PadFile->IntegrityCheck.Checksum.Header = 0;
623 PadFile->IntegrityCheck.Checksum.File = 0;
624 PadFile->State = 0;
625 PadFile->IntegrityCheck.Checksum.Header = CalculateChecksum8 ((UINT8 *) PadFile, sizeof (EFI_FFS_FILE_HEADER));
626 PadFile->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;
628 PadFile->State = EFI_FILE_HEADER_CONSTRUCTION | EFI_FILE_HEADER_VALID | EFI_FILE_DATA_VALID;
629 UpdateFfsFileState (
630 (EFI_FFS_FILE_HEADER *) PadFile,
631 (EFI_FIRMWARE_VOLUME_HEADER *) FvImage->FileImage
635 // Update the current FV pointer
637 FvImage->CurrentFilePointer += PadFileSize;
639 if (ExtHeader != NULL) {
641 // Copy Fv Extension Header and Set Fv Extension header offset
643 memcpy (PadFile + 1, ExtHeader, ExtHeader->ExtHeaderSize);
644 ((EFI_FIRMWARE_VOLUME_HEADER *) FvImage->FileImage)->ExtHeaderOffset = (UINT16) ((UINTN) (PadFile + 1) - (UINTN) FvImage->FileImage);
646 // Make next file start at QWord Boundry
648 while (((UINTN) FvImage->CurrentFilePointer & (EFI_FFS_FILE_HEADER_ALIGNMENT - 1)) != 0) {
649 FvImage->CurrentFilePointer++;
653 return EFI_SUCCESS;
656 BOOLEAN
657 IsVtfFile (
658 IN EFI_FFS_FILE_HEADER *FileBuffer
660 /*++
662 Routine Description:
664 This function checks the header to validate if it is a VTF file
666 Arguments:
668 FileBuffer Buffer in which content of a file has been read.
670 Returns:
672 TRUE If this is a VTF file
673 FALSE If this is not a VTF file
675 --*/
677 if (!memcmp (&FileBuffer->Name, &mEfiFirmwareVolumeTopFileGuid, sizeof (EFI_GUID))) {
678 return TRUE;
679 } else {
680 return FALSE;
684 EFI_STATUS
685 WriteMapFile (
686 IN OUT FILE *FvMapFile,
687 IN CHAR8 *FileName,
688 IN EFI_GUID *FileGuidPtr,
689 IN EFI_PHYSICAL_ADDRESS ImageBaseAddress,
690 IN PE_COFF_LOADER_IMAGE_CONTEXT *pImageContext
692 /*++
694 Routine Description:
696 This function gets the basic debug information (entrypoint, baseaddress, .text, .data section base address)
697 from PE/COFF image and abstracts Pe Map file information and add them into FvMap file for Debug.
699 Arguments:
701 FvMapFile A pointer to FvMap File
702 FileName Ffs File PathName
703 FileGuidPtr Guid Value of Ffs file
704 ImageBaseAddress PeImage Base Address.
705 pImageContext Image Context Information.
707 Returns:
709 EFI_SUCCESS Added required map information.
711 --*/
713 CHAR8 PeMapFileName [_MAX_PATH];
714 CHAR8 *Cptr, *Cptr2;
715 CHAR8 FileGuidName [MAX_LINE_LEN];
716 FILE *PeMapFile;
717 CHAR8 Line [MAX_LINE_LEN];
718 CHAR8 KeyWord [MAX_LINE_LEN];
719 CHAR8 FunctionName [MAX_LINE_LEN];
720 EFI_PHYSICAL_ADDRESS FunctionAddress;
721 UINT32 FunctionType;
722 CHAR8 FunctionTypeName [MAX_LINE_LEN];
723 UINT32 Index;
724 UINT32 AddressOfEntryPoint;
725 UINT32 Offset;
726 EFI_IMAGE_OPTIONAL_HEADER_UNION *ImgHdr;
727 EFI_TE_IMAGE_HEADER *TEImageHeader;
728 EFI_IMAGE_SECTION_HEADER *SectionHeader;
729 unsigned long long TempLongAddress;
731 // Init local variable
733 FunctionType = 0;
735 // Print FileGuid to string buffer.
737 PrintGuidToBuffer (FileGuidPtr, (UINT8 *)FileGuidName, MAX_LINE_LEN, TRUE);
740 // Construct Map file Name
742 strcpy (PeMapFileName, FileName);
745 // Change '\\' to '/', unified path format.
747 Cptr = PeMapFileName;
748 while (*Cptr != '\0') {
749 if (*Cptr == '\\') {
750 *Cptr = FILE_SEP_CHAR;
752 Cptr ++;
756 // Get Map file
758 Cptr = PeMapFileName + strlen (PeMapFileName);
759 while ((*Cptr != '.') && (Cptr >= PeMapFileName)) {
760 Cptr --;
762 if (Cptr < PeMapFileName) {
763 return EFI_NOT_FOUND;
764 } else {
765 *(Cptr + 1) = 'm';
766 *(Cptr + 2) = 'a';
767 *(Cptr + 3) = 'p';
768 *(Cptr + 4) = '\0';
772 // Get module Name
774 Cptr2 = Cptr;
775 while ((*Cptr != FILE_SEP_CHAR) && (Cptr >= PeMapFileName)) {
776 Cptr --;
778 *Cptr2 = '\0';
779 strcpy (KeyWord, Cptr + 1);
780 *Cptr2 = '.';
783 // AddressOfEntryPoint and Offset in Image
785 if (!pImageContext->IsTeImage) {
786 ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *) ((UINT8 *) pImageContext->Handle + pImageContext->PeCoffHeaderOffset);
787 AddressOfEntryPoint = ImgHdr->Pe32.OptionalHeader.AddressOfEntryPoint;
788 Offset = 0;
789 SectionHeader = (EFI_IMAGE_SECTION_HEADER *) (
790 (UINT8 *) ImgHdr +
791 sizeof (UINT32) +
792 sizeof (EFI_IMAGE_FILE_HEADER) +
793 ImgHdr->Pe32.FileHeader.SizeOfOptionalHeader
795 Index = ImgHdr->Pe32.FileHeader.NumberOfSections;
796 } else {
797 TEImageHeader = (EFI_TE_IMAGE_HEADER *) pImageContext->Handle;
798 AddressOfEntryPoint = TEImageHeader->AddressOfEntryPoint;
799 Offset = TEImageHeader->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER);
800 SectionHeader = (EFI_IMAGE_SECTION_HEADER *) (TEImageHeader + 1);
801 Index = TEImageHeader->NumberOfSections;
805 // module information output
807 if (ImageBaseAddress == 0) {
808 fprintf (FvMapFile, "%s (dummy) (", KeyWord);
809 fprintf (FvMapFile, "BaseAddress=%08llx, ", (unsigned long long) ImageBaseAddress);
810 } else {
811 fprintf (FvMapFile, "%s (", KeyWord);
812 fprintf (FvMapFile, "BaseAddress=%08llx, ", (unsigned long long) (ImageBaseAddress + Offset));
814 fprintf (FvMapFile, "EntryPoint=%08llx, ", (unsigned long long) (ImageBaseAddress + AddressOfEntryPoint));
815 fprintf (FvMapFile, "GUID=%s", FileGuidName);
816 fprintf (FvMapFile, ")\n");
818 for (; Index > 0; Index --, SectionHeader ++) {
819 if (stricmp ((CHAR8 *)SectionHeader->Name, ".text") == 0) {
820 fprintf (FvMapFile, ".textbaseaddress=%08llx ", (unsigned long long) (ImageBaseAddress + SectionHeader->VirtualAddress));
821 } else if (stricmp ((CHAR8 *)SectionHeader->Name, ".data") == 0) {
822 fprintf (FvMapFile, ".databaseaddress=%08llx ", (unsigned long long) (ImageBaseAddress + SectionHeader->VirtualAddress));
825 fprintf (FvMapFile, "\n\n");
828 // Open PeMapFile
830 PeMapFile = fopen (PeMapFileName, "r");
831 if (PeMapFile == NULL) {
832 // fprintf (stdout, "can't open %s file to reading\n", PeMapFileName);
833 return EFI_ABORTED;
835 VerboseMsg ("The map file is %s", PeMapFileName);
838 // Output Functions information into Fv Map file
840 while (fgets (Line, MAX_LINE_LEN, PeMapFile) != NULL) {
842 // Skip blank line
844 if (Line[0] == 0x0a) {
845 FunctionType = 0;
846 continue;
849 // By Address and Static keyword
851 if (FunctionType == 0) {
852 sscanf (Line, "%s", KeyWord);
853 if (stricmp (KeyWord, "Address") == 0) {
855 // function list
857 FunctionType = 1;
858 fgets (Line, MAX_LINE_LEN, PeMapFile);
859 } else if (stricmp (KeyWord, "Static") == 0) {
861 // static function list
863 FunctionType = 2;
864 fgets (Line, MAX_LINE_LEN, PeMapFile);
866 continue;
869 // Printf Function Information
871 if (FunctionType == 1) {
872 sscanf (Line, "%s %s %llx %s", KeyWord, FunctionName, &TempLongAddress, FunctionTypeName);
873 FunctionAddress = (UINT64) TempLongAddress;
874 if (FunctionTypeName [1] == '\0' && (FunctionTypeName [0] == 'f' || FunctionTypeName [0] == 'F')) {
875 fprintf (FvMapFile, " %016llx ", (unsigned long long) (ImageBaseAddress + FunctionAddress));
876 fprintf (FvMapFile, "(%08llx) F ", (unsigned long long) (FunctionAddress - Offset));
877 fprintf (FvMapFile, "%s\n", FunctionName);
878 } else {
879 fprintf (FvMapFile, " %016llx ", (unsigned long long) (ImageBaseAddress + FunctionAddress));
880 fprintf (FvMapFile, "(%08llx) ", (unsigned long long) (FunctionAddress - Offset));
881 fprintf (FvMapFile, "%s\n", FunctionName);
883 } else if (FunctionType == 2) {
884 sscanf (Line, "%s %s %llx %s", KeyWord, FunctionName, &TempLongAddress, FunctionTypeName);
885 FunctionAddress = (UINT64) TempLongAddress;
886 if (FunctionTypeName [1] == '\0' && (FunctionTypeName [0] == 'f' || FunctionTypeName [0] == 'F')) {
887 fprintf (FvMapFile, " %016llx ", (unsigned long long) (ImageBaseAddress + FunctionAddress));
888 fprintf (FvMapFile, "(%08llx) FS ", (unsigned long long) (FunctionAddress - Offset));
889 fprintf (FvMapFile, "%s\n", FunctionName);
890 } else {
891 fprintf (FvMapFile, " %016llx ", (unsigned long long) (ImageBaseAddress + FunctionAddress));
892 fprintf (FvMapFile, "(%08llx) ", (unsigned long long) (FunctionAddress - Offset));
893 fprintf (FvMapFile, "%s\n", FunctionName);
898 // Close PeMap file
900 fprintf (FvMapFile, "\n\n");
901 fclose (PeMapFile);
903 return EFI_SUCCESS;
906 EFI_STATUS
907 AddFile (
908 IN OUT MEMORY_FILE *FvImage,
909 IN FV_INFO *FvInfo,
910 IN UINTN Index,
911 IN OUT EFI_FFS_FILE_HEADER **VtfFileImage,
912 IN FILE *FvMapFile
914 /*++
916 Routine Description:
918 This function adds a file to the FV image. The file will pad to the
919 appropriate alignment if required.
921 Arguments:
923 FvImage The memory image of the FV to add it to. The current offset
924 must be valid.
925 FvInfo Pointer to information about the FV.
926 Index The file in the FvInfo file list to add.
927 VtfFileImage A pointer to the VTF file within the FvImage. If this is equal
928 to the end of the FvImage then no VTF previously found.
929 FvMapFile Pointer to FvMap File
931 Returns:
933 EFI_SUCCESS The function completed successfully.
934 EFI_INVALID_PARAMETER One of the input parameters was invalid.
935 EFI_ABORTED An error occurred.
936 EFI_OUT_OF_RESOURCES Insufficient resources exist to complete the add.
938 --*/
940 FILE *NewFile;
941 UINTN FileSize;
942 UINT8 *FileBuffer;
943 UINTN NumBytesRead;
944 UINT32 CurrentFileAlignment;
945 EFI_STATUS Status;
946 UINTN Index1;
948 Index1 = 0;
950 // Verify input parameters.
952 if (FvImage == NULL || FvInfo == NULL || FvInfo->FvFiles[Index][0] == 0 || VtfFileImage == NULL) {
953 return EFI_INVALID_PARAMETER;
957 // Read the file to add
959 NewFile = fopen (FvInfo->FvFiles[Index], "rb");
961 if (NewFile == NULL) {
962 Error (NULL, 0, 0001, "Error opening file", FvInfo->FvFiles[Index]);
963 return EFI_ABORTED;
967 // Get the file size
969 FileSize = _filelength (fileno (NewFile));
972 // Read the file into a buffer
974 FileBuffer = malloc (FileSize);
975 if (FileBuffer == NULL) {
976 Error (NULL, 0, 4001, "Resouce", "memory cannot be allocated!");
977 return EFI_OUT_OF_RESOURCES;
980 NumBytesRead = fread (FileBuffer, sizeof (UINT8), FileSize, NewFile);
983 // Done with the file, from this point on we will just use the buffer read.
985 fclose (NewFile);
988 // Verify read successful
990 if (NumBytesRead != sizeof (UINT8) * FileSize) {
991 free (FileBuffer);
992 Error (NULL, 0, 0004, "Error reading file", FvInfo->FvFiles[Index]);
993 return EFI_ABORTED;
997 // For None PI Ffs file, directly add them into FvImage.
999 if (!FvInfo->IsPiFvImage) {
1000 memcpy (FvImage->CurrentFilePointer, FileBuffer, FileSize);
1001 if (FvInfo->SizeofFvFiles[Index] > FileSize) {
1002 FvImage->CurrentFilePointer += FvInfo->SizeofFvFiles[Index];
1003 } else {
1004 FvImage->CurrentFilePointer += FileSize;
1006 goto Done;
1010 // Verify Ffs file
1012 Status = VerifyFfsFile ((EFI_FFS_FILE_HEADER *)FileBuffer);
1013 if (EFI_ERROR (Status)) {
1014 free (FileBuffer);
1015 Error (NULL, 0, 3000, "Invalid", "%s is a FFS file.", FvInfo->FvFiles[Index]);
1016 return EFI_INVALID_PARAMETER;
1020 // Verify space exists to add the file
1022 if (FileSize > (UINTN) ((UINTN) *VtfFileImage - (UINTN) FvImage->CurrentFilePointer)) {
1023 free (FileBuffer);
1024 Error (NULL, 0, 4002, "Resource", "FV space is full, not enough room to add file %s.", FvInfo->FvFiles[Index]);
1025 return EFI_OUT_OF_RESOURCES;
1029 // Verify the input file is the duplicated file in this Fv image
1031 for (Index1 = 0; Index1 < Index; Index1 ++) {
1032 if (CompareGuid ((EFI_GUID *) FileBuffer, &mFileGuidArray [Index1]) == 0) {
1033 Error (NULL, 0, 2000, "Invalid parameter", "the %dth file and %uth file have the same file GUID.", (unsigned) Index1 + 1, (unsigned) Index + 1);
1034 PrintGuid ((EFI_GUID *) FileBuffer);
1035 return EFI_INVALID_PARAMETER;
1038 CopyMem (&mFileGuidArray [Index], FileBuffer, sizeof (EFI_GUID));
1041 // Update the file state based on polarity of the FV.
1043 UpdateFfsFileState (
1044 (EFI_FFS_FILE_HEADER *) FileBuffer,
1045 (EFI_FIRMWARE_VOLUME_HEADER *) FvImage->FileImage
1049 // Check if alignment is required
1051 ReadFfsAlignment ((EFI_FFS_FILE_HEADER *) FileBuffer, &CurrentFileAlignment);
1054 // Find the largest alignment of all the FFS files in the FV
1056 if (CurrentFileAlignment > MaxFfsAlignment) {
1057 MaxFfsAlignment = CurrentFileAlignment;
1060 // If we have a VTF file, add it at the top.
1062 if (IsVtfFile ((EFI_FFS_FILE_HEADER *) FileBuffer)) {
1063 if ((UINTN) *VtfFileImage == (UINTN) FvImage->Eof) {
1065 // No previous VTF, add this one.
1067 *VtfFileImage = (EFI_FFS_FILE_HEADER *) (UINTN) ((UINTN) FvImage->FileImage + FvInfo->Size - FileSize);
1069 // Sanity check. The file MUST align appropriately
1071 if (((UINTN) *VtfFileImage + sizeof (EFI_FFS_FILE_HEADER) - (UINTN) FvImage->FileImage) % (1 << CurrentFileAlignment)) {
1072 Error (NULL, 0, 3000, "Invalid", "VTF file cannot be aligned on a %u-byte boundary.", (unsigned) (1 << CurrentFileAlignment));
1073 free (FileBuffer);
1074 return EFI_ABORTED;
1077 // Rebase the PE or TE image in FileBuffer of FFS file for XIP
1078 // Rebase for the debug genfvmap tool
1080 FfsRebase (FvInfo, FvInfo->FvFiles[Index], (EFI_FFS_FILE_HEADER *) FileBuffer, (UINTN) *VtfFileImage - (UINTN) FvImage->FileImage, FvMapFile);
1082 // copy VTF File
1084 memcpy (*VtfFileImage, FileBuffer, FileSize);
1085 free (FileBuffer);
1086 DebugMsg (NULL, 0, 9, "Add VTF FFS file in FV image", NULL);
1087 return EFI_SUCCESS;
1088 } else {
1090 // Already found a VTF file.
1092 Error (NULL, 0, 3000, "Invalid", "multiple VTF files are not permitted within a single FV.");
1093 free (FileBuffer);
1094 return EFI_ABORTED;
1099 // Add pad file if necessary
1101 Status = AddPadFile (FvImage, 1 << CurrentFileAlignment, *VtfFileImage, NULL);
1102 if (EFI_ERROR (Status)) {
1103 Error (NULL, 0, 4002, "Resource", "FV space is full, could not add pad file for data alignment property.");
1104 free (FileBuffer);
1105 return EFI_ABORTED;
1108 // Add file
1110 if ((UINTN) (FvImage->CurrentFilePointer + FileSize) <= (UINTN) (*VtfFileImage)) {
1112 // Rebase the PE or TE image in FileBuffer of FFS file for XIP.
1113 // Rebase Bs and Rt drivers for the debug genfvmap tool.
1115 FfsRebase (FvInfo, FvInfo->FvFiles[Index], (EFI_FFS_FILE_HEADER *) FileBuffer, (UINTN) FvImage->CurrentFilePointer - (UINTN) FvImage->FileImage, FvMapFile);
1117 // Copy the file
1119 memcpy (FvImage->CurrentFilePointer, FileBuffer, FileSize);
1120 FvImage->CurrentFilePointer += FileSize;
1121 } else {
1122 Error (NULL, 0, 4002, "Resource", "FV space is full, cannot add file %s.", FvInfo->FvFiles[Index]);
1123 free (FileBuffer);
1124 return EFI_ABORTED;
1127 // Make next file start at QWord Boundry
1129 while (((UINTN) FvImage->CurrentFilePointer & (EFI_FFS_FILE_HEADER_ALIGNMENT - 1)) != 0) {
1130 FvImage->CurrentFilePointer++;
1133 Done:
1135 // Free allocated memory.
1137 free (FileBuffer);
1139 return EFI_SUCCESS;
1142 EFI_STATUS
1143 PadFvImage (
1144 IN MEMORY_FILE *FvImage,
1145 IN EFI_FFS_FILE_HEADER *VtfFileImage
1147 /*++
1149 Routine Description:
1151 This function places a pad file between the last file in the FV and the VTF
1152 file if the VTF file exists.
1154 Arguments:
1156 FvImage Memory file for the FV memory image
1157 VtfFileImage The address of the VTF file. If this is the end of the FV
1158 image, no VTF exists and no pad file is needed.
1160 Returns:
1162 EFI_SUCCESS Completed successfully.
1163 EFI_INVALID_PARAMETER One of the input parameters was NULL.
1165 --*/
1167 EFI_FFS_FILE_HEADER *PadFile;
1168 UINTN FileSize;
1171 // If there is no VTF or the VTF naturally follows the previous file without a
1172 // pad file, then there's nothing to do
1174 if ((UINTN) VtfFileImage == (UINTN) FvImage->Eof || \
1175 ((UINTN) VtfFileImage == (UINTN) FvImage->CurrentFilePointer)) {
1176 return EFI_SUCCESS;
1179 if ((UINTN) VtfFileImage < (UINTN) FvImage->CurrentFilePointer) {
1180 return EFI_INVALID_PARAMETER;
1184 // Pad file starts at beginning of free space
1186 PadFile = (EFI_FFS_FILE_HEADER *) FvImage->CurrentFilePointer;
1189 // write PadFile FFS header with PadType, don't need to set PAD file guid in its header.
1191 PadFile->Type = EFI_FV_FILETYPE_FFS_PAD;
1192 PadFile->Attributes = 0;
1195 // FileSize includes the EFI_FFS_FILE_HEADER
1197 FileSize = (UINTN) VtfFileImage - (UINTN) FvImage->CurrentFilePointer;
1198 PadFile->Size[0] = (UINT8) (FileSize & 0x000000FF);
1199 PadFile->Size[1] = (UINT8) ((FileSize & 0x0000FF00) >> 8);
1200 PadFile->Size[2] = (UINT8) ((FileSize & 0x00FF0000) >> 16);
1203 // Fill in checksums and state, must be zero during checksum calculation.
1205 PadFile->IntegrityCheck.Checksum.Header = 0;
1206 PadFile->IntegrityCheck.Checksum.File = 0;
1207 PadFile->State = 0;
1208 PadFile->IntegrityCheck.Checksum.Header = CalculateChecksum8 ((UINT8 *) PadFile, sizeof (EFI_FFS_FILE_HEADER));
1209 PadFile->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;
1211 PadFile->State = EFI_FILE_HEADER_CONSTRUCTION | EFI_FILE_HEADER_VALID | EFI_FILE_DATA_VALID;
1213 UpdateFfsFileState (
1214 (EFI_FFS_FILE_HEADER *) PadFile,
1215 (EFI_FIRMWARE_VOLUME_HEADER *) FvImage->FileImage
1218 // Update the current FV pointer
1220 FvImage->CurrentFilePointer = FvImage->Eof;
1222 return EFI_SUCCESS;
1225 EFI_STATUS
1226 UpdateResetVector (
1227 IN MEMORY_FILE *FvImage,
1228 IN FV_INFO *FvInfo,
1229 IN EFI_FFS_FILE_HEADER *VtfFile
1231 /*++
1233 Routine Description:
1235 This parses the FV looking for the PEI core and then plugs the address into
1236 the SALE_ENTRY point of the BSF/VTF for IPF and does BUGBUG TBD action to
1237 complete an IA32 Bootstrap FV.
1239 Arguments:
1241 FvImage Memory file for the FV memory image
1242 FvInfo Information read from INF file.
1243 VtfFile Pointer to the VTF file in the FV image.
1245 Returns:
1247 EFI_SUCCESS Function Completed successfully.
1248 EFI_ABORTED Error encountered.
1249 EFI_INVALID_PARAMETER A required parameter was NULL.
1250 EFI_NOT_FOUND PEI Core file not found.
1252 --*/
1254 EFI_FFS_FILE_HEADER *PeiCoreFile;
1255 EFI_FFS_FILE_HEADER *SecCoreFile;
1256 EFI_STATUS Status;
1257 EFI_FILE_SECTION_POINTER Pe32Section;
1258 UINT32 EntryPoint;
1259 UINT32 BaseOfCode;
1260 UINT16 MachineType;
1261 EFI_PHYSICAL_ADDRESS PeiCorePhysicalAddress;
1262 EFI_PHYSICAL_ADDRESS SecCorePhysicalAddress;
1263 EFI_PHYSICAL_ADDRESS *SecCoreEntryAddressPtr;
1264 INT32 Ia32SecEntryOffset;
1265 UINT32 *Ia32ResetAddressPtr;
1266 UINT8 *BytePointer;
1267 UINT8 *BytePointer2;
1268 UINT16 *WordPointer;
1269 UINT16 CheckSum;
1270 UINT32 IpiVector;
1271 UINTN Index;
1272 EFI_FFS_FILE_STATE SavedState;
1273 UINT64 FitAddress;
1274 FIT_TABLE *FitTablePtr;
1277 // Verify input parameters
1279 if (FvImage == NULL || FvInfo == NULL || VtfFile == NULL) {
1280 return EFI_INVALID_PARAMETER;
1283 // Initialize FV library
1285 InitializeFvLib (FvImage->FileImage, FvInfo->Size);
1288 // Verify VTF file
1290 Status = VerifyFfsFile (VtfFile);
1291 if (EFI_ERROR (Status)) {
1292 return EFI_INVALID_PARAMETER;
1296 // Find the Sec Core
1298 Status = GetFileByType (EFI_FV_FILETYPE_SECURITY_CORE, 1, &SecCoreFile);
1299 if (EFI_ERROR (Status) || SecCoreFile == NULL) {
1300 Error (NULL, 0, 3000, "Invalid", "could not find the SEC core file in the FV.");
1301 return EFI_ABORTED;
1304 // Sec Core found, now find PE32 section
1306 Status = GetSectionByType (SecCoreFile, EFI_SECTION_PE32, 1, &Pe32Section);
1307 if (Status == EFI_NOT_FOUND) {
1308 Status = GetSectionByType (SecCoreFile, EFI_SECTION_TE, 1, &Pe32Section);
1311 if (EFI_ERROR (Status)) {
1312 Error (NULL, 0, 3000, "Invalid", "could not find a PE32 section in the SEC core file.");
1313 return EFI_ABORTED;
1316 Status = GetPe32Info (
1317 (VOID *) ((UINTN) Pe32Section.Pe32Section + sizeof (EFI_SECTION_PE32)),
1318 &EntryPoint,
1319 &BaseOfCode,
1320 &MachineType
1323 if (EFI_ERROR (Status)) {
1324 Error (NULL, 0, 3000, "Invalid", "could not get the PE32 entry point for the SEC core.");
1325 return EFI_ABORTED;
1329 // Physical address is FV base + offset of PE32 + offset of the entry point
1331 SecCorePhysicalAddress = FvInfo->BaseAddress;
1332 SecCorePhysicalAddress += (UINTN) Pe32Section.Pe32Section + sizeof (EFI_SECTION_PE32) - (UINTN) FvImage->FileImage;
1333 SecCorePhysicalAddress += EntryPoint;
1334 DebugMsg (NULL, 0, 9, "SecCore physical entry point address", "Address = 0x%llX", (unsigned long long) SecCorePhysicalAddress);
1337 // Find the PEI Core
1339 Status = GetFileByType (EFI_FV_FILETYPE_PEI_CORE, 1, &PeiCoreFile);
1340 if (EFI_ERROR (Status) || PeiCoreFile == NULL) {
1341 Error (NULL, 0, 3000, "Invalid", "could not find the PEI core in the FV.");
1342 return EFI_ABORTED;
1345 // PEI Core found, now find PE32 or TE section
1347 Status = GetSectionByType (PeiCoreFile, EFI_SECTION_PE32, 1, &Pe32Section);
1348 if (Status == EFI_NOT_FOUND) {
1349 Status = GetSectionByType (PeiCoreFile, EFI_SECTION_TE, 1, &Pe32Section);
1352 if (EFI_ERROR (Status)) {
1353 Error (NULL, 0, 3000, "Invalid", "could not find either a PE32 or a TE section in PEI core file.");
1354 return EFI_ABORTED;
1357 Status = GetPe32Info (
1358 (VOID *) ((UINTN) Pe32Section.Pe32Section + sizeof (EFI_SECTION_PE32)),
1359 &EntryPoint,
1360 &BaseOfCode,
1361 &MachineType
1364 if (EFI_ERROR (Status)) {
1365 Error (NULL, 0, 3000, "Invalid", "could not get the PE32 entry point for the PEI core.");
1366 return EFI_ABORTED;
1369 // Physical address is FV base + offset of PE32 + offset of the entry point
1371 PeiCorePhysicalAddress = FvInfo->BaseAddress;
1372 PeiCorePhysicalAddress += (UINTN) Pe32Section.Pe32Section + sizeof (EFI_SECTION_PE32) - (UINTN) FvImage->FileImage;
1373 PeiCorePhysicalAddress += EntryPoint;
1374 DebugMsg (NULL, 0, 9, "PeiCore physical entry point address", "Address = 0x%llX", (unsigned long long) PeiCorePhysicalAddress);
1376 if (MachineType == EFI_IMAGE_MACHINE_IA64) {
1378 // Update PEI_CORE address
1381 // Set the uncached attribute bit in the physical address
1383 PeiCorePhysicalAddress |= 0x8000000000000000ULL;
1386 // Check if address is aligned on a 16 byte boundary
1388 if (PeiCorePhysicalAddress & 0xF) {
1389 Error (NULL, 0, 3000, "Invalid",
1390 "PEI_CORE entry point is not aligned on a 16 byte boundary, address specified is %llXh.",
1391 (unsigned long long) PeiCorePhysicalAddress
1393 return EFI_ABORTED;
1396 // First Get the FIT table address
1398 FitAddress = (*(UINT64 *) (FvImage->Eof - IPF_FIT_ADDRESS_OFFSET)) & 0xFFFFFFFF;
1400 FitTablePtr = (FIT_TABLE *) (FvImage->FileImage + (FitAddress - FvInfo->BaseAddress));
1402 Status = UpdatePeiCoreEntryInFit (FitTablePtr, PeiCorePhysicalAddress);
1404 if (!EFI_ERROR (Status)) {
1405 UpdateFitCheckSum (FitTablePtr);
1409 // Update SEC_CORE address
1412 // Set the uncached attribute bit in the physical address
1414 SecCorePhysicalAddress |= 0x8000000000000000ULL;
1416 // Check if address is aligned on a 16 byte boundary
1418 if (SecCorePhysicalAddress & 0xF) {
1419 Error (NULL, 0, 3000, "Invalid",
1420 "SALE_ENTRY entry point is not aligned on a 16 byte boundary, address specified is %llXh.",
1421 (unsigned long long) SecCorePhysicalAddress
1423 return EFI_ABORTED;
1426 // Update the address
1428 SecCoreEntryAddressPtr = (EFI_PHYSICAL_ADDRESS *) ((UINTN) FvImage->Eof - IPF_SALE_ENTRY_ADDRESS_OFFSET);
1429 *SecCoreEntryAddressPtr = SecCorePhysicalAddress;
1431 } else if (
1432 (MachineType == EFI_IMAGE_MACHINE_IA32 ||
1433 MachineType == EFI_IMAGE_MACHINE_X64) &&
1434 (((UINTN)FvImage->Eof - (UINTN)FvImage->FileImage) >= IA32_X64_VTF_SIGNATURE_OFFSET) &&
1435 (*(UINT32 *)(VOID*)((UINTN) FvImage->Eof - IA32_X64_VTF_SIGNATURE_OFFSET) ==
1436 IA32_X64_VTF0_SIGNATURE)
1439 // If VTF-0 signature is found, then no modifications are needed.
1441 } else if (MachineType == EFI_IMAGE_MACHINE_IA32 || MachineType == EFI_IMAGE_MACHINE_X64) {
1443 // Get the location to update
1445 Ia32ResetAddressPtr = (UINT32 *) ((UINTN) FvImage->Eof - IA32_PEI_CORE_ENTRY_OFFSET);
1448 // Write lower 32 bits of physical address for Pei Core entry
1450 *Ia32ResetAddressPtr = (UINT32) PeiCorePhysicalAddress;
1453 // Write SecCore Entry point relative address into the jmp instruction in reset vector.
1455 Ia32ResetAddressPtr = (UINT32 *) ((UINTN) FvImage->Eof - IA32_SEC_CORE_ENTRY_OFFSET);
1457 Ia32SecEntryOffset = (INT32) (SecCorePhysicalAddress - (FV_IMAGES_TOP_ADDRESS - IA32_SEC_CORE_ENTRY_OFFSET + 2));
1458 if (Ia32SecEntryOffset <= -65536) {
1459 Error (NULL, 0, 3000, "Invalid", "The SEC EXE file size is too large, it must be less than 64K.");
1460 return STATUS_ERROR;
1463 *(UINT16 *) Ia32ResetAddressPtr = (UINT16) Ia32SecEntryOffset;
1466 // Update the BFV base address
1468 Ia32ResetAddressPtr = (UINT32 *) ((UINTN) FvImage->Eof - 4);
1469 *Ia32ResetAddressPtr = (UINT32) (FvInfo->BaseAddress);
1470 DebugMsg (NULL, 0, 9, "update BFV base address in the top FV image", "BFV base address = 0x%llX.", (unsigned long long) FvInfo->BaseAddress);
1473 // Update the Startup AP in the FVH header block ZeroVector region.
1475 BytePointer = (UINT8 *) ((UINTN) FvImage->FileImage);
1476 if (FvInfo->Size <= 0x10000) {
1477 BytePointer2 = m64kRecoveryStartupApDataArray;
1478 } else if (FvInfo->Size <= 0x20000) {
1479 BytePointer2 = m128kRecoveryStartupApDataArray;
1480 } else {
1481 BytePointer2 = m128kRecoveryStartupApDataArray;
1483 // Find the position to place Ap reset vector, the offset
1484 // between the position and the end of Fvrecovery.fv file
1485 // should not exceed 128kB to prevent Ap reset vector from
1486 // outside legacy E and F segment
1488 Status = FindApResetVectorPosition (FvImage, &BytePointer);
1489 if (EFI_ERROR (Status)) {
1490 Error (NULL, 0, 3000, "Invalid", "Cannot find the appropriate location in FvImage to add Ap reset vector!");
1491 return EFI_ABORTED;
1495 for (Index = 0; Index < SIZEOF_STARTUP_DATA_ARRAY; Index++) {
1496 BytePointer[Index] = BytePointer2[Index];
1499 // Calculate the checksum
1501 CheckSum = 0x0000;
1502 WordPointer = (UINT16 *) (BytePointer);
1503 for (Index = 0; Index < SIZEOF_STARTUP_DATA_ARRAY / 2; Index++) {
1504 CheckSum = (UINT16) (CheckSum + ((UINT16) *WordPointer));
1505 WordPointer++;
1508 // Update the checksum field
1510 WordPointer = (UINT16 *) (BytePointer + SIZEOF_STARTUP_DATA_ARRAY - 2);
1511 *WordPointer = (UINT16) (0x10000 - (UINT32) CheckSum);
1514 // IpiVector at the 4k aligned address in the top 2 blocks in the PEI FV.
1516 IpiVector = (UINT32) (FV_IMAGES_TOP_ADDRESS - ((UINTN) FvImage->Eof - (UINTN) BytePointer));
1517 DebugMsg (NULL, 0, 9, "Startup AP Vector address", "IpiVector at 0x%X", (unsigned) IpiVector);
1518 if ((IpiVector & 0xFFF) != 0) {
1519 Error (NULL, 0, 3000, "Invalid", "Startup AP Vector address are not 4K aligned, because the FV size is not 4K aligned");
1520 return EFI_ABORTED;
1522 IpiVector = IpiVector >> 12;
1523 IpiVector = IpiVector & 0xFF;
1526 // Write IPI Vector at Offset FvrecoveryFileSize - 8
1528 Ia32ResetAddressPtr = (UINT32 *) ((UINTN) FvImage->Eof - 8);
1529 *Ia32ResetAddressPtr = IpiVector;
1530 } else if (MachineType == EFI_IMAGE_MACHINE_ARMT) {
1532 // Since the ARM reset vector is in the FV Header you really don't need a
1533 // Volume Top File, but if you have one for some reason don't crash...
1535 } else {
1536 Error (NULL, 0, 3000, "Invalid", "machine type=0x%X in PEI core.", MachineType);
1537 return EFI_ABORTED;
1541 // Now update file checksum
1543 SavedState = VtfFile->State;
1544 VtfFile->IntegrityCheck.Checksum.File = 0;
1545 VtfFile->State = 0;
1546 if (VtfFile->Attributes & FFS_ATTRIB_CHECKSUM) {
1547 VtfFile->IntegrityCheck.Checksum.File = CalculateChecksum8 (
1548 (UINT8 *) VtfFile,
1549 GetLength (VtfFile->Size)
1551 } else {
1552 VtfFile->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;
1555 VtfFile->State = SavedState;
1557 return EFI_SUCCESS;
1561 EFI_STATUS
1562 UpdateArmResetVectorIfNeeded (
1563 IN MEMORY_FILE *FvImage,
1564 IN FV_INFO *FvInfo
1566 /*++
1568 Routine Description:
1569 This parses the FV looking for SEC and patches that address into the
1570 beginning of the FV header.
1572 For ARM the reset vector is at 0x00000000 or 0xFFFF0000.
1573 This would commonly map to the first entry in the ROM.
1574 ARM Exceptions:
1575 Reset +0
1576 Undefined +4
1577 SWI +8
1578 Prefetch Abort +12
1579 Data Abort +16
1580 IRQ +20
1581 FIQ +24
1583 We support two schemes on ARM.
1584 1) Beginning of the FV is the reset vector
1585 2) Reset vector is data bytes FDF file and that code branches to reset vector
1586 in the beginning of the FV (fixed size offset).
1589 Need to have the jump for the reset vector at location zero.
1590 We also need to store the address or PEI (if it exists).
1591 We stub out a return from interrupt in case the debugger
1592 is using SWI.
1593 The optional entry to the common exception handler is
1594 to support full featured exception handling from ROM and is currently
1595 not support by this tool.
1597 Arguments:
1598 FvImage Memory file for the FV memory image
1599 FvInfo Information read from INF file.
1601 Returns:
1603 EFI_SUCCESS Function Completed successfully.
1604 EFI_ABORTED Error encountered.
1605 EFI_INVALID_PARAMETER A required parameter was NULL.
1606 EFI_NOT_FOUND PEI Core file not found.
1608 --*/
1610 EFI_FFS_FILE_HEADER *PeiCoreFile;
1611 EFI_FFS_FILE_HEADER *SecCoreFile;
1612 EFI_STATUS Status;
1613 EFI_FILE_SECTION_POINTER Pe32Section;
1614 UINT32 EntryPoint;
1615 UINT32 BaseOfCode;
1616 UINT16 MachineType;
1617 EFI_PHYSICAL_ADDRESS PeiCorePhysicalAddress;
1618 EFI_PHYSICAL_ADDRESS SecCorePhysicalAddress;
1619 INT32 ResetVector[4]; // 0 - is branch relative to SEC entry point
1620 // 1 - PEI Entry Point
1621 // 2 - movs pc,lr for a SWI handler
1622 // 3 - Place holder for Common Exception Handler
1625 // Verify input parameters
1627 if (FvImage == NULL || FvInfo == NULL) {
1628 return EFI_INVALID_PARAMETER;
1631 // Initialize FV library
1633 InitializeFvLib (FvImage->FileImage, FvInfo->Size);
1636 // Find the Sec Core
1638 Status = GetFileByType (EFI_FV_FILETYPE_SECURITY_CORE, 1, &SecCoreFile);
1639 if (EFI_ERROR (Status) || SecCoreFile == NULL) {
1641 // Maybe hardware does SEC job and we only have PEI Core?
1645 // Find the PEI Core. It may not exist if SEC loads DXE core directly
1647 PeiCorePhysicalAddress = 0;
1648 Status = GetFileByType (EFI_FV_FILETYPE_PEI_CORE, 1, &PeiCoreFile);
1649 if (!EFI_ERROR (Status) && PeiCoreFile != NULL) {
1651 // PEI Core found, now find PE32 or TE section
1653 Status = GetSectionByType (PeiCoreFile, EFI_SECTION_PE32, 1, &Pe32Section);
1654 if (Status == EFI_NOT_FOUND) {
1655 Status = GetSectionByType (PeiCoreFile, EFI_SECTION_TE, 1, &Pe32Section);
1658 if (EFI_ERROR (Status)) {
1659 Error (NULL, 0, 3000, "Invalid", "could not find either a PE32 or a TE section in PEI core file!");
1660 return EFI_ABORTED;
1663 Status = GetPe32Info (
1664 (VOID *) ((UINTN) Pe32Section.Pe32Section + sizeof (EFI_SECTION_PE32)),
1665 &EntryPoint,
1666 &BaseOfCode,
1667 &MachineType
1670 if (EFI_ERROR (Status)) {
1671 Error (NULL, 0, 3000, "Invalid", "could not get the PE32 entry point for the PEI core!");
1672 return EFI_ABORTED;
1675 // Physical address is FV base + offset of PE32 + offset of the entry point
1677 PeiCorePhysicalAddress = FvInfo->BaseAddress;
1678 PeiCorePhysicalAddress += (UINTN) Pe32Section.Pe32Section + sizeof (EFI_SECTION_PE32) - (UINTN) FvImage->FileImage;
1679 PeiCorePhysicalAddress += EntryPoint;
1680 DebugMsg (NULL, 0, 9, "PeiCore physical entry point address", "Address = 0x%llX", (unsigned long long) PeiCorePhysicalAddress);
1682 if (MachineType == EFI_IMAGE_MACHINE_ARMT) {
1683 memset (ResetVector, 0, sizeof (ResetVector));
1684 // Address of PEI Core, if we have one
1685 ResetVector[1] = (UINT32)PeiCorePhysicalAddress;
1689 // Copy to the beginning of the FV
1691 memcpy ((UINT8 *) ((UINTN) FvImage->FileImage), ResetVector, sizeof (ResetVector));
1695 return EFI_SUCCESS;
1699 // Sec Core found, now find PE32 section
1701 Status = GetSectionByType (SecCoreFile, EFI_SECTION_PE32, 1, &Pe32Section);
1702 if (Status == EFI_NOT_FOUND) {
1703 Status = GetSectionByType (SecCoreFile, EFI_SECTION_TE, 1, &Pe32Section);
1706 if (EFI_ERROR (Status)) {
1707 Error (NULL, 0, 3000, "Invalid", "could not find a PE32 section in the SEC core file.");
1708 return EFI_ABORTED;
1711 Status = GetPe32Info (
1712 (VOID *) ((UINTN) Pe32Section.Pe32Section + sizeof (EFI_SECTION_PE32)),
1713 &EntryPoint,
1714 &BaseOfCode,
1715 &MachineType
1717 if (EFI_ERROR (Status)) {
1718 Error (NULL, 0, 3000, "Invalid", "could not get the PE32 entry point for the SEC core.");
1719 return EFI_ABORTED;
1722 if (MachineType != EFI_IMAGE_MACHINE_ARMT) {
1724 // If SEC is not ARM we have nothing to do
1726 return EFI_SUCCESS;
1730 // Physical address is FV base + offset of PE32 + offset of the entry point
1732 SecCorePhysicalAddress = FvInfo->BaseAddress;
1733 SecCorePhysicalAddress += (UINTN) Pe32Section.Pe32Section + sizeof (EFI_SECTION_PE32) - (UINTN) FvImage->FileImage;
1734 SecCorePhysicalAddress += EntryPoint;
1735 DebugMsg (NULL, 0, 9, "SecCore physical entry point address", "Address = 0x%llX", (unsigned long long) SecCorePhysicalAddress);
1738 // Find the PEI Core. It may not exist if SEC loads DXE core directly
1740 PeiCorePhysicalAddress = 0;
1741 Status = GetFileByType (EFI_FV_FILETYPE_PEI_CORE, 1, &PeiCoreFile);
1742 if (!EFI_ERROR (Status) && PeiCoreFile != NULL) {
1744 // PEI Core found, now find PE32 or TE section
1746 Status = GetSectionByType (PeiCoreFile, EFI_SECTION_PE32, 1, &Pe32Section);
1747 if (Status == EFI_NOT_FOUND) {
1748 Status = GetSectionByType (PeiCoreFile, EFI_SECTION_TE, 1, &Pe32Section);
1751 if (EFI_ERROR (Status)) {
1752 Error (NULL, 0, 3000, "Invalid", "could not find either a PE32 or a TE section in PEI core file!");
1753 return EFI_ABORTED;
1756 Status = GetPe32Info (
1757 (VOID *) ((UINTN) Pe32Section.Pe32Section + sizeof (EFI_SECTION_PE32)),
1758 &EntryPoint,
1759 &BaseOfCode,
1760 &MachineType
1763 if (EFI_ERROR (Status)) {
1764 Error (NULL, 0, 3000, "Invalid", "could not get the PE32 entry point for the PEI core!");
1765 return EFI_ABORTED;
1768 // Physical address is FV base + offset of PE32 + offset of the entry point
1770 PeiCorePhysicalAddress = FvInfo->BaseAddress;
1771 PeiCorePhysicalAddress += (UINTN) Pe32Section.Pe32Section + sizeof (EFI_SECTION_PE32) - (UINTN) FvImage->FileImage;
1772 PeiCorePhysicalAddress += EntryPoint;
1773 DebugMsg (NULL, 0, 9, "PeiCore physical entry point address", "Address = 0x%llX", (unsigned long long) PeiCorePhysicalAddress);
1777 // B SecEntryPoint - signed_immed_24 part +/-32MB offset
1778 // on ARM, the PC is always 8 ahead, so we're not really jumping from the base address, but from base address + 8
1779 ResetVector[0] = (INT32)(SecCorePhysicalAddress - FvInfo->BaseAddress - 8) >> 2;
1781 if (ResetVector[0] > 0x00FFFFFF) {
1782 Error (NULL, 0, 3000, "Invalid", "SEC Entry point must be within 32MB of the start of the FV");
1783 return EFI_ABORTED;
1786 // Add opcode for an uncondional branch with no link. AKA B SecEntryPoint
1787 ResetVector[0] |= 0xEA000000;
1790 // Address of PEI Core, if we have one
1791 ResetVector[1] = (UINT32)PeiCorePhysicalAddress;
1793 // SWI handler movs pc,lr. Just in case a debugger uses SWI
1794 ResetVector[2] = 0xE1B0F07E;
1796 // Place holder to support a common interrupt handler from ROM.
1797 // Currently not suppprted. For this to be used the reset vector would not be in this FV
1798 // and the exception vectors would be hard coded in the ROM and just through this address
1799 // to find a common handler in the a module in the FV.
1800 ResetVector[3] = 0;
1803 // Copy to the beginning of the FV
1805 memcpy ((UINT8 *) ((UINTN) FvImage->FileImage), ResetVector, sizeof (ResetVector));
1807 DebugMsg (NULL, 0, 9, "Update Reset vector in FV Header", NULL);
1809 return EFI_SUCCESS;
1812 EFI_STATUS
1813 GetPe32Info (
1814 IN UINT8 *Pe32,
1815 OUT UINT32 *EntryPoint,
1816 OUT UINT32 *BaseOfCode,
1817 OUT UINT16 *MachineType
1819 /*++
1821 Routine Description:
1823 Retrieves the PE32 entry point offset and machine type from PE image or TeImage.
1824 See EfiImage.h for machine types. The entry point offset is from the beginning
1825 of the PE32 buffer passed in.
1827 Arguments:
1829 Pe32 Beginning of the PE32.
1830 EntryPoint Offset from the beginning of the PE32 to the image entry point.
1831 BaseOfCode Base address of code.
1832 MachineType Magic number for the machine type.
1834 Returns:
1836 EFI_SUCCESS Function completed successfully.
1837 EFI_ABORTED Error encountered.
1838 EFI_INVALID_PARAMETER A required parameter was NULL.
1839 EFI_UNSUPPORTED The operation is unsupported.
1841 --*/
1843 EFI_IMAGE_DOS_HEADER *DosHeader;
1844 EFI_IMAGE_OPTIONAL_HEADER_UNION *ImgHdr;
1845 EFI_TE_IMAGE_HEADER *TeHeader;
1848 // Verify input parameters
1850 if (Pe32 == NULL) {
1851 return EFI_INVALID_PARAMETER;
1855 // First check whether it is one TE Image.
1857 TeHeader = (EFI_TE_IMAGE_HEADER *) Pe32;
1858 if (TeHeader->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {
1860 // By TeImage Header to get output
1862 *EntryPoint = TeHeader->AddressOfEntryPoint + sizeof (EFI_TE_IMAGE_HEADER) - TeHeader->StrippedSize;
1863 *BaseOfCode = TeHeader->BaseOfCode + sizeof (EFI_TE_IMAGE_HEADER) - TeHeader->StrippedSize;
1864 *MachineType = TeHeader->Machine;
1865 } else {
1868 // Then check whether
1869 // First is the DOS header
1871 DosHeader = (EFI_IMAGE_DOS_HEADER *) Pe32;
1874 // Verify DOS header is expected
1876 if (DosHeader->e_magic != EFI_IMAGE_DOS_SIGNATURE) {
1877 Error (NULL, 0, 3000, "Invalid", "Unknown magic number in the DOS header, 0x%04X.", DosHeader->e_magic);
1878 return EFI_UNSUPPORTED;
1881 // Immediately following is the NT header.
1883 ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *) ((UINTN) Pe32 + DosHeader->e_lfanew);
1886 // Verify NT header is expected
1888 if (ImgHdr->Pe32.Signature != EFI_IMAGE_NT_SIGNATURE) {
1889 Error (NULL, 0, 3000, "Invalid", "Unrecognized image signature 0x%08X.", (unsigned) ImgHdr->Pe32.Signature);
1890 return EFI_UNSUPPORTED;
1893 // Get output
1895 *EntryPoint = ImgHdr->Pe32.OptionalHeader.AddressOfEntryPoint;
1896 *BaseOfCode = ImgHdr->Pe32.OptionalHeader.BaseOfCode;
1897 *MachineType = ImgHdr->Pe32.FileHeader.Machine;
1901 // Verify machine type is supported
1903 if (*MachineType != EFI_IMAGE_MACHINE_IA32 && *MachineType != EFI_IMAGE_MACHINE_IA64 && *MachineType != EFI_IMAGE_MACHINE_X64 && *MachineType != EFI_IMAGE_MACHINE_EBC &&
1904 *MachineType != EFI_IMAGE_MACHINE_ARMT) {
1905 Error (NULL, 0, 3000, "Invalid", "Unrecognized machine type in the PE32 file.");
1906 return EFI_UNSUPPORTED;
1909 return EFI_SUCCESS;
1912 EFI_STATUS
1913 GenerateFvImage (
1914 IN CHAR8 *InfFileImage,
1915 IN UINTN InfFileSize,
1916 IN CHAR8 *FvFileName,
1917 IN CHAR8 *MapFileName
1919 /*++
1921 Routine Description:
1923 This is the main function which will be called from application.
1925 Arguments:
1927 InfFileImage Buffer containing the INF file contents.
1928 InfFileSize Size of the contents of the InfFileImage buffer.
1929 FvFileName Requested name for the FV file.
1930 MapFileName Fv map file to log fv driver information.
1932 Returns:
1934 EFI_SUCCESS Function completed successfully.
1935 EFI_OUT_OF_RESOURCES Could not allocate required resources.
1936 EFI_ABORTED Error encountered.
1937 EFI_INVALID_PARAMETER A required parameter was NULL.
1939 --*/
1941 EFI_STATUS Status;
1942 MEMORY_FILE InfMemoryFile;
1943 MEMORY_FILE FvImageMemoryFile;
1944 UINTN Index;
1945 EFI_FIRMWARE_VOLUME_HEADER *FvHeader;
1946 EFI_FFS_FILE_HEADER *VtfFileImage;
1947 UINT8 *FvBufferHeader; // to make sure fvimage header 8 type alignment.
1948 UINT8 *FvImage;
1949 UINTN FvImageSize;
1950 FILE *FvFile;
1951 CHAR8 FvMapName [_MAX_PATH];
1952 FILE *FvMapFile;
1953 EFI_FIRMWARE_VOLUME_EXT_HEADER FvExtHeader;
1955 FvBufferHeader = NULL;
1956 FvFile = NULL;
1957 FvMapFile = NULL;
1959 if (InfFileImage != NULL) {
1961 // Initialize file structures
1963 InfMemoryFile.FileImage = InfFileImage;
1964 InfMemoryFile.CurrentFilePointer = InfFileImage;
1965 InfMemoryFile.Eof = InfFileImage + InfFileSize;
1968 // Parse the FV inf file for header information
1970 Status = ParseFvInf (&InfMemoryFile, &mFvDataInfo);
1971 if (EFI_ERROR (Status)) {
1972 Error (NULL, 0, 0003, "Error parsing file", "the input FV INF file.");
1973 return Status;
1978 // Update the file name return values
1980 if (FvFileName == NULL && mFvDataInfo.FvName[0] != '\0') {
1981 FvFileName = mFvDataInfo.FvName;
1984 if (FvFileName == NULL) {
1985 Error (NULL, 0, 1001, "Missing option", "Output file name");
1986 return EFI_ABORTED;
1989 if (mFvDataInfo.FvBlocks[0].Length == 0) {
1990 Error (NULL, 0, 1001, "Missing required argument", "Block Size");
1991 return EFI_ABORTED;
1995 // Debug message Fv File System Guid
1997 if (mFvDataInfo.FvFileSystemGuidSet) {
1998 DebugMsg (NULL, 0, 9, "FV File System Guid", "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
1999 (unsigned) mFvDataInfo.FvFileSystemGuid.Data1,
2000 mFvDataInfo.FvFileSystemGuid.Data2,
2001 mFvDataInfo.FvFileSystemGuid.Data3,
2002 mFvDataInfo.FvFileSystemGuid.Data4[0],
2003 mFvDataInfo.FvFileSystemGuid.Data4[1],
2004 mFvDataInfo.FvFileSystemGuid.Data4[2],
2005 mFvDataInfo.FvFileSystemGuid.Data4[3],
2006 mFvDataInfo.FvFileSystemGuid.Data4[4],
2007 mFvDataInfo.FvFileSystemGuid.Data4[5],
2008 mFvDataInfo.FvFileSystemGuid.Data4[6],
2009 mFvDataInfo.FvFileSystemGuid.Data4[7]);
2012 // Debug message Fv Name Guid
2014 if (mFvDataInfo.FvNameGuidSet) {
2015 DebugMsg (NULL, 0, 9, "FV Name Guid", "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
2016 (unsigned) mFvDataInfo.FvNameGuid.Data1,
2017 mFvDataInfo.FvNameGuid.Data2,
2018 mFvDataInfo.FvNameGuid.Data3,
2019 mFvDataInfo.FvNameGuid.Data4[0],
2020 mFvDataInfo.FvNameGuid.Data4[1],
2021 mFvDataInfo.FvNameGuid.Data4[2],
2022 mFvDataInfo.FvNameGuid.Data4[3],
2023 mFvDataInfo.FvNameGuid.Data4[4],
2024 mFvDataInfo.FvNameGuid.Data4[5],
2025 mFvDataInfo.FvNameGuid.Data4[6],
2026 mFvDataInfo.FvNameGuid.Data4[7]);
2029 if (CompareGuid (&mFvDataInfo.FvFileSystemGuid, &mEfiFirmwareFileSystem2Guid) == 0) {
2030 mFvDataInfo.IsPiFvImage = TRUE;
2034 // FvMap file to log the function address of all modules in one Fvimage
2036 if (MapFileName != NULL) {
2037 strcpy (FvMapName, MapFileName);
2038 } else {
2039 strcpy (FvMapName, FvFileName);
2040 strcat (FvMapName, ".map");
2042 VerboseMsg ("FV Map file name is %s", FvMapName);
2045 // Calculate the FV size and Update Fv Size based on the actual FFS files.
2046 // And Update mFvDataInfo data.
2048 Status = CalculateFvSize (&mFvDataInfo);
2049 if (EFI_ERROR (Status)) {
2050 return Status;
2052 VerboseMsg ("the generated FV image size is %u bytes", (unsigned) mFvDataInfo.Size);
2055 // support fv image and empty fv image
2057 FvImageSize = mFvDataInfo.Size;
2060 // Allocate the FV, assure FvImage Header 8 byte alignment
2062 FvBufferHeader = malloc (FvImageSize + sizeof (UINT64));
2063 if (FvBufferHeader == NULL) {
2064 return EFI_OUT_OF_RESOURCES;
2066 FvImage = (UINT8 *) (((UINTN) FvBufferHeader + 7) & ~7);
2069 // Initialize the FV to the erase polarity
2071 if (mFvDataInfo.FvAttributes == 0) {
2073 // Set Default Fv Attribute
2075 mFvDataInfo.FvAttributes = FV_DEFAULT_ATTRIBUTE;
2077 if (mFvDataInfo.FvAttributes & EFI_FVB2_ERASE_POLARITY) {
2078 memset (FvImage, -1, FvImageSize);
2079 } else {
2080 memset (FvImage, 0, FvImageSize);
2084 // Initialize FV header
2086 FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) FvImage;
2089 // Initialize the zero vector to all zeros.
2091 memset (FvHeader->ZeroVector, 0, 16);
2094 // Copy the Fv file system GUID
2096 memcpy (&FvHeader->FileSystemGuid, &mFvDataInfo.FvFileSystemGuid, sizeof (EFI_GUID));
2098 FvHeader->FvLength = FvImageSize;
2099 FvHeader->Signature = EFI_FVH_SIGNATURE;
2100 FvHeader->Attributes = mFvDataInfo.FvAttributes;
2101 FvHeader->Revision = EFI_FVH_REVISION;
2102 FvHeader->ExtHeaderOffset = 0;
2103 FvHeader->Reserved[0] = 0;
2106 // Copy firmware block map
2108 for (Index = 0; mFvDataInfo.FvBlocks[Index].Length != 0; Index++) {
2109 FvHeader->BlockMap[Index].NumBlocks = mFvDataInfo.FvBlocks[Index].NumBlocks;
2110 FvHeader->BlockMap[Index].Length = mFvDataInfo.FvBlocks[Index].Length;
2114 // Add block map terminator
2116 FvHeader->BlockMap[Index].NumBlocks = 0;
2117 FvHeader->BlockMap[Index].Length = 0;
2120 // Complete the header
2122 FvHeader->HeaderLength = (UINT16) (((UINTN) &(FvHeader->BlockMap[Index + 1])) - (UINTN) FvImage);
2123 FvHeader->Checksum = 0;
2124 FvHeader->Checksum = CalculateChecksum16 ((UINT16 *) FvHeader, FvHeader->HeaderLength / sizeof (UINT16));
2127 // If there is no FFS file, generate one empty FV
2129 if (mFvDataInfo.FvFiles[0][0] == 0 && !mFvDataInfo.FvNameGuidSet) {
2130 goto WriteFile;
2134 // Initialize our "file" view of the buffer
2136 FvImageMemoryFile.FileImage = (CHAR8 *)FvImage;
2137 FvImageMemoryFile.CurrentFilePointer = (CHAR8 *)FvImage + FvHeader->HeaderLength;
2138 FvImageMemoryFile.Eof = (CHAR8 *)FvImage + FvImageSize;
2141 // Initialize the FV library.
2143 InitializeFvLib (FvImageMemoryFile.FileImage, FvImageSize);
2146 // Initialize the VTF file address.
2148 VtfFileImage = (EFI_FFS_FILE_HEADER *) FvImageMemoryFile.Eof;
2151 // Open FvMap file
2153 FvMapFile = fopen (FvMapName, "w");
2154 if (FvMapFile == NULL) {
2155 Error (NULL, 0, 0001, "Error opening file", FvMapName);
2156 return EFI_ABORTED;
2160 // record FV size information into FvMap file.
2162 if (mFvTotalSize != 0) {
2163 fprintf (FvMapFile, EFI_FV_TOTAL_SIZE_STRING);
2164 fprintf (FvMapFile, " = 0x%x\n", (unsigned) mFvTotalSize);
2166 if (mFvTakenSize != 0) {
2167 fprintf (FvMapFile, EFI_FV_TAKEN_SIZE_STRING);
2168 fprintf (FvMapFile, " = 0x%x\n", (unsigned) mFvTakenSize);
2170 if (mFvTotalSize != 0 && mFvTakenSize != 0) {
2171 fprintf (FvMapFile, EFI_FV_SPACE_SIZE_STRING);
2172 fprintf (FvMapFile, " = 0x%x\n\n", (unsigned) (mFvTotalSize - mFvTakenSize));
2176 // Set PI FV extension header
2178 if (mFvDataInfo.FvNameGuidSet) {
2179 memcpy (&FvExtHeader.FvName, &mFvDataInfo.FvNameGuid, sizeof (EFI_GUID));
2180 FvExtHeader.ExtHeaderSize = sizeof (EFI_FIRMWARE_VOLUME_EXT_HEADER);
2181 AddPadFile (&FvImageMemoryFile, 4, VtfFileImage, &FvExtHeader);
2183 // Fv Extension header change update Fv Header Check sum
2185 FvHeader->Checksum = 0;
2186 FvHeader->Checksum = CalculateChecksum16 ((UINT16 *) FvHeader, FvHeader->HeaderLength / sizeof (UINT16));
2190 // Add files to FV
2192 for (Index = 0; mFvDataInfo.FvFiles[Index][0] != 0; Index++) {
2194 // Add the file
2196 Status = AddFile (&FvImageMemoryFile, &mFvDataInfo, Index, &VtfFileImage, FvMapFile);
2199 // Exit if error detected while adding the file
2201 if (EFI_ERROR (Status)) {
2202 goto Finish;
2207 // If there is a VTF file, some special actions need to occur.
2209 if ((UINTN) VtfFileImage != (UINTN) FvImageMemoryFile.Eof) {
2211 // Pad from the end of the last file to the beginning of the VTF file.
2212 // If the left space is less than sizeof (EFI_FFS_FILE_HEADER)?
2214 Status = PadFvImage (&FvImageMemoryFile, VtfFileImage);
2215 if (EFI_ERROR (Status)) {
2216 Error (NULL, 0, 4002, "Resource", "FV space is full, cannot add pad file between the last file and the VTF file.");
2217 goto Finish;
2219 if (!mArm) {
2221 // Update reset vector (SALE_ENTRY for IPF)
2222 // Now for IA32 and IA64 platform, the fv which has bsf file must have the
2223 // EndAddress of 0xFFFFFFFF. Thus, only this type fv needs to update the
2224 // reset vector. If the PEI Core is found, the VTF file will probably get
2225 // corrupted by updating the entry point.
2227 if ((mFvDataInfo.BaseAddress + mFvDataInfo.Size) == FV_IMAGES_TOP_ADDRESS) {
2228 Status = UpdateResetVector (&FvImageMemoryFile, &mFvDataInfo, VtfFileImage);
2229 if (EFI_ERROR(Status)) {
2230 Error (NULL, 0, 3000, "Invalid", "Could not update the reset vector.");
2231 goto Finish;
2233 DebugMsg (NULL, 0, 9, "Update Reset vector in VTF file", NULL);
2238 if (mArm) {
2239 Status = UpdateArmResetVectorIfNeeded (&FvImageMemoryFile, &mFvDataInfo);
2240 if (EFI_ERROR (Status)) {
2241 Error (NULL, 0, 3000, "Invalid", "Could not update the reset vector.");
2242 goto Finish;
2246 // Update Checksum for FvHeader
2248 FvHeader->Checksum = 0;
2249 FvHeader->Checksum = CalculateChecksum16 ((UINT16 *) FvHeader, FvHeader->HeaderLength / sizeof (UINT16));
2253 // Update FV Alignment attribute to the largest alignment of all the FFS files in the FV
2255 if ((((FvHeader->Attributes & EFI_FVB2_ALIGNMENT) >> 16)) < MaxFfsAlignment) {
2256 FvHeader->Attributes = ((MaxFfsAlignment << 16) | (FvHeader->Attributes & 0xFFFF));
2258 // Update Checksum for FvHeader
2260 FvHeader->Checksum = 0;
2261 FvHeader->Checksum = CalculateChecksum16 ((UINT16 *) FvHeader, FvHeader->HeaderLength / sizeof (UINT16));
2264 WriteFile:
2266 // Write fv file
2268 FvFile = fopen (FvFileName, "wb");
2269 if (FvFile == NULL) {
2270 Error (NULL, 0, 0001, "Error opening file", FvFileName);
2271 Status = EFI_ABORTED;
2272 goto Finish;
2275 if (fwrite (FvImage, 1, FvImageSize, FvFile) != FvImageSize) {
2276 Error (NULL, 0, 0002, "Error writing file", FvFileName);
2277 Status = EFI_ABORTED;
2278 goto Finish;
2281 Finish:
2282 if (FvBufferHeader != NULL) {
2283 free (FvBufferHeader);
2286 if (FvFile != NULL) {
2287 fclose (FvFile);
2290 if (FvMapFile != NULL) {
2291 fclose (FvMapFile);
2294 return Status;
2297 EFI_STATUS
2298 UpdatePeiCoreEntryInFit (
2299 IN FIT_TABLE *FitTablePtr,
2300 IN UINT64 PeiCorePhysicalAddress
2302 /*++
2304 Routine Description:
2306 This function is used to update the Pei Core address in FIT, this can be used by Sec core to pass control from
2307 Sec to Pei Core
2309 Arguments:
2311 FitTablePtr - The pointer of FIT_TABLE.
2312 PeiCorePhysicalAddress - The address of Pei Core entry.
2314 Returns:
2316 EFI_SUCCESS - The PEI_CORE FIT entry was updated successfully.
2317 EFI_NOT_FOUND - Not found the PEI_CORE FIT entry.
2319 --*/
2321 FIT_TABLE *TmpFitPtr;
2322 UINTN Index;
2323 UINTN NumFitComponents;
2325 TmpFitPtr = FitTablePtr;
2326 NumFitComponents = TmpFitPtr->CompSize;
2328 for (Index = 0; Index < NumFitComponents; Index++) {
2329 if ((TmpFitPtr->CvAndType & FIT_TYPE_MASK) == COMP_TYPE_FIT_PEICORE) {
2330 TmpFitPtr->CompAddress = PeiCorePhysicalAddress;
2331 return EFI_SUCCESS;
2334 TmpFitPtr++;
2337 return EFI_NOT_FOUND;
2340 VOID
2341 UpdateFitCheckSum (
2342 IN FIT_TABLE *FitTablePtr
2344 /*++
2346 Routine Description:
2348 This function is used to update the checksum for FIT.
2351 Arguments:
2353 FitTablePtr - The pointer of FIT_TABLE.
2355 Returns:
2357 None.
2359 --*/
2361 if ((FitTablePtr->CvAndType & CHECKSUM_BIT_MASK) >> 7) {
2362 FitTablePtr->CheckSum = 0;
2363 FitTablePtr->CheckSum = CalculateChecksum8 ((UINT8 *) FitTablePtr, FitTablePtr->CompSize * 16);
2367 EFI_STATUS
2368 CalculateFvSize (
2369 FV_INFO *FvInfoPtr
2371 /*++
2372 Routine Description:
2373 Calculate the FV size and Update Fv Size based on the actual FFS files.
2374 And Update FvInfo data.
2376 Arguments:
2377 FvInfoPtr - The pointer to FV_INFO structure.
2379 Returns:
2380 EFI_ABORTED - Ffs Image Error
2381 EFI_SUCCESS - Successfully update FvSize
2382 --*/
2384 UINTN CurrentOffset;
2385 UINTN Index;
2386 FILE *fpin;
2387 UINTN FfsFileSize;
2388 UINT32 FfsAlignment;
2389 EFI_FFS_FILE_HEADER FfsHeader;
2390 BOOLEAN VtfFileFlag;
2391 UINTN VtfFileSize;
2393 VtfFileSize = 0;
2394 VtfFileFlag = FALSE;
2395 fpin = NULL;
2396 Index = 0;
2399 // Compute size for easy access later
2401 FvInfoPtr->Size = 0;
2402 for (Index = 0; FvInfoPtr->FvBlocks[Index].NumBlocks > 0 && FvInfoPtr->FvBlocks[Index].Length > 0; Index++) {
2403 FvInfoPtr->Size += FvInfoPtr->FvBlocks[Index].NumBlocks * FvInfoPtr->FvBlocks[Index].Length;
2407 // Caculate the required sizes for all FFS files.
2409 CurrentOffset = sizeof (EFI_FIRMWARE_VOLUME_HEADER);
2411 for (Index = 1;; Index ++) {
2412 CurrentOffset += sizeof (EFI_FV_BLOCK_MAP_ENTRY);
2413 if (FvInfoPtr->FvBlocks[Index].NumBlocks == 0 || FvInfoPtr->FvBlocks[Index].Length == 0) {
2414 break;
2419 // Calculate PI extension header
2421 if (CompareGuid (&mFvDataInfo.FvNameGuid, &mZeroGuid) != 0) {
2422 CurrentOffset += sizeof (EFI_FFS_FILE_HEADER) + sizeof (EFI_FIRMWARE_VOLUME_EXT_HEADER);
2423 CurrentOffset = (CurrentOffset + 7) & (~7);
2427 // Accumlate every FFS file size.
2429 for (Index = 0; FvInfoPtr->FvFiles[Index][0] != 0; Index++) {
2431 // Open FFS file
2433 fpin = NULL;
2434 fpin = fopen (FvInfoPtr->FvFiles[Index], "rb");
2435 if (fpin == NULL) {
2436 Error (NULL, 0, 0001, "Error opening file", FvInfoPtr->FvFiles[Index]);
2437 return EFI_ABORTED;
2440 // Get the file size
2442 FfsFileSize = _filelength (fileno (fpin));
2444 // Read Ffs File header
2446 fread (&FfsHeader, sizeof (UINT8), sizeof (EFI_FFS_FILE_HEADER), fpin);
2448 // close file
2450 fclose (fpin);
2452 if (FvInfoPtr->IsPiFvImage) {
2454 // Check whether this ffs file is vtf file
2456 if (IsVtfFile (&FfsHeader)) {
2457 if (VtfFileFlag) {
2459 // One Fv image can't have two vtf files.
2461 return EFI_ABORTED;
2463 VtfFileFlag = TRUE;
2464 VtfFileSize = FfsFileSize;
2465 continue;
2469 // Get the alignment of FFS file
2471 ReadFfsAlignment (&FfsHeader, &FfsAlignment);
2472 FfsAlignment = 1 << FfsAlignment;
2474 // Add Pad file
2476 if (((CurrentOffset + sizeof (EFI_FFS_FILE_HEADER)) % FfsAlignment) != 0) {
2477 CurrentOffset = (CurrentOffset + sizeof (EFI_FFS_FILE_HEADER) * 2 + FfsAlignment - 1) & ~(FfsAlignment - 1);
2478 CurrentOffset -= sizeof (EFI_FFS_FILE_HEADER);
2483 // Add ffs file size
2485 if (FvInfoPtr->SizeofFvFiles[Index] > FfsFileSize) {
2486 CurrentOffset += FvInfoPtr->SizeofFvFiles[Index];
2487 } else {
2488 CurrentOffset += FfsFileSize;
2492 // Make next ffs file start at QWord Boundry
2494 if (FvInfoPtr->IsPiFvImage) {
2495 CurrentOffset = (CurrentOffset + EFI_FFS_FILE_HEADER_ALIGNMENT - 1) & ~(EFI_FFS_FILE_HEADER_ALIGNMENT - 1);
2498 CurrentOffset += VtfFileSize;
2499 DebugMsg (NULL, 0, 9, "FvImage size", "The caculated fv image size is 0x%x and the current set fv image size is 0x%x", (unsigned) CurrentOffset, (unsigned) FvInfoPtr->Size);
2501 if (FvInfoPtr->Size == 0) {
2503 // Update FvInfo data
2505 FvInfoPtr->FvBlocks[0].NumBlocks = CurrentOffset / FvInfoPtr->FvBlocks[0].Length + ((CurrentOffset % FvInfoPtr->FvBlocks[0].Length)?1:0);
2506 FvInfoPtr->Size = FvInfoPtr->FvBlocks[0].NumBlocks * FvInfoPtr->FvBlocks[0].Length;
2507 FvInfoPtr->FvBlocks[1].NumBlocks = 0;
2508 FvInfoPtr->FvBlocks[1].Length = 0;
2509 } else if (FvInfoPtr->Size < CurrentOffset) {
2511 // Not invalid
2513 Error (NULL, 0, 3000, "Invalid", "the required fv image size 0x%x exceeds the set fv image size 0x%x", (unsigned) CurrentOffset, (unsigned) FvInfoPtr->Size);
2514 return EFI_INVALID_PARAMETER;
2518 // Set Fv Size Information
2520 mFvTotalSize = FvInfoPtr->Size;
2521 mFvTakenSize = CurrentOffset;
2523 return EFI_SUCCESS;
2526 EFI_STATUS
2527 FfsRebaseImageRead (
2528 IN VOID *FileHandle,
2529 IN UINTN FileOffset,
2530 IN OUT UINT32 *ReadSize,
2531 OUT VOID *Buffer
2533 /*++
2535 Routine Description:
2537 Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file
2539 Arguments:
2541 FileHandle - The handle to the PE/COFF file
2543 FileOffset - The offset, in bytes, into the file to read
2545 ReadSize - The number of bytes to read from the file starting at FileOffset
2547 Buffer - A pointer to the buffer to read the data into.
2549 Returns:
2551 EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset
2553 --*/
2555 CHAR8 *Destination8;
2556 CHAR8 *Source8;
2557 UINT32 Length;
2559 Destination8 = Buffer;
2560 Source8 = (CHAR8 *) ((UINTN) FileHandle + FileOffset);
2561 Length = *ReadSize;
2562 while (Length--) {
2563 *(Destination8++) = *(Source8++);
2566 return EFI_SUCCESS;
2569 EFI_STATUS
2570 FfsRebase (
2571 IN OUT FV_INFO *FvInfo,
2572 IN CHAR8 *FileName,
2573 IN OUT EFI_FFS_FILE_HEADER *FfsFile,
2574 IN UINTN XipOffset,
2575 IN FILE *FvMapFile
2577 /*++
2579 Routine Description:
2581 This function determines if a file is XIP and should be rebased. It will
2582 rebase any PE32 sections found in the file using the base address.
2584 Arguments:
2586 FvInfo A pointer to FV_INFO struture.
2587 FileName Ffs File PathName
2588 FfsFile A pointer to Ffs file image.
2589 XipOffset The offset address to use for rebasing the XIP file image.
2590 FvMapFile FvMapFile to record the function address in one Fvimage
2592 Returns:
2594 EFI_SUCCESS The image was properly rebased.
2595 EFI_INVALID_PARAMETER An input parameter is invalid.
2596 EFI_ABORTED An error occurred while rebasing the input file image.
2597 EFI_OUT_OF_RESOURCES Could not allocate a required resource.
2598 EFI_NOT_FOUND No compressed sections could be found.
2600 --*/
2602 EFI_STATUS Status;
2603 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
2604 PE_COFF_LOADER_IMAGE_CONTEXT OrigImageContext;
2605 EFI_PHYSICAL_ADDRESS XipBase;
2606 EFI_PHYSICAL_ADDRESS NewPe32BaseAddress;
2607 EFI_PHYSICAL_ADDRESS *BaseToUpdate;
2608 UINTN Index;
2609 EFI_FILE_SECTION_POINTER CurrentPe32Section;
2610 EFI_FFS_FILE_STATE SavedState;
2611 EFI_IMAGE_OPTIONAL_HEADER_UNION *ImgHdr;
2612 EFI_TE_IMAGE_HEADER *TEImageHeader;
2613 UINT8 Flags;
2614 UINT8 *MemoryImagePointer;
2615 EFI_IMAGE_SECTION_HEADER *SectionHeader;
2616 CHAR8 PeFileName [_MAX_PATH];
2617 CHAR8 *Cptr;
2618 FILE *PeFile;
2619 UINT8 *PeFileBuffer;
2620 UINT32 PeFileSize;
2621 CHAR8 *PdbPointer;
2623 Index = 0;
2624 MemoryImagePointer = NULL;
2625 BaseToUpdate = NULL;
2626 TEImageHeader = NULL;
2627 ImgHdr = NULL;
2628 SectionHeader = NULL;
2629 Cptr = NULL;
2630 PeFile = NULL;
2631 PeFileBuffer = NULL;
2634 // Check XipAddress, BootAddress and RuntimeAddress
2636 Flags = 0;
2637 XipBase = 0;
2638 if (FvInfo->BaseAddress != 0) {
2639 Flags |= REBASE_XIP_FILE;
2640 XipBase = FvInfo->BaseAddress + XipOffset;
2642 if (FvInfo->BootBaseAddress != 0) {
2643 Flags |= REBASE_BOOTTIME_FILE;
2645 if (FvInfo->RuntimeBaseAddress != 0) {
2646 Flags |= REBASE_RUNTIME_FILE;
2650 // Don't Rebase this FFS.
2651 // Only copy the original map file into the FvMap file
2652 // for the image that is not required to be relocated.
2656 // We only process files potentially containing PE32 sections.
2658 switch (FfsFile->Type) {
2659 case EFI_FV_FILETYPE_SECURITY_CORE:
2660 case EFI_FV_FILETYPE_PEI_CORE:
2661 case EFI_FV_FILETYPE_PEIM:
2662 case EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER:
2663 case EFI_FV_FILETYPE_DRIVER:
2664 case EFI_FV_FILETYPE_DXE_CORE:
2665 break;
2666 default:
2667 return EFI_SUCCESS;
2670 // Rebase each PE32 section
2672 Status = EFI_SUCCESS;
2673 for (Index = 1;; Index++) {
2675 // Init Value
2677 NewPe32BaseAddress = 0;
2680 // Find Pe Image
2682 Status = GetSectionByType (FfsFile, EFI_SECTION_PE32, Index, &CurrentPe32Section);
2683 if (EFI_ERROR (Status)) {
2684 break;
2688 // Initialize context
2690 memset (&ImageContext, 0, sizeof (ImageContext));
2691 ImageContext.Handle = (VOID *) ((UINTN) CurrentPe32Section.Pe32Section + sizeof (EFI_PE32_SECTION));
2692 ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) FfsRebaseImageRead;
2693 Status = PeCoffLoaderGetImageInfo (&ImageContext);
2694 if (EFI_ERROR (Status)) {
2695 Error (NULL, 0, 3000, "Invalid PeImage", "The input file is %s and the return status is %x", FileName, (int) Status);
2696 return Status;
2699 if (ImageContext.Machine == EFI_IMAGE_MACHINE_ARMT) {
2700 mArm = TRUE;
2704 // Keep Image Context for PE image in FV
2706 memcpy (&OrigImageContext, &ImageContext, sizeof (ImageContext));
2709 // Get File PdbPointer
2711 PdbPointer = PeCoffLoaderGetPdbPointer (ImageContext.Handle);
2714 // Get PeHeader pointer
2716 ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((UINTN) CurrentPe32Section.Pe32Section + sizeof (EFI_PE32_SECTION) + ImageContext.PeCoffHeaderOffset);
2719 // Calculate the PE32 base address, based on file type
2721 switch (FfsFile->Type) {
2722 case EFI_FV_FILETYPE_SECURITY_CORE:
2723 case EFI_FV_FILETYPE_PEI_CORE:
2724 case EFI_FV_FILETYPE_PEIM:
2725 case EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER:
2726 if ((Flags & REBASE_XIP_FILE) == 0) {
2728 // We aren't relocating XIP code, so skip it.
2730 goto WritePeMap;
2734 // Check if section-alignment and file-alignment match or not
2736 if ((ImgHdr->Pe32.OptionalHeader.SectionAlignment != ImgHdr->Pe32.OptionalHeader.FileAlignment)) {
2738 // Xip module has the same section alignment and file alignment.
2740 Error (NULL, 0, 3000, "Invalid", "Section-Alignment and File-Alignment do not match : %s.", FileName);
2741 return EFI_ABORTED;
2744 // PeImage has no reloc section. It will try to get reloc data from the original EFI image.
2746 if (ImageContext.RelocationsStripped) {
2748 // Construct the original efi file Name
2750 strcpy (PeFileName, FileName);
2751 Cptr = PeFileName + strlen (PeFileName);
2752 while (*Cptr != '.') {
2753 Cptr --;
2755 if (*Cptr != '.') {
2756 Error (NULL, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName);
2757 return EFI_ABORTED;
2758 } else {
2759 *(Cptr + 1) = 'e';
2760 *(Cptr + 2) = 'f';
2761 *(Cptr + 3) = 'i';
2762 *(Cptr + 4) = '\0';
2764 PeFile = fopen (PeFileName, "rb");
2765 if (PeFile == NULL) {
2766 Warning (NULL, 0, 0, "Invalid", "The file %s has no .reloc section.", FileName);
2767 //Error (NULL, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName);
2768 //return EFI_ABORTED;
2769 break;
2772 // Get the file size
2774 PeFileSize = _filelength (fileno (PeFile));
2775 PeFileBuffer = (UINT8 *) malloc (PeFileSize);
2776 if (PeFileBuffer == NULL) {
2777 Error (NULL, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName);
2778 return EFI_OUT_OF_RESOURCES;
2781 // Read Pe File
2783 fread (PeFileBuffer, sizeof (UINT8), PeFileSize, PeFile);
2785 // close file
2787 fclose (PeFile);
2789 // Handle pointer to the original efi image.
2791 ImageContext.Handle = PeFileBuffer;
2792 Status = PeCoffLoaderGetImageInfo (&ImageContext);
2793 if (EFI_ERROR (Status)) {
2794 Error (NULL, 0, 3000, "Invalid PeImage", "The input file is %s and the return status is %x", FileName, (int) Status);
2795 return Status;
2797 ImageContext.RelocationsStripped = FALSE;
2800 NewPe32BaseAddress = XipBase + (UINTN) CurrentPe32Section.Pe32Section + sizeof (EFI_PE32_SECTION) - (UINTN)FfsFile;
2801 BaseToUpdate = &XipBase;
2802 break;
2804 case EFI_FV_FILETYPE_DRIVER:
2805 case EFI_FV_FILETYPE_DXE_CORE:
2806 switch (ImgHdr->Pe32.OptionalHeader.Subsystem) {
2807 case EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER:
2808 if ((Flags & REBASE_XIP_FILE) == REBASE_XIP_FILE) {
2810 // Check if section-alignment and file-alignment match or not
2812 if ((ImgHdr->Pe32.OptionalHeader.SectionAlignment != ImgHdr->Pe32.OptionalHeader.FileAlignment)) {
2814 // Xip module has the same section alignment and file alignment.
2816 Error (NULL, 0, 3000, "Invalid", "Section-Alignment and File-Alignment do not match : %s.", FileName);
2817 return EFI_ABORTED;
2819 NewPe32BaseAddress = XipBase + (UINTN) CurrentPe32Section.Pe32Section + sizeof (EFI_PE32_SECTION) - (UINTN)FfsFile;
2820 BaseToUpdate = &XipBase;
2821 } else if ((Flags & REBASE_RUNTIME_FILE) == REBASE_RUNTIME_FILE) {
2823 // make sure image base address at the section alignment
2825 FvInfo->RuntimeBaseAddress = (FvInfo->RuntimeBaseAddress - ImageContext.ImageSize) & (~(ImageContext.SectionAlignment - 1));
2826 FvInfo->RuntimeBaseAddress = FvInfo->RuntimeBaseAddress & (~(EFI_PAGE_SIZE - 1));
2827 NewPe32BaseAddress = FvInfo->RuntimeBaseAddress;
2828 BaseToUpdate = &(FvInfo->RuntimeBaseAddress);
2829 } else {
2831 // RT drivers aren't supposed to be relocated
2833 goto WritePeMap;
2835 break;
2837 default:
2839 // We treat all other subsystems the same as BS_DRIVER
2841 if ((Flags & REBASE_XIP_FILE) == REBASE_XIP_FILE) {
2843 // Check if section-alignment and file-alignment match or not
2845 if ((ImgHdr->Pe32.OptionalHeader.SectionAlignment != ImgHdr->Pe32.OptionalHeader.FileAlignment)) {
2847 // Xip module has the same section alignment and file alignment.
2849 Error (NULL, 0, 3000, "Invalid", "Section-Alignment and File-Alignment do not match : %s.", FileName);
2850 return EFI_ABORTED;
2852 NewPe32BaseAddress = XipBase + (UINTN) CurrentPe32Section.Pe32Section + sizeof (EFI_PE32_SECTION) - (UINTN)FfsFile;
2853 BaseToUpdate = &XipBase;
2854 } else if ((Flags & REBASE_BOOTTIME_FILE) == REBASE_BOOTTIME_FILE) {
2856 // make sure image base address at the Section and Page alignment
2858 FvInfo->BootBaseAddress = (FvInfo->BootBaseAddress - ImageContext.ImageSize) & (~(ImageContext.SectionAlignment - 1));
2859 FvInfo->BootBaseAddress = FvInfo->BootBaseAddress & (~(EFI_PAGE_SIZE - 1));
2860 NewPe32BaseAddress = FvInfo->BootBaseAddress;
2861 BaseToUpdate = &(FvInfo->BootBaseAddress);
2862 } else {
2864 // Skip all BS_DRIVER's
2866 goto WritePeMap;
2868 break;
2870 break;
2872 default:
2874 // Not supported file type
2876 return EFI_SUCCESS;
2880 // Relocation exist and rebase
2882 if (!ImageContext.RelocationsStripped) {
2884 // Load and Relocate Image Data
2886 MemoryImagePointer = (UINT8 *) malloc ((UINTN) ImageContext.ImageSize + ImageContext.SectionAlignment);
2887 if (MemoryImagePointer == NULL) {
2888 Error (NULL, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName);
2889 return EFI_OUT_OF_RESOURCES;
2891 memset ((VOID *) MemoryImagePointer, 0, (UINTN) ImageContext.ImageSize + ImageContext.SectionAlignment);
2892 ImageContext.ImageAddress = ((UINTN) MemoryImagePointer + ImageContext.SectionAlignment - 1) & (~(ImageContext.SectionAlignment - 1));
2894 Status = PeCoffLoaderLoadImage (&ImageContext);
2895 if (EFI_ERROR (Status)) {
2896 Error (NULL, 0, 3000, "Invalid", "LocateImage() call failed on rebase of %s", FileName);
2897 free ((VOID *) MemoryImagePointer);
2898 return Status;
2901 ImageContext.DestinationAddress = NewPe32BaseAddress;
2902 Status = PeCoffLoaderRelocateImage (&ImageContext);
2903 if (EFI_ERROR (Status)) {
2904 Error (NULL, 0, 3000, "Invalid", "RelocateImage() call failed on rebase of %s", FileName);
2905 free ((VOID *) MemoryImagePointer);
2906 return Status;
2910 // Copy Relocated data to raw image file.
2912 SectionHeader = (EFI_IMAGE_SECTION_HEADER *) (
2913 (UINTN) ImgHdr +
2914 sizeof (UINT32) +
2915 sizeof (EFI_IMAGE_FILE_HEADER) +
2916 ImgHdr->Pe32.FileHeader.SizeOfOptionalHeader
2919 for (Index = 0; Index < ImgHdr->Pe32.FileHeader.NumberOfSections; Index ++, SectionHeader ++) {
2920 CopyMem (
2921 (UINT8 *) CurrentPe32Section.Pe32Section + sizeof (EFI_COMMON_SECTION_HEADER) + SectionHeader->PointerToRawData,
2922 (VOID*) (UINTN) (ImageContext.ImageAddress + SectionHeader->VirtualAddress),
2923 SectionHeader->SizeOfRawData
2927 free ((VOID *) MemoryImagePointer);
2928 MemoryImagePointer = NULL;
2929 if (PeFileBuffer != NULL) {
2930 free (PeFileBuffer);
2931 PeFileBuffer = NULL;
2936 // Update Image Base Address
2938 if (ImgHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
2939 ImgHdr->Pe32.OptionalHeader.ImageBase = (UINT32) NewPe32BaseAddress;
2940 } else if (ImgHdr->Pe32Plus.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
2941 ImgHdr->Pe32Plus.OptionalHeader.ImageBase = NewPe32BaseAddress;
2942 } else {
2943 Error (NULL, 0, 3000, "Invalid", "unknown PE magic signature %X in PE32 image %s",
2944 ImgHdr->Pe32.OptionalHeader.Magic,
2945 FileName
2947 return EFI_ABORTED;
2951 // Update BASE address by add one page size.
2953 *BaseToUpdate -= EFI_PAGE_SIZE;
2956 // Now update file checksum
2958 if (FfsFile->Attributes & FFS_ATTRIB_CHECKSUM) {
2959 SavedState = FfsFile->State;
2960 FfsFile->IntegrityCheck.Checksum.File = 0;
2961 FfsFile->State = 0;
2962 if (FfsFile->Attributes & FFS_ATTRIB_CHECKSUM) {
2963 FfsFile->IntegrityCheck.Checksum.File = CalculateChecksum8 (
2964 (UINT8 *) FfsFile,
2965 GetLength (FfsFile->Size)
2967 } else {
2968 FfsFile->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;
2971 FfsFile->State = SavedState;
2975 // Get this module function address from ModulePeMapFile and add them into FvMap file
2977 WritePeMap:
2979 // Default use FileName as map file path
2981 if (PdbPointer == NULL) {
2982 PdbPointer = FileName;
2985 WriteMapFile (FvMapFile, PdbPointer, (EFI_GUID *) FfsFile, NewPe32BaseAddress, &OrigImageContext);
2988 if (FfsFile->Type != EFI_FV_FILETYPE_SECURITY_CORE &&
2989 FfsFile->Type != EFI_FV_FILETYPE_PEI_CORE &&
2990 FfsFile->Type != EFI_FV_FILETYPE_PEIM &&
2991 FfsFile->Type != EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER
2994 // Only Peim code may have a TE section
2996 return EFI_SUCCESS;
3000 // Now process TE sections
3002 for (Index = 1;; Index++) {
3003 NewPe32BaseAddress = 0;
3006 // Find Te Image
3008 Status = GetSectionByType (FfsFile, EFI_SECTION_TE, Index, &CurrentPe32Section);
3009 if (EFI_ERROR (Status)) {
3010 break;
3014 // Calculate the TE base address, the FFS file base plus the offset of the TE section less the size stripped off
3015 // by GenTEImage
3017 TEImageHeader = (EFI_TE_IMAGE_HEADER *) ((UINT8 *) CurrentPe32Section.Pe32Section + sizeof (EFI_COMMON_SECTION_HEADER));
3020 // Initialize context, load image info.
3022 memset (&ImageContext, 0, sizeof (ImageContext));
3023 ImageContext.Handle = (VOID *) TEImageHeader;
3024 ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) FfsRebaseImageRead;
3025 Status = PeCoffLoaderGetImageInfo (&ImageContext);
3026 if (EFI_ERROR (Status)) {
3027 Error (NULL, 0, 3000, "Invalid TeImage", "The input file is %s and the return status is %x", FileName, (int) Status);
3028 return Status;
3031 if (ImageContext.Machine == EFI_IMAGE_MACHINE_ARMT) {
3032 mArm = TRUE;
3036 // Keep Image Context for TE image in FV
3038 memcpy (&OrigImageContext, &ImageContext, sizeof (ImageContext));
3041 // Get File PdbPointer
3043 PdbPointer = PeCoffLoaderGetPdbPointer (ImageContext.Handle);
3045 if ((Flags & REBASE_XIP_FILE) == 0) {
3047 // For none XIP PEIM module, their map info also are collected.
3049 goto WriteTeMap;
3053 // Set new rebased address.
3055 NewPe32BaseAddress = XipBase + (UINTN) TEImageHeader + sizeof (EFI_TE_IMAGE_HEADER) \
3056 - TEImageHeader->StrippedSize - (UINTN) FfsFile;
3059 // if reloc is stripped, try to get the original efi image to get reloc info.
3061 if (ImageContext.RelocationsStripped == TRUE) {
3063 // Construct the original efi file name
3065 strcpy (PeFileName, FileName);
3066 Cptr = PeFileName + strlen (PeFileName);
3067 while (*Cptr != '.') {
3068 Cptr --;
3071 if (*Cptr != '.') {
3072 Error (NULL, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName);
3073 return EFI_ABORTED;
3074 } else {
3075 *(Cptr + 1) = 'e';
3076 *(Cptr + 2) = 'f';
3077 *(Cptr + 3) = 'i';
3078 *(Cptr + 4) = '\0';
3081 PeFile = fopen (PeFileName, "rb");
3082 if (PeFile == NULL) {
3083 Warning (NULL, 0, 0, "Invalid", "The file %s has no .reloc section.", FileName);
3084 //Error (NULL, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName);
3085 //return EFI_ABORTED;
3086 } else {
3088 // Get the file size
3090 PeFileSize = _filelength (fileno (PeFile));
3091 PeFileBuffer = (UINT8 *) malloc (PeFileSize);
3092 if (PeFileBuffer == NULL) {
3093 Error (NULL, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName);
3094 return EFI_OUT_OF_RESOURCES;
3097 // Read Pe File
3099 fread (PeFileBuffer, sizeof (UINT8), PeFileSize, PeFile);
3101 // close file
3103 fclose (PeFile);
3105 // Append reloc section into TeImage
3107 ImageContext.Handle = PeFileBuffer;
3108 Status = PeCoffLoaderGetImageInfo (&ImageContext);
3109 if (EFI_ERROR (Status)) {
3110 Error (NULL, 0, 3000, "Invalid TeImage", "The input file is %s and the return status is %x", FileName, (int) Status);
3111 return Status;
3113 ImageContext.RelocationsStripped = FALSE;
3118 // Relocation exist and rebase
3120 if (!ImageContext.RelocationsStripped) {
3122 // Load and Relocate Image Data
3124 MemoryImagePointer = (UINT8 *) malloc ((UINTN) ImageContext.ImageSize + ImageContext.SectionAlignment);
3125 if (MemoryImagePointer == NULL) {
3126 Error (NULL, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName);
3127 return EFI_OUT_OF_RESOURCES;
3129 memset ((VOID *) MemoryImagePointer, 0, (UINTN) ImageContext.ImageSize + ImageContext.SectionAlignment);
3130 ImageContext.ImageAddress = ((UINTN) MemoryImagePointer + ImageContext.SectionAlignment - 1) & (~(ImageContext.SectionAlignment - 1));
3132 Status = PeCoffLoaderLoadImage (&ImageContext);
3133 if (EFI_ERROR (Status)) {
3134 Error (NULL, 0, 3000, "Invalid", "LocateImage() call failed on rebase of %s", FileName);
3135 free ((VOID *) MemoryImagePointer);
3136 return Status;
3139 // Reloacate TeImage
3141 ImageContext.DestinationAddress = NewPe32BaseAddress;
3142 Status = PeCoffLoaderRelocateImage (&ImageContext);
3143 if (EFI_ERROR (Status)) {
3144 Error (NULL, 0, 3000, "Invalid", "RelocateImage() call failed on rebase of TE image %s", FileName);
3145 free ((VOID *) MemoryImagePointer);
3146 return Status;
3150 // Copy the relocated image into raw image file.
3152 SectionHeader = (EFI_IMAGE_SECTION_HEADER *) (TEImageHeader + 1);
3153 for (Index = 0; Index < TEImageHeader->NumberOfSections; Index ++, SectionHeader ++) {
3154 if (!ImageContext.IsTeImage) {
3155 CopyMem (
3156 (UINT8 *) TEImageHeader + sizeof (EFI_TE_IMAGE_HEADER) - TEImageHeader->StrippedSize + SectionHeader->PointerToRawData,
3157 (VOID*) (UINTN) (ImageContext.ImageAddress + SectionHeader->VirtualAddress),
3158 SectionHeader->SizeOfRawData
3160 } else {
3161 CopyMem (
3162 (UINT8 *) TEImageHeader + sizeof (EFI_TE_IMAGE_HEADER) - TEImageHeader->StrippedSize + SectionHeader->PointerToRawData,
3163 (VOID*) (UINTN) (ImageContext.ImageAddress + sizeof (EFI_TE_IMAGE_HEADER) - TEImageHeader->StrippedSize + SectionHeader->VirtualAddress),
3164 SectionHeader->SizeOfRawData
3170 // Free the allocated memory resource
3172 free ((VOID *) MemoryImagePointer);
3173 MemoryImagePointer = NULL;
3174 if (PeFileBuffer != NULL) {
3175 free (PeFileBuffer);
3176 PeFileBuffer = NULL;
3181 // Update Image Base Address
3183 TEImageHeader->ImageBase = NewPe32BaseAddress;
3186 // Now update file checksum
3188 if (FfsFile->Attributes & FFS_ATTRIB_CHECKSUM) {
3189 SavedState = FfsFile->State;
3190 FfsFile->IntegrityCheck.Checksum.File = 0;
3191 FfsFile->State = 0;
3192 if (FfsFile->Attributes & FFS_ATTRIB_CHECKSUM) {
3193 FfsFile->IntegrityCheck.Checksum.File = CalculateChecksum8 (
3194 (UINT8 *) FfsFile,
3195 GetLength (FfsFile->Size)
3197 } else {
3198 FfsFile->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;
3201 FfsFile->State = SavedState;
3204 // Get this module function address from ModulePeMapFile and add them into FvMap file
3206 WriteTeMap:
3208 // Default use FileName as map file path
3210 if (PdbPointer == NULL) {
3211 PdbPointer = FileName;
3214 WriteMapFile (
3215 FvMapFile,
3216 PdbPointer,
3217 (EFI_GUID *) FfsFile,
3218 NewPe32BaseAddress,
3219 &OrigImageContext
3223 return EFI_SUCCESS;
3226 EFI_STATUS
3227 FindApResetVectorPosition (
3228 IN MEMORY_FILE *FvImage,
3229 OUT UINT8 **Pointer
3231 /*++
3233 Routine Description:
3235 Find the position in this FvImage to place Ap reset vector.
3237 Arguments:
3239 FvImage Memory file for the FV memory image.
3240 Pointer Pointer to pointer to position.
3242 Returns:
3244 EFI_NOT_FOUND - No satisfied position is found.
3245 EFI_SUCCESS - The suitable position is return.
3247 --*/
3249 EFI_FFS_FILE_HEADER *PadFile;
3250 UINT32 Index;
3251 EFI_STATUS Status;
3252 UINT8 *FixPoint;
3253 UINT32 FileLength;
3255 for (Index = 1; ;Index ++) {
3257 // Find Pad File to add ApResetVector info
3259 Status = GetFileByType (EFI_FV_FILETYPE_FFS_PAD, Index, &PadFile);
3260 if (EFI_ERROR (Status) || (PadFile == NULL)) {
3262 // No Pad file to be found.
3264 break;
3267 // Get Pad file size.
3269 FileLength = (*(UINT32 *)(PadFile->Size)) & 0x00FFFFFF;
3270 FileLength = (FileLength + EFI_FFS_FILE_HEADER_ALIGNMENT - 1) & ~(EFI_FFS_FILE_HEADER_ALIGNMENT - 1);
3272 // FixPoint must be align on 0x1000 relative to FvImage Header
3274 FixPoint = (UINT8*) PadFile + sizeof (EFI_FFS_FILE_HEADER);
3275 FixPoint = FixPoint + 0x1000 - (((UINTN) FixPoint - (UINTN) FvImage->FileImage) & 0xFFF);
3277 // FixPoint be larger at the last place of one fv image.
3279 while (((UINTN) FixPoint + SIZEOF_STARTUP_DATA_ARRAY - (UINTN) PadFile) <= FileLength) {
3280 FixPoint += 0x1000;
3282 FixPoint -= 0x1000;
3284 if ((UINTN) FixPoint < ((UINTN) PadFile + sizeof (EFI_FFS_FILE_HEADER))) {
3286 // No alignment FixPoint in this Pad File.
3288 continue;
3291 if ((UINTN) FvImage->Eof - (UINTN)FixPoint <= 0x20000) {
3293 // Find the position to place ApResetVector
3295 *Pointer = FixPoint;
3296 return EFI_SUCCESS;
3300 return EFI_NOT_FOUND;
3303 EFI_STATUS
3304 ParseCapInf (
3305 IN MEMORY_FILE *InfFile,
3306 OUT CAP_INFO *CapInfo
3308 /*++
3310 Routine Description:
3312 This function parses a Cap.INF file and copies info into a CAP_INFO structure.
3314 Arguments:
3316 InfFile Memory file image.
3317 CapInfo Information read from INF file.
3319 Returns:
3321 EFI_SUCCESS INF file information successfully retrieved.
3322 EFI_ABORTED INF file has an invalid format.
3323 EFI_NOT_FOUND A required string was not found in the INF file.
3324 --*/
3326 CHAR8 Value[_MAX_PATH];
3327 UINT64 Value64;
3328 UINTN Index, Number;
3329 EFI_STATUS Status;
3332 // Initialize Cap info
3334 // memset (CapInfo, 0, sizeof (CAP_INFO));
3338 // Read the Capsule Guid
3340 Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_CAPSULE_GUID_STRING, 0, Value);
3341 if (Status == EFI_SUCCESS) {
3343 // Get the Capsule Guid
3345 Status = StringToGuid (Value, &CapInfo->CapGuid);
3346 if (EFI_ERROR (Status)) {
3347 Error (NULL, 0, 2000, "Invalid parameter", "%s = %s", EFI_CAPSULE_GUID_STRING, Value);
3348 return EFI_ABORTED;
3350 DebugMsg (NULL, 0, 9, "Capsule Guid", "%s = %s", EFI_CAPSULE_GUID_STRING, Value);
3354 // Read the Capsule Header Size
3356 Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_CAPSULE_HEADER_SIZE_STRING, 0, Value);
3357 if (Status == EFI_SUCCESS) {
3358 Status = AsciiStringToUint64 (Value, FALSE, &Value64);
3359 if (EFI_ERROR (Status)) {
3360 Error (NULL, 0, 2000, "Invalid parameter", "%s = %s", EFI_CAPSULE_HEADER_SIZE_STRING, Value);
3361 return EFI_ABORTED;
3363 CapInfo->HeaderSize = (UINT32) Value64;
3364 DebugMsg (NULL, 0, 9, "Capsule Header size", "%s = %s", EFI_CAPSULE_HEADER_SIZE_STRING, Value);
3368 // Read the Capsule Flag
3370 Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_CAPSULE_FLAGS_STRING, 0, Value);
3371 if (Status == EFI_SUCCESS) {
3372 if (strstr (Value, "PopulateSystemTable") != NULL) {
3373 CapInfo->Flags |= CAPSULE_FLAGS_PERSIST_ACROSS_RESET | CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE;
3374 if (strstr (Value, "InitiateReset") != NULL) {
3375 CapInfo->Flags |= CAPSULE_FLAGS_INITIATE_RESET;
3377 } else if (strstr (Value, "PersistAcrossReset") != NULL) {
3378 CapInfo->Flags |= CAPSULE_FLAGS_PERSIST_ACROSS_RESET;
3379 if (strstr (Value, "InitiateReset") != NULL) {
3380 CapInfo->Flags |= CAPSULE_FLAGS_INITIATE_RESET;
3382 } else {
3383 Error (NULL, 0, 2000, "Invalid parameter", "invalid Flag setting for %s.", EFI_CAPSULE_FLAGS_STRING);
3384 return EFI_ABORTED;
3386 DebugMsg (NULL, 0, 9, "Capsule Flag", Value);
3390 // Read Capsule File name
3392 Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_FILE_NAME_STRING, 0, Value);
3393 if (Status == EFI_SUCCESS) {
3395 // Get output file name
3397 strcpy (CapInfo->CapName, Value);
3401 // Read the Capsule FileImage
3403 Number = 0;
3404 for (Index = 0; Index < MAX_NUMBER_OF_FILES_IN_CAP; Index++) {
3405 if (CapInfo->CapFiles[Index][0] != '\0') {
3406 continue;
3409 // Read the capsule file name
3411 Status = FindToken (InfFile, FILES_SECTION_STRING, EFI_FILE_NAME_STRING, Number++, Value);
3413 if (Status == EFI_SUCCESS) {
3415 // Add the file
3417 strcpy (CapInfo->CapFiles[Index], Value);
3418 DebugMsg (NULL, 0, 9, "Capsule component file", "the %uth file name is %s", (unsigned) Index, CapInfo->CapFiles[Index]);
3419 } else {
3420 break;
3424 if (Index == 0) {
3425 Warning (NULL, 0, 0, "Capsule components are not specified.", NULL);
3428 return EFI_SUCCESS;
3431 EFI_STATUS
3432 GenerateCapImage (
3433 IN CHAR8 *InfFileImage,
3434 IN UINTN InfFileSize,
3435 IN CHAR8 *CapFileName
3437 /*++
3439 Routine Description:
3441 This is the main function which will be called from application to create UEFI Capsule image.
3443 Arguments:
3445 InfFileImage Buffer containing the INF file contents.
3446 InfFileSize Size of the contents of the InfFileImage buffer.
3447 CapFileName Requested name for the Cap file.
3449 Returns:
3451 EFI_SUCCESS Function completed successfully.
3452 EFI_OUT_OF_RESOURCES Could not allocate required resources.
3453 EFI_ABORTED Error encountered.
3454 EFI_INVALID_PARAMETER A required parameter was NULL.
3456 --*/
3458 UINT32 CapSize;
3459 UINT8 *CapBuffer;
3460 EFI_CAPSULE_HEADER *CapsuleHeader;
3461 MEMORY_FILE InfMemoryFile;
3462 UINT32 FileSize;
3463 UINT32 Index;
3464 FILE *fpin, *fpout;
3465 EFI_STATUS Status;
3467 if (InfFileImage != NULL) {
3469 // Initialize file structures
3471 InfMemoryFile.FileImage = InfFileImage;
3472 InfMemoryFile.CurrentFilePointer = InfFileImage;
3473 InfMemoryFile.Eof = InfFileImage + InfFileSize;
3476 // Parse the Cap inf file for header information
3478 Status = ParseCapInf (&InfMemoryFile, &mCapDataInfo);
3479 if (Status != EFI_SUCCESS) {
3480 return Status;
3484 if (mCapDataInfo.HeaderSize == 0) {
3486 // make header size align 16 bytes.
3488 mCapDataInfo.HeaderSize = sizeof (EFI_CAPSULE_HEADER);
3489 mCapDataInfo.HeaderSize = (mCapDataInfo.HeaderSize + 0xF) & ~0xF;
3492 if (mCapDataInfo.HeaderSize < sizeof (EFI_CAPSULE_HEADER)) {
3493 Error (NULL, 0, 2000, "Invalid parameter", "The specified HeaderSize cannot be less than the size of EFI_CAPSULE_HEADER.");
3494 return EFI_INVALID_PARAMETER;
3497 if (CapFileName == NULL && mCapDataInfo.CapName[0] != '\0') {
3498 CapFileName = mCapDataInfo.CapName;
3501 if (CapFileName == NULL) {
3502 Error (NULL, 0, 2001, "Missing required argument", "Output Capsule file name");
3503 return EFI_INVALID_PARAMETER;
3507 // Set Default Capsule Guid value
3509 if (CompareGuid (&mCapDataInfo.CapGuid, &mZeroGuid) == 0) {
3510 memcpy (&mCapDataInfo.CapGuid, &mDefaultCapsuleGuid, sizeof (EFI_GUID));
3513 // Calculate the size of capsule image.
3515 Index = 0;
3516 FileSize = 0;
3517 CapSize = mCapDataInfo.HeaderSize;
3518 while (mCapDataInfo.CapFiles [Index][0] != '\0') {
3519 fpin = fopen (mCapDataInfo.CapFiles[Index], "rb");
3520 if (fpin == NULL) {
3521 Error (NULL, 0, 0001, "Error opening file", mCapDataInfo.CapFiles[Index]);
3522 return EFI_ABORTED;
3524 FileSize = _filelength (fileno (fpin));
3525 CapSize += FileSize;
3526 fclose (fpin);
3527 Index ++;
3531 // Allocate buffer for capsule image.
3533 CapBuffer = (UINT8 *) malloc (CapSize);
3534 if (CapBuffer == NULL) {
3535 Error (NULL, 0, 4001, "Resource", "memory cannot be allocated for creating the capsule.");
3536 return EFI_OUT_OF_RESOURCES;
3540 // Initialize the capsule header to zero
3542 memset (CapBuffer, 0, mCapDataInfo.HeaderSize);
3545 // create capsule header and get capsule body
3547 CapsuleHeader = (EFI_CAPSULE_HEADER *) CapBuffer;
3548 memcpy (&CapsuleHeader->CapsuleGuid, &mCapDataInfo.CapGuid, sizeof (EFI_GUID));
3549 CapsuleHeader->HeaderSize = mCapDataInfo.HeaderSize;
3550 CapsuleHeader->Flags = mCapDataInfo.Flags;
3551 CapsuleHeader->CapsuleImageSize = CapSize;
3553 Index = 0;
3554 FileSize = 0;
3555 CapSize = CapsuleHeader->HeaderSize;
3556 while (mCapDataInfo.CapFiles [Index][0] != '\0') {
3557 fpin = fopen (mCapDataInfo.CapFiles[Index], "rb");
3558 if (fpin == NULL) {
3559 Error (NULL, 0, 0001, "Error opening file", mCapDataInfo.CapFiles[Index]);
3560 free (CapBuffer);
3561 return EFI_ABORTED;
3563 FileSize = _filelength (fileno (fpin));
3564 fread (CapBuffer + CapSize, 1, FileSize, fpin);
3565 fclose (fpin);
3566 Index ++;
3567 CapSize += FileSize;
3571 // write capsule data into the output file
3573 fpout = fopen (CapFileName, "wb");
3574 if (fpout == NULL) {
3575 Error (NULL, 0, 0001, "Error opening file", CapFileName);
3576 free (CapBuffer);
3577 return EFI_ABORTED;
3580 fwrite (CapBuffer, 1, CapSize, fpout);
3581 fclose (fpout);
3583 VerboseMsg ("The size of the generated capsule image is %u bytes", (unsigned) CapSize);
3585 return EFI_SUCCESS;