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