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