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