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