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