• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /** @file
2 This file contains the internal functions required to generate a Firmware Volume.
3 
4 Copyright (c) 2004 - 2016, Intel Corporation. All rights reserved.<BR>
5 Portions Copyright (c) 2011 - 2013, ARM Ltd. All rights reserved.<BR>
6 Portions Copyright (c) 2016 HP Development Company, L.P.<BR>
7 This program and the accompanying materials
8 are licensed and made available under the terms and conditions of the BSD License
9 which accompanies this distribution.  The full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
11 
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14 
15 **/
16 
17 //
18 // Include files
19 //
20 
21 #if defined(__FreeBSD__)
22 #include <uuid.h>
23 #elif defined(__GNUC__)
24 #include <uuid/uuid.h>
25 #endif
26 #ifdef __GNUC__
27 #include <sys/stat.h>
28 #endif
29 #include <string.h>
30 #ifndef __GNUC__
31 #include <io.h>
32 #endif
33 #include <assert.h>
34 
35 #include <Guid/FfsSectionAlignmentPadding.h>
36 
37 #include "GenFvInternalLib.h"
38 #include "FvLib.h"
39 #include "PeCoffLib.h"
40 #include "WinNtInclude.h"
41 
42 #define ARMT_UNCONDITIONAL_JUMP_INSTRUCTION       0xEB000000
43 #define ARM64_UNCONDITIONAL_JUMP_INSTRUCTION      0x14000000
44 
45 BOOLEAN mArm = FALSE;
46 STATIC UINT32   MaxFfsAlignment = 0;
47 
48 EFI_GUID  mEfiFirmwareVolumeTopFileGuid       = EFI_FFS_VOLUME_TOP_FILE_GUID;
49 EFI_GUID  mFileGuidArray [MAX_NUMBER_OF_FILES_IN_FV];
50 EFI_GUID  mZeroGuid                           = {0x0, 0x0, 0x0, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}};
51 EFI_GUID  mDefaultCapsuleGuid                 = {0x3B6686BD, 0x0D76, 0x4030, { 0xB7, 0x0E, 0xB5, 0x51, 0x9E, 0x2F, 0xC5, 0xA0 }};
52 EFI_GUID  mEfiFfsSectionAlignmentPaddingGuid  = EFI_FFS_SECTION_ALIGNMENT_PADDING_GUID;
53 
54 CHAR8      *mFvbAttributeName[] = {
55   EFI_FVB2_READ_DISABLED_CAP_STRING,
56   EFI_FVB2_READ_ENABLED_CAP_STRING,
57   EFI_FVB2_READ_STATUS_STRING,
58   EFI_FVB2_WRITE_DISABLED_CAP_STRING,
59   EFI_FVB2_WRITE_ENABLED_CAP_STRING,
60   EFI_FVB2_WRITE_STATUS_STRING,
61   EFI_FVB2_LOCK_CAP_STRING,
62   EFI_FVB2_LOCK_STATUS_STRING,
63   NULL,
64   EFI_FVB2_STICKY_WRITE_STRING,
65   EFI_FVB2_MEMORY_MAPPED_STRING,
66   EFI_FVB2_ERASE_POLARITY_STRING,
67   EFI_FVB2_READ_LOCK_CAP_STRING,
68   EFI_FVB2_READ_LOCK_STATUS_STRING,
69   EFI_FVB2_WRITE_LOCK_CAP_STRING,
70   EFI_FVB2_WRITE_LOCK_STATUS_STRING
71 };
72 
73 CHAR8      *mFvbAlignmentName[] = {
74   EFI_FVB2_ALIGNMENT_1_STRING,
75   EFI_FVB2_ALIGNMENT_2_STRING,
76   EFI_FVB2_ALIGNMENT_4_STRING,
77   EFI_FVB2_ALIGNMENT_8_STRING,
78   EFI_FVB2_ALIGNMENT_16_STRING,
79   EFI_FVB2_ALIGNMENT_32_STRING,
80   EFI_FVB2_ALIGNMENT_64_STRING,
81   EFI_FVB2_ALIGNMENT_128_STRING,
82   EFI_FVB2_ALIGNMENT_256_STRING,
83   EFI_FVB2_ALIGNMENT_512_STRING,
84   EFI_FVB2_ALIGNMENT_1K_STRING,
85   EFI_FVB2_ALIGNMENT_2K_STRING,
86   EFI_FVB2_ALIGNMENT_4K_STRING,
87   EFI_FVB2_ALIGNMENT_8K_STRING,
88   EFI_FVB2_ALIGNMENT_16K_STRING,
89   EFI_FVB2_ALIGNMENT_32K_STRING,
90   EFI_FVB2_ALIGNMENT_64K_STRING,
91   EFI_FVB2_ALIGNMENT_128K_STRING,
92   EFI_FVB2_ALIGNMENT_256K_STRING,
93   EFI_FVB2_ALIGNMENT_512K_STRING,
94   EFI_FVB2_ALIGNMENT_1M_STRING,
95   EFI_FVB2_ALIGNMENT_2M_STRING,
96   EFI_FVB2_ALIGNMENT_4M_STRING,
97   EFI_FVB2_ALIGNMENT_8M_STRING,
98   EFI_FVB2_ALIGNMENT_16M_STRING,
99   EFI_FVB2_ALIGNMENT_32M_STRING,
100   EFI_FVB2_ALIGNMENT_64M_STRING,
101   EFI_FVB2_ALIGNMENT_128M_STRING,
102   EFI_FVB2_ALIGNMENT_256M_STRING,
103   EFI_FVB2_ALIGNMENT_512M_STRING,
104   EFI_FVB2_ALIGNMENT_1G_STRING,
105   EFI_FVB2_ALIGNMENT_2G_STRING
106 };
107 
108 //
109 // This data array will be located at the base of the Firmware Volume Header (FVH)
110 // in the boot block.  It must not exceed 14 bytes of code.  The last 2 bytes
111 // will be used to keep the FVH checksum consistent.
112 // This code will be run in response to a starutp IPI for HT-enabled systems.
113 //
114 #define SIZEOF_STARTUP_DATA_ARRAY 0x10
115 
116 UINT8                                   m128kRecoveryStartupApDataArray[SIZEOF_STARTUP_DATA_ARRAY] = {
117   //
118   // EA D0 FF 00 F0               ; far jmp F000:FFD0
119   // 0, 0, 0, 0, 0, 0, 0, 0, 0,   ; Reserved bytes
120   // 0, 0                         ; Checksum Padding
121   //
122   0xEA,
123   0xD0,
124   0xFF,
125   0x0,
126   0xF0,
127   0x00,
128   0x00,
129   0x00,
130   0x00,
131   0x00,
132   0x00,
133   0x00,
134   0x00,
135   0x00,
136   0x00,
137   0x00
138 };
139 
140 UINT8                                   m64kRecoveryStartupApDataArray[SIZEOF_STARTUP_DATA_ARRAY] = {
141   //
142   // EB CE                               ; jmp short ($-0x30)
143   // ; (from offset 0x0 to offset 0xFFD0)
144   // 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ; Reserved bytes
145   // 0, 0                                ; Checksum Padding
146   //
147   0xEB,
148   0xCE,
149   0x00,
150   0x00,
151   0x00,
152   0x00,
153   0x00,
154   0x00,
155   0x00,
156   0x00,
157   0x00,
158   0x00,
159   0x00,
160   0x00,
161   0x00,
162   0x00
163 };
164 
165 FV_INFO                     mFvDataInfo;
166 CAP_INFO                    mCapDataInfo;
167 BOOLEAN                     mIsLargeFfs = FALSE;
168 
169 EFI_PHYSICAL_ADDRESS mFvBaseAddress[0x10];
170 UINT32               mFvBaseAddressNumber = 0;
171 
172 EFI_STATUS
ParseFvInf(IN MEMORY_FILE * InfFile,OUT FV_INFO * FvInfo)173 ParseFvInf (
174   IN  MEMORY_FILE  *InfFile,
175   OUT FV_INFO      *FvInfo
176   )
177 /*++
178 
179 Routine Description:
180 
181   This function parses a FV.INF file and copies info into a FV_INFO structure.
182 
183 Arguments:
184 
185   InfFile         Memory file image.
186   FvInfo          Information read from INF file.
187 
188 Returns:
189 
190   EFI_SUCCESS       INF file information successfully retrieved.
191   EFI_ABORTED       INF file has an invalid format.
192   EFI_NOT_FOUND     A required string was not found in the INF file.
193 --*/
194 {
195   CHAR8       Value[MAX_LONG_FILE_PATH];
196   UINT64      Value64;
197   UINTN       Index;
198   UINTN       Number;
199   EFI_STATUS  Status;
200   EFI_GUID    GuidValue;
201 
202   //
203   // Read the FV base address
204   //
205   if (!mFvDataInfo.BaseAddressSet) {
206     Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_FV_BASE_ADDRESS_STRING, 0, Value);
207     if (Status == EFI_SUCCESS) {
208       //
209       // Get the base address
210       //
211       Status = AsciiStringToUint64 (Value, FALSE, &Value64);
212       if (EFI_ERROR (Status)) {
213         Error (NULL, 0, 2000, "Invalid parameter", "%s = %s", EFI_FV_BASE_ADDRESS_STRING, Value);
214         return EFI_ABORTED;
215       }
216       DebugMsg (NULL, 0, 9, "rebase address", "%s = %s", EFI_FV_BASE_ADDRESS_STRING, Value);
217 
218       FvInfo->BaseAddress = Value64;
219       FvInfo->BaseAddressSet = TRUE;
220     }
221   }
222 
223   //
224   // Read the FV File System Guid
225   //
226   if (!FvInfo->FvFileSystemGuidSet) {
227     Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_FV_FILESYSTEMGUID_STRING, 0, Value);
228     if (Status == EFI_SUCCESS) {
229       //
230       // Get the guid value
231       //
232       Status = StringToGuid (Value, &GuidValue);
233       if (EFI_ERROR (Status)) {
234         Error (NULL, 0, 2000, "Invalid parameter", "%s = %s", EFI_FV_FILESYSTEMGUID_STRING, Value);
235         return EFI_ABORTED;
236       }
237       memcpy (&FvInfo->FvFileSystemGuid, &GuidValue, sizeof (EFI_GUID));
238       FvInfo->FvFileSystemGuidSet = TRUE;
239     }
240   }
241 
242   //
243   // Read the FV Extension Header File Name
244   //
245   Status = FindToken (InfFile, ATTRIBUTES_SECTION_STRING, EFI_FV_EXT_HEADER_FILE_NAME, 0, Value);
246   if (Status == EFI_SUCCESS) {
247     strcpy (FvInfo->FvExtHeaderFile, Value);
248   }
249 
250   //
251   // Read the FV file name
252   //
253   Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_FV_FILE_NAME_STRING, 0, Value);
254   if (Status == EFI_SUCCESS) {
255     //
256     // copy the file name
257     //
258     strcpy (FvInfo->FvName, Value);
259   }
260 
261   //
262   // Read Fv Attribute
263   //
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;
272       }
273     }
274   }
275 
276   //
277   // Read Fv Alignment
278   //
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;
285       }
286     }
287   }
288 
289   //
290   // Read weak alignment flag
291   //
292   Status = FindToken (InfFile, ATTRIBUTES_SECTION_STRING, EFI_FV_WEAK_ALIGNMENT_STRING, 0, Value);
293   if (Status == EFI_SUCCESS) {
294     if ((strcmp (Value, TRUE_STRING) == 0) || (strcmp (Value, ONE_STRING) == 0)) {
295       FvInfo->FvAttributes |= EFI_FVB2_WEAK_ALIGNMENT;
296     } else if ((strcmp (Value, FALSE_STRING) != 0) && (strcmp (Value, ZERO_STRING) != 0)) {
297       Error (NULL, 0, 2000, "Invalid parameter", "Weak alignment value expected one of TRUE, FALSE, 1 or 0.");
298       return EFI_ABORTED;
299     }
300   }
301 
302   //
303   // Read block maps
304   //
305   for (Index = 0; Index < MAX_NUMBER_OF_FV_BLOCKS; Index++) {
306     if (FvInfo->FvBlocks[Index].Length == 0) {
307       //
308       // Read block size
309       //
310       Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_BLOCK_SIZE_STRING, Index, Value);
311 
312       if (Status == EFI_SUCCESS) {
313         //
314         // Update the size of block
315         //
316         Status = AsciiStringToUint64 (Value, FALSE, &Value64);
317         if (EFI_ERROR (Status)) {
318           Error (NULL, 0, 2000, "Invalid parameter", "%s = %s", EFI_BLOCK_SIZE_STRING, Value);
319           return EFI_ABORTED;
320         }
321 
322         FvInfo->FvBlocks[Index].Length = (UINT32) Value64;
323         DebugMsg (NULL, 0, 9, "FV Block Size", "%s = %s", EFI_BLOCK_SIZE_STRING, Value);
324       } else {
325         //
326         // If there is no blocks size, but there is the number of block, then we have a mismatched pair
327         // and should return an error.
328         //
329         Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_NUM_BLOCKS_STRING, Index, Value);
330         if (!EFI_ERROR (Status)) {
331           Error (NULL, 0, 2000, "Invalid parameter", "both %s and %s must be specified.", EFI_NUM_BLOCKS_STRING, EFI_BLOCK_SIZE_STRING);
332           return EFI_ABORTED;
333         } else {
334           //
335           // We are done
336           //
337           break;
338         }
339       }
340 
341       //
342       // Read blocks number
343       //
344       Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_NUM_BLOCKS_STRING, Index, Value);
345 
346       if (Status == EFI_SUCCESS) {
347         //
348         // Update the number of blocks
349         //
350         Status = AsciiStringToUint64 (Value, FALSE, &Value64);
351         if (EFI_ERROR (Status)) {
352           Error (NULL, 0, 2000, "Invalid parameter", "%s = %s", EFI_NUM_BLOCKS_STRING, Value);
353           return EFI_ABORTED;
354         }
355 
356         FvInfo->FvBlocks[Index].NumBlocks = (UINT32) Value64;
357         DebugMsg (NULL, 0, 9, "FV Block Number", "%s = %s", EFI_NUM_BLOCKS_STRING, Value);
358       }
359     }
360   }
361 
362   if (Index == 0) {
363     Error (NULL, 0, 2001, "Missing required argument", "block size.");
364     return EFI_ABORTED;
365   }
366 
367   //
368   // Read files
369   //
370   Number = 0;
371   for (Number = 0; Number < MAX_NUMBER_OF_FILES_IN_FV; Number ++) {
372     if (FvInfo->FvFiles[Number][0] == '\0') {
373       break;
374     }
375   }
376 
377   for (Index = 0; Number + Index < MAX_NUMBER_OF_FILES_IN_FV; Index++) {
378     //
379     // Read the FFS file list
380     //
381     Status = FindToken (InfFile, FILES_SECTION_STRING, EFI_FILE_NAME_STRING, Index, Value);
382 
383     if (Status == EFI_SUCCESS) {
384       //
385       // Add the file
386       //
387       strcpy (FvInfo->FvFiles[Number + Index], Value);
388       DebugMsg (NULL, 0, 9, "FV component file", "the %uth name is %s", (unsigned) Index, Value);
389     } else {
390       break;
391     }
392   }
393 
394   if ((Index + Number) == 0) {
395     Warning (NULL, 0, 0, "FV components are not specified.", NULL);
396   }
397 
398   return EFI_SUCCESS;
399 }
400 
401 VOID
UpdateFfsFileState(IN EFI_FFS_FILE_HEADER * FfsFile,IN EFI_FIRMWARE_VOLUME_HEADER * FvHeader)402 UpdateFfsFileState (
403   IN EFI_FFS_FILE_HEADER          *FfsFile,
404   IN EFI_FIRMWARE_VOLUME_HEADER   *FvHeader
405   )
406 /*++
407 
408 Routine Description:
409 
410   This function changes the FFS file attributes based on the erase polarity
411   of the FV. Update the reserved bits of State to EFI_FVB2_ERASE_POLARITY.
412 
413 Arguments:
414 
415   FfsFile   File header.
416   FvHeader  FV header.
417 
418 Returns:
419 
420   None
421 
422 --*/
423 {
424   if (FvHeader->Attributes & EFI_FVB2_ERASE_POLARITY) {
425     FfsFile->State = (UINT8)~(FfsFile->State);
426     // FfsFile->State |= ~(UINT8) EFI_FILE_ALL_STATE_BITS;
427   }
428 }
429 
430 EFI_STATUS
ReadFfsAlignment(IN EFI_FFS_FILE_HEADER * FfsFile,IN OUT UINT32 * Alignment)431 ReadFfsAlignment (
432   IN EFI_FFS_FILE_HEADER    *FfsFile,
433   IN OUT UINT32             *Alignment
434   )
435 /*++
436 
437 Routine Description:
438 
439   This function determines the alignment of the FFS input file from the file
440   attributes.
441 
442 Arguments:
443 
444   FfsFile       FFS file to parse
445   Alignment     The minimum required alignment offset of the FFS file
446 
447 Returns:
448 
449   EFI_SUCCESS              The function completed successfully.
450   EFI_INVALID_PARAMETER    One of the input parameters was invalid.
451   EFI_ABORTED              An error occurred.
452 
453 --*/
454 {
455   //
456   // Verify input parameters.
457   //
458   if (FfsFile == NULL || Alignment == NULL) {
459     return EFI_INVALID_PARAMETER;
460   }
461 
462   switch ((FfsFile->Attributes >> 3) & 0x07) {
463 
464   case 0:
465     //
466     // 1 byte alignment
467     //
468     *Alignment = 0;
469     break;
470 
471   case 1:
472     //
473     // 16 byte alignment
474     //
475     *Alignment = 4;
476     break;
477 
478   case 2:
479     //
480     // 128 byte alignment
481     //
482     *Alignment = 7;
483     break;
484 
485   case 3:
486     //
487     // 512 byte alignment
488     //
489     *Alignment = 9;
490     break;
491 
492   case 4:
493     //
494     // 1K byte alignment
495     //
496     *Alignment = 10;
497     break;
498 
499   case 5:
500     //
501     // 4K byte alignment
502     //
503     *Alignment = 12;
504     break;
505 
506   case 6:
507     //
508     // 32K byte alignment
509     //
510     *Alignment = 15;
511     break;
512 
513   case 7:
514     //
515     // 64K byte alignment
516     //
517     *Alignment = 16;
518     break;
519 
520   default:
521     break;
522   }
523 
524   return EFI_SUCCESS;
525 }
526 
527 EFI_STATUS
AddPadFile(IN OUT MEMORY_FILE * FvImage,IN UINT32 DataAlignment,IN VOID * FvEnd,IN EFI_FIRMWARE_VOLUME_EXT_HEADER * ExtHeader,IN UINT32 NextFfsSize)528 AddPadFile (
529   IN OUT MEMORY_FILE  *FvImage,
530   IN UINT32           DataAlignment,
531   IN VOID             *FvEnd,
532   IN EFI_FIRMWARE_VOLUME_EXT_HEADER *ExtHeader,
533   IN UINT32           NextFfsSize
534   )
535 /*++
536 
537 Routine Description:
538 
539   This function adds a pad file to the FV image if it required to align the
540   data of the next file.
541 
542 Arguments:
543 
544   FvImage         The memory image of the FV to add it to.
545                   The current offset must be valid.
546   DataAlignment   The data alignment of the next FFS file.
547   FvEnd           End of the empty data in FvImage.
548   ExtHeader       PI FvExtHeader Optional
549 
550 Returns:
551 
552   EFI_SUCCESS              The function completed successfully.
553   EFI_INVALID_PARAMETER    One of the input parameters was invalid.
554   EFI_OUT_OF_RESOURCES     Insufficient resources exist in the FV to complete
555                            the pad file add.
556 
557 --*/
558 {
559   EFI_FFS_FILE_HEADER *PadFile;
560   UINTN               PadFileSize;
561   UINT32              NextFfsHeaderSize;
562   UINT32              CurFfsHeaderSize;
563 
564   CurFfsHeaderSize = sizeof (EFI_FFS_FILE_HEADER);
565   //
566   // Verify input parameters.
567   //
568   if (FvImage == NULL) {
569     return EFI_INVALID_PARAMETER;
570   }
571 
572   //
573   // Calculate the pad file size
574   //
575 
576   //
577   // Append extension header size
578   //
579   if (ExtHeader != NULL) {
580     PadFileSize = ExtHeader->ExtHeaderSize;
581     if (PadFileSize + sizeof (EFI_FFS_FILE_HEADER) >= MAX_FFS_SIZE) {
582       CurFfsHeaderSize = sizeof (EFI_FFS_FILE_HEADER2);
583     }
584     PadFileSize += CurFfsHeaderSize;
585   } else {
586     NextFfsHeaderSize = sizeof (EFI_FFS_FILE_HEADER);
587     if (NextFfsSize >= MAX_FFS_SIZE) {
588       NextFfsHeaderSize = sizeof (EFI_FFS_FILE_HEADER2);
589     }
590     //
591     // Check if a pad file is necessary
592     //
593     if (((UINTN) FvImage->CurrentFilePointer - (UINTN) FvImage->FileImage + NextFfsHeaderSize) % DataAlignment == 0) {
594       return EFI_SUCCESS;
595     }
596     PadFileSize = (UINTN) FvImage->CurrentFilePointer - (UINTN) FvImage->FileImage + sizeof (EFI_FFS_FILE_HEADER) + NextFfsHeaderSize;
597     //
598     // Add whatever it takes to get to the next aligned address
599     //
600     while ((PadFileSize % DataAlignment) != 0) {
601       PadFileSize++;
602     }
603     //
604     // Subtract the next file header size
605     //
606     PadFileSize -= NextFfsHeaderSize;
607     //
608     // Subtract the starting offset to get size
609     //
610     PadFileSize -= (UINTN) FvImage->CurrentFilePointer - (UINTN) FvImage->FileImage;
611   }
612 
613   //
614   // Verify that we have enough space for the file header
615   //
616   if (((UINTN) FvImage->CurrentFilePointer + PadFileSize) > (UINTN) FvEnd) {
617     return EFI_OUT_OF_RESOURCES;
618   }
619 
620   //
621   // Write pad file header
622   //
623   PadFile = (EFI_FFS_FILE_HEADER *) FvImage->CurrentFilePointer;
624 
625   //
626   // Write PadFile FFS header with PadType, don't need to set PAD file guid in its header.
627   //
628   PadFile->Type       = EFI_FV_FILETYPE_FFS_PAD;
629   PadFile->Attributes = 0;
630 
631   //
632   // Write pad file size (calculated size minus next file header size)
633   //
634   if (PadFileSize >= MAX_FFS_SIZE) {
635     memset(PadFile->Size, 0, sizeof(UINT8) * 3);
636     ((EFI_FFS_FILE_HEADER2 *)PadFile)->ExtendedSize = PadFileSize;
637     PadFile->Attributes |= FFS_ATTRIB_LARGE_FILE;
638   } else {
639     PadFile->Size[0]  = (UINT8) (PadFileSize & 0xFF);
640     PadFile->Size[1]  = (UINT8) ((PadFileSize >> 8) & 0xFF);
641     PadFile->Size[2]  = (UINT8) ((PadFileSize >> 16) & 0xFF);
642   }
643 
644   //
645   // Fill in checksums and state, they must be 0 for checksumming.
646   //
647   PadFile->IntegrityCheck.Checksum.Header = 0;
648   PadFile->IntegrityCheck.Checksum.File   = 0;
649   PadFile->State                          = 0;
650   PadFile->IntegrityCheck.Checksum.Header = CalculateChecksum8 ((UINT8 *) PadFile, CurFfsHeaderSize);
651   PadFile->IntegrityCheck.Checksum.File   = FFS_FIXED_CHECKSUM;
652 
653   PadFile->State = EFI_FILE_HEADER_CONSTRUCTION | EFI_FILE_HEADER_VALID | EFI_FILE_DATA_VALID;
654   UpdateFfsFileState (
655     (EFI_FFS_FILE_HEADER *) PadFile,
656     (EFI_FIRMWARE_VOLUME_HEADER *) FvImage->FileImage
657     );
658 
659   //
660   // Update the current FV pointer
661   //
662   FvImage->CurrentFilePointer += PadFileSize;
663 
664   if (ExtHeader != NULL) {
665     //
666     // Copy Fv Extension Header and Set Fv Extension header offset
667     //
668     memcpy ((UINT8 *)PadFile + CurFfsHeaderSize, ExtHeader, ExtHeader->ExtHeaderSize);
669     ((EFI_FIRMWARE_VOLUME_HEADER *) FvImage->FileImage)->ExtHeaderOffset = (UINT16) ((UINTN) ((UINT8 *)PadFile + CurFfsHeaderSize) - (UINTN) FvImage->FileImage);
670 	  //
671 	  // Make next file start at QWord Boundry
672 	  //
673 	  while (((UINTN) FvImage->CurrentFilePointer & (EFI_FFS_FILE_HEADER_ALIGNMENT - 1)) != 0) {
674 	    FvImage->CurrentFilePointer++;
675 	  }
676   }
677 
678   return EFI_SUCCESS;
679 }
680 
681 BOOLEAN
IsVtfFile(IN EFI_FFS_FILE_HEADER * FileBuffer)682 IsVtfFile (
683   IN EFI_FFS_FILE_HEADER    *FileBuffer
684   )
685 /*++
686 
687 Routine Description:
688 
689   This function checks the header to validate if it is a VTF file
690 
691 Arguments:
692 
693   FileBuffer     Buffer in which content of a file has been read.
694 
695 Returns:
696 
697   TRUE    If this is a VTF file
698   FALSE   If this is not a VTF file
699 
700 --*/
701 {
702   if (!memcmp (&FileBuffer->Name, &mEfiFirmwareVolumeTopFileGuid, sizeof (EFI_GUID))) {
703     return TRUE;
704   } else {
705     return FALSE;
706   }
707 }
708 
709 EFI_STATUS
WriteMapFile(IN OUT FILE * FvMapFile,IN CHAR8 * FileName,IN EFI_FFS_FILE_HEADER * FfsFile,IN EFI_PHYSICAL_ADDRESS ImageBaseAddress,IN PE_COFF_LOADER_IMAGE_CONTEXT * pImageContext)710 WriteMapFile (
711   IN OUT FILE                  *FvMapFile,
712   IN     CHAR8                 *FileName,
713   IN     EFI_FFS_FILE_HEADER   *FfsFile,
714   IN     EFI_PHYSICAL_ADDRESS  ImageBaseAddress,
715   IN     PE_COFF_LOADER_IMAGE_CONTEXT *pImageContext
716   )
717 /*++
718 
719 Routine Description:
720 
721   This function gets the basic debug information (entrypoint, baseaddress, .text, .data section base address)
722   from PE/COFF image and abstracts Pe Map file information and add them into FvMap file for Debug.
723 
724 Arguments:
725 
726   FvMapFile             A pointer to FvMap File
727   FileName              Ffs File PathName
728   FfsFile               A pointer to Ffs file image.
729   ImageBaseAddress      PeImage Base Address.
730   pImageContext         Image Context Information.
731 
732 Returns:
733 
734   EFI_SUCCESS           Added required map information.
735 
736 --*/
737 {
738   CHAR8                               PeMapFileName [MAX_LONG_FILE_PATH];
739   CHAR8                               *Cptr, *Cptr2;
740   CHAR8                               FileGuidName [MAX_LINE_LEN];
741   FILE                                *PeMapFile;
742   CHAR8                               Line [MAX_LINE_LEN];
743   CHAR8                               KeyWord [MAX_LINE_LEN];
744   CHAR8                               FunctionName [MAX_LINE_LEN];
745   EFI_PHYSICAL_ADDRESS                FunctionAddress;
746   UINT32                              FunctionType;
747   CHAR8                               FunctionTypeName [MAX_LINE_LEN];
748   UINT32                              Index;
749   UINT32                              AddressOfEntryPoint;
750   UINT32                              Offset;
751   EFI_IMAGE_OPTIONAL_HEADER_UNION     *ImgHdr;
752   EFI_TE_IMAGE_HEADER                 *TEImageHeader;
753   EFI_IMAGE_SECTION_HEADER            *SectionHeader;
754   long long                           TempLongAddress;
755   UINT32                              TextVirtualAddress;
756   UINT32                              DataVirtualAddress;
757   EFI_PHYSICAL_ADDRESS                LinkTimeBaseAddress;
758 
759   //
760   // Init local variable
761   //
762   FunctionType = 0;
763   //
764   // Print FileGuid to string buffer.
765   //
766   PrintGuidToBuffer (&FfsFile->Name, (UINT8 *)FileGuidName, MAX_LINE_LEN, TRUE);
767 
768   //
769   // Construct Map file Name
770   //
771   strcpy (PeMapFileName, FileName);
772 
773   //
774   // Change '\\' to '/', unified path format.
775   //
776   Cptr = PeMapFileName;
777   while (*Cptr != '\0') {
778     if (*Cptr == '\\') {
779       *Cptr = FILE_SEP_CHAR;
780     }
781     Cptr ++;
782   }
783 
784   //
785   // Get Map file
786   //
787   Cptr = PeMapFileName + strlen (PeMapFileName);
788   while ((*Cptr != '.') && (Cptr >= PeMapFileName)) {
789     Cptr --;
790   }
791   if (Cptr < PeMapFileName) {
792     return EFI_NOT_FOUND;
793   } else {
794     *(Cptr + 1) = 'm';
795     *(Cptr + 2) = 'a';
796     *(Cptr + 3) = 'p';
797     *(Cptr + 4) = '\0';
798   }
799 
800   //
801   // Get module Name
802   //
803   Cptr2 = Cptr;
804   while ((*Cptr != FILE_SEP_CHAR) && (Cptr >= PeMapFileName)) {
805     Cptr --;
806   }
807 	*Cptr2 = '\0';
808 	strcpy (KeyWord, Cptr + 1);
809 	*Cptr2 = '.';
810 
811   //
812   // AddressOfEntryPoint and Offset in Image
813   //
814   if (!pImageContext->IsTeImage) {
815   	ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *) ((UINT8 *) pImageContext->Handle + pImageContext->PeCoffHeaderOffset);
816   	AddressOfEntryPoint = ImgHdr->Pe32.OptionalHeader.AddressOfEntryPoint;
817   	Offset = 0;
818     SectionHeader = (EFI_IMAGE_SECTION_HEADER *) (
819                        (UINT8 *) ImgHdr +
820                        sizeof (UINT32) +
821                        sizeof (EFI_IMAGE_FILE_HEADER) +
822                        ImgHdr->Pe32.FileHeader.SizeOfOptionalHeader
823                        );
824     Index = ImgHdr->Pe32.FileHeader.NumberOfSections;
825   } else {
826   	TEImageHeader = (EFI_TE_IMAGE_HEADER *) pImageContext->Handle;
827     AddressOfEntryPoint = TEImageHeader->AddressOfEntryPoint;
828     Offset = TEImageHeader->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER);
829     SectionHeader = (EFI_IMAGE_SECTION_HEADER *) (TEImageHeader + 1);
830     Index = TEImageHeader->NumberOfSections;
831   }
832 
833   //
834   // module information output
835   //
836   if (ImageBaseAddress == 0) {
837     fprintf (FvMapFile, "%s (dummy) (", KeyWord);
838     fprintf (FvMapFile, "BaseAddress=%010llx, ", (unsigned long long) ImageBaseAddress);
839   } else {
840     fprintf (FvMapFile, "%s (Fixed Flash Address, ", KeyWord);
841     fprintf (FvMapFile, "BaseAddress=0x%010llx, ", (unsigned long long) (ImageBaseAddress + Offset));
842   }
843 
844   if (FfsFile->Type != EFI_FV_FILETYPE_SECURITY_CORE && pImageContext->Machine == EFI_IMAGE_MACHINE_IA64) {
845     //
846     // Process IPF PLABEL to get the real address after the image has been rebased.
847     // PLABEL structure is got by AddressOfEntryPoint offset to ImageBuffer stored in pImageContext->Handle.
848     //
849     fprintf (FvMapFile, "EntryPoint=0x%010llx", (unsigned long long) (*(UINT64 *)((UINTN) pImageContext->Handle + (UINTN) AddressOfEntryPoint)));
850   } else {
851     fprintf (FvMapFile, "EntryPoint=0x%010llx", (unsigned long long) (ImageBaseAddress + AddressOfEntryPoint));
852   }
853   fprintf (FvMapFile, ")\n");
854 
855   fprintf (FvMapFile, "(GUID=%s", FileGuidName);
856   TextVirtualAddress = 0;
857   DataVirtualAddress = 0;
858   for (; Index > 0; Index --, SectionHeader ++) {
859     if (stricmp ((CHAR8 *)SectionHeader->Name, ".text") == 0) {
860   		TextVirtualAddress = SectionHeader->VirtualAddress;
861   	} else if (stricmp ((CHAR8 *)SectionHeader->Name, ".data") == 0) {
862   	  DataVirtualAddress = SectionHeader->VirtualAddress;
863   	} else if (stricmp ((CHAR8 *)SectionHeader->Name, ".sdata") == 0) {
864   	  DataVirtualAddress = SectionHeader->VirtualAddress;
865   	}
866   }
867   fprintf (FvMapFile, " .textbaseaddress=0x%010llx", (unsigned long long) (ImageBaseAddress + TextVirtualAddress));
868   fprintf (FvMapFile, " .databaseaddress=0x%010llx", (unsigned long long) (ImageBaseAddress + DataVirtualAddress));
869   fprintf (FvMapFile, ")\n\n");
870 
871   //
872   // Open PeMapFile
873   //
874   PeMapFile = fopen (LongFilePath (PeMapFileName), "r");
875   if (PeMapFile == NULL) {
876     // fprintf (stdout, "can't open %s file to reading\n", PeMapFileName);
877     return EFI_ABORTED;
878   }
879   VerboseMsg ("The map file is %s", PeMapFileName);
880 
881   //
882   // Output Functions information into Fv Map file
883   //
884   LinkTimeBaseAddress = 0;
885   while (fgets (Line, MAX_LINE_LEN, PeMapFile) != NULL) {
886     //
887     // Skip blank line
888     //
889     if (Line[0] == 0x0a) {
890       FunctionType = 0;
891       continue;
892     }
893     //
894     // By Address and Static keyword
895     //
896     if (FunctionType == 0) {
897       sscanf (Line, "%s", KeyWord);
898       if (stricmp (KeyWord, "Address") == 0) {
899         //
900         // function list
901         //
902         FunctionType = 1;
903         fgets (Line, MAX_LINE_LEN, PeMapFile);
904       } else if (stricmp (KeyWord, "Static") == 0) {
905         //
906         // static function list
907         //
908         FunctionType = 2;
909         fgets (Line, MAX_LINE_LEN, PeMapFile);
910       } else if (stricmp (KeyWord, "Preferred") ==0) {
911         sscanf (Line + strlen (" Preferred load address is"), "%llx", &TempLongAddress);
912         LinkTimeBaseAddress = (UINT64) TempLongAddress;
913       }
914       continue;
915     }
916     //
917     // Printf Function Information
918     //
919     if (FunctionType == 1) {
920       sscanf (Line, "%s %s %llx %s", KeyWord, FunctionName, &TempLongAddress, FunctionTypeName);
921       FunctionAddress = (UINT64) TempLongAddress;
922       if (FunctionTypeName [1] == '\0' && (FunctionTypeName [0] == 'f' || FunctionTypeName [0] == 'F')) {
923         fprintf (FvMapFile, "  0x%010llx    ", (unsigned long long) (ImageBaseAddress + FunctionAddress - LinkTimeBaseAddress));
924         fprintf (FvMapFile, "%s\n", FunctionName);
925       }
926     } else if (FunctionType == 2) {
927       sscanf (Line, "%s %s %llx %s", KeyWord, FunctionName, &TempLongAddress, FunctionTypeName);
928       FunctionAddress = (UINT64) TempLongAddress;
929       if (FunctionTypeName [1] == '\0' && (FunctionTypeName [0] == 'f' || FunctionTypeName [0] == 'F')) {
930         fprintf (FvMapFile, "  0x%010llx    ", (unsigned long long) (ImageBaseAddress + FunctionAddress - LinkTimeBaseAddress));
931         fprintf (FvMapFile, "%s\n", FunctionName);
932       }
933     }
934   }
935   //
936   // Close PeMap file
937   //
938   fprintf (FvMapFile, "\n\n");
939   fclose (PeMapFile);
940 
941   return EFI_SUCCESS;
942 }
943 
944 STATIC
945 BOOLEAN
AdjustInternalFfsPadding(IN OUT EFI_FFS_FILE_HEADER * FfsFile,IN OUT MEMORY_FILE * FvImage,IN UINTN Alignment,IN OUT UINTN * FileSize)946 AdjustInternalFfsPadding (
947   IN OUT  EFI_FFS_FILE_HEADER   *FfsFile,
948   IN OUT  MEMORY_FILE           *FvImage,
949   IN      UINTN                 Alignment,
950   IN OUT  UINTN                 *FileSize
951   )
952 /*++
953 
954 Routine Description:
955 
956   This function looks for a dedicated alignment padding section in the FFS, and
957   shrinks it to the size required to line up subsequent sections correctly.
958 
959 Arguments:
960 
961   FfsFile               A pointer to Ffs file image.
962   FvImage               The memory image of the FV to adjust it to.
963   Alignment             Current file alignment
964   FileSize              Reference to a variable holding the size of the FFS file
965 
966 Returns:
967 
968   TRUE                  Padding section was found and updated successfully
969   FALSE                 Otherwise
970 
971 --*/
972 {
973   EFI_FILE_SECTION_POINTER  PadSection;
974   UINT8                     *Remainder;
975   EFI_STATUS                Status;
976   UINT32                    FfsHeaderLength;
977   UINT32                    FfsFileLength;
978   UINT32                    PadSize;
979   UINTN                     Misalignment;
980   EFI_FFS_INTEGRITY_CHECK   *IntegrityCheck;
981 
982   //
983   // Figure out the misalignment: all FFS sections are aligned relative to the
984   // start of the FFS payload, so use that as the base of the misalignment
985   // computation.
986   //
987   FfsHeaderLength = GetFfsHeaderLength(FfsFile);
988   Misalignment = (UINTN) FvImage->CurrentFilePointer -
989                  (UINTN) FvImage->FileImage + FfsHeaderLength;
990   Misalignment &= Alignment - 1;
991   if (Misalignment == 0) {
992     // Nothing to do, return success
993     return TRUE;
994   }
995 
996   //
997   // We only apply this optimization to FFS files with the FIXED attribute set,
998   // since the FFS will not be loadable at arbitrary offsets anymore after
999   // we adjust the size of the padding section.
1000   //
1001   if ((FfsFile->Attributes & FFS_ATTRIB_FIXED) == 0) {
1002     return FALSE;
1003   }
1004 
1005   //
1006   // Look for a dedicated padding section that we can adjust to compensate
1007   // for the misalignment. If such a padding section exists, it precedes all
1008   // sections with alignment requirements, and so the adjustment will correct
1009   // all of them.
1010   //
1011   Status = GetSectionByType (FfsFile, EFI_SECTION_FREEFORM_SUBTYPE_GUID, 1,
1012              &PadSection);
1013   if (EFI_ERROR (Status) ||
1014       CompareGuid (&PadSection.FreeformSubtypeSection->SubTypeGuid,
1015         &mEfiFfsSectionAlignmentPaddingGuid) != 0) {
1016     return FALSE;
1017   }
1018 
1019   //
1020   // Find out if the size of the padding section is sufficient to compensate
1021   // for the misalignment.
1022   //
1023   PadSize = GetSectionFileLength (PadSection.CommonHeader);
1024   if (Misalignment > PadSize - sizeof (EFI_FREEFORM_SUBTYPE_GUID_SECTION)) {
1025     return FALSE;
1026   }
1027 
1028   //
1029   // Move the remainder of the FFS file towards the front, and adjust the
1030   // file size output parameter.
1031   //
1032   Remainder = (UINT8 *) PadSection.CommonHeader + PadSize;
1033   memmove (Remainder - Misalignment, Remainder,
1034            *FileSize - (UINTN) (Remainder - (UINTN) FfsFile));
1035   *FileSize -= Misalignment;
1036 
1037   //
1038   // Update the padding section's length with the new values. Note that the
1039   // padding is always < 64 KB, so we can ignore EFI_COMMON_SECTION_HEADER2
1040   // ExtendedSize.
1041   //
1042   PadSize -= Misalignment;
1043   PadSection.CommonHeader->Size[0] = (UINT8) (PadSize & 0xff);
1044   PadSection.CommonHeader->Size[1] = (UINT8) ((PadSize & 0xff00) >> 8);
1045   PadSection.CommonHeader->Size[2] = (UINT8) ((PadSize & 0xff0000) >> 16);
1046 
1047   //
1048   // Update the FFS header with the new overall length
1049   //
1050   FfsFileLength = GetFfsFileLength (FfsFile) - Misalignment;
1051   if (FfsHeaderLength > sizeof(EFI_FFS_FILE_HEADER)) {
1052     ((EFI_FFS_FILE_HEADER2 *)FfsFile)->ExtendedSize = FfsFileLength;
1053   } else {
1054     FfsFile->Size[0] = (UINT8) (FfsFileLength & 0x000000FF);
1055     FfsFile->Size[1] = (UINT8) ((FfsFileLength & 0x0000FF00) >> 8);
1056     FfsFile->Size[2] = (UINT8) ((FfsFileLength & 0x00FF0000) >> 16);
1057   }
1058 
1059   //
1060   // Clear the alignment bits: these have become meaningless now that we have
1061   // adjusted the padding section.
1062   //
1063   FfsFile->Attributes &= ~FFS_ATTRIB_DATA_ALIGNMENT;
1064 
1065   //
1066   // Recalculate the FFS header checksum. Instead of setting Header and State
1067   // both to zero, set Header to (UINT8)(-State) so State preserves its original
1068   // value
1069   //
1070   IntegrityCheck = &FfsFile->IntegrityCheck;
1071   IntegrityCheck->Checksum.Header = (UINT8) (0x100 - FfsFile->State);
1072   IntegrityCheck->Checksum.File = 0;
1073 
1074   IntegrityCheck->Checksum.Header = CalculateChecksum8 (
1075                                       (UINT8 *) FfsFile, FfsHeaderLength);
1076 
1077   if (FfsFile->Attributes & FFS_ATTRIB_CHECKSUM) {
1078     //
1079     // Ffs header checksum = zero, so only need to calculate ffs body.
1080     //
1081     IntegrityCheck->Checksum.File = CalculateChecksum8 (
1082                                       (UINT8 *) FfsFile + FfsHeaderLength,
1083                                       FfsFileLength - FfsHeaderLength);
1084   } else {
1085     IntegrityCheck->Checksum.File = FFS_FIXED_CHECKSUM;
1086   }
1087 
1088   return TRUE;
1089 }
1090 
1091 EFI_STATUS
AddFile(IN OUT MEMORY_FILE * FvImage,IN FV_INFO * FvInfo,IN UINTN Index,IN OUT EFI_FFS_FILE_HEADER ** VtfFileImage,IN FILE * FvMapFile,IN FILE * FvReportFile)1092 AddFile (
1093   IN OUT MEMORY_FILE          *FvImage,
1094   IN FV_INFO                  *FvInfo,
1095   IN UINTN                    Index,
1096   IN OUT EFI_FFS_FILE_HEADER  **VtfFileImage,
1097   IN FILE                     *FvMapFile,
1098   IN FILE                     *FvReportFile
1099   )
1100 /*++
1101 
1102 Routine Description:
1103 
1104   This function adds a file to the FV image.  The file will pad to the
1105   appropriate alignment if required.
1106 
1107 Arguments:
1108 
1109   FvImage       The memory image of the FV to add it to.  The current offset
1110                 must be valid.
1111   FvInfo        Pointer to information about the FV.
1112   Index         The file in the FvInfo file list to add.
1113   VtfFileImage  A pointer to the VTF file within the FvImage.  If this is equal
1114                 to the end of the FvImage then no VTF previously found.
1115   FvMapFile     Pointer to FvMap File
1116   FvReportFile  Pointer to FvReport File
1117 
1118 Returns:
1119 
1120   EFI_SUCCESS              The function completed successfully.
1121   EFI_INVALID_PARAMETER    One of the input parameters was invalid.
1122   EFI_ABORTED              An error occurred.
1123   EFI_OUT_OF_RESOURCES     Insufficient resources exist to complete the add.
1124 
1125 --*/
1126 {
1127   FILE                  *NewFile;
1128   UINTN                 FileSize;
1129   UINT8                 *FileBuffer;
1130   UINTN                 NumBytesRead;
1131   UINT32                CurrentFileAlignment;
1132   EFI_STATUS            Status;
1133   UINTN                 Index1;
1134   UINT8                 FileGuidString[PRINTED_GUID_BUFFER_SIZE];
1135 
1136   Index1 = 0;
1137   //
1138   // Verify input parameters.
1139   //
1140   if (FvImage == NULL || FvInfo == NULL || FvInfo->FvFiles[Index][0] == 0 || VtfFileImage == NULL) {
1141     return EFI_INVALID_PARAMETER;
1142   }
1143 
1144   //
1145   // Read the file to add
1146   //
1147   NewFile = fopen (LongFilePath (FvInfo->FvFiles[Index]), "rb");
1148 
1149   if (NewFile == NULL) {
1150     Error (NULL, 0, 0001, "Error opening file", FvInfo->FvFiles[Index]);
1151     return EFI_ABORTED;
1152   }
1153 
1154   //
1155   // Get the file size
1156   //
1157   FileSize = _filelength (fileno (NewFile));
1158 
1159   //
1160   // Read the file into a buffer
1161   //
1162   FileBuffer = malloc (FileSize);
1163   if (FileBuffer == NULL) {
1164     fclose (NewFile);
1165     Error (NULL, 0, 4001, "Resouce", "memory cannot be allocated!");
1166     return EFI_OUT_OF_RESOURCES;
1167   }
1168 
1169   NumBytesRead = fread (FileBuffer, sizeof (UINT8), FileSize, NewFile);
1170 
1171   //
1172   // Done with the file, from this point on we will just use the buffer read.
1173   //
1174   fclose (NewFile);
1175 
1176   //
1177   // Verify read successful
1178   //
1179   if (NumBytesRead != sizeof (UINT8) * FileSize) {
1180     free  (FileBuffer);
1181     Error (NULL, 0, 0004, "Error reading file", FvInfo->FvFiles[Index]);
1182     return EFI_ABORTED;
1183   }
1184 
1185   //
1186   // For None PI Ffs file, directly add them into FvImage.
1187   //
1188   if (!FvInfo->IsPiFvImage) {
1189     memcpy (FvImage->CurrentFilePointer, FileBuffer, FileSize);
1190     if (FvInfo->SizeofFvFiles[Index] > FileSize) {
1191     	FvImage->CurrentFilePointer += FvInfo->SizeofFvFiles[Index];
1192     } else {
1193     	FvImage->CurrentFilePointer += FileSize;
1194     }
1195     goto Done;
1196   }
1197 
1198   //
1199   // Verify Ffs file
1200   //
1201   Status = VerifyFfsFile ((EFI_FFS_FILE_HEADER *)FileBuffer);
1202   if (EFI_ERROR (Status)) {
1203     free (FileBuffer);
1204     Error (NULL, 0, 3000, "Invalid", "%s is not a valid FFS file.", FvInfo->FvFiles[Index]);
1205     return EFI_INVALID_PARAMETER;
1206   }
1207 
1208   //
1209   // Verify space exists to add the file
1210   //
1211   if (FileSize > (UINTN) ((UINTN) *VtfFileImage - (UINTN) FvImage->CurrentFilePointer)) {
1212     free (FileBuffer);
1213     Error (NULL, 0, 4002, "Resource", "FV space is full, not enough room to add file %s.", FvInfo->FvFiles[Index]);
1214     return EFI_OUT_OF_RESOURCES;
1215   }
1216 
1217   //
1218   // Verify the input file is the duplicated file in this Fv image
1219   //
1220   for (Index1 = 0; Index1 < Index; Index1 ++) {
1221     if (CompareGuid ((EFI_GUID *) FileBuffer, &mFileGuidArray [Index1]) == 0) {
1222       Error (NULL, 0, 2000, "Invalid parameter", "the %dth file and %uth file have the same file GUID.", (unsigned) Index1 + 1, (unsigned) Index + 1);
1223       PrintGuid ((EFI_GUID *) FileBuffer);
1224       free (FileBuffer);
1225       return EFI_INVALID_PARAMETER;
1226     }
1227   }
1228   CopyMem (&mFileGuidArray [Index], FileBuffer, sizeof (EFI_GUID));
1229 
1230   //
1231   // Update the file state based on polarity of the FV.
1232   //
1233   UpdateFfsFileState (
1234     (EFI_FFS_FILE_HEADER *) FileBuffer,
1235     (EFI_FIRMWARE_VOLUME_HEADER *) FvImage->FileImage
1236     );
1237 
1238   //
1239   // Check if alignment is required
1240   //
1241   ReadFfsAlignment ((EFI_FFS_FILE_HEADER *) FileBuffer, &CurrentFileAlignment);
1242 
1243   //
1244   // Find the largest alignment of all the FFS files in the FV
1245   //
1246   if (CurrentFileAlignment > MaxFfsAlignment) {
1247     MaxFfsAlignment = CurrentFileAlignment;
1248   }
1249   //
1250   // If we have a VTF file, add it at the top.
1251   //
1252   if (IsVtfFile ((EFI_FFS_FILE_HEADER *) FileBuffer)) {
1253     if ((UINTN) *VtfFileImage == (UINTN) FvImage->Eof) {
1254       //
1255       // No previous VTF, add this one.
1256       //
1257       *VtfFileImage = (EFI_FFS_FILE_HEADER *) (UINTN) ((UINTN) FvImage->FileImage + FvInfo->Size - FileSize);
1258       //
1259       // Sanity check. The file MUST align appropriately
1260       //
1261       if (((UINTN) *VtfFileImage + GetFfsHeaderLength((EFI_FFS_FILE_HEADER *)FileBuffer) - (UINTN) FvImage->FileImage) % (1 << CurrentFileAlignment)) {
1262         Error (NULL, 0, 3000, "Invalid", "VTF file cannot be aligned on a %u-byte boundary.", (unsigned) (1 << CurrentFileAlignment));
1263         free (FileBuffer);
1264         return EFI_ABORTED;
1265       }
1266       //
1267       // Rebase the PE or TE image in FileBuffer of FFS file for XIP
1268       // Rebase for the debug genfvmap tool
1269       //
1270       Status = FfsRebase (FvInfo, FvInfo->FvFiles[Index], (EFI_FFS_FILE_HEADER *) FileBuffer, (UINTN) *VtfFileImage - (UINTN) FvImage->FileImage, FvMapFile);
1271       if (EFI_ERROR (Status)) {
1272         Error (NULL, 0, 3000, "Invalid", "Could not rebase %s.", FvInfo->FvFiles[Index]);
1273         return Status;
1274       }
1275       //
1276       // copy VTF File
1277       //
1278       memcpy (*VtfFileImage, FileBuffer, FileSize);
1279 
1280       PrintGuidToBuffer ((EFI_GUID *) FileBuffer, FileGuidString, sizeof (FileGuidString), TRUE);
1281       fprintf (FvReportFile, "0x%08X %s\n", (unsigned)(UINTN) (((UINT8 *)*VtfFileImage) - (UINTN)FvImage->FileImage), FileGuidString);
1282 
1283       free (FileBuffer);
1284       DebugMsg (NULL, 0, 9, "Add VTF FFS file in FV image", NULL);
1285       return EFI_SUCCESS;
1286     } else {
1287       //
1288       // Already found a VTF file.
1289       //
1290       Error (NULL, 0, 3000, "Invalid", "multiple VTF files are not permitted within a single FV.");
1291       free (FileBuffer);
1292       return EFI_ABORTED;
1293     }
1294   }
1295 
1296   //
1297   // Add pad file if necessary
1298   //
1299   if (!AdjustInternalFfsPadding ((EFI_FFS_FILE_HEADER *) FileBuffer, FvImage,
1300          1 << CurrentFileAlignment, &FileSize)) {
1301     Status = AddPadFile (FvImage, 1 << CurrentFileAlignment, *VtfFileImage, NULL, FileSize);
1302     if (EFI_ERROR (Status)) {
1303       Error (NULL, 0, 4002, "Resource", "FV space is full, could not add pad file for data alignment property.");
1304       free (FileBuffer);
1305       return EFI_ABORTED;
1306     }
1307   }
1308   //
1309   // Add file
1310   //
1311   if ((UINTN) (FvImage->CurrentFilePointer + FileSize) <= (UINTN) (*VtfFileImage)) {
1312     //
1313     // Rebase the PE or TE image in FileBuffer of FFS file for XIP.
1314     // Rebase Bs and Rt drivers for the debug genfvmap tool.
1315     //
1316     Status = FfsRebase (FvInfo, FvInfo->FvFiles[Index], (EFI_FFS_FILE_HEADER *) FileBuffer, (UINTN) FvImage->CurrentFilePointer - (UINTN) FvImage->FileImage, FvMapFile);
1317 	if (EFI_ERROR (Status)) {
1318 	  Error (NULL, 0, 3000, "Invalid", "Could not rebase %s.", FvInfo->FvFiles[Index]);
1319 	  return Status;
1320 	}
1321     //
1322     // Copy the file
1323     //
1324     memcpy (FvImage->CurrentFilePointer, FileBuffer, FileSize);
1325     PrintGuidToBuffer ((EFI_GUID *) FileBuffer, FileGuidString, sizeof (FileGuidString), TRUE);
1326     fprintf (FvReportFile, "0x%08X %s\n", (unsigned) (FvImage->CurrentFilePointer - FvImage->FileImage), FileGuidString);
1327     FvImage->CurrentFilePointer += FileSize;
1328   } else {
1329     Error (NULL, 0, 4002, "Resource", "FV space is full, cannot add file %s.", FvInfo->FvFiles[Index]);
1330     free (FileBuffer);
1331     return EFI_ABORTED;
1332   }
1333   //
1334   // Make next file start at QWord Boundry
1335   //
1336   while (((UINTN) FvImage->CurrentFilePointer & (EFI_FFS_FILE_HEADER_ALIGNMENT - 1)) != 0) {
1337     FvImage->CurrentFilePointer++;
1338   }
1339 
1340 Done:
1341   //
1342   // Free allocated memory.
1343   //
1344   free (FileBuffer);
1345 
1346   return EFI_SUCCESS;
1347 }
1348 
1349 EFI_STATUS
PadFvImage(IN MEMORY_FILE * FvImage,IN EFI_FFS_FILE_HEADER * VtfFileImage)1350 PadFvImage (
1351   IN MEMORY_FILE          *FvImage,
1352   IN EFI_FFS_FILE_HEADER  *VtfFileImage
1353   )
1354 /*++
1355 
1356 Routine Description:
1357 
1358   This function places a pad file between the last file in the FV and the VTF
1359   file if the VTF file exists.
1360 
1361 Arguments:
1362 
1363   FvImage       Memory file for the FV memory image
1364   VtfFileImage  The address of the VTF file.  If this is the end of the FV
1365                 image, no VTF exists and no pad file is needed.
1366 
1367 Returns:
1368 
1369   EFI_SUCCESS             Completed successfully.
1370   EFI_INVALID_PARAMETER   One of the input parameters was NULL.
1371 
1372 --*/
1373 {
1374   EFI_FFS_FILE_HEADER *PadFile;
1375   UINTN               FileSize;
1376   UINT32              FfsHeaderSize;
1377 
1378   //
1379   // If there is no VTF or the VTF naturally follows the previous file without a
1380   // pad file, then there's nothing to do
1381   //
1382   if ((UINTN) VtfFileImage == (UINTN) FvImage->Eof || \
1383       ((UINTN) VtfFileImage == (UINTN) FvImage->CurrentFilePointer)) {
1384     return EFI_SUCCESS;
1385   }
1386 
1387   if ((UINTN) VtfFileImage < (UINTN) FvImage->CurrentFilePointer) {
1388     return EFI_INVALID_PARAMETER;
1389   }
1390 
1391   //
1392   // Pad file starts at beginning of free space
1393   //
1394   PadFile = (EFI_FFS_FILE_HEADER *) FvImage->CurrentFilePointer;
1395 
1396   //
1397   // write PadFile FFS header with PadType, don't need to set PAD file guid in its header.
1398   //
1399   PadFile->Type       = EFI_FV_FILETYPE_FFS_PAD;
1400   PadFile->Attributes = 0;
1401 
1402   //
1403   // FileSize includes the EFI_FFS_FILE_HEADER
1404   //
1405   FileSize          = (UINTN) VtfFileImage - (UINTN) FvImage->CurrentFilePointer;
1406   if (FileSize >= MAX_FFS_SIZE) {
1407     PadFile->Attributes |= FFS_ATTRIB_LARGE_FILE;
1408     memset(PadFile->Size, 0, sizeof(UINT8) * 3);
1409     ((EFI_FFS_FILE_HEADER2 *)PadFile)->ExtendedSize = FileSize;
1410     FfsHeaderSize = sizeof(EFI_FFS_FILE_HEADER2);
1411     mIsLargeFfs = TRUE;
1412   } else {
1413     PadFile->Size[0]  = (UINT8) (FileSize & 0x000000FF);
1414     PadFile->Size[1]  = (UINT8) ((FileSize & 0x0000FF00) >> 8);
1415     PadFile->Size[2]  = (UINT8) ((FileSize & 0x00FF0000) >> 16);
1416     FfsHeaderSize = sizeof(EFI_FFS_FILE_HEADER);
1417   }
1418 
1419   //
1420   // Fill in checksums and state, must be zero during checksum calculation.
1421   //
1422   PadFile->IntegrityCheck.Checksum.Header = 0;
1423   PadFile->IntegrityCheck.Checksum.File   = 0;
1424   PadFile->State                          = 0;
1425   PadFile->IntegrityCheck.Checksum.Header = CalculateChecksum8 ((UINT8 *) PadFile, FfsHeaderSize);
1426   PadFile->IntegrityCheck.Checksum.File   = FFS_FIXED_CHECKSUM;
1427 
1428   PadFile->State = EFI_FILE_HEADER_CONSTRUCTION | EFI_FILE_HEADER_VALID | EFI_FILE_DATA_VALID;
1429 
1430   UpdateFfsFileState (
1431     (EFI_FFS_FILE_HEADER *) PadFile,
1432     (EFI_FIRMWARE_VOLUME_HEADER *) FvImage->FileImage
1433     );
1434   //
1435   // Update the current FV pointer
1436   //
1437   FvImage->CurrentFilePointer = FvImage->Eof;
1438 
1439   return EFI_SUCCESS;
1440 }
1441 
1442 EFI_STATUS
UpdateResetVector(IN MEMORY_FILE * FvImage,IN FV_INFO * FvInfo,IN EFI_FFS_FILE_HEADER * VtfFile)1443 UpdateResetVector (
1444   IN MEMORY_FILE            *FvImage,
1445   IN FV_INFO                *FvInfo,
1446   IN EFI_FFS_FILE_HEADER    *VtfFile
1447   )
1448 /*++
1449 
1450 Routine Description:
1451 
1452   This parses the FV looking for the PEI core and then plugs the address into
1453   the SALE_ENTRY point of the BSF/VTF for IPF and does BUGBUG TBD action to
1454   complete an IA32 Bootstrap FV.
1455 
1456 Arguments:
1457 
1458   FvImage       Memory file for the FV memory image
1459   FvInfo        Information read from INF file.
1460   VtfFile       Pointer to the VTF file in the FV image.
1461 
1462 Returns:
1463 
1464   EFI_SUCCESS             Function Completed successfully.
1465   EFI_ABORTED             Error encountered.
1466   EFI_INVALID_PARAMETER   A required parameter was NULL.
1467   EFI_NOT_FOUND           PEI Core file not found.
1468 
1469 --*/
1470 {
1471   EFI_FFS_FILE_HEADER       *PeiCoreFile;
1472   EFI_FFS_FILE_HEADER       *SecCoreFile;
1473   EFI_STATUS                Status;
1474   EFI_FILE_SECTION_POINTER  Pe32Section;
1475   UINT32                    EntryPoint;
1476   UINT32                    BaseOfCode;
1477   UINT16                    MachineType;
1478   EFI_PHYSICAL_ADDRESS      PeiCorePhysicalAddress;
1479   EFI_PHYSICAL_ADDRESS      SecCorePhysicalAddress;
1480   EFI_PHYSICAL_ADDRESS      *SecCoreEntryAddressPtr;
1481   INT32                     Ia32SecEntryOffset;
1482   UINT32                    *Ia32ResetAddressPtr;
1483   UINT8                     *BytePointer;
1484   UINT8                     *BytePointer2;
1485   UINT16                    *WordPointer;
1486   UINT16                    CheckSum;
1487   UINT32                    IpiVector;
1488   UINTN                     Index;
1489   EFI_FFS_FILE_STATE        SavedState;
1490   UINT64                    FitAddress;
1491   FIT_TABLE                 *FitTablePtr;
1492   BOOLEAN                   Vtf0Detected;
1493   UINT32                    FfsHeaderSize;
1494   UINT32                    SecHeaderSize;
1495 
1496   //
1497   // Verify input parameters
1498   //
1499   if (FvImage == NULL || FvInfo == NULL || VtfFile == NULL) {
1500     return EFI_INVALID_PARAMETER;
1501   }
1502   //
1503   // Initialize FV library
1504   //
1505   InitializeFvLib (FvImage->FileImage, FvInfo->Size);
1506 
1507   //
1508   // Verify VTF file
1509   //
1510   Status = VerifyFfsFile (VtfFile);
1511   if (EFI_ERROR (Status)) {
1512     return EFI_INVALID_PARAMETER;
1513   }
1514 
1515   if (
1516       (((UINTN)FvImage->Eof - (UINTN)FvImage->FileImage) >=
1517         IA32_X64_VTF_SIGNATURE_OFFSET) &&
1518       (*(UINT32 *)(VOID*)((UINTN) FvImage->Eof -
1519                                   IA32_X64_VTF_SIGNATURE_OFFSET) ==
1520         IA32_X64_VTF0_SIGNATURE)
1521      ) {
1522     Vtf0Detected = TRUE;
1523   } else {
1524     Vtf0Detected = FALSE;
1525   }
1526 
1527   //
1528   // Find the Sec Core
1529   //
1530   Status = GetFileByType (EFI_FV_FILETYPE_SECURITY_CORE, 1, &SecCoreFile);
1531   if (EFI_ERROR (Status) || SecCoreFile == NULL) {
1532     if (Vtf0Detected) {
1533       //
1534       // If the SEC core file is not found, but the VTF-0 signature
1535       // is found, we'll treat it as a VTF-0 'Volume Top File'.
1536       // This means no modifications are required to the VTF.
1537       //
1538       return EFI_SUCCESS;
1539     }
1540 
1541     Error (NULL, 0, 3000, "Invalid", "could not find the SEC core file in the FV.");
1542     return EFI_ABORTED;
1543   }
1544   //
1545   // Sec Core found, now find PE32 section
1546   //
1547   Status = GetSectionByType (SecCoreFile, EFI_SECTION_PE32, 1, &Pe32Section);
1548   if (Status == EFI_NOT_FOUND) {
1549     Status = GetSectionByType (SecCoreFile, EFI_SECTION_TE, 1, &Pe32Section);
1550   }
1551 
1552   if (EFI_ERROR (Status)) {
1553     Error (NULL, 0, 3000, "Invalid", "could not find a PE32 section in the SEC core file.");
1554     return EFI_ABORTED;
1555   }
1556 
1557   SecHeaderSize = GetSectionHeaderLength(Pe32Section.CommonHeader);
1558   Status = GetPe32Info (
1559             (VOID *) ((UINTN) Pe32Section.Pe32Section + SecHeaderSize),
1560             &EntryPoint,
1561             &BaseOfCode,
1562             &MachineType
1563             );
1564 
1565   if (EFI_ERROR (Status)) {
1566     Error (NULL, 0, 3000, "Invalid", "could not get the PE32 entry point for the SEC core.");
1567     return EFI_ABORTED;
1568   }
1569 
1570   if (
1571        Vtf0Detected &&
1572        (MachineType == EFI_IMAGE_MACHINE_IA32 ||
1573         MachineType == EFI_IMAGE_MACHINE_X64)
1574      ) {
1575     //
1576     // If the SEC core code is IA32 or X64 and the VTF-0 signature
1577     // is found, we'll treat it as a VTF-0 'Volume Top File'.
1578     // This means no modifications are required to the VTF.
1579     //
1580     return EFI_SUCCESS;
1581   }
1582 
1583   //
1584   // Physical address is FV base + offset of PE32 + offset of the entry point
1585   //
1586   SecCorePhysicalAddress = FvInfo->BaseAddress;
1587   SecCorePhysicalAddress += (UINTN) Pe32Section.Pe32Section + SecHeaderSize - (UINTN) FvImage->FileImage;
1588   SecCorePhysicalAddress += EntryPoint;
1589   DebugMsg (NULL, 0, 9, "SecCore physical entry point address", "Address = 0x%llX", (unsigned long long) SecCorePhysicalAddress);
1590 
1591   //
1592   // Find the PEI Core
1593   //
1594   Status = GetFileByType (EFI_FV_FILETYPE_PEI_CORE, 1, &PeiCoreFile);
1595   if (EFI_ERROR (Status) || PeiCoreFile == NULL) {
1596     Error (NULL, 0, 3000, "Invalid", "could not find the PEI core in the FV.");
1597     return EFI_ABORTED;
1598   }
1599   //
1600   // PEI Core found, now find PE32 or TE section
1601   //
1602   Status = GetSectionByType (PeiCoreFile, EFI_SECTION_PE32, 1, &Pe32Section);
1603   if (Status == EFI_NOT_FOUND) {
1604     Status = GetSectionByType (PeiCoreFile, EFI_SECTION_TE, 1, &Pe32Section);
1605   }
1606 
1607   if (EFI_ERROR (Status)) {
1608     Error (NULL, 0, 3000, "Invalid", "could not find either a PE32 or a TE section in PEI core file.");
1609     return EFI_ABORTED;
1610   }
1611 
1612   SecHeaderSize = GetSectionHeaderLength(Pe32Section.CommonHeader);
1613   Status = GetPe32Info (
1614             (VOID *) ((UINTN) Pe32Section.Pe32Section + SecHeaderSize),
1615             &EntryPoint,
1616             &BaseOfCode,
1617             &MachineType
1618             );
1619 
1620   if (EFI_ERROR (Status)) {
1621     Error (NULL, 0, 3000, "Invalid", "could not get the PE32 entry point for the PEI core.");
1622     return EFI_ABORTED;
1623   }
1624   //
1625   // Physical address is FV base + offset of PE32 + offset of the entry point
1626   //
1627   PeiCorePhysicalAddress = FvInfo->BaseAddress;
1628   PeiCorePhysicalAddress += (UINTN) Pe32Section.Pe32Section + SecHeaderSize - (UINTN) FvImage->FileImage;
1629   PeiCorePhysicalAddress += EntryPoint;
1630   DebugMsg (NULL, 0, 9, "PeiCore physical entry point address", "Address = 0x%llX", (unsigned long long) PeiCorePhysicalAddress);
1631 
1632   if (MachineType == EFI_IMAGE_MACHINE_IA64) {
1633     //
1634     // Update PEI_CORE address
1635     //
1636     //
1637     // Set the uncached attribute bit in the physical address
1638     //
1639     PeiCorePhysicalAddress |= 0x8000000000000000ULL;
1640 
1641     //
1642     // Check if address is aligned on a 16 byte boundary
1643     //
1644     if (PeiCorePhysicalAddress & 0xF) {
1645       Error (NULL, 0, 3000, "Invalid",
1646         "PEI_CORE entry point is not aligned on a 16 byte boundary, address specified is %llXh.",
1647         (unsigned long long) PeiCorePhysicalAddress
1648         );
1649       return EFI_ABORTED;
1650     }
1651     //
1652     // First Get the FIT table address
1653     //
1654     FitAddress  = (*(UINT64 *) (FvImage->Eof - IPF_FIT_ADDRESS_OFFSET)) & 0xFFFFFFFF;
1655 
1656     FitTablePtr = (FIT_TABLE *) (FvImage->FileImage + (FitAddress - FvInfo->BaseAddress));
1657 
1658     Status      = UpdatePeiCoreEntryInFit (FitTablePtr, PeiCorePhysicalAddress);
1659 
1660     if (!EFI_ERROR (Status)) {
1661       UpdateFitCheckSum (FitTablePtr);
1662     }
1663 
1664     //
1665     // Update SEC_CORE address
1666     //
1667     //
1668     // Set the uncached attribute bit in the physical address
1669     //
1670     SecCorePhysicalAddress |= 0x8000000000000000ULL;
1671     //
1672     // Check if address is aligned on a 16 byte boundary
1673     //
1674     if (SecCorePhysicalAddress & 0xF) {
1675       Error (NULL, 0, 3000, "Invalid",
1676         "SALE_ENTRY entry point is not aligned on a 16 byte boundary, address specified is %llXh.",
1677         (unsigned long long) SecCorePhysicalAddress
1678         );
1679       return EFI_ABORTED;
1680     }
1681     //
1682     // Update the address
1683     //
1684     SecCoreEntryAddressPtr  = (EFI_PHYSICAL_ADDRESS *) ((UINTN) FvImage->Eof - IPF_SALE_ENTRY_ADDRESS_OFFSET);
1685     *SecCoreEntryAddressPtr = SecCorePhysicalAddress;
1686 
1687   } else if (MachineType == EFI_IMAGE_MACHINE_IA32 || MachineType == EFI_IMAGE_MACHINE_X64) {
1688     //
1689     // Get the location to update
1690     //
1691     Ia32ResetAddressPtr  = (UINT32 *) ((UINTN) FvImage->Eof - IA32_PEI_CORE_ENTRY_OFFSET);
1692 
1693     //
1694     // Write lower 32 bits of physical address for Pei Core entry
1695     //
1696     *Ia32ResetAddressPtr = (UINT32) PeiCorePhysicalAddress;
1697 
1698     //
1699     // Write SecCore Entry point relative address into the jmp instruction in reset vector.
1700     //
1701     Ia32ResetAddressPtr  = (UINT32 *) ((UINTN) FvImage->Eof - IA32_SEC_CORE_ENTRY_OFFSET);
1702 
1703     Ia32SecEntryOffset   = (INT32) (SecCorePhysicalAddress - (FV_IMAGES_TOP_ADDRESS - IA32_SEC_CORE_ENTRY_OFFSET + 2));
1704     if (Ia32SecEntryOffset <= -65536) {
1705       Error (NULL, 0, 3000, "Invalid", "The SEC EXE file size is too large, it must be less than 64K.");
1706       return STATUS_ERROR;
1707     }
1708 
1709     *(UINT16 *) Ia32ResetAddressPtr = (UINT16) Ia32SecEntryOffset;
1710 
1711     //
1712     // Update the BFV base address
1713     //
1714     Ia32ResetAddressPtr   = (UINT32 *) ((UINTN) FvImage->Eof - 4);
1715     *Ia32ResetAddressPtr  = (UINT32) (FvInfo->BaseAddress);
1716     DebugMsg (NULL, 0, 9, "update BFV base address in the top FV image", "BFV base address = 0x%llX.", (unsigned long long) FvInfo->BaseAddress);
1717 
1718     //
1719     // Update the Startup AP in the FVH header block ZeroVector region.
1720     //
1721     BytePointer   = (UINT8 *) ((UINTN) FvImage->FileImage);
1722     if (FvInfo->Size <= 0x10000) {
1723       BytePointer2 = m64kRecoveryStartupApDataArray;
1724     } else if (FvInfo->Size <= 0x20000) {
1725       BytePointer2 = m128kRecoveryStartupApDataArray;
1726     } else {
1727       BytePointer2 = m128kRecoveryStartupApDataArray;
1728       //
1729       // Find the position to place Ap reset vector, the offset
1730       // between the position and the end of Fvrecovery.fv file
1731       // should not exceed 128kB to prevent Ap reset vector from
1732       // outside legacy E and F segment
1733       //
1734       Status = FindApResetVectorPosition (FvImage, &BytePointer);
1735       if (EFI_ERROR (Status)) {
1736         Error (NULL, 0, 3000, "Invalid", "FV image does not have enough space to place AP reset vector. The FV image needs to reserve at least 4KB of unused space.");
1737         return EFI_ABORTED;
1738       }
1739     }
1740 
1741     for (Index = 0; Index < SIZEOF_STARTUP_DATA_ARRAY; Index++) {
1742       BytePointer[Index] = BytePointer2[Index];
1743     }
1744     //
1745     // Calculate the checksum
1746     //
1747     CheckSum              = 0x0000;
1748     WordPointer = (UINT16 *) (BytePointer);
1749     for (Index = 0; Index < SIZEOF_STARTUP_DATA_ARRAY / 2; Index++) {
1750       CheckSum = (UINT16) (CheckSum + ((UINT16) *WordPointer));
1751       WordPointer++;
1752     }
1753     //
1754     // Update the checksum field
1755     //
1756     WordPointer   = (UINT16 *) (BytePointer + SIZEOF_STARTUP_DATA_ARRAY - 2);
1757     *WordPointer  = (UINT16) (0x10000 - (UINT32) CheckSum);
1758 
1759     //
1760     // IpiVector at the 4k aligned address in the top 2 blocks in the PEI FV.
1761     //
1762     IpiVector  = (UINT32) (FV_IMAGES_TOP_ADDRESS - ((UINTN) FvImage->Eof - (UINTN) BytePointer));
1763     DebugMsg (NULL, 0, 9, "Startup AP Vector address", "IpiVector at 0x%X", (unsigned) IpiVector);
1764     if ((IpiVector & 0xFFF) != 0) {
1765       Error (NULL, 0, 3000, "Invalid", "Startup AP Vector address are not 4K aligned, because the FV size is not 4K aligned");
1766       return EFI_ABORTED;
1767     }
1768     IpiVector  = IpiVector >> 12;
1769     IpiVector  = IpiVector & 0xFF;
1770 
1771     //
1772     // Write IPI Vector at Offset FvrecoveryFileSize - 8
1773     //
1774     Ia32ResetAddressPtr   = (UINT32 *) ((UINTN) FvImage->Eof - 8);
1775     *Ia32ResetAddressPtr  = IpiVector;
1776   } else if (MachineType == EFI_IMAGE_MACHINE_ARMT) {
1777     //
1778     // Since the ARM reset vector is in the FV Header you really don't need a
1779     // Volume Top File, but if you have one for some reason don't crash...
1780     //
1781   } else if (MachineType == EFI_IMAGE_MACHINE_AARCH64) {
1782     //
1783     // Since the AArch64 reset vector is in the FV Header you really don't need a
1784     // Volume Top File, but if you have one for some reason don't crash...
1785     //
1786   } else {
1787     Error (NULL, 0, 3000, "Invalid", "machine type=0x%X in PEI core.", MachineType);
1788     return EFI_ABORTED;
1789   }
1790 
1791   //
1792   // Now update file checksum
1793   //
1794   SavedState  = VtfFile->State;
1795   VtfFile->IntegrityCheck.Checksum.File = 0;
1796   VtfFile->State                        = 0;
1797   if (VtfFile->Attributes & FFS_ATTRIB_CHECKSUM) {
1798     FfsHeaderSize = GetFfsHeaderLength(VtfFile);
1799     VtfFile->IntegrityCheck.Checksum.File = CalculateChecksum8 (
1800                                               (UINT8 *) ((UINT8 *)VtfFile + FfsHeaderSize),
1801                                               GetFfsFileLength (VtfFile) - FfsHeaderSize
1802                                               );
1803   } else {
1804     VtfFile->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;
1805   }
1806 
1807   VtfFile->State = SavedState;
1808 
1809   return EFI_SUCCESS;
1810 }
1811 
1812 EFI_STATUS
FindCorePeSection(IN VOID * FvImageBuffer,IN UINT64 FvSize,IN EFI_FV_FILETYPE FileType,OUT EFI_FILE_SECTION_POINTER * Pe32Section)1813 FindCorePeSection(
1814   IN VOID                       *FvImageBuffer,
1815   IN UINT64                     FvSize,
1816   IN EFI_FV_FILETYPE            FileType,
1817   OUT EFI_FILE_SECTION_POINTER  *Pe32Section
1818   )
1819 /*++
1820 
1821 Routine Description:
1822 
1823   Recursively searches the FV for the FFS file of specified type (typically
1824   SEC or PEI core) and extracts the PE32 section for further processing.
1825 
1826 Arguments:
1827 
1828   FvImageBuffer   Buffer containing FV data
1829   FvSize          Size of the FV
1830   FileType        Type of FFS file to search for
1831   Pe32Section     PE32 section pointer when FFS file is found.
1832 
1833 Returns:
1834 
1835   EFI_SUCCESS             Function Completed successfully.
1836   EFI_ABORTED             Error encountered.
1837   EFI_INVALID_PARAMETER   A required parameter was NULL.
1838   EFI_NOT_FOUND           Core file not found.
1839 
1840 --*/
1841 {
1842   EFI_STATUS                  Status;
1843   EFI_FIRMWARE_VOLUME_HEADER  *OrigFvHeader;
1844   UINT32                      OrigFvLength;
1845   EFI_FFS_FILE_HEADER         *CoreFfsFile;
1846   UINTN                       FvImageFileCount;
1847   EFI_FFS_FILE_HEADER         *FvImageFile;
1848   UINTN                       EncapFvSectionCount;
1849   EFI_FILE_SECTION_POINTER    EncapFvSection;
1850   EFI_FIRMWARE_VOLUME_HEADER  *EncapsulatedFvHeader;
1851 
1852   if (Pe32Section == NULL) {
1853     return EFI_INVALID_PARAMETER;
1854   }
1855 
1856   //
1857   // Initialize FV library, saving previous values
1858   //
1859   OrigFvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)NULL;
1860   GetFvHeader (&OrigFvHeader, &OrigFvLength);
1861   InitializeFvLib(FvImageBuffer, (UINT32)FvSize);
1862 
1863   //
1864   // First see if we can obtain the file directly in outer FV
1865   //
1866   Status = GetFileByType(FileType, 1, &CoreFfsFile);
1867   if (!EFI_ERROR(Status) && (CoreFfsFile != NULL) ) {
1868 
1869     //
1870     // Core found, now find PE32 or TE section
1871     //
1872     Status = GetSectionByType(CoreFfsFile, EFI_SECTION_PE32, 1, Pe32Section);
1873     if (EFI_ERROR(Status)) {
1874       Status = GetSectionByType(CoreFfsFile, EFI_SECTION_TE, 1, Pe32Section);
1875     }
1876 
1877     if (EFI_ERROR(Status)) {
1878       Error(NULL, 0, 3000, "Invalid", "could not find a PE32 section in the core file.");
1879       return EFI_ABORTED;
1880     }
1881 
1882     //
1883     // Core PE/TE section, found, return
1884     //
1885     Status = EFI_SUCCESS;
1886     goto EarlyExit;
1887   }
1888 
1889   //
1890   // File was not found, look for FV Image file
1891   //
1892 
1893   // iterate through all FV image files in outer FV
1894   for (FvImageFileCount = 1;; FvImageFileCount++) {
1895 
1896     Status = GetFileByType(EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE, FvImageFileCount, &FvImageFile);
1897 
1898     if (EFI_ERROR(Status) || (FvImageFile == NULL) ) {
1899       // exit FV image file loop, no more found
1900       break;
1901     }
1902 
1903     // Found an fv image file, look for an FV image section.  The PI spec does not
1904     // preclude multiple FV image sections so we loop accordingly.
1905     for (EncapFvSectionCount = 1;; EncapFvSectionCount++) {
1906 
1907       // Look for the next FV image section.  The section search code will
1908       // iterate into encapsulation sections.  For example, it will iterate
1909       // into an EFI_SECTION_GUID_DEFINED encapsulation section to find the
1910       // EFI_SECTION_FIRMWARE_VOLUME_IMAGE sections contained therein.
1911       Status = GetSectionByType(FvImageFile, EFI_SECTION_FIRMWARE_VOLUME_IMAGE, EncapFvSectionCount, &EncapFvSection);
1912 
1913       if (EFI_ERROR(Status)) {
1914         // exit section inner loop, no more found
1915         break;
1916       }
1917 
1918       EncapsulatedFvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)((UINT8 *)EncapFvSection.FVImageSection + GetSectionHeaderLength(EncapFvSection.FVImageSection));
1919 
1920       // recurse to search the encapsulated FV for this core file type
1921       Status = FindCorePeSection(EncapsulatedFvHeader, EncapsulatedFvHeader->FvLength, FileType, Pe32Section);
1922 
1923       if (!EFI_ERROR(Status)) {
1924         // we found the core in the capsulated image, success
1925         goto EarlyExit;
1926       }
1927 
1928     } // end encapsulated fv image section loop
1929   } // end fv image file loop
1930 
1931   // core was not found
1932   Status = EFI_NOT_FOUND;
1933 
1934 EarlyExit:
1935 
1936   // restore FV lib values
1937   if(OrigFvHeader != NULL) {
1938     InitializeFvLib(OrigFvHeader, OrigFvLength);
1939   }
1940 
1941   return Status;
1942 }
1943 
1944 EFI_STATUS
GetCoreMachineType(IN EFI_FILE_SECTION_POINTER Pe32Section,OUT UINT16 * CoreMachineType)1945 GetCoreMachineType(
1946   IN  EFI_FILE_SECTION_POINTER     Pe32Section,
1947   OUT UINT16                      *CoreMachineType
1948   )
1949 /*++
1950 
1951 Routine Description:
1952 
1953   Returns the machine type of a P32 image, typically SEC or PEI core.
1954 
1955 Arguments:
1956 
1957   Pe32Section       PE32 section data
1958   CoreMachineType   The extracted machine type
1959 
1960 Returns:
1961 
1962   EFI_SUCCESS             Function Completed successfully.
1963   EFI_ABORTED             Error encountered.
1964   EFI_INVALID_PARAMETER   A required parameter was NULL.
1965 
1966 --*/
1967 {
1968   EFI_STATUS                  Status;
1969   UINT32                      EntryPoint;
1970   UINT32                      BaseOfCode;
1971 
1972   if (CoreMachineType == NULL) {
1973     return EFI_INVALID_PARAMETER;
1974   }
1975 
1976   Status = GetPe32Info(
1977     (VOID *)((UINTN)Pe32Section.Pe32Section + GetSectionHeaderLength(Pe32Section.CommonHeader)),
1978     &EntryPoint,
1979     &BaseOfCode,
1980     CoreMachineType
1981     );
1982   if (EFI_ERROR(Status)) {
1983     Error(NULL, 0, 3000, "Invalid", "could not get the PE32 machine type for the core.");
1984     return EFI_ABORTED;
1985   }
1986 
1987   return EFI_SUCCESS;
1988 }
1989 
1990 EFI_STATUS
GetCoreEntryPointAddress(IN VOID * FvImageBuffer,IN FV_INFO * FvInfo,IN EFI_FILE_SECTION_POINTER Pe32Section,OUT EFI_PHYSICAL_ADDRESS * CoreEntryAddress)1991 GetCoreEntryPointAddress(
1992   IN VOID                         *FvImageBuffer,
1993   IN FV_INFO                      *FvInfo,
1994   IN  EFI_FILE_SECTION_POINTER     Pe32Section,
1995   OUT EFI_PHYSICAL_ADDRESS        *CoreEntryAddress
1996 )
1997 /*++
1998 
1999 Routine Description:
2000 
2001   Returns the physical address of the core (SEC or PEI) entry point.
2002 
2003 Arguments:
2004 
2005   FvImageBuffer     Pointer to buffer containing FV data
2006   FvInfo            Info for the parent FV
2007   Pe32Section       PE32 section data
2008   CoreEntryAddress  The extracted core entry physical address
2009 
2010 Returns:
2011 
2012   EFI_SUCCESS             Function Completed successfully.
2013   EFI_ABORTED             Error encountered.
2014   EFI_INVALID_PARAMETER   A required parameter was NULL.
2015 
2016 --*/
2017 {
2018   EFI_STATUS                  Status;
2019   UINT32                      EntryPoint;
2020   UINT32                      BaseOfCode;
2021   UINT16                      MachineType;
2022   EFI_PHYSICAL_ADDRESS        EntryPhysicalAddress;
2023 
2024   if (CoreEntryAddress == NULL) {
2025     return EFI_INVALID_PARAMETER;
2026   }
2027 
2028   Status = GetPe32Info(
2029     (VOID *)((UINTN)Pe32Section.Pe32Section + GetSectionHeaderLength(Pe32Section.CommonHeader)),
2030     &EntryPoint,
2031     &BaseOfCode,
2032     &MachineType
2033     );
2034   if (EFI_ERROR(Status)) {
2035     Error(NULL, 0, 3000, "Invalid", "could not get the PE32 entry point for the core.");
2036     return EFI_ABORTED;
2037   }
2038 
2039   //
2040   // Physical address is FV base + offset of PE32 + offset of the entry point
2041   //
2042   EntryPhysicalAddress = FvInfo->BaseAddress;
2043   EntryPhysicalAddress += (UINTN)Pe32Section.Pe32Section + GetSectionHeaderLength(Pe32Section.CommonHeader) - (UINTN)FvImageBuffer;
2044   EntryPhysicalAddress += EntryPoint;
2045 
2046   *CoreEntryAddress = EntryPhysicalAddress;
2047 
2048   return EFI_SUCCESS;
2049 }
2050 
2051 EFI_STATUS
UpdateArmResetVectorIfNeeded(IN MEMORY_FILE * FvImage,IN FV_INFO * FvInfo)2052 UpdateArmResetVectorIfNeeded (
2053   IN MEMORY_FILE            *FvImage,
2054   IN FV_INFO                *FvInfo
2055   )
2056 /*++
2057 
2058 Routine Description:
2059   This parses the FV looking for SEC and patches that address into the
2060   beginning of the FV header.
2061 
2062   For ARM32 the reset vector is at 0x00000000 or 0xFFFF0000.
2063   For AArch64 the reset vector is at 0x00000000.
2064 
2065   This would commonly map to the first entry in the ROM.
2066   ARM32 Exceptions:
2067   Reset            +0
2068   Undefined        +4
2069   SWI              +8
2070   Prefetch Abort   +12
2071   Data Abort       +16
2072   IRQ              +20
2073   FIQ              +24
2074 
2075   We support two schemes on ARM.
2076   1) Beginning of the FV is the reset vector
2077   2) Reset vector is data bytes FDF file and that code branches to reset vector
2078     in the beginning of the FV (fixed size offset).
2079 
2080   Need to have the jump for the reset vector at location zero.
2081   We also need to store the address or PEI (if it exists).
2082   We stub out a return from interrupt in case the debugger
2083    is using SWI (not done for AArch64, not enough space in struct).
2084   The optional entry to the common exception handler is
2085    to support full featured exception handling from ROM and is currently
2086     not support by this tool.
2087 
2088 Arguments:
2089   FvImage       Memory file for the FV memory image
2090   FvInfo        Information read from INF file.
2091 
2092 Returns:
2093 
2094   EFI_SUCCESS             Function Completed successfully.
2095   EFI_ABORTED             Error encountered.
2096   EFI_INVALID_PARAMETER   A required parameter was NULL.
2097   EFI_NOT_FOUND           PEI Core file not found.
2098 
2099 --*/
2100 {
2101   EFI_STATUS                  Status;
2102   EFI_FILE_SECTION_POINTER    SecPe32;
2103   EFI_FILE_SECTION_POINTER    PeiPe32;
2104   BOOLEAN                     UpdateVectorSec = FALSE;
2105   BOOLEAN                     UpdateVectorPei = FALSE;
2106   UINT16                      MachineType = 0;
2107   EFI_PHYSICAL_ADDRESS        SecCoreEntryAddress = 0;
2108   UINT16                      PeiMachineType = 0;
2109   EFI_PHYSICAL_ADDRESS        PeiCoreEntryAddress = 0;
2110 
2111   //
2112   // Verify input parameters
2113   //
2114   if (FvImage == NULL || FvInfo == NULL) {
2115     return EFI_INVALID_PARAMETER;
2116   }
2117 
2118   //
2119   // Locate an SEC Core instance and if found extract the machine type and entry point address
2120   //
2121   Status = FindCorePeSection(FvImage->FileImage, FvInfo->Size, EFI_FV_FILETYPE_SECURITY_CORE, &SecPe32);
2122   if (!EFI_ERROR(Status)) {
2123 
2124     Status = GetCoreMachineType(SecPe32, &MachineType);
2125     if (EFI_ERROR(Status)) {
2126       Error(NULL, 0, 3000, "Invalid", "Could not get the PE32 machine type for SEC Core.");
2127       return EFI_ABORTED;
2128     }
2129 
2130     Status = GetCoreEntryPointAddress(FvImage->FileImage, FvInfo, SecPe32, &SecCoreEntryAddress);
2131     if (EFI_ERROR(Status)) {
2132       Error(NULL, 0, 3000, "Invalid", "Could not get the PE32 entry point address for SEC Core.");
2133       return EFI_ABORTED;
2134     }
2135 
2136     VerboseMsg("UpdateArmResetVectorIfNeeded found SEC core entry at 0x%llx", (unsigned long long)SecCoreEntryAddress);
2137     UpdateVectorSec = TRUE;
2138   }
2139 
2140   //
2141   // Locate a PEI Core instance and if found extract the machine type and entry point address
2142   //
2143   Status = FindCorePeSection(FvImage->FileImage, FvInfo->Size, EFI_FV_FILETYPE_PEI_CORE, &PeiPe32);
2144   if (!EFI_ERROR(Status)) {
2145 
2146     Status = GetCoreMachineType(PeiPe32, &PeiMachineType);
2147     if (EFI_ERROR(Status)) {
2148       Error(NULL, 0, 3000, "Invalid", "Could not get the PE32 machine type for PEI Core.");
2149       return EFI_ABORTED;
2150     }
2151 
2152     Status = GetCoreEntryPointAddress(FvImage->FileImage, FvInfo, PeiPe32, &PeiCoreEntryAddress);
2153     if (EFI_ERROR(Status)) {
2154       Error(NULL, 0, 3000, "Invalid", "Could not get the PE32 entry point address for PEI Core.");
2155       return EFI_ABORTED;
2156     }
2157 
2158     VerboseMsg("UpdateArmResetVectorIfNeeded found PEI core entry at 0x%llx", (unsigned long long)PeiCoreEntryAddress);
2159 
2160     // if we previously found an SEC Core make sure machine types match
2161     if (UpdateVectorSec && (MachineType != PeiMachineType)) {
2162       Error(NULL, 0, 3000, "Invalid", "SEC and PEI machine types do not match, can't update reset vector");
2163       return EFI_ABORTED;
2164     }
2165     else {
2166       MachineType = PeiMachineType;
2167     }
2168 
2169     UpdateVectorPei = TRUE;
2170   }
2171 
2172   if (!UpdateVectorSec && !UpdateVectorPei) {
2173     return EFI_SUCCESS;
2174   }
2175 
2176   if (MachineType == EFI_IMAGE_MACHINE_ARMT) {
2177     // ARM: Array of 4 UINT32s:
2178     // 0 - is branch relative to SEC entry point
2179     // 1 - PEI Entry Point
2180     // 2 - movs pc,lr for a SWI handler
2181     // 3 - Place holder for Common Exception Handler
2182     UINT32                      ResetVector[4];
2183 
2184     memset(ResetVector, 0, sizeof (ResetVector));
2185 
2186     // if we found an SEC core entry point then generate a branch instruction
2187     // to it and populate a debugger SWI entry as well
2188     if (UpdateVectorSec) {
2189 
2190       VerboseMsg("UpdateArmResetVectorIfNeeded updating ARM SEC vector");
2191 
2192       // B SecEntryPoint - signed_immed_24 part +/-32MB offset
2193       // on ARM, the PC is always 8 ahead, so we're not really jumping from the base address, but from base address + 8
2194       ResetVector[0] = (INT32)(SecCoreEntryAddress - FvInfo->BaseAddress - 8) >> 2;
2195 
2196       if (ResetVector[0] > 0x00FFFFFF) {
2197         Error(NULL, 0, 3000, "Invalid", "SEC Entry point must be within 32MB of the start of the FV");
2198         return EFI_ABORTED;
2199       }
2200 
2201       // Add opcode for an uncondional branch with no link. i.e.: " B SecEntryPoint"
2202       ResetVector[0] |= ARMT_UNCONDITIONAL_JUMP_INSTRUCTION;
2203 
2204       // SWI handler movs   pc,lr. Just in case a debugger uses SWI
2205       ResetVector[2] = 0xE1B0F07E;
2206 
2207       // Place holder to support a common interrupt handler from ROM.
2208       // Currently not suppprted. For this to be used the reset vector would not be in this FV
2209       // and the exception vectors would be hard coded in the ROM and just through this address
2210       // to find a common handler in the a module in the FV.
2211       ResetVector[3] = 0;
2212     }
2213 
2214     // if a PEI core entry was found place its address in the vector area
2215     if (UpdateVectorPei) {
2216 
2217       VerboseMsg("UpdateArmResetVectorIfNeeded updating ARM PEI address");
2218 
2219       // Address of PEI Core, if we have one
2220       ResetVector[1] = (UINT32)PeiCoreEntryAddress;
2221     }
2222 
2223     //
2224     // Copy to the beginning of the FV
2225     //
2226     memcpy(FvImage->FileImage, ResetVector, sizeof (ResetVector));
2227 
2228   } else if (MachineType == EFI_IMAGE_MACHINE_AARCH64) {
2229     // AArch64: Used as UINT64 ResetVector[2]
2230     // 0 - is branch relative to SEC entry point
2231     // 1 - PEI Entry Point
2232     UINT64                      ResetVector[2];
2233 
2234     memset(ResetVector, 0, sizeof (ResetVector));
2235 
2236     /* NOTE:
2237     ARMT above has an entry in ResetVector[2] for SWI. The way we are using the ResetVector
2238     array at the moment, for AArch64, does not allow us space for this as the header only
2239     allows for a fixed amount of bytes at the start. If we are sure that UEFI will live
2240     within the first 4GB of addressable RAM we could potensioally adopt the same ResetVector
2241     layout as above. But for the moment we replace the four 32bit vectors with two 64bit
2242     vectors in the same area of the Image heasder. This allows UEFI to start from a 64bit
2243     base.
2244     */
2245 
2246     // if we found an SEC core entry point then generate a branch instruction to it
2247     if (UpdateVectorSec) {
2248 
2249       VerboseMsg("UpdateArmResetVectorIfNeeded updating AArch64 SEC vector");
2250 
2251       ResetVector[0] = (UINT64)(SecCoreEntryAddress - FvInfo->BaseAddress) >> 2;
2252 
2253       // B SecEntryPoint - signed_immed_26 part +/-128MB offset
2254       if (ResetVector[0] > 0x03FFFFFF) {
2255         Error(NULL, 0, 3000, "Invalid", "SEC Entry point must be within 128MB of the start of the FV");
2256         return EFI_ABORTED;
2257       }
2258       // Add opcode for an uncondional branch with no link. i.e.: " B SecEntryPoint"
2259       ResetVector[0] |= ARM64_UNCONDITIONAL_JUMP_INSTRUCTION;
2260     }
2261 
2262     // if a PEI core entry was found place its address in the vector area
2263     if (UpdateVectorPei) {
2264 
2265       VerboseMsg("UpdateArmResetVectorIfNeeded updating AArch64 PEI address");
2266 
2267       // Address of PEI Core, if we have one
2268       ResetVector[1] = (UINT64)PeiCoreEntryAddress;
2269     }
2270 
2271     //
2272     // Copy to the beginning of the FV
2273     //
2274     memcpy(FvImage->FileImage, ResetVector, sizeof (ResetVector));
2275 
2276   } else {
2277     Error(NULL, 0, 3000, "Invalid", "Unknown machine type");
2278     return EFI_ABORTED;
2279   }
2280 
2281   return EFI_SUCCESS;
2282 }
2283 
2284 EFI_STATUS
GetPe32Info(IN UINT8 * Pe32,OUT UINT32 * EntryPoint,OUT UINT32 * BaseOfCode,OUT UINT16 * MachineType)2285 GetPe32Info (
2286   IN UINT8                  *Pe32,
2287   OUT UINT32                *EntryPoint,
2288   OUT UINT32                *BaseOfCode,
2289   OUT UINT16                *MachineType
2290   )
2291 /*++
2292 
2293 Routine Description:
2294 
2295   Retrieves the PE32 entry point offset and machine type from PE image or TeImage.
2296   See EfiImage.h for machine types.  The entry point offset is from the beginning
2297   of the PE32 buffer passed in.
2298 
2299 Arguments:
2300 
2301   Pe32          Beginning of the PE32.
2302   EntryPoint    Offset from the beginning of the PE32 to the image entry point.
2303   BaseOfCode    Base address of code.
2304   MachineType   Magic number for the machine type.
2305 
2306 Returns:
2307 
2308   EFI_SUCCESS             Function completed successfully.
2309   EFI_ABORTED             Error encountered.
2310   EFI_INVALID_PARAMETER   A required parameter was NULL.
2311   EFI_UNSUPPORTED         The operation is unsupported.
2312 
2313 --*/
2314 {
2315   EFI_IMAGE_DOS_HEADER             *DosHeader;
2316   EFI_IMAGE_OPTIONAL_HEADER_UNION  *ImgHdr;
2317   EFI_TE_IMAGE_HEADER              *TeHeader;
2318 
2319   //
2320   // Verify input parameters
2321   //
2322   if (Pe32 == NULL) {
2323     return EFI_INVALID_PARAMETER;
2324   }
2325 
2326   //
2327   // First check whether it is one TE Image.
2328   //
2329   TeHeader = (EFI_TE_IMAGE_HEADER *) Pe32;
2330   if (TeHeader->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {
2331     //
2332     // By TeImage Header to get output
2333     //
2334     *EntryPoint   = TeHeader->AddressOfEntryPoint + sizeof (EFI_TE_IMAGE_HEADER) - TeHeader->StrippedSize;
2335     *BaseOfCode   = TeHeader->BaseOfCode + sizeof (EFI_TE_IMAGE_HEADER) - TeHeader->StrippedSize;
2336     *MachineType  = TeHeader->Machine;
2337   } else {
2338 
2339     //
2340     // Then check whether
2341     // First is the DOS header
2342     //
2343     DosHeader = (EFI_IMAGE_DOS_HEADER *) Pe32;
2344 
2345     //
2346     // Verify DOS header is expected
2347     //
2348     if (DosHeader->e_magic != EFI_IMAGE_DOS_SIGNATURE) {
2349       Error (NULL, 0, 3000, "Invalid", "Unknown magic number in the DOS header, 0x%04X.", DosHeader->e_magic);
2350       return EFI_UNSUPPORTED;
2351     }
2352     //
2353     // Immediately following is the NT header.
2354     //
2355     ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *) ((UINTN) Pe32 + DosHeader->e_lfanew);
2356 
2357     //
2358     // Verify NT header is expected
2359     //
2360     if (ImgHdr->Pe32.Signature != EFI_IMAGE_NT_SIGNATURE) {
2361       Error (NULL, 0, 3000, "Invalid", "Unrecognized image signature 0x%08X.", (unsigned) ImgHdr->Pe32.Signature);
2362       return EFI_UNSUPPORTED;
2363     }
2364     //
2365     // Get output
2366     //
2367     *EntryPoint   = ImgHdr->Pe32.OptionalHeader.AddressOfEntryPoint;
2368     *BaseOfCode   = ImgHdr->Pe32.OptionalHeader.BaseOfCode;
2369     *MachineType  = ImgHdr->Pe32.FileHeader.Machine;
2370   }
2371 
2372   //
2373   // Verify machine type is supported
2374   //
2375   if ((*MachineType != EFI_IMAGE_MACHINE_IA32) && (*MachineType != EFI_IMAGE_MACHINE_IA64) && (*MachineType != EFI_IMAGE_MACHINE_X64) && (*MachineType != EFI_IMAGE_MACHINE_EBC) &&
2376       (*MachineType != EFI_IMAGE_MACHINE_ARMT) && (*MachineType != EFI_IMAGE_MACHINE_AARCH64)) {
2377     Error (NULL, 0, 3000, "Invalid", "Unrecognized machine type in the PE32 file.");
2378     return EFI_UNSUPPORTED;
2379   }
2380 
2381   return EFI_SUCCESS;
2382 }
2383 
2384 EFI_STATUS
GenerateFvImage(IN CHAR8 * InfFileImage,IN UINTN InfFileSize,IN CHAR8 * FvFileName,IN CHAR8 * MapFileName)2385 GenerateFvImage (
2386   IN CHAR8                *InfFileImage,
2387   IN UINTN                InfFileSize,
2388   IN CHAR8                *FvFileName,
2389   IN CHAR8                *MapFileName
2390   )
2391 /*++
2392 
2393 Routine Description:
2394 
2395   This is the main function which will be called from application.
2396 
2397 Arguments:
2398 
2399   InfFileImage   Buffer containing the INF file contents.
2400   InfFileSize    Size of the contents of the InfFileImage buffer.
2401   FvFileName     Requested name for the FV file.
2402   MapFileName    Fv map file to log fv driver information.
2403 
2404 Returns:
2405 
2406   EFI_SUCCESS             Function completed successfully.
2407   EFI_OUT_OF_RESOURCES    Could not allocate required resources.
2408   EFI_ABORTED             Error encountered.
2409   EFI_INVALID_PARAMETER   A required parameter was NULL.
2410 
2411 --*/
2412 {
2413   EFI_STATUS                      Status;
2414   MEMORY_FILE                     InfMemoryFile;
2415   MEMORY_FILE                     FvImageMemoryFile;
2416   UINTN                           Index;
2417   EFI_FIRMWARE_VOLUME_HEADER      *FvHeader;
2418   EFI_FFS_FILE_HEADER             *VtfFileImage;
2419   UINT8                           *FvBufferHeader; // to make sure fvimage header 8 type alignment.
2420   UINT8                           *FvImage;
2421   UINTN                           FvImageSize;
2422   FILE                            *FvFile;
2423   CHAR8                           *FvMapName;
2424   FILE                            *FvMapFile;
2425   EFI_FIRMWARE_VOLUME_EXT_HEADER  *FvExtHeader;
2426   FILE                            *FvExtHeaderFile;
2427   UINTN                           FileSize;
2428   CHAR8                           *FvReportName;
2429   FILE                            *FvReportFile;
2430 
2431   FvBufferHeader = NULL;
2432   FvFile         = NULL;
2433   FvMapName      = NULL;
2434   FvMapFile      = NULL;
2435   FvReportName   = NULL;
2436   FvReportFile   = NULL;
2437 
2438   if (InfFileImage != NULL) {
2439     //
2440     // Initialize file structures
2441     //
2442     InfMemoryFile.FileImage           = InfFileImage;
2443     InfMemoryFile.CurrentFilePointer  = InfFileImage;
2444     InfMemoryFile.Eof                 = InfFileImage + InfFileSize;
2445 
2446     //
2447     // Parse the FV inf file for header information
2448     //
2449     Status = ParseFvInf (&InfMemoryFile, &mFvDataInfo);
2450     if (EFI_ERROR (Status)) {
2451       Error (NULL, 0, 0003, "Error parsing file", "the input FV INF file.");
2452       return Status;
2453     }
2454   }
2455 
2456   //
2457   // Update the file name return values
2458   //
2459   if (FvFileName == NULL && mFvDataInfo.FvName[0] != '\0') {
2460     FvFileName = mFvDataInfo.FvName;
2461   }
2462 
2463   if (FvFileName == NULL) {
2464     Error (NULL, 0, 1001, "Missing option", "Output file name");
2465     return EFI_ABORTED;
2466   }
2467 
2468   if (mFvDataInfo.FvBlocks[0].Length == 0) {
2469     Error (NULL, 0, 1001, "Missing required argument", "Block Size");
2470     return EFI_ABORTED;
2471   }
2472 
2473   //
2474   // Debug message Fv File System Guid
2475   //
2476   if (mFvDataInfo.FvFileSystemGuidSet) {
2477     DebugMsg (NULL, 0, 9, "FV File System Guid", "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
2478                   (unsigned) mFvDataInfo.FvFileSystemGuid.Data1,
2479                   mFvDataInfo.FvFileSystemGuid.Data2,
2480                   mFvDataInfo.FvFileSystemGuid.Data3,
2481                   mFvDataInfo.FvFileSystemGuid.Data4[0],
2482                   mFvDataInfo.FvFileSystemGuid.Data4[1],
2483                   mFvDataInfo.FvFileSystemGuid.Data4[2],
2484                   mFvDataInfo.FvFileSystemGuid.Data4[3],
2485                   mFvDataInfo.FvFileSystemGuid.Data4[4],
2486                   mFvDataInfo.FvFileSystemGuid.Data4[5],
2487                   mFvDataInfo.FvFileSystemGuid.Data4[6],
2488                   mFvDataInfo.FvFileSystemGuid.Data4[7]);
2489   }
2490 
2491   //
2492   // Add PI FV extension header
2493   //
2494   FvExtHeader = NULL;
2495   FvExtHeaderFile = NULL;
2496   if (mFvDataInfo.FvExtHeaderFile[0] != 0) {
2497     //
2498     // Open the FV Extension Header file
2499     //
2500     FvExtHeaderFile = fopen (LongFilePath (mFvDataInfo.FvExtHeaderFile), "rb");
2501     if (FvExtHeaderFile == NULL) {
2502       Error (NULL, 0, 0001, "Error opening file", mFvDataInfo.FvExtHeaderFile);
2503       return EFI_ABORTED;
2504     }
2505 
2506     //
2507     // Get the file size
2508     //
2509     FileSize = _filelength (fileno (FvExtHeaderFile));
2510 
2511     //
2512     // Allocate a buffer for the FV Extension Header
2513     //
2514     FvExtHeader = malloc(FileSize);
2515     if (FvExtHeader == NULL) {
2516       fclose (FvExtHeaderFile);
2517       return EFI_OUT_OF_RESOURCES;
2518     }
2519 
2520     //
2521     // Read the FV Extension Header
2522     //
2523     fread (FvExtHeader, sizeof (UINT8), FileSize, FvExtHeaderFile);
2524     fclose (FvExtHeaderFile);
2525 
2526     //
2527     // See if there is an override for the FV Name GUID
2528     //
2529     if (mFvDataInfo.FvNameGuidSet) {
2530       memcpy (&FvExtHeader->FvName, &mFvDataInfo.FvNameGuid, sizeof (EFI_GUID));
2531     }
2532     memcpy (&mFvDataInfo.FvNameGuid, &FvExtHeader->FvName, sizeof (EFI_GUID));
2533     mFvDataInfo.FvNameGuidSet = TRUE;
2534   } else if (mFvDataInfo.FvNameGuidSet) {
2535     //
2536     // Allocate a buffer for the FV Extension Header
2537     //
2538     FvExtHeader = malloc(sizeof (EFI_FIRMWARE_VOLUME_EXT_HEADER));
2539     if (FvExtHeader == NULL) {
2540       return EFI_OUT_OF_RESOURCES;
2541     }
2542     memcpy (&FvExtHeader->FvName, &mFvDataInfo.FvNameGuid, sizeof (EFI_GUID));
2543     FvExtHeader->ExtHeaderSize = sizeof (EFI_FIRMWARE_VOLUME_EXT_HEADER);
2544   }
2545 
2546   //
2547   // Debug message Fv Name Guid
2548   //
2549   if (mFvDataInfo.FvNameGuidSet) {
2550       DebugMsg (NULL, 0, 9, "FV Name Guid", "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
2551                   (unsigned) mFvDataInfo.FvNameGuid.Data1,
2552                   mFvDataInfo.FvNameGuid.Data2,
2553                   mFvDataInfo.FvNameGuid.Data3,
2554                   mFvDataInfo.FvNameGuid.Data4[0],
2555                   mFvDataInfo.FvNameGuid.Data4[1],
2556                   mFvDataInfo.FvNameGuid.Data4[2],
2557                   mFvDataInfo.FvNameGuid.Data4[3],
2558                   mFvDataInfo.FvNameGuid.Data4[4],
2559                   mFvDataInfo.FvNameGuid.Data4[5],
2560                   mFvDataInfo.FvNameGuid.Data4[6],
2561                   mFvDataInfo.FvNameGuid.Data4[7]);
2562   }
2563 
2564   if (CompareGuid (&mFvDataInfo.FvFileSystemGuid, &mEfiFirmwareFileSystem2Guid) == 0 ||
2565     CompareGuid (&mFvDataInfo.FvFileSystemGuid, &mEfiFirmwareFileSystem3Guid) == 0) {
2566     mFvDataInfo.IsPiFvImage = TRUE;
2567   }
2568 
2569   //
2570   // FvMap file to log the function address of all modules in one Fvimage
2571   //
2572   if (MapFileName != NULL) {
2573     if (strlen (MapFileName) > MAX_LONG_FILE_PATH - 1) {
2574       Error (NULL, 0, 1003, "Invalid option value", "MapFileName %s is too long!", MapFileName);
2575       Status = EFI_ABORTED;
2576       goto Finish;
2577     }
2578 
2579     FvMapName = malloc (strlen (MapFileName) + 1);
2580     if (FvMapName == NULL) {
2581       Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");
2582       Status = EFI_OUT_OF_RESOURCES;
2583       goto Finish;
2584     }
2585 
2586     strcpy (FvMapName, MapFileName);
2587   } else {
2588     if (strlen (FvFileName) + strlen (".map") > MAX_LONG_FILE_PATH - 1) {
2589       Error (NULL, 0, 1003, "Invalid option value", "FvFileName %s is too long!", FvFileName);
2590       Status = EFI_ABORTED;
2591       goto Finish;
2592     }
2593 
2594     FvMapName = malloc (strlen (FvFileName) + strlen (".map") + 1);
2595     if (FvMapName == NULL) {
2596       Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");
2597       Status = EFI_OUT_OF_RESOURCES;
2598       goto Finish;
2599     }
2600 
2601     strcpy (FvMapName, FvFileName);
2602     strcat (FvMapName, ".map");
2603   }
2604   VerboseMsg ("FV Map file name is %s", FvMapName);
2605 
2606   //
2607   // FvReport file to log the FV information in one Fvimage
2608   //
2609   if (strlen (FvFileName) + strlen (".txt") > MAX_LONG_FILE_PATH - 1) {
2610     Error (NULL, 0, 1003, "Invalid option value", "FvFileName %s is too long!", FvFileName);
2611     Status = EFI_ABORTED;
2612     goto Finish;
2613   }
2614 
2615   FvReportName = malloc (strlen (FvFileName) + strlen (".txt") + 1);
2616   if (FvReportName == NULL) {
2617     Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");
2618     Status = EFI_OUT_OF_RESOURCES;
2619     goto Finish;
2620   }
2621 
2622   strcpy (FvReportName, FvFileName);
2623   strcat (FvReportName, ".txt");
2624 
2625   //
2626   // Calculate the FV size and Update Fv Size based on the actual FFS files.
2627   // And Update mFvDataInfo data.
2628   //
2629   Status = CalculateFvSize (&mFvDataInfo);
2630   if (EFI_ERROR (Status)) {
2631     goto Finish;
2632   }
2633   VerboseMsg ("the generated FV image size is %u bytes", (unsigned) mFvDataInfo.Size);
2634 
2635   //
2636   // support fv image and empty fv image
2637   //
2638   FvImageSize = mFvDataInfo.Size;
2639 
2640   //
2641   // Allocate the FV, assure FvImage Header 8 byte alignment
2642   //
2643   FvBufferHeader = malloc (FvImageSize + sizeof (UINT64));
2644   if (FvBufferHeader == NULL) {
2645     Status = EFI_OUT_OF_RESOURCES;
2646     goto Finish;
2647   }
2648   FvImage = (UINT8 *) (((UINTN) FvBufferHeader + 7) & ~7);
2649 
2650   //
2651   // Initialize the FV to the erase polarity
2652   //
2653   if (mFvDataInfo.FvAttributes == 0) {
2654     //
2655     // Set Default Fv Attribute
2656     //
2657     mFvDataInfo.FvAttributes = FV_DEFAULT_ATTRIBUTE;
2658   }
2659   if (mFvDataInfo.FvAttributes & EFI_FVB2_ERASE_POLARITY) {
2660     memset (FvImage, -1, FvImageSize);
2661   } else {
2662     memset (FvImage, 0, FvImageSize);
2663   }
2664 
2665   //
2666   // Initialize FV header
2667   //
2668   FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) FvImage;
2669 
2670   //
2671   // Initialize the zero vector to all zeros.
2672   //
2673   memset (FvHeader->ZeroVector, 0, 16);
2674 
2675   //
2676   // Copy the Fv file system GUID
2677   //
2678   memcpy (&FvHeader->FileSystemGuid, &mFvDataInfo.FvFileSystemGuid, sizeof (EFI_GUID));
2679 
2680   FvHeader->FvLength        = FvImageSize;
2681   FvHeader->Signature       = EFI_FVH_SIGNATURE;
2682   FvHeader->Attributes      = mFvDataInfo.FvAttributes;
2683   FvHeader->Revision        = EFI_FVH_REVISION;
2684   FvHeader->ExtHeaderOffset = 0;
2685   FvHeader->Reserved[0]     = 0;
2686 
2687   //
2688   // Copy firmware block map
2689   //
2690   for (Index = 0; mFvDataInfo.FvBlocks[Index].Length != 0; Index++) {
2691     FvHeader->BlockMap[Index].NumBlocks   = mFvDataInfo.FvBlocks[Index].NumBlocks;
2692     FvHeader->BlockMap[Index].Length      = mFvDataInfo.FvBlocks[Index].Length;
2693   }
2694 
2695   //
2696   // Add block map terminator
2697   //
2698   FvHeader->BlockMap[Index].NumBlocks   = 0;
2699   FvHeader->BlockMap[Index].Length      = 0;
2700 
2701   //
2702   // Complete the header
2703   //
2704   FvHeader->HeaderLength  = (UINT16) (((UINTN) &(FvHeader->BlockMap[Index + 1])) - (UINTN) FvImage);
2705   FvHeader->Checksum      = 0;
2706   FvHeader->Checksum      = CalculateChecksum16 ((UINT16 *) FvHeader, FvHeader->HeaderLength / sizeof (UINT16));
2707 
2708   //
2709   // If there is no FFS file, generate one empty FV
2710   //
2711   if (mFvDataInfo.FvFiles[0][0] == 0 && !mFvDataInfo.FvNameGuidSet) {
2712     goto WriteFile;
2713   }
2714 
2715   //
2716   // Initialize our "file" view of the buffer
2717   //
2718   FvImageMemoryFile.FileImage           = (CHAR8 *)FvImage;
2719   FvImageMemoryFile.CurrentFilePointer  = (CHAR8 *)FvImage + FvHeader->HeaderLength;
2720   FvImageMemoryFile.Eof                 = (CHAR8 *)FvImage + FvImageSize;
2721 
2722   //
2723   // Initialize the FV library.
2724   //
2725   InitializeFvLib (FvImageMemoryFile.FileImage, FvImageSize);
2726 
2727   //
2728   // Initialize the VTF file address.
2729   //
2730   VtfFileImage = (EFI_FFS_FILE_HEADER *) FvImageMemoryFile.Eof;
2731 
2732   //
2733   // Open FvMap file
2734   //
2735   FvMapFile = fopen (LongFilePath (FvMapName), "w");
2736   if (FvMapFile == NULL) {
2737     Error (NULL, 0, 0001, "Error opening file", FvMapName);
2738     Status = EFI_ABORTED;
2739     goto Finish;
2740   }
2741 
2742   //
2743   // Open FvReport file
2744   //
2745   FvReportFile = fopen (LongFilePath (FvReportName), "w");
2746   if (FvReportFile == NULL) {
2747     Error (NULL, 0, 0001, "Error opening file", FvReportName);
2748     Status = EFI_ABORTED;
2749     goto Finish;
2750   }
2751   //
2752   // record FV size information into FvMap file.
2753   //
2754   if (mFvTotalSize != 0) {
2755     fprintf (FvMapFile, EFI_FV_TOTAL_SIZE_STRING);
2756     fprintf (FvMapFile, " = 0x%x\n", (unsigned) mFvTotalSize);
2757   }
2758   if (mFvTakenSize != 0) {
2759     fprintf (FvMapFile, EFI_FV_TAKEN_SIZE_STRING);
2760     fprintf (FvMapFile, " = 0x%x\n", (unsigned) mFvTakenSize);
2761   }
2762   if (mFvTotalSize != 0 && mFvTakenSize != 0) {
2763     fprintf (FvMapFile, EFI_FV_SPACE_SIZE_STRING);
2764     fprintf (FvMapFile, " = 0x%x\n\n", (unsigned) (mFvTotalSize - mFvTakenSize));
2765   }
2766 
2767   //
2768   // record FV size information to FvReportFile.
2769   //
2770   fprintf (FvReportFile, "%s = 0x%x\n", EFI_FV_TOTAL_SIZE_STRING, (unsigned) mFvTotalSize);
2771   fprintf (FvReportFile, "%s = 0x%x\n", EFI_FV_TAKEN_SIZE_STRING, (unsigned) mFvTakenSize);
2772 
2773   //
2774   // Add PI FV extension header
2775   //
2776   if (FvExtHeader != NULL) {
2777     //
2778     // Add FV Extended Header contents to the FV as a PAD file
2779     //
2780     AddPadFile (&FvImageMemoryFile, 4, VtfFileImage, FvExtHeader, 0);
2781 
2782     //
2783     // Fv Extension header change update Fv Header Check sum
2784     //
2785     FvHeader->Checksum      = 0;
2786     FvHeader->Checksum      = CalculateChecksum16 ((UINT16 *) FvHeader, FvHeader->HeaderLength / sizeof (UINT16));
2787   }
2788 
2789   //
2790   // Add files to FV
2791   //
2792   for (Index = 0; mFvDataInfo.FvFiles[Index][0] != 0; Index++) {
2793     //
2794     // Add the file
2795     //
2796     Status = AddFile (&FvImageMemoryFile, &mFvDataInfo, Index, &VtfFileImage, FvMapFile, FvReportFile);
2797 
2798     //
2799     // Exit if error detected while adding the file
2800     //
2801     if (EFI_ERROR (Status)) {
2802       goto Finish;
2803     }
2804   }
2805 
2806   //
2807   // If there is a VTF file, some special actions need to occur.
2808   //
2809   if ((UINTN) VtfFileImage != (UINTN) FvImageMemoryFile.Eof) {
2810     //
2811     // Pad from the end of the last file to the beginning of the VTF file.
2812     // If the left space is less than sizeof (EFI_FFS_FILE_HEADER)?
2813     //
2814     Status = PadFvImage (&FvImageMemoryFile, VtfFileImage);
2815     if (EFI_ERROR (Status)) {
2816       Error (NULL, 0, 4002, "Resource", "FV space is full, cannot add pad file between the last file and the VTF file.");
2817       goto Finish;
2818     }
2819     if (!mArm) {
2820       //
2821       // Update reset vector (SALE_ENTRY for IPF)
2822       // Now for IA32 and IA64 platform, the fv which has bsf file must have the
2823       // EndAddress of 0xFFFFFFFF (unless the section was rebased).
2824       // Thus, only this type fv needs to update the  reset vector.
2825       // If the PEI Core is found, the VTF file will probably get
2826       // corrupted by updating the entry point.
2827       //
2828       if (mFvDataInfo.ForceRebase == 1 ||
2829           (mFvDataInfo.BaseAddress + mFvDataInfo.Size) == FV_IMAGES_TOP_ADDRESS) {
2830         Status = UpdateResetVector (&FvImageMemoryFile, &mFvDataInfo, VtfFileImage);
2831         if (EFI_ERROR(Status)) {
2832           Error (NULL, 0, 3000, "Invalid", "Could not update the reset vector.");
2833           goto Finish;
2834         }
2835         DebugMsg (NULL, 0, 9, "Update Reset vector in VTF file", NULL);
2836       }
2837     }
2838   }
2839 
2840   if (mArm) {
2841     Status = UpdateArmResetVectorIfNeeded (&FvImageMemoryFile, &mFvDataInfo);
2842     if (EFI_ERROR (Status)) {
2843       Error (NULL, 0, 3000, "Invalid", "Could not update the reset vector.");
2844       goto Finish;
2845     }
2846 
2847     //
2848     // Update Checksum for FvHeader
2849     //
2850     FvHeader->Checksum = 0;
2851     FvHeader->Checksum = CalculateChecksum16 ((UINT16 *) FvHeader, FvHeader->HeaderLength / sizeof (UINT16));
2852   }
2853 
2854   //
2855   // Update FV Alignment attribute to the largest alignment of all the FFS files in the FV
2856   //
2857   if (((FvHeader->Attributes & EFI_FVB2_WEAK_ALIGNMENT) != EFI_FVB2_WEAK_ALIGNMENT) &&
2858       (((FvHeader->Attributes & EFI_FVB2_ALIGNMENT) >> 16)) < MaxFfsAlignment) {
2859     FvHeader->Attributes = ((MaxFfsAlignment << 16) | (FvHeader->Attributes & 0xFFFF));
2860     //
2861     // Update Checksum for FvHeader
2862     //
2863     FvHeader->Checksum      = 0;
2864     FvHeader->Checksum      = CalculateChecksum16 ((UINT16 *) FvHeader, FvHeader->HeaderLength / sizeof (UINT16));
2865   }
2866 
2867   //
2868   // If there are large FFS in FV, the file system GUID should set to system 3 GUID.
2869   //
2870   if (mIsLargeFfs && CompareGuid (&FvHeader->FileSystemGuid, &mEfiFirmwareFileSystem2Guid) == 0) {
2871     memcpy (&FvHeader->FileSystemGuid, &mEfiFirmwareFileSystem3Guid, sizeof (EFI_GUID));
2872     FvHeader->Checksum      = 0;
2873     FvHeader->Checksum      = CalculateChecksum16 ((UINT16 *) FvHeader, FvHeader->HeaderLength / sizeof (UINT16));
2874   }
2875 
2876 WriteFile:
2877   //
2878   // Write fv file
2879   //
2880   FvFile = fopen (LongFilePath (FvFileName), "wb");
2881   if (FvFile == NULL) {
2882     Error (NULL, 0, 0001, "Error opening file", FvFileName);
2883     Status = EFI_ABORTED;
2884     goto Finish;
2885   }
2886 
2887   if (fwrite (FvImage, 1, FvImageSize, FvFile) != FvImageSize) {
2888     Error (NULL, 0, 0002, "Error writing file", FvFileName);
2889     Status = EFI_ABORTED;
2890     goto Finish;
2891   }
2892 
2893 Finish:
2894   if (FvBufferHeader != NULL) {
2895     free (FvBufferHeader);
2896   }
2897 
2898   if (FvExtHeader != NULL) {
2899     free (FvExtHeader);
2900   }
2901 
2902   if (FvMapName != NULL) {
2903     free (FvMapName);
2904   }
2905 
2906   if (FvReportName != NULL) {
2907     free (FvReportName);
2908   }
2909 
2910   if (FvFile != NULL) {
2911     fflush (FvFile);
2912     fclose (FvFile);
2913   }
2914 
2915   if (FvMapFile != NULL) {
2916     fflush (FvMapFile);
2917     fclose (FvMapFile);
2918   }
2919 
2920   if (FvReportFile != NULL) {
2921     fflush (FvReportFile);
2922     fclose (FvReportFile);
2923   }
2924   return Status;
2925 }
2926 
2927 EFI_STATUS
UpdatePeiCoreEntryInFit(IN FIT_TABLE * FitTablePtr,IN UINT64 PeiCorePhysicalAddress)2928 UpdatePeiCoreEntryInFit (
2929   IN FIT_TABLE     *FitTablePtr,
2930   IN UINT64        PeiCorePhysicalAddress
2931   )
2932 /*++
2933 
2934 Routine Description:
2935 
2936   This function is used to update the Pei Core address in FIT, this can be used by Sec core to pass control from
2937   Sec to Pei Core
2938 
2939 Arguments:
2940 
2941   FitTablePtr             - The pointer of FIT_TABLE.
2942   PeiCorePhysicalAddress  - The address of Pei Core entry.
2943 
2944 Returns:
2945 
2946   EFI_SUCCESS             - The PEI_CORE FIT entry was updated successfully.
2947   EFI_NOT_FOUND           - Not found the PEI_CORE FIT entry.
2948 
2949 --*/
2950 {
2951   FIT_TABLE *TmpFitPtr;
2952   UINTN     Index;
2953   UINTN     NumFitComponents;
2954 
2955   TmpFitPtr         = FitTablePtr;
2956   NumFitComponents  = TmpFitPtr->CompSize;
2957 
2958   for (Index = 0; Index < NumFitComponents; Index++) {
2959     if ((TmpFitPtr->CvAndType & FIT_TYPE_MASK) == COMP_TYPE_FIT_PEICORE) {
2960       TmpFitPtr->CompAddress = PeiCorePhysicalAddress;
2961       return EFI_SUCCESS;
2962     }
2963 
2964     TmpFitPtr++;
2965   }
2966 
2967   return EFI_NOT_FOUND;
2968 }
2969 
2970 VOID
UpdateFitCheckSum(IN FIT_TABLE * FitTablePtr)2971 UpdateFitCheckSum (
2972   IN FIT_TABLE   *FitTablePtr
2973   )
2974 /*++
2975 
2976 Routine Description:
2977 
2978   This function is used to update the checksum for FIT.
2979 
2980 
2981 Arguments:
2982 
2983   FitTablePtr             - The pointer of FIT_TABLE.
2984 
2985 Returns:
2986 
2987   None.
2988 
2989 --*/
2990 {
2991   if ((FitTablePtr->CvAndType & CHECKSUM_BIT_MASK) >> 7) {
2992     FitTablePtr->CheckSum = 0;
2993     FitTablePtr->CheckSum = CalculateChecksum8 ((UINT8 *) FitTablePtr, FitTablePtr->CompSize * 16);
2994   }
2995 }
2996 
2997 EFI_STATUS
CalculateFvSize(FV_INFO * FvInfoPtr)2998 CalculateFvSize (
2999   FV_INFO *FvInfoPtr
3000   )
3001 /*++
3002 Routine Description:
3003   Calculate the FV size and Update Fv Size based on the actual FFS files.
3004   And Update FvInfo data.
3005 
3006 Arguments:
3007   FvInfoPtr     - The pointer to FV_INFO structure.
3008 
3009 Returns:
3010   EFI_ABORTED   - Ffs Image Error
3011   EFI_SUCCESS   - Successfully update FvSize
3012 --*/
3013 {
3014   UINTN               CurrentOffset;
3015   UINTN               Index;
3016   FILE                *fpin;
3017   UINTN               FfsFileSize;
3018   UINTN               FvExtendHeaderSize;
3019   UINT32              FfsAlignment;
3020   UINT32              FfsHeaderSize;
3021   EFI_FFS_FILE_HEADER FfsHeader;
3022   BOOLEAN             VtfFileFlag;
3023   UINTN               VtfFileSize;
3024 
3025   FvExtendHeaderSize = 0;
3026   VtfFileSize = 0;
3027   VtfFileFlag = FALSE;
3028   fpin  = NULL;
3029   Index = 0;
3030 
3031   //
3032   // Compute size for easy access later
3033   //
3034   FvInfoPtr->Size = 0;
3035   for (Index = 0; FvInfoPtr->FvBlocks[Index].NumBlocks > 0 && FvInfoPtr->FvBlocks[Index].Length > 0; Index++) {
3036     FvInfoPtr->Size += FvInfoPtr->FvBlocks[Index].NumBlocks * FvInfoPtr->FvBlocks[Index].Length;
3037   }
3038 
3039   //
3040   // Calculate the required sizes for all FFS files.
3041   //
3042   CurrentOffset = sizeof (EFI_FIRMWARE_VOLUME_HEADER);
3043 
3044   for (Index = 1;; Index ++) {
3045     CurrentOffset += sizeof (EFI_FV_BLOCK_MAP_ENTRY);
3046     if (FvInfoPtr->FvBlocks[Index].NumBlocks == 0 || FvInfoPtr->FvBlocks[Index].Length == 0) {
3047       break;
3048     }
3049   }
3050 
3051   //
3052   // Calculate PI extension header
3053   //
3054   if (mFvDataInfo.FvExtHeaderFile[0] != '\0') {
3055     fpin = fopen (LongFilePath (mFvDataInfo.FvExtHeaderFile), "rb");
3056     if (fpin == NULL) {
3057       Error (NULL, 0, 0001, "Error opening file", mFvDataInfo.FvExtHeaderFile);
3058       return EFI_ABORTED;
3059     }
3060     FvExtendHeaderSize = _filelength (fileno (fpin));
3061     fclose (fpin);
3062     if (sizeof (EFI_FFS_FILE_HEADER) + FvExtendHeaderSize >= MAX_FFS_SIZE) {
3063       CurrentOffset += sizeof (EFI_FFS_FILE_HEADER2) + FvExtendHeaderSize;
3064       mIsLargeFfs = TRUE;
3065     } else {
3066       CurrentOffset += sizeof (EFI_FFS_FILE_HEADER) + FvExtendHeaderSize;
3067     }
3068     CurrentOffset = (CurrentOffset + 7) & (~7);
3069   } else if (mFvDataInfo.FvNameGuidSet) {
3070     CurrentOffset += sizeof (EFI_FFS_FILE_HEADER) + sizeof (EFI_FIRMWARE_VOLUME_EXT_HEADER);
3071     CurrentOffset = (CurrentOffset + 7) & (~7);
3072   }
3073 
3074   //
3075   // Accumlate every FFS file size.
3076   //
3077   for (Index = 0; FvInfoPtr->FvFiles[Index][0] != 0; Index++) {
3078     //
3079     // Open FFS file
3080     //
3081     fpin = NULL;
3082     fpin = fopen (LongFilePath (FvInfoPtr->FvFiles[Index]), "rb");
3083     if (fpin == NULL) {
3084       Error (NULL, 0, 0001, "Error opening file", FvInfoPtr->FvFiles[Index]);
3085       return EFI_ABORTED;
3086     }
3087     //
3088     // Get the file size
3089     //
3090     FfsFileSize = _filelength (fileno (fpin));
3091     if (FfsFileSize >= MAX_FFS_SIZE) {
3092       FfsHeaderSize = sizeof(EFI_FFS_FILE_HEADER2);
3093       mIsLargeFfs = TRUE;
3094     } else {
3095       FfsHeaderSize = sizeof(EFI_FFS_FILE_HEADER);
3096     }
3097     //
3098     // Read Ffs File header
3099     //
3100     fread (&FfsHeader, sizeof (UINT8), sizeof (EFI_FFS_FILE_HEADER), fpin);
3101     //
3102     // close file
3103     //
3104     fclose (fpin);
3105 
3106     if (FvInfoPtr->IsPiFvImage) {
3107         //
3108         // Check whether this ffs file is vtf file
3109         //
3110         if (IsVtfFile (&FfsHeader)) {
3111           if (VtfFileFlag) {
3112             //
3113             // One Fv image can't have two vtf files.
3114             //
3115             Error (NULL, 0, 3000,"Invalid", "One Fv image can't have two vtf files.");
3116             return EFI_ABORTED;
3117           }
3118           VtfFileFlag = TRUE;
3119         VtfFileSize = FfsFileSize;
3120         continue;
3121       }
3122 
3123       //
3124       // Get the alignment of FFS file
3125       //
3126       ReadFfsAlignment (&FfsHeader, &FfsAlignment);
3127       FfsAlignment = 1 << FfsAlignment;
3128       //
3129       // Add Pad file
3130       //
3131       if (((CurrentOffset + FfsHeaderSize) % FfsAlignment) != 0) {
3132         //
3133         // Only EFI_FFS_FILE_HEADER is needed for a pad section.
3134         //
3135         CurrentOffset = (CurrentOffset + FfsHeaderSize + sizeof(EFI_FFS_FILE_HEADER) + FfsAlignment - 1) & ~(FfsAlignment - 1);
3136         CurrentOffset -= FfsHeaderSize;
3137       }
3138 	  }
3139 
3140     //
3141     // Add ffs file size
3142     //
3143     if (FvInfoPtr->SizeofFvFiles[Index] > FfsFileSize) {
3144     	CurrentOffset += FvInfoPtr->SizeofFvFiles[Index];
3145     } else {
3146     	CurrentOffset += FfsFileSize;
3147     }
3148 
3149     //
3150     // Make next ffs file start at QWord Boundry
3151     //
3152     if (FvInfoPtr->IsPiFvImage) {
3153     	CurrentOffset = (CurrentOffset + EFI_FFS_FILE_HEADER_ALIGNMENT - 1) & ~(EFI_FFS_FILE_HEADER_ALIGNMENT - 1);
3154     }
3155   }
3156   CurrentOffset += VtfFileSize;
3157   DebugMsg (NULL, 0, 9, "FvImage size", "The calculated fv image size is 0x%x and the current set fv image size is 0x%x", (unsigned) CurrentOffset, (unsigned) FvInfoPtr->Size);
3158 
3159   if (FvInfoPtr->Size == 0) {
3160     //
3161     // Update FvInfo data
3162     //
3163     FvInfoPtr->FvBlocks[0].NumBlocks = CurrentOffset / FvInfoPtr->FvBlocks[0].Length + ((CurrentOffset % FvInfoPtr->FvBlocks[0].Length)?1:0);
3164     FvInfoPtr->Size = FvInfoPtr->FvBlocks[0].NumBlocks * FvInfoPtr->FvBlocks[0].Length;
3165     FvInfoPtr->FvBlocks[1].NumBlocks = 0;
3166     FvInfoPtr->FvBlocks[1].Length = 0;
3167   } else if (FvInfoPtr->Size < CurrentOffset) {
3168     //
3169     // Not invalid
3170     //
3171     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);
3172     return EFI_INVALID_PARAMETER;
3173   }
3174 
3175   //
3176   // Set Fv Size Information
3177   //
3178   mFvTotalSize = FvInfoPtr->Size;
3179   mFvTakenSize = CurrentOffset;
3180 
3181   return EFI_SUCCESS;
3182 }
3183 
3184 EFI_STATUS
FfsRebaseImageRead(IN VOID * FileHandle,IN UINTN FileOffset,IN OUT UINT32 * ReadSize,OUT VOID * Buffer)3185 FfsRebaseImageRead (
3186   IN     VOID    *FileHandle,
3187   IN     UINTN   FileOffset,
3188   IN OUT UINT32  *ReadSize,
3189   OUT    VOID    *Buffer
3190   )
3191 /*++
3192 
3193 Routine Description:
3194 
3195   Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file
3196 
3197 Arguments:
3198 
3199   FileHandle - The handle to the PE/COFF file
3200 
3201   FileOffset - The offset, in bytes, into the file to read
3202 
3203   ReadSize   - The number of bytes to read from the file starting at FileOffset
3204 
3205   Buffer     - A pointer to the buffer to read the data into.
3206 
3207 Returns:
3208 
3209   EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset
3210 
3211 --*/
3212 {
3213   CHAR8   *Destination8;
3214   CHAR8   *Source8;
3215   UINT32  Length;
3216 
3217   Destination8  = Buffer;
3218   Source8       = (CHAR8 *) ((UINTN) FileHandle + FileOffset);
3219   Length        = *ReadSize;
3220   while (Length--) {
3221     *(Destination8++) = *(Source8++);
3222   }
3223 
3224   return EFI_SUCCESS;
3225 }
3226 
3227 EFI_STATUS
GetChildFvFromFfs(IN FV_INFO * FvInfo,IN EFI_FFS_FILE_HEADER * FfsFile,IN UINTN XipOffset)3228 GetChildFvFromFfs (
3229   IN      FV_INFO               *FvInfo,
3230   IN      EFI_FFS_FILE_HEADER   *FfsFile,
3231   IN      UINTN                 XipOffset
3232   )
3233 /*++
3234 
3235 Routine Description:
3236 
3237   This function gets all child FvImages in the input FfsFile, and records
3238   their base address to the parent image.
3239 
3240 Arguments:
3241   FvInfo            A pointer to FV_INFO struture.
3242   FfsFile           A pointer to Ffs file image that may contain FvImage.
3243   XipOffset         The offset address to the parent FvImage base.
3244 
3245 Returns:
3246 
3247   EFI_SUCCESS        Base address of child Fv image is recorded.
3248 --*/
3249 {
3250   EFI_STATUS                          Status;
3251   UINTN                               Index;
3252   EFI_FILE_SECTION_POINTER            SubFvSection;
3253   EFI_FIRMWARE_VOLUME_HEADER          *SubFvImageHeader;
3254   EFI_PHYSICAL_ADDRESS                SubFvBaseAddress;
3255   EFI_FILE_SECTION_POINTER            CorePe32;
3256   UINT16                              MachineType;
3257 
3258   for (Index = 1;; Index++) {
3259     //
3260     // Find FV section
3261     //
3262     Status = GetSectionByType (FfsFile, EFI_SECTION_FIRMWARE_VOLUME_IMAGE, Index, &SubFvSection);
3263     if (EFI_ERROR (Status)) {
3264       break;
3265     }
3266     SubFvImageHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINT8 *) SubFvSection.FVImageSection + GetSectionHeaderLength(SubFvSection.FVImageSection));
3267 
3268     //
3269     // See if there's an SEC core in the child FV
3270     Status = FindCorePeSection(SubFvImageHeader, SubFvImageHeader->FvLength, EFI_FV_FILETYPE_SECURITY_CORE, &CorePe32);
3271 
3272     // if we couldn't find the SEC core, look for a PEI core
3273     if (EFI_ERROR(Status)) {
3274       Status = FindCorePeSection(SubFvImageHeader, SubFvImageHeader->FvLength, EFI_FV_FILETYPE_PEI_CORE, &CorePe32);
3275     }
3276 
3277     if (!EFI_ERROR(Status)) {
3278       Status = GetCoreMachineType(CorePe32, &MachineType);
3279       if (EFI_ERROR(Status)) {
3280         Error(NULL, 0, 3000, "Invalid", "Could not get the PE32 machine type for SEC/PEI Core.");
3281         return EFI_ABORTED;
3282       }
3283 
3284       // machine type is ARM, set a flag so ARM reset vector procesing occurs
3285       if ((MachineType == EFI_IMAGE_MACHINE_ARMT) || (MachineType == EFI_IMAGE_MACHINE_AARCH64)) {
3286         VerboseMsg("Located ARM/AArch64 SEC/PEI core in child FV");
3287         mArm = TRUE;
3288       }
3289     }
3290 
3291     //
3292     // Rebase on Flash
3293     //
3294     SubFvBaseAddress = FvInfo->BaseAddress + (UINTN) SubFvImageHeader - (UINTN) FfsFile + XipOffset;
3295     mFvBaseAddress[mFvBaseAddressNumber ++ ] = SubFvBaseAddress;
3296   }
3297 
3298   return EFI_SUCCESS;
3299 }
3300 
3301 EFI_STATUS
FfsRebase(IN OUT FV_INFO * FvInfo,IN CHAR8 * FileName,IN OUT EFI_FFS_FILE_HEADER * FfsFile,IN UINTN XipOffset,IN FILE * FvMapFile)3302 FfsRebase (
3303   IN OUT  FV_INFO               *FvInfo,
3304   IN      CHAR8                 *FileName,
3305   IN OUT  EFI_FFS_FILE_HEADER   *FfsFile,
3306   IN      UINTN                 XipOffset,
3307   IN      FILE                  *FvMapFile
3308   )
3309 /*++
3310 
3311 Routine Description:
3312 
3313   This function determines if a file is XIP and should be rebased.  It will
3314   rebase any PE32 sections found in the file using the base address.
3315 
3316 Arguments:
3317 
3318   FvInfo            A pointer to FV_INFO struture.
3319   FileName          Ffs File PathName
3320   FfsFile           A pointer to Ffs file image.
3321   XipOffset         The offset address to use for rebasing the XIP file image.
3322   FvMapFile         FvMapFile to record the function address in one Fvimage
3323 
3324 Returns:
3325 
3326   EFI_SUCCESS             The image was properly rebased.
3327   EFI_INVALID_PARAMETER   An input parameter is invalid.
3328   EFI_ABORTED             An error occurred while rebasing the input file image.
3329   EFI_OUT_OF_RESOURCES    Could not allocate a required resource.
3330   EFI_NOT_FOUND           No compressed sections could be found.
3331 
3332 --*/
3333 {
3334   EFI_STATUS                            Status;
3335   PE_COFF_LOADER_IMAGE_CONTEXT          ImageContext;
3336   PE_COFF_LOADER_IMAGE_CONTEXT          OrigImageContext;
3337   EFI_PHYSICAL_ADDRESS                  XipBase;
3338   EFI_PHYSICAL_ADDRESS                  NewPe32BaseAddress;
3339   UINTN                                 Index;
3340   EFI_FILE_SECTION_POINTER              CurrentPe32Section;
3341   EFI_FFS_FILE_STATE                    SavedState;
3342   EFI_IMAGE_OPTIONAL_HEADER_UNION       *ImgHdr;
3343   EFI_TE_IMAGE_HEADER                   *TEImageHeader;
3344   UINT8                                 *MemoryImagePointer;
3345   EFI_IMAGE_SECTION_HEADER              *SectionHeader;
3346   CHAR8                                 PeFileName [MAX_LONG_FILE_PATH];
3347   CHAR8                                 *Cptr;
3348   FILE                                  *PeFile;
3349   UINT8                                 *PeFileBuffer;
3350   UINT32                                PeFileSize;
3351   CHAR8                                 *PdbPointer;
3352   UINT32                                FfsHeaderSize;
3353   UINT32                                CurSecHdrSize;
3354 
3355   Index              = 0;
3356   MemoryImagePointer = NULL;
3357   TEImageHeader      = NULL;
3358   ImgHdr             = NULL;
3359   SectionHeader      = NULL;
3360   Cptr               = NULL;
3361   PeFile             = NULL;
3362   PeFileBuffer       = NULL;
3363 
3364   //
3365   // Don't need to relocate image when BaseAddress is zero and no ForceRebase Flag specified.
3366   //
3367   if ((FvInfo->BaseAddress == 0) && (FvInfo->ForceRebase == -1)) {
3368     return EFI_SUCCESS;
3369   }
3370 
3371   //
3372   // If ForceRebase Flag specified to FALSE, will always not take rebase action.
3373   //
3374   if (FvInfo->ForceRebase == 0) {
3375     return EFI_SUCCESS;
3376   }
3377 
3378 
3379   XipBase = FvInfo->BaseAddress + XipOffset;
3380 
3381   //
3382   // We only process files potentially containing PE32 sections.
3383   //
3384   switch (FfsFile->Type) {
3385     case EFI_FV_FILETYPE_SECURITY_CORE:
3386     case EFI_FV_FILETYPE_PEI_CORE:
3387     case EFI_FV_FILETYPE_PEIM:
3388     case EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER:
3389     case EFI_FV_FILETYPE_DRIVER:
3390     case EFI_FV_FILETYPE_DXE_CORE:
3391       break;
3392     case EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE:
3393       //
3394       // Rebase the inside FvImage.
3395       //
3396       GetChildFvFromFfs (FvInfo, FfsFile, XipOffset);
3397 
3398       //
3399       // Search PE/TE section in FV sectin.
3400       //
3401       break;
3402     default:
3403       return EFI_SUCCESS;
3404   }
3405 
3406   FfsHeaderSize = GetFfsHeaderLength(FfsFile);
3407   //
3408   // Rebase each PE32 section
3409   //
3410   Status      = EFI_SUCCESS;
3411   for (Index = 1;; Index++) {
3412     //
3413     // Init Value
3414     //
3415     NewPe32BaseAddress = 0;
3416 
3417     //
3418     // Find Pe Image
3419     //
3420     Status = GetSectionByType (FfsFile, EFI_SECTION_PE32, Index, &CurrentPe32Section);
3421     if (EFI_ERROR (Status)) {
3422       break;
3423     }
3424     CurSecHdrSize = GetSectionHeaderLength(CurrentPe32Section.CommonHeader);
3425 
3426     //
3427     // Initialize context
3428     //
3429     memset (&ImageContext, 0, sizeof (ImageContext));
3430     ImageContext.Handle     = (VOID *) ((UINTN) CurrentPe32Section.Pe32Section + CurSecHdrSize);
3431     ImageContext.ImageRead  = (PE_COFF_LOADER_READ_FILE) FfsRebaseImageRead;
3432     Status                  = PeCoffLoaderGetImageInfo (&ImageContext);
3433     if (EFI_ERROR (Status)) {
3434       Error (NULL, 0, 3000, "Invalid PeImage", "The input file is %s and the return status is %x", FileName, (int) Status);
3435       return Status;
3436     }
3437 
3438     if ( (ImageContext.Machine == EFI_IMAGE_MACHINE_ARMT) ||
3439          (ImageContext.Machine == EFI_IMAGE_MACHINE_AARCH64) ) {
3440       mArm = TRUE;
3441     }
3442 
3443     //
3444     // Keep Image Context for PE image in FV
3445     //
3446     memcpy (&OrigImageContext, &ImageContext, sizeof (ImageContext));
3447 
3448     //
3449     // Get File PdbPointer
3450     //
3451     PdbPointer = PeCoffLoaderGetPdbPointer (ImageContext.Handle);
3452 
3453     //
3454     // Get PeHeader pointer
3455     //
3456     ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((UINTN) CurrentPe32Section.Pe32Section + CurSecHdrSize + ImageContext.PeCoffHeaderOffset);
3457 
3458     //
3459     // Calculate the PE32 base address, based on file type
3460     //
3461     switch (FfsFile->Type) {
3462       case EFI_FV_FILETYPE_SECURITY_CORE:
3463       case EFI_FV_FILETYPE_PEI_CORE:
3464       case EFI_FV_FILETYPE_PEIM:
3465       case EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER:
3466         //
3467         // Check if section-alignment and file-alignment match or not
3468         //
3469         if ((ImgHdr->Pe32.OptionalHeader.SectionAlignment != ImgHdr->Pe32.OptionalHeader.FileAlignment)) {
3470           //
3471           // Xip module has the same section alignment and file alignment.
3472           //
3473           Error (NULL, 0, 3000, "Invalid", "Section-Alignment and File-Alignment do not match : %s.", FileName);
3474           return EFI_ABORTED;
3475         }
3476         //
3477         // PeImage has no reloc section. It will try to get reloc data from the original EFI image.
3478         //
3479         if (ImageContext.RelocationsStripped) {
3480           //
3481           // Construct the original efi file Name
3482           //
3483           strcpy (PeFileName, FileName);
3484           Cptr = PeFileName + strlen (PeFileName);
3485           while (*Cptr != '.') {
3486             Cptr --;
3487           }
3488           if (*Cptr != '.') {
3489             Error (NULL, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName);
3490             return EFI_ABORTED;
3491           } else {
3492             *(Cptr + 1) = 'e';
3493             *(Cptr + 2) = 'f';
3494             *(Cptr + 3) = 'i';
3495             *(Cptr + 4) = '\0';
3496           }
3497           PeFile = fopen (LongFilePath (PeFileName), "rb");
3498           if (PeFile == NULL) {
3499             Warning (NULL, 0, 0, "Invalid", "The file %s has no .reloc section.", FileName);
3500             //Error (NULL, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName);
3501             //return EFI_ABORTED;
3502             break;
3503           }
3504           //
3505           // Get the file size
3506           //
3507           PeFileSize = _filelength (fileno (PeFile));
3508           PeFileBuffer = (UINT8 *) malloc (PeFileSize);
3509           if (PeFileBuffer == NULL) {
3510             fclose (PeFile);
3511             Error (NULL, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName);
3512             return EFI_OUT_OF_RESOURCES;
3513           }
3514           //
3515           // Read Pe File
3516           //
3517           fread (PeFileBuffer, sizeof (UINT8), PeFileSize, PeFile);
3518           //
3519           // close file
3520           //
3521           fclose (PeFile);
3522           //
3523           // Handle pointer to the original efi image.
3524           //
3525           ImageContext.Handle = PeFileBuffer;
3526           Status              = PeCoffLoaderGetImageInfo (&ImageContext);
3527           if (EFI_ERROR (Status)) {
3528             Error (NULL, 0, 3000, "Invalid PeImage", "The input file is %s and the return status is %x", FileName, (int) Status);
3529             return Status;
3530           }
3531           ImageContext.RelocationsStripped = FALSE;
3532         }
3533 
3534         NewPe32BaseAddress = XipBase + (UINTN) CurrentPe32Section.Pe32Section + CurSecHdrSize - (UINTN)FfsFile;
3535         break;
3536 
3537       case EFI_FV_FILETYPE_DRIVER:
3538       case EFI_FV_FILETYPE_DXE_CORE:
3539         //
3540         // Check if section-alignment and file-alignment match or not
3541         //
3542         if ((ImgHdr->Pe32.OptionalHeader.SectionAlignment != ImgHdr->Pe32.OptionalHeader.FileAlignment)) {
3543           //
3544           // Xip module has the same section alignment and file alignment.
3545           //
3546           Error (NULL, 0, 3000, "Invalid", "Section-Alignment and File-Alignment do not match : %s.", FileName);
3547           return EFI_ABORTED;
3548         }
3549         NewPe32BaseAddress = XipBase + (UINTN) CurrentPe32Section.Pe32Section + CurSecHdrSize - (UINTN)FfsFile;
3550         break;
3551 
3552       default:
3553         //
3554         // Not supported file type
3555         //
3556         return EFI_SUCCESS;
3557     }
3558 
3559     //
3560     // Relocation doesn't exist
3561     //
3562     if (ImageContext.RelocationsStripped) {
3563       Warning (NULL, 0, 0, "Invalid", "The file %s has no .reloc section.", FileName);
3564       continue;
3565     }
3566 
3567     //
3568     // Relocation exist and rebase
3569     //
3570     //
3571     // Load and Relocate Image Data
3572     //
3573     MemoryImagePointer = (UINT8 *) malloc ((UINTN) ImageContext.ImageSize + ImageContext.SectionAlignment);
3574     if (MemoryImagePointer == NULL) {
3575       Error (NULL, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName);
3576       return EFI_OUT_OF_RESOURCES;
3577     }
3578     memset ((VOID *) MemoryImagePointer, 0, (UINTN) ImageContext.ImageSize + ImageContext.SectionAlignment);
3579     ImageContext.ImageAddress = ((UINTN) MemoryImagePointer + ImageContext.SectionAlignment - 1) & (~((UINTN) ImageContext.SectionAlignment - 1));
3580 
3581     Status =  PeCoffLoaderLoadImage (&ImageContext);
3582     if (EFI_ERROR (Status)) {
3583       Error (NULL, 0, 3000, "Invalid", "LocateImage() call failed on rebase of %s", FileName);
3584       free ((VOID *) MemoryImagePointer);
3585       return Status;
3586     }
3587 
3588     ImageContext.DestinationAddress = NewPe32BaseAddress;
3589     Status                          = PeCoffLoaderRelocateImage (&ImageContext);
3590     if (EFI_ERROR (Status)) {
3591       Error (NULL, 0, 3000, "Invalid", "RelocateImage() call failed on rebase of %s", FileName);
3592       free ((VOID *) MemoryImagePointer);
3593       return Status;
3594     }
3595 
3596     //
3597     // Copy Relocated data to raw image file.
3598     //
3599     SectionHeader = (EFI_IMAGE_SECTION_HEADER *) (
3600                        (UINTN) ImgHdr +
3601                        sizeof (UINT32) +
3602                        sizeof (EFI_IMAGE_FILE_HEADER) +
3603                        ImgHdr->Pe32.FileHeader.SizeOfOptionalHeader
3604                        );
3605 
3606     for (Index = 0; Index < ImgHdr->Pe32.FileHeader.NumberOfSections; Index ++, SectionHeader ++) {
3607       CopyMem (
3608         (UINT8 *) CurrentPe32Section.Pe32Section + CurSecHdrSize + SectionHeader->PointerToRawData,
3609         (VOID*) (UINTN) (ImageContext.ImageAddress + SectionHeader->VirtualAddress),
3610         SectionHeader->SizeOfRawData
3611         );
3612     }
3613 
3614     free ((VOID *) MemoryImagePointer);
3615     MemoryImagePointer = NULL;
3616     if (PeFileBuffer != NULL) {
3617       free (PeFileBuffer);
3618       PeFileBuffer = NULL;
3619     }
3620 
3621     //
3622     // Update Image Base Address
3623     //
3624     if (ImgHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
3625       ImgHdr->Pe32.OptionalHeader.ImageBase = (UINT32) NewPe32BaseAddress;
3626     } else if (ImgHdr->Pe32Plus.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
3627       ImgHdr->Pe32Plus.OptionalHeader.ImageBase = NewPe32BaseAddress;
3628     } else {
3629       Error (NULL, 0, 3000, "Invalid", "unknown PE magic signature %X in PE32 image %s",
3630         ImgHdr->Pe32.OptionalHeader.Magic,
3631         FileName
3632         );
3633       return EFI_ABORTED;
3634     }
3635 
3636     //
3637     // Now update file checksum
3638     //
3639     if (FfsFile->Attributes & FFS_ATTRIB_CHECKSUM) {
3640       SavedState  = FfsFile->State;
3641       FfsFile->IntegrityCheck.Checksum.File = 0;
3642       FfsFile->State                        = 0;
3643       FfsFile->IntegrityCheck.Checksum.File = CalculateChecksum8 (
3644                                                 (UINT8 *) ((UINT8 *)FfsFile + FfsHeaderSize),
3645                                                 GetFfsFileLength (FfsFile) - FfsHeaderSize
3646                                                 );
3647       FfsFile->State = SavedState;
3648     }
3649 
3650     //
3651     // Get this module function address from ModulePeMapFile and add them into FvMap file
3652     //
3653 
3654     //
3655     // Default use FileName as map file path
3656     //
3657     if (PdbPointer == NULL) {
3658       PdbPointer = FileName;
3659     }
3660 
3661     WriteMapFile (FvMapFile, PdbPointer, FfsFile, NewPe32BaseAddress, &OrigImageContext);
3662   }
3663 
3664   if (FfsFile->Type != EFI_FV_FILETYPE_SECURITY_CORE &&
3665       FfsFile->Type != EFI_FV_FILETYPE_PEI_CORE &&
3666       FfsFile->Type != EFI_FV_FILETYPE_PEIM &&
3667       FfsFile->Type != EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER &&
3668       FfsFile->Type != EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE
3669       ) {
3670     //
3671     // Only Peim code may have a TE section
3672     //
3673     return EFI_SUCCESS;
3674   }
3675 
3676   //
3677   // Now process TE sections
3678   //
3679   for (Index = 1;; Index++) {
3680     NewPe32BaseAddress = 0;
3681 
3682     //
3683     // Find Te Image
3684     //
3685     Status = GetSectionByType (FfsFile, EFI_SECTION_TE, Index, &CurrentPe32Section);
3686     if (EFI_ERROR (Status)) {
3687       break;
3688     }
3689 
3690     CurSecHdrSize = GetSectionHeaderLength(CurrentPe32Section.CommonHeader);
3691 
3692     //
3693     // Calculate the TE base address, the FFS file base plus the offset of the TE section less the size stripped off
3694     // by GenTEImage
3695     //
3696     TEImageHeader = (EFI_TE_IMAGE_HEADER *) ((UINT8 *) CurrentPe32Section.Pe32Section + CurSecHdrSize);
3697 
3698     //
3699     // Initialize context, load image info.
3700     //
3701     memset (&ImageContext, 0, sizeof (ImageContext));
3702     ImageContext.Handle     = (VOID *) TEImageHeader;
3703     ImageContext.ImageRead  = (PE_COFF_LOADER_READ_FILE) FfsRebaseImageRead;
3704     Status                  = PeCoffLoaderGetImageInfo (&ImageContext);
3705     if (EFI_ERROR (Status)) {
3706       Error (NULL, 0, 3000, "Invalid TeImage", "The input file is %s and the return status is %x", FileName, (int) Status);
3707       return Status;
3708     }
3709 
3710     if ( (ImageContext.Machine == EFI_IMAGE_MACHINE_ARMT) ||
3711          (ImageContext.Machine == EFI_IMAGE_MACHINE_AARCH64) ) {
3712       mArm = TRUE;
3713     }
3714 
3715     //
3716     // Keep Image Context for TE image in FV
3717     //
3718     memcpy (&OrigImageContext, &ImageContext, sizeof (ImageContext));
3719 
3720     //
3721     // Get File PdbPointer
3722     //
3723     PdbPointer = PeCoffLoaderGetPdbPointer (ImageContext.Handle);
3724 
3725     //
3726     // Set new rebased address.
3727     //
3728     NewPe32BaseAddress = XipBase + (UINTN) TEImageHeader + sizeof (EFI_TE_IMAGE_HEADER) \
3729                          - TEImageHeader->StrippedSize - (UINTN) FfsFile;
3730 
3731     //
3732     // if reloc is stripped, try to get the original efi image to get reloc info.
3733     //
3734     if (ImageContext.RelocationsStripped) {
3735       //
3736       // Construct the original efi file name
3737       //
3738       strcpy (PeFileName, FileName);
3739       Cptr = PeFileName + strlen (PeFileName);
3740       while (*Cptr != '.') {
3741         Cptr --;
3742       }
3743 
3744       if (*Cptr != '.') {
3745         Error (NULL, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName);
3746         return EFI_ABORTED;
3747       } else {
3748         *(Cptr + 1) = 'e';
3749         *(Cptr + 2) = 'f';
3750         *(Cptr + 3) = 'i';
3751         *(Cptr + 4) = '\0';
3752       }
3753 
3754       PeFile = fopen (LongFilePath (PeFileName), "rb");
3755       if (PeFile == NULL) {
3756         Warning (NULL, 0, 0, "Invalid", "The file %s has no .reloc section.", FileName);
3757         //Error (NULL, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName);
3758         //return EFI_ABORTED;
3759       } else {
3760         //
3761         // Get the file size
3762         //
3763         PeFileSize = _filelength (fileno (PeFile));
3764         PeFileBuffer = (UINT8 *) malloc (PeFileSize);
3765         if (PeFileBuffer == NULL) {
3766           fclose (PeFile);
3767           Error (NULL, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName);
3768           return EFI_OUT_OF_RESOURCES;
3769         }
3770         //
3771         // Read Pe File
3772         //
3773         fread (PeFileBuffer, sizeof (UINT8), PeFileSize, PeFile);
3774         //
3775         // close file
3776         //
3777         fclose (PeFile);
3778         //
3779         // Append reloc section into TeImage
3780         //
3781         ImageContext.Handle = PeFileBuffer;
3782         Status              = PeCoffLoaderGetImageInfo (&ImageContext);
3783         if (EFI_ERROR (Status)) {
3784           Error (NULL, 0, 3000, "Invalid TeImage", "The input file is %s and the return status is %x", FileName, (int) Status);
3785           return Status;
3786         }
3787         ImageContext.RelocationsStripped = FALSE;
3788       }
3789     }
3790     //
3791     // Relocation doesn't exist
3792     //
3793     if (ImageContext.RelocationsStripped) {
3794       Warning (NULL, 0, 0, "Invalid", "The file %s has no .reloc section.", FileName);
3795       continue;
3796     }
3797 
3798     //
3799     // Relocation exist and rebase
3800     //
3801     //
3802     // Load and Relocate Image Data
3803     //
3804     MemoryImagePointer = (UINT8 *) malloc ((UINTN) ImageContext.ImageSize + ImageContext.SectionAlignment);
3805     if (MemoryImagePointer == NULL) {
3806       Error (NULL, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName);
3807       return EFI_OUT_OF_RESOURCES;
3808     }
3809     memset ((VOID *) MemoryImagePointer, 0, (UINTN) ImageContext.ImageSize + ImageContext.SectionAlignment);
3810     ImageContext.ImageAddress = ((UINTN) MemoryImagePointer + ImageContext.SectionAlignment - 1) & (~((UINTN) ImageContext.SectionAlignment - 1));
3811 
3812     Status =  PeCoffLoaderLoadImage (&ImageContext);
3813     if (EFI_ERROR (Status)) {
3814       Error (NULL, 0, 3000, "Invalid", "LocateImage() call failed on rebase of %s", FileName);
3815       free ((VOID *) MemoryImagePointer);
3816       return Status;
3817     }
3818     //
3819     // Reloacate TeImage
3820     //
3821     ImageContext.DestinationAddress = NewPe32BaseAddress;
3822     Status                          = PeCoffLoaderRelocateImage (&ImageContext);
3823     if (EFI_ERROR (Status)) {
3824       Error (NULL, 0, 3000, "Invalid", "RelocateImage() call failed on rebase of TE image %s", FileName);
3825       free ((VOID *) MemoryImagePointer);
3826       return Status;
3827     }
3828 
3829     //
3830     // Copy the relocated image into raw image file.
3831     //
3832     SectionHeader = (EFI_IMAGE_SECTION_HEADER *) (TEImageHeader + 1);
3833     for (Index = 0; Index < TEImageHeader->NumberOfSections; Index ++, SectionHeader ++) {
3834       if (!ImageContext.IsTeImage) {
3835         CopyMem (
3836           (UINT8 *) TEImageHeader + sizeof (EFI_TE_IMAGE_HEADER) - TEImageHeader->StrippedSize + SectionHeader->PointerToRawData,
3837           (VOID*) (UINTN) (ImageContext.ImageAddress + SectionHeader->VirtualAddress),
3838           SectionHeader->SizeOfRawData
3839           );
3840       } else {
3841         CopyMem (
3842           (UINT8 *) TEImageHeader + sizeof (EFI_TE_IMAGE_HEADER) - TEImageHeader->StrippedSize + SectionHeader->PointerToRawData,
3843           (VOID*) (UINTN) (ImageContext.ImageAddress + sizeof (EFI_TE_IMAGE_HEADER) - TEImageHeader->StrippedSize + SectionHeader->VirtualAddress),
3844           SectionHeader->SizeOfRawData
3845           );
3846       }
3847     }
3848 
3849     //
3850     // Free the allocated memory resource
3851     //
3852     free ((VOID *) MemoryImagePointer);
3853     MemoryImagePointer = NULL;
3854     if (PeFileBuffer != NULL) {
3855       free (PeFileBuffer);
3856       PeFileBuffer = NULL;
3857     }
3858 
3859     //
3860     // Update Image Base Address
3861     //
3862     TEImageHeader->ImageBase = NewPe32BaseAddress;
3863 
3864     //
3865     // Now update file checksum
3866     //
3867     if (FfsFile->Attributes & FFS_ATTRIB_CHECKSUM) {
3868       SavedState  = FfsFile->State;
3869       FfsFile->IntegrityCheck.Checksum.File = 0;
3870       FfsFile->State                        = 0;
3871       FfsFile->IntegrityCheck.Checksum.File = CalculateChecksum8 (
3872                                                 (UINT8 *)((UINT8 *)FfsFile + FfsHeaderSize),
3873                                                 GetFfsFileLength (FfsFile) - FfsHeaderSize
3874                                                 );
3875       FfsFile->State = SavedState;
3876     }
3877     //
3878     // Get this module function address from ModulePeMapFile and add them into FvMap file
3879     //
3880 
3881     //
3882     // Default use FileName as map file path
3883     //
3884     if (PdbPointer == NULL) {
3885       PdbPointer = FileName;
3886     }
3887 
3888     WriteMapFile (
3889       FvMapFile,
3890       PdbPointer,
3891       FfsFile,
3892       NewPe32BaseAddress,
3893       &OrigImageContext
3894       );
3895   }
3896 
3897   return EFI_SUCCESS;
3898 }
3899 
3900 EFI_STATUS
FindApResetVectorPosition(IN MEMORY_FILE * FvImage,OUT UINT8 ** Pointer)3901 FindApResetVectorPosition (
3902   IN  MEMORY_FILE  *FvImage,
3903   OUT UINT8        **Pointer
3904   )
3905 /*++
3906 
3907 Routine Description:
3908 
3909   Find the position in this FvImage to place Ap reset vector.
3910 
3911 Arguments:
3912 
3913   FvImage       Memory file for the FV memory image.
3914   Pointer       Pointer to pointer to position.
3915 
3916 Returns:
3917 
3918   EFI_NOT_FOUND   - No satisfied position is found.
3919   EFI_SUCCESS     - The suitable position is return.
3920 
3921 --*/
3922 {
3923   EFI_FFS_FILE_HEADER   *PadFile;
3924   UINT32                Index;
3925   EFI_STATUS            Status;
3926   UINT8                 *FixPoint;
3927   UINT32                FileLength;
3928 
3929   for (Index = 1; ;Index ++) {
3930     //
3931     // Find Pad File to add ApResetVector info
3932     //
3933     Status = GetFileByType (EFI_FV_FILETYPE_FFS_PAD, Index, &PadFile);
3934     if (EFI_ERROR (Status) || (PadFile == NULL)) {
3935       //
3936       // No Pad file to be found.
3937       //
3938       break;
3939     }
3940     //
3941     // Get Pad file size.
3942     //
3943     FileLength = GetFfsFileLength(PadFile);
3944     FileLength = (FileLength + EFI_FFS_FILE_HEADER_ALIGNMENT - 1) & ~(EFI_FFS_FILE_HEADER_ALIGNMENT - 1);
3945     //
3946     // FixPoint must be align on 0x1000 relative to FvImage Header
3947     //
3948     FixPoint = (UINT8*) PadFile + GetFfsHeaderLength(PadFile);
3949     FixPoint = FixPoint + 0x1000 - (((UINTN) FixPoint - (UINTN) FvImage->FileImage) & 0xFFF);
3950     //
3951     // FixPoint be larger at the last place of one fv image.
3952     //
3953     while (((UINTN) FixPoint + SIZEOF_STARTUP_DATA_ARRAY - (UINTN) PadFile) <= FileLength) {
3954       FixPoint += 0x1000;
3955     }
3956     FixPoint -= 0x1000;
3957 
3958     if ((UINTN) FixPoint < ((UINTN) PadFile + GetFfsHeaderLength(PadFile))) {
3959       //
3960       // No alignment FixPoint in this Pad File.
3961       //
3962       continue;
3963     }
3964 
3965     if ((UINTN) FvImage->Eof - (UINTN)FixPoint <= 0x20000) {
3966       //
3967       // Find the position to place ApResetVector
3968       //
3969       *Pointer = FixPoint;
3970       return EFI_SUCCESS;
3971     }
3972   }
3973 
3974   return EFI_NOT_FOUND;
3975 }
3976 
3977 EFI_STATUS
ParseCapInf(IN MEMORY_FILE * InfFile,OUT CAP_INFO * CapInfo)3978 ParseCapInf (
3979   IN  MEMORY_FILE  *InfFile,
3980   OUT CAP_INFO     *CapInfo
3981   )
3982 /*++
3983 
3984 Routine Description:
3985 
3986   This function parses a Cap.INF file and copies info into a CAP_INFO structure.
3987 
3988 Arguments:
3989 
3990   InfFile        Memory file image.
3991   CapInfo        Information read from INF file.
3992 
3993 Returns:
3994 
3995   EFI_SUCCESS       INF file information successfully retrieved.
3996   EFI_ABORTED       INF file has an invalid format.
3997   EFI_NOT_FOUND     A required string was not found in the INF file.
3998 --*/
3999 {
4000   CHAR8       Value[MAX_LONG_FILE_PATH];
4001   UINT64      Value64;
4002   UINTN       Index, Number;
4003   EFI_STATUS  Status;
4004 
4005   //
4006   // Initialize Cap info
4007   //
4008   // memset (CapInfo, 0, sizeof (CAP_INFO));
4009   //
4010 
4011   //
4012   // Read the Capsule Guid
4013   //
4014   Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_CAPSULE_GUID_STRING, 0, Value);
4015   if (Status == EFI_SUCCESS) {
4016     //
4017     // Get the Capsule Guid
4018     //
4019     Status = StringToGuid (Value, &CapInfo->CapGuid);
4020     if (EFI_ERROR (Status)) {
4021       Error (NULL, 0, 2000, "Invalid parameter", "%s = %s", EFI_CAPSULE_GUID_STRING, Value);
4022       return EFI_ABORTED;
4023     }
4024     DebugMsg (NULL, 0, 9, "Capsule Guid", "%s = %s", EFI_CAPSULE_GUID_STRING, Value);
4025   }
4026 
4027   //
4028   // Read the Capsule Header Size
4029   //
4030   Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_CAPSULE_HEADER_SIZE_STRING, 0, Value);
4031   if (Status == EFI_SUCCESS) {
4032     Status = AsciiStringToUint64 (Value, FALSE, &Value64);
4033     if (EFI_ERROR (Status)) {
4034       Error (NULL, 0, 2000, "Invalid parameter", "%s = %s", EFI_CAPSULE_HEADER_SIZE_STRING, Value);
4035       return EFI_ABORTED;
4036     }
4037     CapInfo->HeaderSize = (UINT32) Value64;
4038     DebugMsg (NULL, 0, 9, "Capsule Header size", "%s = %s", EFI_CAPSULE_HEADER_SIZE_STRING, Value);
4039   }
4040 
4041   //
4042   // Read the Capsule Flag
4043   //
4044   Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_CAPSULE_FLAGS_STRING, 0, Value);
4045   if (Status == EFI_SUCCESS) {
4046     if (strstr (Value, "PopulateSystemTable") != NULL) {
4047       CapInfo->Flags |= CAPSULE_FLAGS_PERSIST_ACROSS_RESET | CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE;
4048       if (strstr (Value, "InitiateReset") != NULL) {
4049         CapInfo->Flags |= CAPSULE_FLAGS_INITIATE_RESET;
4050       }
4051     } else if (strstr (Value, "PersistAcrossReset") != NULL) {
4052       CapInfo->Flags |= CAPSULE_FLAGS_PERSIST_ACROSS_RESET;
4053       if (strstr (Value, "InitiateReset") != NULL) {
4054         CapInfo->Flags |= CAPSULE_FLAGS_INITIATE_RESET;
4055       }
4056     } else {
4057       Error (NULL, 0, 2000, "Invalid parameter", "invalid Flag setting for %s.", EFI_CAPSULE_FLAGS_STRING);
4058       return EFI_ABORTED;
4059     }
4060     DebugMsg (NULL, 0, 9, "Capsule Flag", Value);
4061   }
4062 
4063   Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_OEM_CAPSULE_FLAGS_STRING, 0, Value);
4064   if (Status == EFI_SUCCESS) {
4065     Status = AsciiStringToUint64 (Value, FALSE, &Value64);
4066     if (EFI_ERROR (Status) || Value64 > 0xffff) {
4067       Error (NULL, 0, 2000, "Invalid parameter",
4068         "invalid Flag setting for %s. Must be integer value between 0x0000 and 0xffff.",
4069         EFI_OEM_CAPSULE_FLAGS_STRING);
4070       return EFI_ABORTED;
4071     }
4072     CapInfo->Flags |= Value64;
4073     DebugMsg (NULL, 0, 9, "Capsule Extend Flag", Value);
4074   }
4075 
4076   //
4077   // Read Capsule File name
4078   //
4079   Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_FILE_NAME_STRING, 0, Value);
4080   if (Status == EFI_SUCCESS) {
4081     //
4082     // Get output file name
4083     //
4084     strcpy (CapInfo->CapName, Value);
4085   }
4086 
4087   //
4088   // Read the Capsule FileImage
4089   //
4090   Number = 0;
4091   for (Index = 0; Index < MAX_NUMBER_OF_FILES_IN_CAP; Index++) {
4092     if (CapInfo->CapFiles[Index][0] != '\0') {
4093       continue;
4094     }
4095     //
4096     // Read the capsule file name
4097     //
4098     Status = FindToken (InfFile, FILES_SECTION_STRING, EFI_FILE_NAME_STRING, Number++, Value);
4099 
4100     if (Status == EFI_SUCCESS) {
4101       //
4102       // Add the file
4103       //
4104       strcpy (CapInfo->CapFiles[Index], Value);
4105       DebugMsg (NULL, 0, 9, "Capsule component file", "the %uth file name is %s", (unsigned) Index, CapInfo->CapFiles[Index]);
4106     } else {
4107       break;
4108     }
4109   }
4110 
4111   if (Index == 0) {
4112     Warning (NULL, 0, 0, "Capsule components are not specified.", NULL);
4113   }
4114 
4115   return EFI_SUCCESS;
4116 }
4117 
4118 EFI_STATUS
GenerateCapImage(IN CHAR8 * InfFileImage,IN UINTN InfFileSize,IN CHAR8 * CapFileName)4119 GenerateCapImage (
4120   IN CHAR8                *InfFileImage,
4121   IN UINTN                InfFileSize,
4122   IN CHAR8                *CapFileName
4123   )
4124 /*++
4125 
4126 Routine Description:
4127 
4128   This is the main function which will be called from application to create UEFI Capsule image.
4129 
4130 Arguments:
4131 
4132   InfFileImage   Buffer containing the INF file contents.
4133   InfFileSize    Size of the contents of the InfFileImage buffer.
4134   CapFileName    Requested name for the Cap file.
4135 
4136 Returns:
4137 
4138   EFI_SUCCESS             Function completed successfully.
4139   EFI_OUT_OF_RESOURCES    Could not allocate required resources.
4140   EFI_ABORTED             Error encountered.
4141   EFI_INVALID_PARAMETER   A required parameter was NULL.
4142 
4143 --*/
4144 {
4145   UINT32                CapSize;
4146   UINT8                 *CapBuffer;
4147   EFI_CAPSULE_HEADER    *CapsuleHeader;
4148   MEMORY_FILE           InfMemoryFile;
4149   UINT32                FileSize;
4150   UINT32                Index;
4151   FILE                  *fpin, *fpout;
4152   EFI_STATUS            Status;
4153 
4154   if (InfFileImage != NULL) {
4155     //
4156     // Initialize file structures
4157     //
4158     InfMemoryFile.FileImage           = InfFileImage;
4159     InfMemoryFile.CurrentFilePointer  = InfFileImage;
4160     InfMemoryFile.Eof                 = InfFileImage + InfFileSize;
4161 
4162     //
4163     // Parse the Cap inf file for header information
4164     //
4165     Status = ParseCapInf (&InfMemoryFile, &mCapDataInfo);
4166     if (Status != EFI_SUCCESS) {
4167       return Status;
4168     }
4169   }
4170 
4171   if (mCapDataInfo.HeaderSize == 0) {
4172     //
4173     // make header size align 16 bytes.
4174     //
4175     mCapDataInfo.HeaderSize = sizeof (EFI_CAPSULE_HEADER);
4176     mCapDataInfo.HeaderSize = (mCapDataInfo.HeaderSize + 0xF) & ~0xF;
4177   }
4178 
4179   if (mCapDataInfo.HeaderSize < sizeof (EFI_CAPSULE_HEADER)) {
4180     Error (NULL, 0, 2000, "Invalid parameter", "The specified HeaderSize cannot be less than the size of EFI_CAPSULE_HEADER.");
4181     return EFI_INVALID_PARAMETER;
4182   }
4183 
4184   if (CapFileName == NULL && mCapDataInfo.CapName[0] != '\0') {
4185     CapFileName = mCapDataInfo.CapName;
4186   }
4187 
4188   if (CapFileName == NULL) {
4189     Error (NULL, 0, 2001, "Missing required argument", "Output Capsule file name");
4190     return EFI_INVALID_PARAMETER;
4191   }
4192 
4193   //
4194   // Set Default Capsule Guid value
4195   //
4196   if (CompareGuid (&mCapDataInfo.CapGuid, &mZeroGuid) == 0) {
4197     memcpy (&mCapDataInfo.CapGuid, &mDefaultCapsuleGuid, sizeof (EFI_GUID));
4198   }
4199   //
4200   // Calculate the size of capsule image.
4201   //
4202   Index    = 0;
4203   FileSize = 0;
4204   CapSize  = mCapDataInfo.HeaderSize;
4205   while (mCapDataInfo.CapFiles [Index][0] != '\0') {
4206     fpin = fopen (LongFilePath (mCapDataInfo.CapFiles[Index]), "rb");
4207     if (fpin == NULL) {
4208       Error (NULL, 0, 0001, "Error opening file", mCapDataInfo.CapFiles[Index]);
4209       return EFI_ABORTED;
4210     }
4211     FileSize  = _filelength (fileno (fpin));
4212     CapSize  += FileSize;
4213     fclose (fpin);
4214     Index ++;
4215   }
4216 
4217   //
4218   // Allocate buffer for capsule image.
4219   //
4220   CapBuffer = (UINT8 *) malloc (CapSize);
4221   if (CapBuffer == NULL) {
4222     Error (NULL, 0, 4001, "Resource", "memory cannot be allocated for creating the capsule.");
4223     return EFI_OUT_OF_RESOURCES;
4224   }
4225 
4226   //
4227   // Initialize the capsule header to zero
4228   //
4229   memset (CapBuffer, 0, mCapDataInfo.HeaderSize);
4230 
4231   //
4232   // create capsule header and get capsule body
4233   //
4234   CapsuleHeader = (EFI_CAPSULE_HEADER *) CapBuffer;
4235   memcpy (&CapsuleHeader->CapsuleGuid, &mCapDataInfo.CapGuid, sizeof (EFI_GUID));
4236   CapsuleHeader->HeaderSize       = mCapDataInfo.HeaderSize;
4237   CapsuleHeader->Flags            = mCapDataInfo.Flags;
4238   CapsuleHeader->CapsuleImageSize = CapSize;
4239 
4240   Index    = 0;
4241   FileSize = 0;
4242   CapSize  = CapsuleHeader->HeaderSize;
4243   while (mCapDataInfo.CapFiles [Index][0] != '\0') {
4244     fpin = fopen (LongFilePath (mCapDataInfo.CapFiles[Index]), "rb");
4245     if (fpin == NULL) {
4246       Error (NULL, 0, 0001, "Error opening file", mCapDataInfo.CapFiles[Index]);
4247       free (CapBuffer);
4248       return EFI_ABORTED;
4249     }
4250     FileSize = _filelength (fileno (fpin));
4251     fread (CapBuffer + CapSize, 1, FileSize, fpin);
4252     fclose (fpin);
4253     Index ++;
4254     CapSize += FileSize;
4255   }
4256 
4257   //
4258   // write capsule data into the output file
4259   //
4260   fpout = fopen (LongFilePath (CapFileName), "wb");
4261   if (fpout == NULL) {
4262     Error (NULL, 0, 0001, "Error opening file", CapFileName);
4263     free (CapBuffer);
4264     return EFI_ABORTED;
4265   }
4266 
4267   fwrite (CapBuffer, 1, CapSize, fpout);
4268   fclose (fpout);
4269   free (CapBuffer);
4270 
4271   VerboseMsg ("The size of the generated capsule image is %u bytes", (unsigned) CapSize);
4272 
4273   return EFI_SUCCESS;
4274 }
4275