Scrub BaseTools C Source to solve some gaps between EFI BaseTypes to POSIX types...
[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 %uth name is %s", (unsigned) 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   unsigned long long                  TempLongAddress;\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, ", (unsigned long long) ImageBaseAddress);\r
811   } else {\r
812     fprintf (FvMapFile, "%s (", KeyWord);\r
813     fprintf (FvMapFile, "BaseAddress=%08llx, ", (unsigned long long) (ImageBaseAddress + Offset));\r
814   }\r
815   fprintf (FvMapFile, "EntryPoint=%08llx, ", (unsigned long long) (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 ", (unsigned long long) (ImageBaseAddress + SectionHeader->VirtualAddress));\r
822         } else if (stricmp ((CHAR8 *)SectionHeader->Name, ".data") == 0) {\r
823           fprintf (FvMapFile, ".databaseaddress=%08llx ", (unsigned long long) (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, &TempLongAddress, FunctionTypeName);\r
874       FunctionAddress = (UINT64) TempLongAddress;\r
875       if (FunctionTypeName [1] == '\0' && (FunctionTypeName [0] == 'f' || FunctionTypeName [0] == 'F')) {\r
876         fprintf (FvMapFile, "  %016llx ", (unsigned long long) (ImageBaseAddress + FunctionAddress));\r
877         fprintf (FvMapFile, "(%08llx) F  ", (unsigned long long) (FunctionAddress - Offset));\r
878         fprintf (FvMapFile, "%s\n", FunctionName);\r
879     } else {\r
880         fprintf (FvMapFile, "  %016llx ", (unsigned long long) (ImageBaseAddress + FunctionAddress));\r
881         fprintf (FvMapFile, "(%08llx)    ", (unsigned long long) (FunctionAddress - Offset));\r
882         fprintf (FvMapFile, "%s\n", FunctionName);\r
883       }\r
884     } else if (FunctionType == 2) {\r
885       sscanf (Line, "%s %s %llx %s", KeyWord, FunctionName, &TempLongAddress, FunctionTypeName);\r
886       FunctionAddress = (UINT64) TempLongAddress;\r
887       if (FunctionTypeName [1] == '\0' && (FunctionTypeName [0] == 'f' || FunctionTypeName [0] == 'F')) {\r
888         fprintf (FvMapFile, "  %016llx ", (unsigned long long) (ImageBaseAddress + FunctionAddress));\r
889         fprintf (FvMapFile, "(%08llx) FS ", (unsigned long long) (FunctionAddress - Offset));\r
890         fprintf (FvMapFile, "%s\n", FunctionName);\r
891       } else {\r
892         fprintf (FvMapFile, "  %016llx ", (unsigned long long) (ImageBaseAddress + FunctionAddress));\r
893         fprintf (FvMapFile, "(%08llx)    ", (unsigned long long) (FunctionAddress - Offset));\r
894         fprintf (FvMapFile, "%s\n", FunctionName);\r
895       }\r
896     }\r
897   }\r
898   //\r
899   // Close PeMap file\r
900   //\r
901   fprintf (FvMapFile, "\n\n");\r
902   fclose (PeMapFile);\r
903   \r
904   return EFI_SUCCESS;\r
905 }\r
906 \r
907 EFI_STATUS\r
908 AddFile (\r
909   IN OUT MEMORY_FILE          *FvImage,\r
910   IN FV_INFO                  *FvInfo,\r
911   IN UINTN                    Index,\r
912   IN OUT EFI_FFS_FILE_HEADER  **VtfFileImage,\r
913   IN FILE                     *FvMapFile  \r
914   )\r
915 /*++\r
916 \r
917 Routine Description:\r
918 \r
919   This function adds a file to the FV image.  The file will pad to the\r
920   appropriate alignment if required.\r
921 \r
922 Arguments:\r
923 \r
924   FvImage       The memory image of the FV to add it to.  The current offset\r
925                 must be valid.\r
926   FvInfo        Pointer to information about the FV.\r
927   Index         The file in the FvInfo file list to add.\r
928   VtfFileImage  A pointer to the VTF file within the FvImage.  If this is equal\r
929                 to the end of the FvImage then no VTF previously found.\r
930   FvMapFile     Pointer to FvMap File\r
931 \r
932 Returns:\r
933 \r
934   EFI_SUCCESS              The function completed successfully.\r
935   EFI_INVALID_PARAMETER    One of the input parameters was invalid.\r
936   EFI_ABORTED              An error occurred.\r
937   EFI_OUT_OF_RESOURCES     Insufficient resources exist to complete the add.\r
938 \r
939 --*/\r
940 {\r
941   FILE                  *NewFile;\r
942   UINTN                 FileSize;\r
943   UINT8                 *FileBuffer;\r
944   UINTN                 NumBytesRead;\r
945   UINT32                CurrentFileAlignment;\r
946   EFI_STATUS            Status;\r
947   UINTN                 Index1;\r
948   \r
949   Index1 = 0;\r
950   //\r
951   // Verify input parameters.\r
952   //\r
953   if (FvImage == NULL || FvInfo == NULL || FvInfo->FvFiles[Index][0] == 0 || VtfFileImage == NULL) {\r
954     return EFI_INVALID_PARAMETER;\r
955   }\r
956 \r
957   //\r
958   // Read the file to add\r
959   //\r
960   NewFile = fopen (FvInfo->FvFiles[Index], "rb");\r
961 \r
962   if (NewFile == NULL) {\r
963     Error (NULL, 0, 0001, "Error opening file", FvInfo->FvFiles[Index]);\r
964     return EFI_ABORTED;\r
965   }\r
966 \r
967   //\r
968   // Get the file size\r
969   //\r
970   FileSize = _filelength (fileno (NewFile));\r
971 \r
972   //\r
973   // Read the file into a buffer\r
974   //\r
975   FileBuffer = malloc (FileSize);\r
976   if (FileBuffer == NULL) {\r
977     Error (NULL, 0, 4001, "Resouce", "memory cannot be allocated!");\r
978     return EFI_OUT_OF_RESOURCES;\r
979   }\r
980 \r
981   NumBytesRead = fread (FileBuffer, sizeof (UINT8), FileSize, NewFile);\r
982 \r
983   //\r
984   // Done with the file, from this point on we will just use the buffer read.\r
985   //\r
986   fclose (NewFile);\r
987   \r
988   //\r
989   // Verify read successful\r
990   //\r
991   if (NumBytesRead != sizeof (UINT8) * FileSize) {\r
992     free  (FileBuffer);\r
993     Error (NULL, 0, 0004, "Error reading file", FvInfo->FvFiles[Index]);\r
994     return EFI_ABORTED;\r
995   }\r
996   \r
997   //\r
998   // For None PI Ffs file, directly add them into FvImage.\r
999   //\r
1000   if (!FvInfo->IsPiFvImage) {\r
1001     memcpy (FvImage->CurrentFilePointer, FileBuffer, FileSize);\r
1002     if (FvInfo->SizeofFvFiles[Index] > FileSize) {\r
1003         FvImage->CurrentFilePointer += FvInfo->SizeofFvFiles[Index];\r
1004     } else {\r
1005         FvImage->CurrentFilePointer += FileSize;\r
1006     }\r
1007     goto Done;\r
1008   }\r
1009   \r
1010   //\r
1011   // Verify Ffs file\r
1012   //\r
1013   Status = VerifyFfsFile ((EFI_FFS_FILE_HEADER *)FileBuffer);\r
1014   if (EFI_ERROR (Status)) {\r
1015     free (FileBuffer);\r
1016     Error (NULL, 0, 3000, "Invalid", "%s is a FFS file.", FvInfo->FvFiles[Index]);\r
1017     return EFI_INVALID_PARAMETER;\r
1018   }\r
1019 \r
1020   //\r
1021   // Verify space exists to add the file\r
1022   //\r
1023   if (FileSize > (UINTN) ((UINTN) *VtfFileImage - (UINTN) FvImage->CurrentFilePointer)) {\r
1024     free (FileBuffer);\r
1025     Error (NULL, 0, 4002, "Resource", "FV space is full, not enough room to add file %s.", FvInfo->FvFiles[Index]);\r
1026     return EFI_OUT_OF_RESOURCES;\r
1027   }\r
1028 \r
1029   //\r
1030   // Verify the input file is the duplicated file in this Fv image\r
1031   //\r
1032   for (Index1 = 0; Index1 < Index; Index1 ++) {\r
1033     if (CompareGuid ((EFI_GUID *) FileBuffer, &mFileGuidArray [Index1]) == 0) {\r
1034       Error (NULL, 0, 2000, "Invalid parameter", "the %dth file and %uth file have the same file GUID.", (unsigned) Index1 + 1, (unsigned) Index + 1);\r
1035       PrintGuid ((EFI_GUID *) FileBuffer);\r
1036       return EFI_INVALID_PARAMETER;\r
1037     }\r
1038   }\r
1039   CopyMem (&mFileGuidArray [Index], FileBuffer, sizeof (EFI_GUID));\r
1040 \r
1041   //\r
1042   // Update the file state based on polarity of the FV.\r
1043   //\r
1044   UpdateFfsFileState (\r
1045     (EFI_FFS_FILE_HEADER *) FileBuffer,\r
1046     (EFI_FIRMWARE_VOLUME_HEADER *) FvImage->FileImage\r
1047     );\r
1048 \r
1049   //\r
1050   // Check if alignment is required\r
1051   //\r
1052   ReadFfsAlignment ((EFI_FFS_FILE_HEADER *) FileBuffer, &CurrentFileAlignment);\r
1053   \r
1054   //\r
1055   // Find the largest alignment of all the FFS files in the FV\r
1056   //\r
1057   if (CurrentFileAlignment > MaxFfsAlignment) {\r
1058     MaxFfsAlignment = CurrentFileAlignment;\r
1059   }\r
1060   //\r
1061   // If we have a VTF file, add it at the top.\r
1062   //\r
1063   if (IsVtfFile ((EFI_FFS_FILE_HEADER *) FileBuffer)) {\r
1064     if ((UINTN) *VtfFileImage == (UINTN) FvImage->Eof) {\r
1065       //\r
1066       // No previous VTF, add this one.\r
1067       //\r
1068       *VtfFileImage = (EFI_FFS_FILE_HEADER *) (UINTN) ((UINTN) FvImage->FileImage + FvInfo->Size - FileSize);\r
1069       //\r
1070       // Sanity check. The file MUST align appropriately\r
1071       //\r
1072       if (((UINTN) *VtfFileImage + sizeof (EFI_FFS_FILE_HEADER) - (UINTN) FvImage->FileImage) % (1 << CurrentFileAlignment)) {\r
1073         Error (NULL, 0, 3000, "Invalid", "VTF file cannot be aligned on a %u-byte boundary.", (unsigned) (1 << CurrentFileAlignment));\r
1074         free (FileBuffer);\r
1075         return EFI_ABORTED;\r
1076       }\r
1077       //\r
1078       // Rebase the PE or TE image in FileBuffer of FFS file for XIP \r
1079       // Rebase for the debug genfvmap tool\r
1080       //\r
1081       FfsRebase (FvInfo, FvInfo->FvFiles[Index], (EFI_FFS_FILE_HEADER *) FileBuffer, (UINTN) *VtfFileImage - (UINTN) FvImage->FileImage, FvMapFile);\r
1082       //\r
1083       // copy VTF File\r
1084       //\r
1085       memcpy (*VtfFileImage, FileBuffer, FileSize);\r
1086       free (FileBuffer);\r
1087       DebugMsg (NULL, 0, 9, "Add VTF FFS file in FV image", NULL);\r
1088       return EFI_SUCCESS;\r
1089     } else {\r
1090       //\r
1091       // Already found a VTF file.\r
1092       //\r
1093       Error (NULL, 0, 3000, "Invalid", "multiple VTF files are not permitted within a single FV.");\r
1094       free (FileBuffer);\r
1095       return EFI_ABORTED;\r
1096     }\r
1097   }\r
1098 \r
1099   //\r
1100   // Add pad file if necessary\r
1101   //\r
1102   Status = AddPadFile (FvImage, 1 << CurrentFileAlignment, NULL);\r
1103   if (EFI_ERROR (Status)) {\r
1104     Error (NULL, 0, 4002, "Resource", "FV space is full, could not add pad file for data alignment property.");\r
1105     free (FileBuffer);\r
1106     return EFI_ABORTED;\r
1107   }\r
1108   //\r
1109   // Add file\r
1110   //\r
1111   if ((FvImage->CurrentFilePointer + FileSize) < FvImage->Eof) {\r
1112     //\r
1113     // Rebase the PE or TE image in FileBuffer of FFS file for XIP. \r
1114     // Rebase Bs and Rt drivers for the debug genfvmap tool.\r
1115     //\r
1116     FfsRebase (FvInfo, FvInfo->FvFiles[Index], (EFI_FFS_FILE_HEADER *) FileBuffer, (UINTN) FvImage->CurrentFilePointer - (UINTN) FvImage->FileImage, FvMapFile);\r
1117     //\r
1118     // Copy the file\r
1119     //\r
1120     memcpy (FvImage->CurrentFilePointer, FileBuffer, FileSize);\r
1121     FvImage->CurrentFilePointer += FileSize;\r
1122   } else {\r
1123     Error (NULL, 0, 4002, "Resource", "FV space is full, cannot add file %s.", FvInfo->FvFiles[Index]);\r
1124     free (FileBuffer);\r
1125     return EFI_ABORTED;\r
1126   }\r
1127   //\r
1128   // Make next file start at QWord Boundry\r
1129   //\r
1130   while (((UINTN) FvImage->CurrentFilePointer & (EFI_FFS_FILE_HEADER_ALIGNMENT - 1)) != 0) {\r
1131     FvImage->CurrentFilePointer++;\r
1132   }\r
1133 \r
1134 Done: \r
1135   //\r
1136   // Free allocated memory.\r
1137   //\r
1138   free (FileBuffer);\r
1139 \r
1140   return EFI_SUCCESS;\r
1141 }\r
1142 \r
1143 EFI_STATUS\r
1144 PadFvImage (\r
1145   IN MEMORY_FILE          *FvImage,\r
1146   IN EFI_FFS_FILE_HEADER  *VtfFileImage\r
1147   )\r
1148 /*++\r
1149 \r
1150 Routine Description:\r
1151 \r
1152   This function places a pad file between the last file in the FV and the VTF\r
1153   file if the VTF file exists.\r
1154 \r
1155 Arguments:\r
1156 \r
1157   FvImage       Memory file for the FV memory image\r
1158   VtfFileImage  The address of the VTF file.  If this is the end of the FV\r
1159                 image, no VTF exists and no pad file is needed.\r
1160 \r
1161 Returns:\r
1162 \r
1163   EFI_SUCCESS             Completed successfully.\r
1164   EFI_INVALID_PARAMETER   One of the input parameters was NULL.\r
1165 \r
1166 --*/\r
1167 {\r
1168   EFI_FFS_FILE_HEADER *PadFile;\r
1169   UINTN               FileSize;\r
1170 \r
1171   //\r
1172   // If there is no VTF or the VTF naturally follows the previous file without a\r
1173   // pad file, then there's nothing to do\r
1174   //\r
1175   if ((UINTN) VtfFileImage == (UINTN) FvImage->Eof || \\r
1176       ((UINTN) VtfFileImage == (UINTN) FvImage->CurrentFilePointer)) {\r
1177     return EFI_SUCCESS;\r
1178   }\r
1179 \r
1180   //\r
1181   // Pad file starts at beginning of free space\r
1182   //\r
1183   PadFile = (EFI_FFS_FILE_HEADER *) FvImage->CurrentFilePointer;\r
1184 \r
1185   //\r
1186   // write PadFile FFS header with PadType, don't need to set PAD file guid in its header. \r
1187   //\r
1188   PadFile->Type       = EFI_FV_FILETYPE_FFS_PAD;\r
1189   PadFile->Attributes = 0;\r
1190 \r
1191   //\r
1192   // FileSize includes the EFI_FFS_FILE_HEADER\r
1193   //\r
1194   FileSize          = (UINTN) VtfFileImage - (UINTN) FvImage->CurrentFilePointer;\r
1195   PadFile->Size[0]  = (UINT8) (FileSize & 0x000000FF);\r
1196   PadFile->Size[1]  = (UINT8) ((FileSize & 0x0000FF00) >> 8);\r
1197   PadFile->Size[2]  = (UINT8) ((FileSize & 0x00FF0000) >> 16);\r
1198 \r
1199   //\r
1200   // Fill in checksums and state, must be zero during checksum calculation.\r
1201   //\r
1202   PadFile->IntegrityCheck.Checksum.Header = 0;\r
1203   PadFile->IntegrityCheck.Checksum.File   = 0;\r
1204   PadFile->State                          = 0;\r
1205   PadFile->IntegrityCheck.Checksum.Header = CalculateChecksum8 ((UINT8 *) PadFile, sizeof (EFI_FFS_FILE_HEADER));\r
1206   PadFile->IntegrityCheck.Checksum.File   = FFS_FIXED_CHECKSUM;\r
1207 \r
1208   PadFile->State = EFI_FILE_HEADER_CONSTRUCTION | EFI_FILE_HEADER_VALID | EFI_FILE_DATA_VALID;\r
1209 \r
1210   UpdateFfsFileState (\r
1211     (EFI_FFS_FILE_HEADER *) PadFile,\r
1212     (EFI_FIRMWARE_VOLUME_HEADER *) FvImage->FileImage\r
1213     );\r
1214   //\r
1215   // Update the current FV pointer\r
1216   //\r
1217   FvImage->CurrentFilePointer = FvImage->Eof;\r
1218 \r
1219   return EFI_SUCCESS;\r
1220 }\r
1221 \r
1222 EFI_STATUS\r
1223 UpdateResetVector (\r
1224   IN MEMORY_FILE            *FvImage,\r
1225   IN FV_INFO                *FvInfo,\r
1226   IN EFI_FFS_FILE_HEADER    *VtfFile\r
1227   )\r
1228 /*++\r
1229 \r
1230 Routine Description:\r
1231 \r
1232   This parses the FV looking for the PEI core and then plugs the address into\r
1233   the SALE_ENTRY point of the BSF/VTF for IPF and does BUGBUG TBD action to\r
1234   complete an IA32 Bootstrap FV.\r
1235 \r
1236 Arguments:\r
1237 \r
1238   FvImage       Memory file for the FV memory image\r
1239   FvInfo        Information read from INF file.\r
1240   VtfFile       Pointer to the VTF file in the FV image.\r
1241 \r
1242 Returns:\r
1243 \r
1244   EFI_SUCCESS             Function Completed successfully.\r
1245   EFI_ABORTED             Error encountered.\r
1246   EFI_INVALID_PARAMETER   A required parameter was NULL.\r
1247   EFI_NOT_FOUND           PEI Core file not found.\r
1248 \r
1249 --*/\r
1250 {\r
1251   EFI_FFS_FILE_HEADER       *PeiCoreFile;\r
1252   EFI_FFS_FILE_HEADER       *SecCoreFile;\r
1253   EFI_STATUS                Status;\r
1254   EFI_FILE_SECTION_POINTER  Pe32Section;\r
1255   UINT32                    EntryPoint;\r
1256   UINT32                    BaseOfCode;\r
1257   UINT16                    MachineType;\r
1258   EFI_PHYSICAL_ADDRESS      PeiCorePhysicalAddress;\r
1259   EFI_PHYSICAL_ADDRESS      SecCorePhysicalAddress;\r
1260   EFI_PHYSICAL_ADDRESS      *SecCoreEntryAddressPtr;\r
1261   INT32                     Ia32SecEntryOffset;\r
1262   UINT32                    *Ia32ResetAddressPtr;\r
1263   UINT8                     *BytePointer;\r
1264   UINT8                     *BytePointer2;\r
1265   UINT16                    *WordPointer;\r
1266   UINT16                    CheckSum;\r
1267   UINTN                     Index;\r
1268   EFI_FFS_FILE_STATE        SavedState;\r
1269   UINT64                    FitAddress;\r
1270   FIT_TABLE                 *FitTablePtr;\r
1271   UINT32                    IpiVector;\r
1272 \r
1273   //\r
1274   // Verify input parameters\r
1275   //\r
1276   if (FvImage == NULL || FvInfo == NULL || VtfFile == NULL) {\r
1277     return EFI_INVALID_PARAMETER;\r
1278   }\r
1279   //\r
1280   // Initialize FV library\r
1281   //\r
1282   InitializeFvLib (FvImage->FileImage, FvInfo->Size);\r
1283 \r
1284   //\r
1285   // Verify VTF file\r
1286   //\r
1287   Status = VerifyFfsFile (VtfFile);\r
1288   if (EFI_ERROR (Status)) {\r
1289     return EFI_INVALID_PARAMETER;\r
1290   }\r
1291 \r
1292   //\r
1293   // Find the Sec Core\r
1294   //\r
1295   Status = GetFileByType (EFI_FV_FILETYPE_SECURITY_CORE, 1, &SecCoreFile);\r
1296   if (EFI_ERROR (Status) || SecCoreFile == NULL) {\r
1297     Error (NULL, 0, 3000, "Invalid", "could not find the SEC core file in the FV.");\r
1298     return EFI_ABORTED;\r
1299   }\r
1300   //\r
1301   // Sec Core found, now find PE32 section\r
1302   //\r
1303   Status = GetSectionByType (SecCoreFile, EFI_SECTION_PE32, 1, &Pe32Section);\r
1304   if (Status == EFI_NOT_FOUND) {\r
1305     Status = GetSectionByType (SecCoreFile, EFI_SECTION_TE, 1, &Pe32Section);\r
1306   }\r
1307 \r
1308   if (EFI_ERROR (Status)) {\r
1309     Error (NULL, 0, 3000, "Invalid", "could not find a PE32 section in the SEC core file.");\r
1310     return EFI_ABORTED;\r
1311   }\r
1312 \r
1313   Status = GetPe32Info (\r
1314             (VOID *) ((UINTN) Pe32Section.Pe32Section + sizeof (EFI_SECTION_PE32)),\r
1315             &EntryPoint,\r
1316             &BaseOfCode,\r
1317             &MachineType\r
1318             );\r
1319 \r
1320   if (EFI_ERROR (Status)) {\r
1321     Error (NULL, 0, 3000, "Invalid", "could not get the PE32 entry point for the SEC core.");\r
1322     return EFI_ABORTED;\r
1323   }  \r
1324 \r
1325   //\r
1326   // Physical address is FV base + offset of PE32 + offset of the entry point\r
1327   //\r
1328   SecCorePhysicalAddress = FvInfo->BaseAddress;\r
1329   SecCorePhysicalAddress += (UINTN) Pe32Section.Pe32Section + sizeof (EFI_SECTION_PE32) - (UINTN) FvImage->FileImage;\r
1330   SecCorePhysicalAddress += EntryPoint;\r
1331   DebugMsg (NULL, 0, 9, "SecCore physical entry point address", "Address = 0x%llX", (unsigned long long) SecCorePhysicalAddress); \r
1332 \r
1333   //\r
1334   // Find the PEI Core\r
1335   //\r
1336   Status = GetFileByType (EFI_FV_FILETYPE_PEI_CORE, 1, &PeiCoreFile);\r
1337   if (EFI_ERROR (Status) || PeiCoreFile == NULL) {\r
1338     Error (NULL, 0, 3000, "Invalid", "could not find the PEI core in the FV.");\r
1339     return EFI_ABORTED;\r
1340   }\r
1341   //\r
1342   // PEI Core found, now find PE32 or TE section\r
1343   //\r
1344   Status = GetSectionByType (PeiCoreFile, EFI_SECTION_PE32, 1, &Pe32Section);\r
1345   if (Status == EFI_NOT_FOUND) {\r
1346     Status = GetSectionByType (PeiCoreFile, EFI_SECTION_TE, 1, &Pe32Section);\r
1347   }\r
1348 \r
1349   if (EFI_ERROR (Status)) {\r
1350     Error (NULL, 0, 3000, "Invalid", "could not find either a PE32 or a TE section in PEI core file.");\r
1351     return EFI_ABORTED;\r
1352   }\r
1353 \r
1354   Status = GetPe32Info (\r
1355             (VOID *) ((UINTN) Pe32Section.Pe32Section + sizeof (EFI_SECTION_PE32)),\r
1356             &EntryPoint,\r
1357             &BaseOfCode,\r
1358             &MachineType\r
1359             );\r
1360 \r
1361   if (EFI_ERROR (Status)) {\r
1362     Error (NULL, 0, 3000, "Invalid", "could not get the PE32 entry point for the PEI core.");\r
1363     return EFI_ABORTED;\r
1364   }\r
1365   //\r
1366   // Physical address is FV base + offset of PE32 + offset of the entry point\r
1367   //\r
1368   PeiCorePhysicalAddress = FvInfo->BaseAddress;\r
1369   PeiCorePhysicalAddress += (UINTN) Pe32Section.Pe32Section + sizeof (EFI_SECTION_PE32) - (UINTN) FvImage->FileImage;\r
1370   PeiCorePhysicalAddress += EntryPoint;\r
1371   DebugMsg (NULL, 0, 9, "PeiCore physical entry point address", "Address = 0x%llX", (unsigned long long) PeiCorePhysicalAddress);\r
1372 \r
1373   if (MachineType == EFI_IMAGE_MACHINE_IA64) {\r
1374     //\r
1375     // Update PEI_CORE address\r
1376     //\r
1377     //\r
1378     // Set the uncached attribute bit in the physical address\r
1379     //\r
1380     PeiCorePhysicalAddress |= 0x8000000000000000ULL;\r
1381 \r
1382     //\r
1383     // Check if address is aligned on a 16 byte boundary\r
1384     //\r
1385     if (PeiCorePhysicalAddress & 0xF) {\r
1386       Error (NULL, 0, 3000, "Invalid",\r
1387         "PEI_CORE entry point is not aligned on a 16 byte boundary, address specified is %llXh.",\r
1388         (unsigned long long) PeiCorePhysicalAddress\r
1389         );\r
1390       return EFI_ABORTED;\r
1391     }\r
1392     //\r
1393     // First Get the FIT table address\r
1394     //\r
1395     FitAddress  = (*(UINT64 *) (FvImage->Eof - IPF_FIT_ADDRESS_OFFSET)) & 0xFFFFFFFF;\r
1396 \r
1397     FitTablePtr = (FIT_TABLE *) (FvImage->FileImage + (FitAddress - FvInfo->BaseAddress));\r
1398 \r
1399     Status      = UpdatePeiCoreEntryInFit (FitTablePtr, PeiCorePhysicalAddress);\r
1400 \r
1401     if (!EFI_ERROR (Status)) {\r
1402       UpdateFitCheckSum (FitTablePtr);\r
1403     }\r
1404 \r
1405     //\r
1406     // Update SEC_CORE address\r
1407     //\r
1408     //\r
1409     // Set the uncached attribute bit in the physical address\r
1410     //\r
1411     SecCorePhysicalAddress |= 0x8000000000000000ULL;\r
1412     //\r
1413     // Check if address is aligned on a 16 byte boundary\r
1414     //\r
1415     if (SecCorePhysicalAddress & 0xF) {\r
1416       Error (NULL, 0, 3000, "Invalid",\r
1417         "SALE_ENTRY entry point is not aligned on a 16 byte boundary, address specified is %llXh.",\r
1418         (unsigned long long) SecCorePhysicalAddress\r
1419         );\r
1420       return EFI_ABORTED;\r
1421     }\r
1422     //\r
1423     // Update the address\r
1424     //\r
1425     SecCoreEntryAddressPtr  = (EFI_PHYSICAL_ADDRESS *) ((UINTN) FvImage->Eof - IPF_SALE_ENTRY_ADDRESS_OFFSET);\r
1426     *SecCoreEntryAddressPtr = SecCorePhysicalAddress;\r
1427 \r
1428   } else if (\r
1429     (MachineType == EFI_IMAGE_MACHINE_IA32 ||\r
1430      MachineType == EFI_IMAGE_MACHINE_X64) &&\r
1431     (((UINTN)FvImage->Eof - (UINTN)FvImage->FileImage) >= IA32_X64_VTF_SIGNATURE_OFFSET) &&\r
1432     (*(UINT32 *)(VOID*)((UINTN) FvImage->Eof - IA32_X64_VTF_SIGNATURE_OFFSET) ==\r
1433       IA32_X64_VTF0_SIGNATURE)\r
1434     ) {\r
1435     //\r
1436     // If VTF-0 signature is found, then no modifications are needed.\r
1437     //\r
1438   } else if (MachineType == EFI_IMAGE_MACHINE_IA32 || MachineType == EFI_IMAGE_MACHINE_X64) {\r
1439     //\r
1440     // Get the location to update\r
1441     //\r
1442     Ia32ResetAddressPtr  = (UINT32 *) ((UINTN) FvImage->Eof - IA32_PEI_CORE_ENTRY_OFFSET);\r
1443 \r
1444     //\r
1445     // Write lower 32 bits of physical address for Pei Core entry\r
1446     //\r
1447     *Ia32ResetAddressPtr = (UINT32) PeiCorePhysicalAddress;\r
1448     \r
1449     //\r
1450     // Write SecCore Entry point relative address into the jmp instruction in reset vector.\r
1451     // \r
1452     Ia32ResetAddressPtr  = (UINT32 *) ((UINTN) FvImage->Eof - IA32_SEC_CORE_ENTRY_OFFSET);\r
1453     \r
1454     Ia32SecEntryOffset   = (INT32) (SecCorePhysicalAddress - (FV_IMAGES_TOP_ADDRESS - IA32_SEC_CORE_ENTRY_OFFSET + 2));\r
1455     if (Ia32SecEntryOffset <= -65536) {\r
1456       Error (NULL, 0, 3000, "Invalid", "The SEC EXE file size is too large, it must be less than 64K.");\r
1457       return STATUS_ERROR;\r
1458     }\r
1459     \r
1460     *(UINT16 *) Ia32ResetAddressPtr = (UINT16) Ia32SecEntryOffset;\r
1461 \r
1462     //\r
1463     // Update the BFV base address\r
1464     //\r
1465     Ia32ResetAddressPtr   = (UINT32 *) ((UINTN) FvImage->Eof - 4);\r
1466     *Ia32ResetAddressPtr  = (UINT32) (FvInfo->BaseAddress);\r
1467     DebugMsg (NULL, 0, 9, "update BFV base address in the top FV image", "BFV base address = 0x%llX.", (unsigned long long) FvInfo->BaseAddress);\r
1468 \r
1469     //\r
1470     // Update the Startup AP in the FVH header block ZeroVector region.\r
1471     //\r
1472     BytePointer   = (UINT8 *) ((UINTN) FvImage->FileImage);\r
1473     if (FvInfo->Size <= 0x10000) {\r
1474       BytePointer2 = m64kRecoveryStartupApDataArray;\r
1475     } else if (FvInfo->Size <= 0x20000) {\r
1476       BytePointer2 = m128kRecoveryStartupApDataArray;\r
1477     } else {\r
1478       BytePointer2 = m128kRecoveryStartupApDataArray;\r
1479       //\r
1480       // Find the position to place Ap reset vector, the offset\r
1481       // between the position and the end of Fvrecovery.fv file\r
1482       // should not exceed 128kB to prevent Ap reset vector from\r
1483       // outside legacy E and F segment\r
1484       //\r
1485       Status = FindApResetVectorPosition (FvImage, &BytePointer);\r
1486       if (EFI_ERROR (Status)) {\r
1487         Error (NULL, 0, 3000, "Invalid", "Cannot find the appropriate location in FvImage to add Ap reset vector!");\r
1488         return EFI_ABORTED;\r
1489       }\r
1490     }\r
1491 \r
1492     for (Index = 0; Index < SIZEOF_STARTUP_DATA_ARRAY; Index++) {\r
1493       BytePointer[Index] = BytePointer2[Index];\r
1494     }\r
1495     //\r
1496     // Calculate the checksum\r
1497     //\r
1498     CheckSum              = 0x0000;\r
1499     WordPointer = (UINT16 *) (BytePointer);\r
1500     for (Index = 0; Index < SIZEOF_STARTUP_DATA_ARRAY / 2; Index++) {\r
1501       CheckSum = (UINT16) (CheckSum + ((UINT16) *WordPointer));\r
1502       WordPointer++;\r
1503     }\r
1504     //\r
1505     // Update the checksum field\r
1506     //\r
1507     WordPointer   = (UINT16 *) (BytePointer + SIZEOF_STARTUP_DATA_ARRAY - 2);\r
1508     *WordPointer  = (UINT16) (0x10000 - (UINT32) CheckSum);\r
1509     \r
1510     //\r
1511     // IpiVector at the 4k aligned address in the top 2 blocks in the PEI FV. \r
1512     //\r
1513     IpiVector  = (UINT32) (FV_IMAGES_TOP_ADDRESS - ((UINTN) FvImage->Eof - (UINTN) BytePointer));\r
1514     DebugMsg (NULL, 0, 9, "Startup AP Vector address", "IpiVector at 0x%X", (unsigned) IpiVector);\r
1515     if ((IpiVector & 0xFFF) != 0) {\r
1516       Error (NULL, 0, 3000, "Invalid", "Startup AP Vector address are not 4K aligned, because the FV size is not 4K aligned");\r
1517       return EFI_ABORTED;\r
1518     }\r
1519     IpiVector  = IpiVector >> 12;\r
1520     IpiVector  = IpiVector & 0xFF;\r
1521 \r
1522     //\r
1523     // Write IPI Vector at Offset FvrecoveryFileSize - 8\r
1524     //\r
1525     Ia32ResetAddressPtr   = (UINT32 *) ((UINTN) FvImage->Eof - 8);\r
1526     *Ia32ResetAddressPtr  = IpiVector;\r
1527   } else if (MachineType == EFI_IMAGE_MACHINE_ARMT) {\r
1528     //\r
1529     // Since the ARM reset vector is in the FV Header you really don't need a\r
1530     // Volume Top File, but if you have one for some reason don't crash...\r
1531     //\r
1532   } else {\r
1533     Error (NULL, 0, 3000, "Invalid", "machine type=0x%X in PEI core.", MachineType);\r
1534     return EFI_ABORTED;\r
1535   }\r
1536 \r
1537   //\r
1538   // Now update file checksum\r
1539   //\r
1540   SavedState  = VtfFile->State;\r
1541   VtfFile->IntegrityCheck.Checksum.File = 0;\r
1542   VtfFile->State                        = 0;\r
1543   if (VtfFile->Attributes & FFS_ATTRIB_CHECKSUM) {\r
1544     VtfFile->IntegrityCheck.Checksum.File = CalculateChecksum8 (\r
1545                                               (UINT8 *) VtfFile,\r
1546                                               GetLength (VtfFile->Size)\r
1547                                               );\r
1548   } else {\r
1549     VtfFile->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;\r
1550   }\r
1551 \r
1552   VtfFile->State = SavedState;\r
1553 \r
1554   return EFI_SUCCESS;\r
1555 }\r
1556 \r
1557 \r
1558 EFI_STATUS\r
1559 UpdateArmResetVectorIfNeeded (\r
1560   IN MEMORY_FILE            *FvImage,\r
1561   IN FV_INFO                *FvInfo\r
1562   )\r
1563 /*++\r
1564 \r
1565 Routine Description:\r
1566   This parses the FV looking for SEC and patches that address into the \r
1567   beginning of the FV header.\r
1568 \r
1569   For ARM the reset vector is at 0x00000000 or 0xFFFF0000.\r
1570   This would commonly map to the first entry in the ROM. \r
1571   ARM Exceptions:\r
1572   Reset            +0    \r
1573   Undefined        +4\r
1574   SWI              +8\r
1575   Prefetch Abort   +12\r
1576   Data Abort       +16\r
1577   IRQ              +20\r
1578   FIQ              +24\r
1579 \r
1580   We support two schemes on ARM.\r
1581   1) Beginning of the FV is the reset vector\r
1582   2) Reset vector is data bytes FDF file and that code branches to reset vector \r
1583     in the beginning of the FV (fixed size offset).\r
1584 \r
1585 \r
1586   Need to have the jump for the reset vector at location zero.\r
1587   We also need to store the address or PEI (if it exists).\r
1588   We stub out a return from interrupt in case the debugger \r
1589    is using SWI.\r
1590   The optional entry to the common exception handler is \r
1591    to support full featured exception handling from ROM and is currently \r
1592     not support by this tool.\r
1593 \r
1594 Arguments:\r
1595   FvImage       Memory file for the FV memory image\r
1596   FvInfo        Information read from INF file.\r
1597 \r
1598 Returns:\r
1599 \r
1600   EFI_SUCCESS             Function Completed successfully.\r
1601   EFI_ABORTED             Error encountered.\r
1602   EFI_INVALID_PARAMETER   A required parameter was NULL.\r
1603   EFI_NOT_FOUND           PEI Core file not found.\r
1604 \r
1605 --*/\r
1606 {\r
1607   EFI_FFS_FILE_HEADER       *PeiCoreFile;\r
1608   EFI_FFS_FILE_HEADER       *SecCoreFile;\r
1609   EFI_STATUS                Status;\r
1610   EFI_FILE_SECTION_POINTER  Pe32Section;\r
1611   UINT32                    EntryPoint;\r
1612   UINT32                    BaseOfCode;\r
1613   UINT16                    MachineType;\r
1614   EFI_PHYSICAL_ADDRESS      PeiCorePhysicalAddress;\r
1615   EFI_PHYSICAL_ADDRESS      SecCorePhysicalAddress;\r
1616   INT32                     ResetVector[4]; // 0 - is branch relative to SEC entry point\r
1617                                             // 1 - PEI Entry Point\r
1618                                             // 2 - movs pc,lr for a SWI handler\r
1619                                             // 3 - Place holder for Common Exception Handler\r
1620 \r
1621   //\r
1622   // Verify input parameters\r
1623   //\r
1624   if (FvImage == NULL || FvInfo == NULL) {\r
1625     return EFI_INVALID_PARAMETER;\r
1626   }\r
1627   //\r
1628   // Initialize FV library\r
1629   //\r
1630   InitializeFvLib (FvImage->FileImage, FvInfo->Size);\r
1631 \r
1632   //\r
1633   // Find the Sec Core\r
1634   //\r
1635   Status = GetFileByType (EFI_FV_FILETYPE_SECURITY_CORE, 1, &SecCoreFile);\r
1636   if (EFI_ERROR (Status) || SecCoreFile == NULL) {\r
1637     //\r
1638     // Maybe hardware does SEC job and we only have PEI Core?\r
1639     //\r
1640 \r
1641     //\r
1642     // Find the PEI Core. It may not exist if SEC loads DXE core directly\r
1643     //\r
1644     PeiCorePhysicalAddress = 0;\r
1645     Status = GetFileByType (EFI_FV_FILETYPE_PEI_CORE, 1, &PeiCoreFile);\r
1646     if (!EFI_ERROR (Status) && PeiCoreFile != NULL) {\r
1647       //\r
1648       // PEI Core found, now find PE32 or TE section\r
1649       //\r
1650       Status = GetSectionByType (PeiCoreFile, EFI_SECTION_PE32, 1, &Pe32Section);\r
1651       if (Status == EFI_NOT_FOUND) {\r
1652         Status = GetSectionByType (PeiCoreFile, EFI_SECTION_TE, 1, &Pe32Section);\r
1653       }\r
1654     \r
1655       if (EFI_ERROR (Status)) {\r
1656         Error (NULL, 0, 3000, "Invalid", "could not find either a PE32 or a TE section in PEI core file!");\r
1657         return EFI_ABORTED;\r
1658       }\r
1659     \r
1660       Status = GetPe32Info (\r
1661                 (VOID *) ((UINTN) Pe32Section.Pe32Section + sizeof (EFI_SECTION_PE32)),\r
1662                 &EntryPoint,\r
1663                 &BaseOfCode,\r
1664                 &MachineType\r
1665                 );\r
1666     \r
1667       if (EFI_ERROR (Status)) {\r
1668         Error (NULL, 0, 3000, "Invalid", "could not get the PE32 entry point for the PEI core!");\r
1669         return EFI_ABORTED;\r
1670       }\r
1671       //\r
1672       // Physical address is FV base + offset of PE32 + offset of the entry point\r
1673       //\r
1674       PeiCorePhysicalAddress = FvInfo->BaseAddress;\r
1675       PeiCorePhysicalAddress += (UINTN) Pe32Section.Pe32Section + sizeof (EFI_SECTION_PE32) - (UINTN) FvImage->FileImage;\r
1676       PeiCorePhysicalAddress += EntryPoint;\r
1677       DebugMsg (NULL, 0, 9, "PeiCore physical entry point address", "Address = 0x%llX", (unsigned long long) PeiCorePhysicalAddress);\r
1678 \r
1679       if (MachineType == EFI_IMAGE_MACHINE_ARMT) {\r
1680         memset (ResetVector, 0, sizeof (ResetVector));\r
1681         // Address of PEI Core, if we have one\r
1682         ResetVector[1] = (UINT32)PeiCorePhysicalAddress;\r
1683       }\r
1684       \r
1685       //\r
1686       // Copy to the beginning of the FV \r
1687       //\r
1688       memcpy ((UINT8 *) ((UINTN) FvImage->FileImage), ResetVector, sizeof (ResetVector));\r
1689 \r
1690     }\r
1691 \r
1692     return EFI_SUCCESS;\r
1693   }\r
1694   \r
1695   //\r
1696   // Sec Core found, now find PE32 section\r
1697   //\r
1698   Status = GetSectionByType (SecCoreFile, EFI_SECTION_PE32, 1, &Pe32Section);\r
1699   if (Status == EFI_NOT_FOUND) {\r
1700     Status = GetSectionByType (SecCoreFile, EFI_SECTION_TE, 1, &Pe32Section);\r
1701   }\r
1702 \r
1703   if (EFI_ERROR (Status)) {\r
1704     Error (NULL, 0, 3000, "Invalid", "could not find a PE32 section in the SEC core file.");\r
1705     return EFI_ABORTED;\r
1706   }\r
1707 \r
1708   Status = GetPe32Info (\r
1709             (VOID *) ((UINTN) Pe32Section.Pe32Section + sizeof (EFI_SECTION_PE32)),\r
1710             &EntryPoint,\r
1711             &BaseOfCode,\r
1712             &MachineType\r
1713             );\r
1714   if (EFI_ERROR (Status)) {\r
1715     Error (NULL, 0, 3000, "Invalid", "could not get the PE32 entry point for the SEC core.");\r
1716     return EFI_ABORTED;\r
1717   }\r
1718   \r
1719   if (MachineType != EFI_IMAGE_MACHINE_ARMT) {\r
1720     //\r
1721     // If SEC is not ARM we have nothing to do\r
1722     //\r
1723     return EFI_SUCCESS;\r
1724   }\r
1725   \r
1726   //\r
1727   // Physical address is FV base + offset of PE32 + offset of the entry point\r
1728   //\r
1729   SecCorePhysicalAddress = FvInfo->BaseAddress;\r
1730   SecCorePhysicalAddress += (UINTN) Pe32Section.Pe32Section + sizeof (EFI_SECTION_PE32) - (UINTN) FvImage->FileImage;\r
1731   SecCorePhysicalAddress += EntryPoint;\r
1732   DebugMsg (NULL, 0, 9, "SecCore physical entry point address", "Address = 0x%llX", (unsigned long long) SecCorePhysicalAddress); \r
1733 \r
1734   //\r
1735   // Find the PEI Core. It may not exist if SEC loads DXE core directly\r
1736   //\r
1737   PeiCorePhysicalAddress = 0;\r
1738   Status = GetFileByType (EFI_FV_FILETYPE_PEI_CORE, 1, &PeiCoreFile);\r
1739   if (!EFI_ERROR (Status) && PeiCoreFile != NULL) {\r
1740     //\r
1741     // PEI Core found, now find PE32 or TE section\r
1742     //\r
1743     Status = GetSectionByType (PeiCoreFile, EFI_SECTION_PE32, 1, &Pe32Section);\r
1744     if (Status == EFI_NOT_FOUND) {\r
1745       Status = GetSectionByType (PeiCoreFile, EFI_SECTION_TE, 1, &Pe32Section);\r
1746     }\r
1747   \r
1748     if (EFI_ERROR (Status)) {\r
1749       Error (NULL, 0, 3000, "Invalid", "could not find either a PE32 or a TE section in PEI core file!");\r
1750       return EFI_ABORTED;\r
1751     }\r
1752   \r
1753     Status = GetPe32Info (\r
1754               (VOID *) ((UINTN) Pe32Section.Pe32Section + sizeof (EFI_SECTION_PE32)),\r
1755               &EntryPoint,\r
1756               &BaseOfCode,\r
1757               &MachineType\r
1758               );\r
1759   \r
1760     if (EFI_ERROR (Status)) {\r
1761       Error (NULL, 0, 3000, "Invalid", "could not get the PE32 entry point for the PEI core!");\r
1762       return EFI_ABORTED;\r
1763     }\r
1764     //\r
1765     // Physical address is FV base + offset of PE32 + offset of the entry point\r
1766     //\r
1767     PeiCorePhysicalAddress = FvInfo->BaseAddress;\r
1768     PeiCorePhysicalAddress += (UINTN) Pe32Section.Pe32Section + sizeof (EFI_SECTION_PE32) - (UINTN) FvImage->FileImage;\r
1769     PeiCorePhysicalAddress += EntryPoint;\r
1770     DebugMsg (NULL, 0, 9, "PeiCore physical entry point address", "Address = 0x%llX", (unsigned long long) PeiCorePhysicalAddress);\r
1771   }\r
1772   \r
1773   \r
1774   // B SecEntryPoint - signed_immed_24 part +/-32MB offset\r
1775   // on ARM, the PC is always 8 ahead, so we're not really jumping from the base address, but from base address + 8\r
1776   ResetVector[0] = (INT32)(SecCorePhysicalAddress - FvInfo->BaseAddress - 8) >> 2;\r
1777   \r
1778   if (ResetVector[0] > 0x00FFFFFF) {\r
1779     Error (NULL, 0, 3000, "Invalid", "SEC Entry point must be within 32MB of the start of the FV");\r
1780     return EFI_ABORTED;    \r
1781   }\r
1782   \r
1783   // Add opcode for an uncondional branch with no link. AKA B SecEntryPoint\r
1784   ResetVector[0] |= 0xEA000000;\r
1785   \r
1786   \r
1787   // Address of PEI Core, if we have one\r
1788   ResetVector[1] = (UINT32)PeiCorePhysicalAddress;\r
1789   \r
1790   // SWI handler movs   pc,lr. Just in case a debugger uses SWI\r
1791   ResetVector[2] = 0xE1B0F07E;\r
1792   \r
1793   // Place holder to support a common interrupt handler from ROM. \r
1794   // Currently not suppprted. For this to be used the reset vector would not be in this FV\r
1795   // and the exception vectors would be hard coded in the ROM and just through this address \r
1796   // to find a common handler in the a module in the FV.\r
1797   ResetVector[3] = 0;\r
1798 \r
1799   //\r
1800   // Copy to the beginning of the FV \r
1801   //\r
1802   memcpy ((UINT8 *) ((UINTN) FvImage->FileImage), ResetVector, sizeof (ResetVector));\r
1803 \r
1804   DebugMsg (NULL, 0, 9, "Update Reset vector in FV Header", NULL);\r
1805 \r
1806   return EFI_SUCCESS;\r
1807 }\r
1808 \r
1809 EFI_STATUS\r
1810 GetPe32Info (\r
1811   IN UINT8                  *Pe32,\r
1812   OUT UINT32                *EntryPoint,\r
1813   OUT UINT32                *BaseOfCode,\r
1814   OUT UINT16                *MachineType\r
1815   )\r
1816 /*++\r
1817 \r
1818 Routine Description:\r
1819 \r
1820   Retrieves the PE32 entry point offset and machine type from PE image or TeImage.  \r
1821   See EfiImage.h for machine types.  The entry point offset is from the beginning \r
1822   of the PE32 buffer passed in.\r
1823 \r
1824 Arguments:\r
1825 \r
1826   Pe32          Beginning of the PE32.\r
1827   EntryPoint    Offset from the beginning of the PE32 to the image entry point.\r
1828   BaseOfCode    Base address of code.\r
1829   MachineType   Magic number for the machine type.\r
1830 \r
1831 Returns:\r
1832 \r
1833   EFI_SUCCESS             Function completed successfully.\r
1834   EFI_ABORTED             Error encountered.\r
1835   EFI_INVALID_PARAMETER   A required parameter was NULL.\r
1836   EFI_UNSUPPORTED         The operation is unsupported.\r
1837 \r
1838 --*/\r
1839 {\r
1840   EFI_IMAGE_DOS_HEADER             *DosHeader;\r
1841   EFI_IMAGE_OPTIONAL_HEADER_UNION  *ImgHdr;\r
1842   EFI_TE_IMAGE_HEADER              *TeHeader;\r
1843 \r
1844   //\r
1845   // Verify input parameters\r
1846   //\r
1847   if (Pe32 == NULL) {\r
1848     return EFI_INVALID_PARAMETER;\r
1849   }\r
1850 \r
1851   //\r
1852   // First check whether it is one TE Image.\r
1853   //\r
1854   TeHeader = (EFI_TE_IMAGE_HEADER *) Pe32;\r
1855   if (TeHeader->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {\r
1856     //\r
1857     // By TeImage Header to get output\r
1858     //\r
1859     *EntryPoint   = TeHeader->AddressOfEntryPoint + sizeof (EFI_TE_IMAGE_HEADER) - TeHeader->StrippedSize;\r
1860     *BaseOfCode   = TeHeader->BaseOfCode + sizeof (EFI_TE_IMAGE_HEADER) - TeHeader->StrippedSize;\r
1861     *MachineType  = TeHeader->Machine;\r
1862   } else {\r
1863   \r
1864     //\r
1865     // Then check whether \r
1866     // First is the DOS header\r
1867     //\r
1868     DosHeader = (EFI_IMAGE_DOS_HEADER *) Pe32;\r
1869   \r
1870     //\r
1871     // Verify DOS header is expected\r
1872     //\r
1873     if (DosHeader->e_magic != EFI_IMAGE_DOS_SIGNATURE) {\r
1874       Error (NULL, 0, 3000, "Invalid", "Unknown magic number in the DOS header, 0x%04X.", DosHeader->e_magic);\r
1875       return EFI_UNSUPPORTED;\r
1876     }\r
1877     //\r
1878     // Immediately following is the NT header.\r
1879     //\r
1880     ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *) ((UINTN) Pe32 + DosHeader->e_lfanew);\r
1881   \r
1882     //\r
1883     // Verify NT header is expected\r
1884     //\r
1885     if (ImgHdr->Pe32.Signature != EFI_IMAGE_NT_SIGNATURE) {\r
1886       Error (NULL, 0, 3000, "Invalid", "Unrecognized image signature 0x%08X.", (unsigned) ImgHdr->Pe32.Signature);\r
1887       return EFI_UNSUPPORTED;\r
1888     }\r
1889     //\r
1890     // Get output\r
1891     //\r
1892     *EntryPoint   = ImgHdr->Pe32.OptionalHeader.AddressOfEntryPoint;\r
1893     *BaseOfCode   = ImgHdr->Pe32.OptionalHeader.BaseOfCode;\r
1894     *MachineType  = ImgHdr->Pe32.FileHeader.Machine;\r
1895   }\r
1896 \r
1897   //\r
1898   // Verify machine type is supported\r
1899   //\r
1900   if (*MachineType != EFI_IMAGE_MACHINE_IA32 && *MachineType != EFI_IMAGE_MACHINE_IA64 && *MachineType != EFI_IMAGE_MACHINE_X64 && *MachineType != EFI_IMAGE_MACHINE_EBC && \r
1901       *MachineType != EFI_IMAGE_MACHINE_ARMT) {\r
1902     Error (NULL, 0, 3000, "Invalid", "Unrecognized machine type in the PE32 file.");\r
1903     return EFI_UNSUPPORTED;\r
1904   }\r
1905 \r
1906   return EFI_SUCCESS;\r
1907 }\r
1908 \r
1909 EFI_STATUS\r
1910 GenerateFvImage (\r
1911   IN CHAR8                *InfFileImage,\r
1912   IN UINTN                InfFileSize,\r
1913   IN CHAR8                *FvFileName,\r
1914   IN CHAR8                *MapFileName\r
1915   )\r
1916 /*++\r
1917 \r
1918 Routine Description:\r
1919 \r
1920   This is the main function which will be called from application.\r
1921 \r
1922 Arguments:\r
1923 \r
1924   InfFileImage   Buffer containing the INF file contents.\r
1925   InfFileSize    Size of the contents of the InfFileImage buffer.\r
1926   FvFileName     Requested name for the FV file.\r
1927   MapFileName    Fv map file to log fv driver information.\r
1928 \r
1929 Returns:\r
1930 \r
1931   EFI_SUCCESS             Function completed successfully.\r
1932   EFI_OUT_OF_RESOURCES    Could not allocate required resources.\r
1933   EFI_ABORTED             Error encountered.\r
1934   EFI_INVALID_PARAMETER   A required parameter was NULL.\r
1935 \r
1936 --*/\r
1937 {\r
1938   EFI_STATUS                  Status;\r
1939   MEMORY_FILE                 InfMemoryFile;\r
1940   MEMORY_FILE                 FvImageMemoryFile;\r
1941   UINTN                       Index;\r
1942   EFI_FIRMWARE_VOLUME_HEADER  *FvHeader;\r
1943   EFI_FFS_FILE_HEADER         *VtfFileImage;\r
1944   UINT8                       *FvBufferHeader; // to make sure fvimage header 8 type alignment.\r
1945   UINT8                       *FvImage;\r
1946   UINTN                       FvImageSize;\r
1947   FILE                        *FvFile;\r
1948   CHAR8                       FvMapName [_MAX_PATH];\r
1949   FILE                        *FvMapFile;\r
1950   EFI_FIRMWARE_VOLUME_EXT_HEADER FvExtHeader;\r
1951 \r
1952   FvBufferHeader = NULL;\r
1953   FvFile         = NULL;\r
1954   FvMapFile      = NULL;\r
1955 \r
1956   if (InfFileImage != NULL) {\r
1957     //\r
1958     // Initialize file structures\r
1959     //\r
1960     InfMemoryFile.FileImage           = InfFileImage;\r
1961     InfMemoryFile.CurrentFilePointer  = InfFileImage;\r
1962     InfMemoryFile.Eof                 = InfFileImage + InfFileSize;\r
1963   \r
1964     //\r
1965     // Parse the FV inf file for header information\r
1966     //\r
1967     Status = ParseFvInf (&InfMemoryFile, &mFvDataInfo);\r
1968     if (EFI_ERROR (Status)) {\r
1969       Error (NULL, 0, 0003, "Error parsing file", "the input FV INF file.");\r
1970       return Status;\r
1971     }\r
1972   }\r
1973 \r
1974   //\r
1975   // Update the file name return values\r
1976   //\r
1977   if (FvFileName == NULL && mFvDataInfo.FvName[0] != '\0') {\r
1978     FvFileName = mFvDataInfo.FvName;\r
1979   }\r
1980 \r
1981   if (FvFileName == NULL) {\r
1982     Error (NULL, 0, 1001, "Missing option", "Output file name");\r
1983     return EFI_ABORTED;\r
1984   }\r
1985   \r
1986   if (mFvDataInfo.FvBlocks[0].Length == 0) {\r
1987     Error (NULL, 0, 1001, "Missing required argument", "Block Size");\r
1988     return EFI_ABORTED;\r
1989   }\r
1990   \r
1991   //\r
1992   // Debug message Fv File System Guid\r
1993   //\r
1994   if (mFvDataInfo.FvFileSystemGuidSet) {\r
1995     DebugMsg (NULL, 0, 9, "FV File System Guid", "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", \r
1996                   (unsigned) mFvDataInfo.FvFileSystemGuid.Data1,\r
1997                   mFvDataInfo.FvFileSystemGuid.Data2,\r
1998                   mFvDataInfo.FvFileSystemGuid.Data3,\r
1999                   mFvDataInfo.FvFileSystemGuid.Data4[0],\r
2000                   mFvDataInfo.FvFileSystemGuid.Data4[1],\r
2001                   mFvDataInfo.FvFileSystemGuid.Data4[2],\r
2002                   mFvDataInfo.FvFileSystemGuid.Data4[3],\r
2003                   mFvDataInfo.FvFileSystemGuid.Data4[4],\r
2004                   mFvDataInfo.FvFileSystemGuid.Data4[5],\r
2005                   mFvDataInfo.FvFileSystemGuid.Data4[6],\r
2006                   mFvDataInfo.FvFileSystemGuid.Data4[7]);\r
2007   }\r
2008   //\r
2009   // Debug message Fv Name Guid\r
2010   //\r
2011   if (mFvDataInfo.FvNameGuidSet) {\r
2012       DebugMsg (NULL, 0, 9, "FV Name Guid", "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", \r
2013                   (unsigned) mFvDataInfo.FvNameGuid.Data1,\r
2014                   mFvDataInfo.FvNameGuid.Data2,\r
2015                   mFvDataInfo.FvNameGuid.Data3,\r
2016                   mFvDataInfo.FvNameGuid.Data4[0],\r
2017                   mFvDataInfo.FvNameGuid.Data4[1],\r
2018                   mFvDataInfo.FvNameGuid.Data4[2],\r
2019                   mFvDataInfo.FvNameGuid.Data4[3],\r
2020                   mFvDataInfo.FvNameGuid.Data4[4],\r
2021                   mFvDataInfo.FvNameGuid.Data4[5],\r
2022                   mFvDataInfo.FvNameGuid.Data4[6],\r
2023                   mFvDataInfo.FvNameGuid.Data4[7]);\r
2024   }\r
2025 \r
2026   if (CompareGuid (&mFvDataInfo.FvFileSystemGuid, &mEfiFirmwareFileSystem2Guid) == 0) {\r
2027     mFvDataInfo.IsPiFvImage = TRUE;\r
2028   }\r
2029 \r
2030   //\r
2031   // FvMap file to log the function address of all modules in one Fvimage\r
2032   //\r
2033   if (MapFileName != NULL) {\r
2034     strcpy (FvMapName, MapFileName);\r
2035   } else {\r
2036     strcpy (FvMapName, FvFileName);\r
2037     strcat (FvMapName, ".map");\r
2038   }\r
2039   VerboseMsg ("FV Map file name is %s", FvMapName);\r
2040 \r
2041   //\r
2042   // Calculate the FV size and Update Fv Size based on the actual FFS files.\r
2043   // And Update mFvDataInfo data.\r
2044   //\r
2045   Status = CalculateFvSize (&mFvDataInfo);\r
2046   if (EFI_ERROR (Status)) {\r
2047     return Status;    \r
2048   }\r
2049   VerboseMsg ("the generated FV image size is %u bytes", (unsigned) mFvDataInfo.Size);\r
2050   \r
2051   //\r
2052   // support fv image and empty fv image\r
2053   //\r
2054   FvImageSize = mFvDataInfo.Size;\r
2055 \r
2056   //\r
2057   // Allocate the FV, assure FvImage Header 8 byte alignment\r
2058   //\r
2059   FvBufferHeader = malloc (FvImageSize + sizeof (UINT64));\r
2060   if (FvBufferHeader == NULL) {\r
2061     return EFI_OUT_OF_RESOURCES;\r
2062   }\r
2063   FvImage = (UINT8 *) (((UINTN) FvBufferHeader + 7) & ~7);\r
2064 \r
2065   //\r
2066   // Initialize the FV to the erase polarity\r
2067   //\r
2068   if (mFvDataInfo.FvAttributes == 0) {\r
2069     //\r
2070     // Set Default Fv Attribute \r
2071     //\r
2072     mFvDataInfo.FvAttributes = FV_DEFAULT_ATTRIBUTE;\r
2073   }\r
2074   if (mFvDataInfo.FvAttributes & EFI_FVB2_ERASE_POLARITY) {\r
2075     memset (FvImage, -1, FvImageSize);\r
2076   } else {\r
2077     memset (FvImage, 0, FvImageSize);\r
2078   }\r
2079 \r
2080   //\r
2081   // Initialize FV header\r
2082   //\r
2083   FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) FvImage;\r
2084 \r
2085   //\r
2086   // Initialize the zero vector to all zeros.\r
2087   //\r
2088   memset (FvHeader->ZeroVector, 0, 16);\r
2089 \r
2090   //\r
2091   // Copy the Fv file system GUID\r
2092   //\r
2093   memcpy (&FvHeader->FileSystemGuid, &mFvDataInfo.FvFileSystemGuid, sizeof (EFI_GUID));\r
2094 \r
2095   FvHeader->FvLength        = FvImageSize;\r
2096   FvHeader->Signature       = EFI_FVH_SIGNATURE;\r
2097   FvHeader->Attributes      = mFvDataInfo.FvAttributes;\r
2098   FvHeader->Revision        = EFI_FVH_REVISION;\r
2099   FvHeader->ExtHeaderOffset = 0;\r
2100   FvHeader->Reserved[0]     = 0;\r
2101   \r
2102   //\r
2103   // Copy firmware block map\r
2104   //\r
2105   for (Index = 0; mFvDataInfo.FvBlocks[Index].Length != 0; Index++) {\r
2106     FvHeader->BlockMap[Index].NumBlocks   = mFvDataInfo.FvBlocks[Index].NumBlocks;\r
2107     FvHeader->BlockMap[Index].Length      = mFvDataInfo.FvBlocks[Index].Length;\r
2108   }\r
2109 \r
2110   //\r
2111   // Add block map terminator\r
2112   //\r
2113   FvHeader->BlockMap[Index].NumBlocks   = 0;\r
2114   FvHeader->BlockMap[Index].Length      = 0;\r
2115 \r
2116   //\r
2117   // Complete the header\r
2118   //\r
2119   FvHeader->HeaderLength  = (UINT16) (((UINTN) &(FvHeader->BlockMap[Index + 1])) - (UINTN) FvImage);\r
2120   FvHeader->Checksum      = 0;\r
2121   FvHeader->Checksum      = CalculateChecksum16 ((UINT16 *) FvHeader, FvHeader->HeaderLength / sizeof (UINT16));\r
2122 \r
2123   //\r
2124   // If there is no FFS file, generate one empty FV\r
2125   //\r
2126   if (mFvDataInfo.FvFiles[0][0] == 0) {\r
2127     goto WriteFile;\r
2128   }\r
2129 \r
2130   //\r
2131   // Initialize our "file" view of the buffer\r
2132   //\r
2133   FvImageMemoryFile.FileImage           = (CHAR8 *)FvImage;\r
2134   FvImageMemoryFile.CurrentFilePointer  = (CHAR8 *)FvImage + FvHeader->HeaderLength;\r
2135   FvImageMemoryFile.Eof                 = (CHAR8 *)FvImage + FvImageSize;\r
2136 \r
2137   //\r
2138   // Initialize the FV library.\r
2139   //\r
2140   InitializeFvLib (FvImageMemoryFile.FileImage, FvImageSize);\r
2141 \r
2142   //\r
2143   // Initialize the VTF file address.\r
2144   //\r
2145   VtfFileImage = (EFI_FFS_FILE_HEADER *) FvImageMemoryFile.Eof;\r
2146 \r
2147   //\r
2148   // Open FvMap file\r
2149   //\r
2150   FvMapFile = fopen (FvMapName, "w");\r
2151   if (FvMapFile == NULL) {\r
2152     Error (NULL, 0, 0001, "Error opening file", FvMapName);\r
2153     return EFI_ABORTED;\r
2154   }\r
2155   \r
2156   //\r
2157   // record FV size information into FvMap file.\r
2158   //\r
2159   if (mFvTotalSize != 0) {\r
2160     fprintf (FvMapFile, EFI_FV_TOTAL_SIZE_STRING);\r
2161     fprintf (FvMapFile, " = 0x%x\n", (unsigned) mFvTotalSize);\r
2162   }\r
2163   if (mFvTakenSize != 0) {\r
2164     fprintf (FvMapFile, EFI_FV_TAKEN_SIZE_STRING);\r
2165     fprintf (FvMapFile, " = 0x%x\n", (unsigned) mFvTakenSize);\r
2166   }\r
2167   if (mFvTotalSize != 0 && mFvTakenSize != 0) {\r
2168     fprintf (FvMapFile, EFI_FV_SPACE_SIZE_STRING);\r
2169     fprintf (FvMapFile, " = 0x%x\n\n", (unsigned) (mFvTotalSize - mFvTakenSize));\r
2170   }\r
2171 \r
2172   //\r
2173   // Set PI FV extension header\r
2174   //\r
2175   if (mFvDataInfo.FvNameGuidSet) {\r
2176     memcpy (&FvExtHeader.FvName, &mFvDataInfo.FvNameGuid, sizeof (EFI_GUID));\r
2177     FvExtHeader.ExtHeaderSize = sizeof (EFI_FIRMWARE_VOLUME_EXT_HEADER);\r
2178     AddPadFile (&FvImageMemoryFile, 8, &FvExtHeader);\r
2179     //\r
2180     // Fv Extension header change update Fv Header Check sum\r
2181     //\r
2182     FvHeader->Checksum      = 0;\r
2183     FvHeader->Checksum      = CalculateChecksum16 ((UINT16 *) FvHeader, FvHeader->HeaderLength / sizeof (UINT16));\r
2184   }\r
2185 \r
2186   //\r
2187   // Add files to FV\r
2188   //\r
2189   for (Index = 0; mFvDataInfo.FvFiles[Index][0] != 0; Index++) {\r
2190     //\r
2191     // Add the file\r
2192     //\r
2193     Status = AddFile (&FvImageMemoryFile, &mFvDataInfo, Index, &VtfFileImage, FvMapFile);\r
2194 \r
2195     //\r
2196     // Exit if error detected while adding the file\r
2197     //\r
2198     if (EFI_ERROR (Status)) {\r
2199       goto Finish;\r
2200     }\r
2201   }\r
2202 \r
2203   //\r
2204   // If there is a VTF file, some special actions need to occur.\r
2205   //\r
2206   if ((UINTN) VtfFileImage != (UINTN) FvImageMemoryFile.Eof) {\r
2207     //\r
2208     // Pad from the end of the last file to the beginning of the VTF file.\r
2209     // If the left space is less than sizeof (EFI_FFS_FILE_HEADER)?\r
2210     //\r
2211     Status = PadFvImage (&FvImageMemoryFile, VtfFileImage);\r
2212     if (EFI_ERROR (Status)) {\r
2213       Error (NULL, 0, 4002, "Resource", "FV space is full, cannot add pad file between the last file and the VTF file.");\r
2214       goto Finish;\r
2215     }\r
2216     if (!mArm) {\r
2217       //\r
2218       // Update reset vector (SALE_ENTRY for IPF)\r
2219       // Now for IA32 and IA64 platform, the fv which has bsf file must have the \r
2220       // EndAddress of 0xFFFFFFFF. Thus, only this type fv needs to update the   \r
2221       // reset vector. If the PEI Core is found, the VTF file will probably get  \r
2222       // corrupted by updating the entry point.                                  \r
2223       //\r
2224       if ((mFvDataInfo.BaseAddress + mFvDataInfo.Size) == FV_IMAGES_TOP_ADDRESS) {       \r
2225         Status = UpdateResetVector (&FvImageMemoryFile, &mFvDataInfo, VtfFileImage);\r
2226         if (EFI_ERROR(Status)) {                                               \r
2227           Error (NULL, 0, 3000, "Invalid", "Could not update the reset vector.");\r
2228           goto Finish;                                              \r
2229         }\r
2230         DebugMsg (NULL, 0, 9, "Update Reset vector in VTF file", NULL);\r
2231       }\r
2232     }\r
2233   } \r
2234 \r
2235   if (mArm) {\r
2236     Status = UpdateArmResetVectorIfNeeded (&FvImageMemoryFile, &mFvDataInfo);\r
2237     if (EFI_ERROR (Status)) {                                               \r
2238       Error (NULL, 0, 3000, "Invalid", "Could not update the reset vector.");\r
2239       goto Finish;                                              \r
2240     }  \r
2241     \r
2242     //\r
2243     // Update Checksum for FvHeader\r
2244     //\r
2245     FvHeader->Checksum = 0;\r
2246     FvHeader->Checksum = CalculateChecksum16 ((UINT16 *) FvHeader, FvHeader->HeaderLength / sizeof (UINT16));\r
2247   }\r
2248   \r
2249   //\r
2250   // Update FV Alignment attribute to the largest alignment of all the FFS files in the FV\r
2251   //\r
2252   if ((((FvHeader->Attributes & EFI_FVB2_ALIGNMENT) >> 16)) < MaxFfsAlignment) {\r
2253     FvHeader->Attributes = ((MaxFfsAlignment << 16) | (FvHeader->Attributes & 0xFFFF));\r
2254     //\r
2255     // Update Checksum for FvHeader\r
2256     //\r
2257     FvHeader->Checksum      = 0;\r
2258     FvHeader->Checksum      = CalculateChecksum16 ((UINT16 *) FvHeader, FvHeader->HeaderLength / sizeof (UINT16));\r
2259   }\r
2260 \r
2261 WriteFile: \r
2262   //\r
2263   // Write fv file\r
2264   //\r
2265   FvFile = fopen (FvFileName, "wb");\r
2266   if (FvFile == NULL) {\r
2267     Error (NULL, 0, 0001, "Error opening file", FvFileName);\r
2268     Status = EFI_ABORTED;\r
2269     goto Finish;\r
2270   }\r
2271 \r
2272   if (fwrite (FvImage, 1, FvImageSize, FvFile) != FvImageSize) {\r
2273     Error (NULL, 0, 0002, "Error writing file", FvFileName);\r
2274     Status = EFI_ABORTED;\r
2275     goto Finish;\r
2276   }\r
2277 \r
2278 Finish:\r
2279   if (FvBufferHeader != NULL) {\r
2280     free (FvBufferHeader);\r
2281   }\r
2282   \r
2283   if (FvFile != NULL) {\r
2284     fclose (FvFile);\r
2285   }\r
2286   \r
2287   if (FvMapFile != NULL) {\r
2288     fclose (FvMapFile);\r
2289   }\r
2290 \r
2291   return Status;\r
2292 }\r
2293 \r
2294 EFI_STATUS\r
2295 UpdatePeiCoreEntryInFit (\r
2296   IN FIT_TABLE     *FitTablePtr,\r
2297   IN UINT64        PeiCorePhysicalAddress\r
2298   )\r
2299 /*++\r
2300 \r
2301 Routine Description:\r
2302 \r
2303   This function is used to update the Pei Core address in FIT, this can be used by Sec core to pass control from\r
2304   Sec to Pei Core\r
2305 \r
2306 Arguments:\r
2307 \r
2308   FitTablePtr             - The pointer of FIT_TABLE.\r
2309   PeiCorePhysicalAddress  - The address of Pei Core entry.\r
2310 \r
2311 Returns:\r
2312 \r
2313   EFI_SUCCESS             - The PEI_CORE FIT entry was updated successfully.\r
2314   EFI_NOT_FOUND           - Not found the PEI_CORE FIT entry.\r
2315 \r
2316 --*/\r
2317 {\r
2318   FIT_TABLE *TmpFitPtr;\r
2319   UINTN     Index;\r
2320   UINTN     NumFitComponents;\r
2321 \r
2322   TmpFitPtr         = FitTablePtr;\r
2323   NumFitComponents  = TmpFitPtr->CompSize;\r
2324 \r
2325   for (Index = 0; Index < NumFitComponents; Index++) {\r
2326     if ((TmpFitPtr->CvAndType & FIT_TYPE_MASK) == COMP_TYPE_FIT_PEICORE) {\r
2327       TmpFitPtr->CompAddress = PeiCorePhysicalAddress;\r
2328       return EFI_SUCCESS;\r
2329     }\r
2330 \r
2331     TmpFitPtr++;\r
2332   }\r
2333 \r
2334   return EFI_NOT_FOUND;\r
2335 }\r
2336 \r
2337 VOID\r
2338 UpdateFitCheckSum (\r
2339   IN FIT_TABLE   *FitTablePtr\r
2340   )\r
2341 /*++\r
2342 \r
2343 Routine Description:\r
2344 \r
2345   This function is used to update the checksum for FIT.\r
2346 \r
2347 \r
2348 Arguments:\r
2349 \r
2350   FitTablePtr             - The pointer of FIT_TABLE.\r
2351 \r
2352 Returns:\r
2353 \r
2354   None.\r
2355 \r
2356 --*/\r
2357 {\r
2358   if ((FitTablePtr->CvAndType & CHECKSUM_BIT_MASK) >> 7) {\r
2359     FitTablePtr->CheckSum = 0;\r
2360     FitTablePtr->CheckSum = CalculateChecksum8 ((UINT8 *) FitTablePtr, FitTablePtr->CompSize * 16);\r
2361   }\r
2362 }\r
2363 \r
2364 EFI_STATUS\r
2365 CalculateFvSize (\r
2366   FV_INFO *FvInfoPtr\r
2367   )\r
2368 /*++\r
2369 Routine Description:\r
2370   Calculate the FV size and Update Fv Size based on the actual FFS files.\r
2371   And Update FvInfo data.\r
2372 \r
2373 Arguments:\r
2374   FvInfoPtr     - The pointer to FV_INFO structure.\r
2375 \r
2376 Returns:\r
2377   EFI_ABORTED   - Ffs Image Error\r
2378   EFI_SUCCESS   - Successfully update FvSize\r
2379 --*/\r
2380 {\r
2381   UINTN               CurrentOffset;\r
2382   UINTN               Index;\r
2383   FILE                *fpin;\r
2384   UINTN               FfsFileSize;\r
2385   UINT32              FfsAlignment;\r
2386   EFI_FFS_FILE_HEADER FfsHeader;\r
2387   BOOLEAN             VtfFileFlag;\r
2388   \r
2389   VtfFileFlag = FALSE;\r
2390   fpin  = NULL;\r
2391   Index = 0;\r
2392 \r
2393   //\r
2394   // Compute size for easy access later\r
2395   //\r
2396   FvInfoPtr->Size = 0;\r
2397   for (Index = 0; FvInfoPtr->FvBlocks[Index].NumBlocks > 0 && FvInfoPtr->FvBlocks[Index].Length > 0; Index++) {\r
2398     FvInfoPtr->Size += FvInfoPtr->FvBlocks[Index].NumBlocks * FvInfoPtr->FvBlocks[Index].Length;\r
2399   }\r
2400   \r
2401   //\r
2402   // Caculate the required sizes for all FFS files.\r
2403   //\r
2404   CurrentOffset = sizeof (EFI_FIRMWARE_VOLUME_HEADER);\r
2405   \r
2406   for (Index = 1;; Index ++) {\r
2407     CurrentOffset += sizeof (EFI_FV_BLOCK_MAP_ENTRY);\r
2408     if (FvInfoPtr->FvBlocks[Index].NumBlocks == 0 || FvInfoPtr->FvBlocks[Index].Length == 0) {\r
2409       break;\r
2410     }\r
2411   }\r
2412   \r
2413   //\r
2414   // Calculate PI extension header\r
2415   //\r
2416   if (CompareGuid (&mFvDataInfo.FvNameGuid, &mZeroGuid) != 0) {\r
2417     CurrentOffset += sizeof (EFI_FFS_FILE_HEADER) + sizeof (EFI_FIRMWARE_VOLUME_EXT_HEADER);\r
2418     CurrentOffset = (CurrentOffset + 7) & (~7);\r
2419   }\r
2420 \r
2421   //\r
2422   // Accumlate every FFS file size.\r
2423   //\r
2424   for (Index = 0; FvInfoPtr->FvFiles[Index][0] != 0; Index++) {\r
2425     //\r
2426     // Open FFS file\r
2427     //\r
2428     fpin = NULL;\r
2429     fpin = fopen (FvInfoPtr->FvFiles[Index], "rb");\r
2430     if (fpin == NULL) {\r
2431       Error (NULL, 0, 0001, "Error opening file", FvInfoPtr->FvFiles[Index]);\r
2432       return EFI_ABORTED;\r
2433     }\r
2434     //\r
2435     // Get the file size\r
2436     //\r
2437     FfsFileSize = _filelength (fileno (fpin));\r
2438     //\r
2439     // Read Ffs File header\r
2440     //\r
2441     fread (&FfsHeader, sizeof (UINT8), sizeof (EFI_FFS_FILE_HEADER), fpin);\r
2442     //\r
2443     // close file\r
2444     //\r
2445     fclose (fpin);\r
2446     \r
2447     if (FvInfoPtr->IsPiFvImage) {\r
2448             //\r
2449             // Check whether this ffs file is vtf file\r
2450             //\r
2451             if (IsVtfFile (&FfsHeader)) {\r
2452               if (VtfFileFlag) {\r
2453                 //\r
2454                 // One Fv image can't have two vtf files.\r
2455                 //\r
2456                 return EFI_ABORTED;\r
2457               }\r
2458               VtfFileFlag = TRUE;\r
2459               //\r
2460               // The space between Vft File and the latest file must be able to contain \r
2461               // one ffs file header in order to add one pad file.\r
2462               //\r
2463               CurrentOffset += sizeof (EFI_FFS_FILE_HEADER);\r
2464             }\r
2465             //\r
2466             // Get the alignment of FFS file \r
2467             //\r
2468             ReadFfsAlignment (&FfsHeader, &FfsAlignment);\r
2469             FfsAlignment = 1 << FfsAlignment;\r
2470             //\r
2471             // Add Pad file\r
2472             //\r
2473             if (((CurrentOffset + sizeof (EFI_FFS_FILE_HEADER)) % FfsAlignment) != 0) {\r
2474               CurrentOffset = (CurrentOffset + sizeof (EFI_FFS_FILE_HEADER) * 2 + FfsAlignment - 1) & ~(FfsAlignment - 1);\r
2475               CurrentOffset -= sizeof (EFI_FFS_FILE_HEADER);\r
2476             }\r
2477           }\r
2478 \r
2479     //\r
2480     // Add ffs file size\r
2481     //\r
2482     if (FvInfoPtr->SizeofFvFiles[Index] > FfsFileSize) {\r
2483         CurrentOffset += FvInfoPtr->SizeofFvFiles[Index];\r
2484     } else {\r
2485         CurrentOffset += FfsFileSize;\r
2486     }\r
2487         \r
2488     //\r
2489     // Make next ffs file start at QWord Boundry\r
2490     //\r
2491     if (FvInfoPtr->IsPiFvImage) {\r
2492         CurrentOffset = (CurrentOffset + EFI_FFS_FILE_HEADER_ALIGNMENT - 1) & ~(EFI_FFS_FILE_HEADER_ALIGNMENT - 1);\r
2493     }\r
2494   }\r
2495   \r
2496   DebugMsg (NULL, 0, 9, "FvImage size", "The caculated fv image size is 0x%x and the current set fv image size is 0x%x", (unsigned) CurrentOffset, (unsigned) FvInfoPtr->Size);\r
2497   \r
2498   if (FvInfoPtr->Size == 0) { \r
2499     //\r
2500     // Update FvInfo data\r
2501     //\r
2502     FvInfoPtr->FvBlocks[0].NumBlocks = CurrentOffset / FvInfoPtr->FvBlocks[0].Length + ((CurrentOffset % FvInfoPtr->FvBlocks[0].Length)?1:0);\r
2503     FvInfoPtr->Size = FvInfoPtr->FvBlocks[0].NumBlocks * FvInfoPtr->FvBlocks[0].Length;\r
2504     FvInfoPtr->FvBlocks[1].NumBlocks = 0;\r
2505     FvInfoPtr->FvBlocks[1].Length = 0;\r
2506   } else if (FvInfoPtr->Size < CurrentOffset) {\r
2507     //\r
2508     // Not invalid\r
2509     //\r
2510     Error (NULL, 0, 3000, "Invalid", "the required fv image size 0x%x exceeds the set fv image size 0x%x", (unsigned) CurrentOffset, (unsigned) FvInfoPtr->Size);\r
2511     return EFI_INVALID_PARAMETER;\r
2512   }\r
2513   \r
2514   //\r
2515   // Set Fv Size Information\r
2516   //\r
2517   mFvTotalSize = FvInfoPtr->Size;\r
2518   mFvTakenSize = CurrentOffset;\r
2519 \r
2520   return EFI_SUCCESS;\r
2521 }\r
2522 \r
2523 EFI_STATUS\r
2524 FfsRebaseImageRead (\r
2525   IN     VOID    *FileHandle,\r
2526   IN     UINTN   FileOffset,\r
2527   IN OUT UINT32  *ReadSize,\r
2528   OUT    VOID    *Buffer\r
2529   )\r
2530 /*++\r
2531 \r
2532 Routine Description:\r
2533 \r
2534   Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file\r
2535 \r
2536 Arguments:\r
2537 \r
2538   FileHandle - The handle to the PE/COFF file\r
2539 \r
2540   FileOffset - The offset, in bytes, into the file to read\r
2541 \r
2542   ReadSize   - The number of bytes to read from the file starting at FileOffset\r
2543 \r
2544   Buffer     - A pointer to the buffer to read the data into.\r
2545 \r
2546 Returns:\r
2547 \r
2548   EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset\r
2549 \r
2550 --*/\r
2551 {\r
2552   CHAR8   *Destination8;\r
2553   CHAR8   *Source8;\r
2554   UINT32  Length;\r
2555 \r
2556   Destination8  = Buffer;\r
2557   Source8       = (CHAR8 *) ((UINTN) FileHandle + FileOffset);\r
2558   Length        = *ReadSize;\r
2559   while (Length--) {\r
2560     *(Destination8++) = *(Source8++);\r
2561   }\r
2562 \r
2563   return EFI_SUCCESS;\r
2564 }\r
2565 \r
2566 EFI_STATUS\r
2567 FfsRebase ( \r
2568   IN OUT  FV_INFO               *FvInfo, \r
2569   IN      CHAR8                 *FileName,           \r
2570   IN OUT  EFI_FFS_FILE_HEADER   *FfsFile,\r
2571   IN      UINTN                 XipOffset,\r
2572   IN      FILE                  *FvMapFile\r
2573   )\r
2574 /*++\r
2575 \r
2576 Routine Description:\r
2577 \r
2578   This function determines if a file is XIP and should be rebased.  It will\r
2579   rebase any PE32 sections found in the file using the base address.\r
2580 \r
2581 Arguments:\r
2582   \r
2583   FvInfo            A pointer to FV_INFO struture.\r
2584   FileName          Ffs File PathName\r
2585   FfsFile           A pointer to Ffs file image.\r
2586   XipOffset         The offset address to use for rebasing the XIP file image.\r
2587   FvMapFile         FvMapFile to record the function address in one Fvimage\r
2588 \r
2589 Returns:\r
2590 \r
2591   EFI_SUCCESS             The image was properly rebased.\r
2592   EFI_INVALID_PARAMETER   An input parameter is invalid.\r
2593   EFI_ABORTED             An error occurred while rebasing the input file image.\r
2594   EFI_OUT_OF_RESOURCES    Could not allocate a required resource.\r
2595   EFI_NOT_FOUND           No compressed sections could be found.\r
2596 \r
2597 --*/\r
2598 {\r
2599   EFI_STATUS                            Status;\r
2600   PE_COFF_LOADER_IMAGE_CONTEXT          ImageContext;\r
2601   PE_COFF_LOADER_IMAGE_CONTEXT          OrigImageContext;  \r
2602   EFI_PHYSICAL_ADDRESS                  XipBase;\r
2603   EFI_PHYSICAL_ADDRESS                  NewPe32BaseAddress;\r
2604   EFI_PHYSICAL_ADDRESS                  *BaseToUpdate;\r
2605   UINTN                                 Index;\r
2606   EFI_FILE_SECTION_POINTER              CurrentPe32Section;\r
2607   EFI_FFS_FILE_STATE                    SavedState;\r
2608   EFI_IMAGE_OPTIONAL_HEADER_UNION       *ImgHdr;\r
2609   EFI_TE_IMAGE_HEADER                   *TEImageHeader;\r
2610   UINT8                                 Flags;\r
2611   UINT8                                 *MemoryImagePointer;\r
2612   EFI_IMAGE_SECTION_HEADER              *SectionHeader;\r
2613   CHAR8                                 PeFileName [_MAX_PATH];\r
2614   CHAR8                                 *Cptr;\r
2615   FILE                                  *PeFile;\r
2616   UINT8                                 *PeFileBuffer;\r
2617   UINT32                                PeFileSize;\r
2618   CHAR8                                 *PdbPointer;\r
2619 \r
2620   Index              = 0;  \r
2621   MemoryImagePointer = NULL;\r
2622   BaseToUpdate       = NULL;\r
2623   TEImageHeader      = NULL;\r
2624   ImgHdr             = NULL;\r
2625   SectionHeader      = NULL;\r
2626   Cptr               = NULL;\r
2627   PeFile             = NULL;\r
2628   PeFileBuffer       = NULL;\r
2629 \r
2630   //\r
2631   // Check XipAddress, BootAddress and RuntimeAddress\r
2632   //\r
2633   Flags   = 0;\r
2634   XipBase = 0;\r
2635   if (FvInfo->BaseAddress != 0) {\r
2636     Flags  |= REBASE_XIP_FILE;\r
2637     XipBase = FvInfo->BaseAddress + XipOffset;\r
2638   }\r
2639   if (FvInfo->BootBaseAddress != 0) {\r
2640     Flags  |= REBASE_BOOTTIME_FILE;\r
2641   }\r
2642   if (FvInfo->RuntimeBaseAddress != 0) {\r
2643     Flags  |= REBASE_RUNTIME_FILE;\r
2644   }\r
2645 \r
2646   //\r
2647   //  Don't Rebase this FFS.\r
2648   //  Only copy the original map file into the FvMap file \r
2649   //  for the image that is not required to be relocated.\r
2650   //\r
2651 \r
2652   //\r
2653   // We only process files potentially containing PE32 sections.\r
2654   //\r
2655   switch (FfsFile->Type) {\r
2656     case EFI_FV_FILETYPE_SECURITY_CORE:\r
2657     case EFI_FV_FILETYPE_PEI_CORE:\r
2658     case EFI_FV_FILETYPE_PEIM:\r
2659     case EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER:\r
2660     case EFI_FV_FILETYPE_DRIVER:\r
2661     case EFI_FV_FILETYPE_DXE_CORE:\r
2662       break;\r
2663     default:\r
2664       return EFI_SUCCESS;\r
2665   }\r
2666   //\r
2667   // Rebase each PE32 section\r
2668   //\r
2669   Status      = EFI_SUCCESS;\r
2670   for (Index = 1;; Index++) {\r
2671     //\r
2672     // Init Value\r
2673     //\r
2674     NewPe32BaseAddress = 0;\r
2675     \r
2676     //\r
2677     // Find Pe Image\r
2678     //\r
2679     Status = GetSectionByType (FfsFile, EFI_SECTION_PE32, Index, &CurrentPe32Section);\r
2680     if (EFI_ERROR (Status)) {\r
2681       break;\r
2682     }\r
2683 \r
2684     //\r
2685     // Initialize context\r
2686     //\r
2687     memset (&ImageContext, 0, sizeof (ImageContext));\r
2688     ImageContext.Handle     = (VOID *) ((UINTN) CurrentPe32Section.Pe32Section + sizeof (EFI_PE32_SECTION));\r
2689     ImageContext.ImageRead  = (PE_COFF_LOADER_READ_FILE) FfsRebaseImageRead;\r
2690     Status                  = PeCoffLoaderGetImageInfo (&ImageContext);\r
2691     if (EFI_ERROR (Status)) {\r
2692       Error (NULL, 0, 3000, "Invalid PeImage", "The input file is %s and the return status is %x", FileName, (int) Status);\r
2693       return Status;\r
2694     }\r
2695 \r
2696     if (ImageContext.Machine == EFI_IMAGE_MACHINE_ARMT) {\r
2697       mArm = TRUE;\r
2698     }\r
2699 \r
2700     //\r
2701     // Keep Image Context for PE image in FV\r
2702     //\r
2703     memcpy (&OrigImageContext, &ImageContext, sizeof (ImageContext));\r
2704     \r
2705     //\r
2706     // Get File PdbPointer\r
2707     //\r
2708     PdbPointer = PeCoffLoaderGetPdbPointer (ImageContext.Handle);\r
2709 \r
2710     //\r
2711     // Get PeHeader pointer\r
2712     //\r
2713     ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((UINTN) CurrentPe32Section.Pe32Section + sizeof (EFI_PE32_SECTION) + ImageContext.PeCoffHeaderOffset);\r
2714 \r
2715     //\r
2716     // Calculate the PE32 base address, based on file type\r
2717     //\r
2718     switch (FfsFile->Type) {\r
2719       case EFI_FV_FILETYPE_SECURITY_CORE:\r
2720       case EFI_FV_FILETYPE_PEI_CORE:\r
2721       case EFI_FV_FILETYPE_PEIM:\r
2722       case EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER:\r
2723         if ((Flags & REBASE_XIP_FILE) == 0) {\r
2724           //\r
2725           // We aren't relocating XIP code, so skip it.\r
2726           //\r
2727           goto WritePeMap;\r
2728         }\r
2729         \r
2730         //\r
2731         // Check if section-alignment and file-alignment match or not\r
2732         //\r
2733         if ((ImgHdr->Pe32.OptionalHeader.SectionAlignment != ImgHdr->Pe32.OptionalHeader.FileAlignment)) {\r
2734           //\r
2735           // Xip module has the same section alignment and file alignment.\r
2736           //\r
2737           Error (NULL, 0, 3000, "Invalid", "Section-Alignment and File-Alignment do not match : %s.", FileName);\r
2738           return EFI_ABORTED;\r
2739         }\r
2740         //\r
2741         // PeImage has no reloc section. It will try to get reloc data from the original EFI image. \r
2742         //\r
2743         if (ImageContext.RelocationsStripped) {\r
2744           //\r
2745           // Construct the original efi file Name \r
2746           //\r
2747           strcpy (PeFileName, FileName);\r
2748           Cptr = PeFileName + strlen (PeFileName);\r
2749           while (*Cptr != '.') {\r
2750             Cptr --;\r
2751           }\r
2752           if (*Cptr != '.') {\r
2753             Error (NULL, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName);\r
2754             return EFI_ABORTED;\r
2755           } else {\r
2756             *(Cptr + 1) = 'e';\r
2757             *(Cptr + 2) = 'f';\r
2758             *(Cptr + 3) = 'i';\r
2759             *(Cptr + 4) = '\0';\r
2760           }\r
2761           PeFile = fopen (PeFileName, "rb");\r
2762           if (PeFile == NULL) {\r
2763             Warning (NULL, 0, 0, "Invalid", "The file %s has no .reloc section.", FileName);\r
2764             //Error (NULL, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName);\r
2765             //return EFI_ABORTED;\r
2766             break;\r
2767           }\r
2768           //\r
2769           // Get the file size\r
2770           //\r
2771           PeFileSize = _filelength (fileno (PeFile));\r
2772           PeFileBuffer = (UINT8 *) malloc (PeFileSize);\r
2773           if (PeFileBuffer == NULL) {\r
2774             Error (NULL, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName);\r
2775             return EFI_OUT_OF_RESOURCES;\r
2776           }\r
2777           //\r
2778           // Read Pe File\r
2779           //\r
2780           fread (PeFileBuffer, sizeof (UINT8), PeFileSize, PeFile);\r
2781           //\r
2782           // close file\r
2783           //\r
2784           fclose (PeFile);\r
2785           //\r
2786           // Handle pointer to the original efi image.\r
2787           //\r
2788           ImageContext.Handle = PeFileBuffer;\r
2789           Status              = PeCoffLoaderGetImageInfo (&ImageContext);\r
2790           if (EFI_ERROR (Status)) {\r
2791             Error (NULL, 0, 3000, "Invalid PeImage", "The input file is %s and the return status is %x", FileName, (int) Status);\r
2792             return Status;\r
2793           }\r
2794           ImageContext.RelocationsStripped = FALSE;\r
2795         }\r
2796 \r
2797         NewPe32BaseAddress = XipBase + (UINTN) CurrentPe32Section.Pe32Section + sizeof (EFI_PE32_SECTION) - (UINTN)FfsFile;\r
2798         BaseToUpdate = &XipBase;\r
2799         break;\r
2800 \r
2801       case EFI_FV_FILETYPE_DRIVER:\r
2802       case EFI_FV_FILETYPE_DXE_CORE:\r
2803         switch (ImgHdr->Pe32.OptionalHeader.Subsystem) {\r
2804           case EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER:\r
2805                                                 if ((Flags & REBASE_XIP_FILE) == REBASE_XIP_FILE) {\r
2806                                 //\r
2807                                 // Check if section-alignment and file-alignment match or not\r
2808                                 //\r
2809                                 if ((ImgHdr->Pe32.OptionalHeader.SectionAlignment != ImgHdr->Pe32.OptionalHeader.FileAlignment)) {\r
2810                                   //\r
2811                                   // Xip module has the same section alignment and file alignment.\r
2812                                   //\r
2813                                   Error (NULL, 0, 3000, "Invalid", "Section-Alignment and File-Alignment do not match : %s.", FileName);\r
2814                                   return EFI_ABORTED;\r
2815                                 }\r
2816                                 NewPe32BaseAddress = XipBase + (UINTN) CurrentPe32Section.Pe32Section + sizeof (EFI_PE32_SECTION) - (UINTN)FfsFile;\r
2817                                 BaseToUpdate = &XipBase;                        \r
2818                   } else if ((Flags & REBASE_RUNTIME_FILE) == REBASE_RUNTIME_FILE) {\r
2819                     //\r
2820                     // make sure image base address at the section alignment\r
2821                     //\r
2822                     FvInfo->RuntimeBaseAddress = (FvInfo->RuntimeBaseAddress - ImageContext.ImageSize) & (~(ImageContext.SectionAlignment - 1));\r
2823                     FvInfo->RuntimeBaseAddress = FvInfo->RuntimeBaseAddress & (~(EFI_PAGE_SIZE - 1));\r
2824                     NewPe32BaseAddress = FvInfo->RuntimeBaseAddress;\r
2825                     BaseToUpdate = &(FvInfo->RuntimeBaseAddress);\r
2826                   } else {\r
2827               //\r
2828               // RT drivers aren't supposed to be relocated\r
2829               //\r
2830               goto WritePeMap;\r
2831             }\r
2832             break;\r
2833 \r
2834           default:\r
2835             //\r
2836             // We treat all other subsystems the same as BS_DRIVER\r
2837             //\r
2838                                                 if ((Flags & REBASE_XIP_FILE) == REBASE_XIP_FILE) {\r
2839                                 //\r
2840                                 // Check if section-alignment and file-alignment match or not\r
2841                                 //\r
2842                                 if ((ImgHdr->Pe32.OptionalHeader.SectionAlignment != ImgHdr->Pe32.OptionalHeader.FileAlignment)) {\r
2843                                   //\r
2844                                   // Xip module has the same section alignment and file alignment.\r
2845                                   //\r
2846                                   Error (NULL, 0, 3000, "Invalid", "Section-Alignment and File-Alignment do not match : %s.", FileName);\r
2847                                   return EFI_ABORTED;\r
2848                                 }\r
2849                                 NewPe32BaseAddress = XipBase + (UINTN) CurrentPe32Section.Pe32Section + sizeof (EFI_PE32_SECTION) - (UINTN)FfsFile;\r
2850                                 BaseToUpdate = &XipBase;                        \r
2851                   } else if ((Flags & REBASE_BOOTTIME_FILE) == REBASE_BOOTTIME_FILE) {\r
2852                     //\r
2853                     // make sure image base address at the Section and Page alignment\r
2854                     //\r
2855                     FvInfo->BootBaseAddress = (FvInfo->BootBaseAddress - ImageContext.ImageSize) & (~(ImageContext.SectionAlignment - 1));\r
2856                     FvInfo->BootBaseAddress = FvInfo->BootBaseAddress & (~(EFI_PAGE_SIZE - 1));\r
2857                     NewPe32BaseAddress = FvInfo->BootBaseAddress;\r
2858                     BaseToUpdate = &(FvInfo->BootBaseAddress);\r
2859                   } else {\r
2860               //\r
2861               // Skip all BS_DRIVER's\r
2862               //\r
2863               goto WritePeMap;\r
2864             }\r
2865             break;\r
2866         }\r
2867         break;\r
2868 \r
2869       default:\r
2870         //\r
2871         // Not supported file type\r
2872         //\r
2873         return EFI_SUCCESS;\r
2874     }\r
2875     \r
2876     //\r
2877     // Relocation exist and rebase\r
2878     //\r
2879     if (!ImageContext.RelocationsStripped) {  \r
2880       //\r
2881       // Load and Relocate Image Data\r
2882       //\r
2883       MemoryImagePointer = (UINT8 *) malloc ((UINTN) ImageContext.ImageSize + ImageContext.SectionAlignment);\r
2884       if (MemoryImagePointer == NULL) {\r
2885         Error (NULL, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName);\r
2886         return EFI_OUT_OF_RESOURCES;\r
2887       }\r
2888       memset ((VOID *) MemoryImagePointer, 0, (UINTN) ImageContext.ImageSize + ImageContext.SectionAlignment);\r
2889       ImageContext.ImageAddress = ((UINTN) MemoryImagePointer + ImageContext.SectionAlignment - 1) & (~(ImageContext.SectionAlignment - 1));\r
2890       \r
2891       Status =  PeCoffLoaderLoadImage (&ImageContext);\r
2892       if (EFI_ERROR (Status)) {\r
2893         Error (NULL, 0, 3000, "Invalid", "LocateImage() call failed on rebase of %s", FileName);\r
2894         free ((VOID *) MemoryImagePointer);\r
2895         return Status;\r
2896       }\r
2897            \r
2898       ImageContext.DestinationAddress = NewPe32BaseAddress;\r
2899       Status                          = PeCoffLoaderRelocateImage (&ImageContext);\r
2900       if (EFI_ERROR (Status)) {\r
2901         Error (NULL, 0, 3000, "Invalid", "RelocateImage() call failed on rebase of %s", FileName);\r
2902         free ((VOID *) MemoryImagePointer);\r
2903         return Status;\r
2904       }\r
2905 \r
2906       //\r
2907       // Copy Relocated data to raw image file.\r
2908       //\r
2909       SectionHeader = (EFI_IMAGE_SECTION_HEADER *) (\r
2910                          (UINTN) ImgHdr +\r
2911                          sizeof (UINT32) + \r
2912                          sizeof (EFI_IMAGE_FILE_HEADER) +  \r
2913                          ImgHdr->Pe32.FileHeader.SizeOfOptionalHeader\r
2914                          );\r
2915       \r
2916       for (Index = 0; Index < ImgHdr->Pe32.FileHeader.NumberOfSections; Index ++, SectionHeader ++) {\r
2917         CopyMem (\r
2918           (UINT8 *) CurrentPe32Section.Pe32Section + sizeof (EFI_COMMON_SECTION_HEADER) + SectionHeader->PointerToRawData, \r
2919           (VOID*) (UINTN) (ImageContext.ImageAddress + SectionHeader->VirtualAddress), \r
2920           SectionHeader->SizeOfRawData\r
2921           );\r
2922       }\r
2923   \r
2924       free ((VOID *) MemoryImagePointer);\r
2925       MemoryImagePointer = NULL;\r
2926       if (PeFileBuffer != NULL) {\r
2927         free (PeFileBuffer);\r
2928         PeFileBuffer = NULL;\r
2929       }\r
2930     }\r
2931     \r
2932     //\r
2933     // Update Image Base Address\r
2934     //\r
2935     if (ImgHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
2936       ImgHdr->Pe32.OptionalHeader.ImageBase     = (UINT32) NewPe32BaseAddress;\r
2937     } else if (ImgHdr->Pe32Plus.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {\r
2938       ImgHdr->Pe32Plus.OptionalHeader.ImageBase     = NewPe32BaseAddress;\r
2939     } else {\r
2940       Error (NULL, 0, 3000, "Invalid", "unknown PE magic signature %X in PE32 image %s",\r
2941         ImgHdr->Pe32.OptionalHeader.Magic,\r
2942         FileName\r
2943         );\r
2944       return EFI_ABORTED;\r
2945     }\r
2946 \r
2947     //\r
2948     // Update BASE address by add one page size.\r
2949     //\r
2950     *BaseToUpdate -= EFI_PAGE_SIZE;\r
2951 \r
2952     //\r
2953     // Now update file checksum\r
2954     //\r
2955     if (FfsFile->Attributes & FFS_ATTRIB_CHECKSUM) {\r
2956       SavedState  = FfsFile->State;\r
2957       FfsFile->IntegrityCheck.Checksum.File = 0;\r
2958       FfsFile->State                        = 0;\r
2959       if (FfsFile->Attributes & FFS_ATTRIB_CHECKSUM) {\r
2960         FfsFile->IntegrityCheck.Checksum.File = CalculateChecksum8 (\r
2961                                                   (UINT8 *) FfsFile,\r
2962                                                   GetLength (FfsFile->Size)\r
2963                                                   );\r
2964       } else {\r
2965         FfsFile->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;\r
2966       }\r
2967 \r
2968       FfsFile->State = SavedState;\r
2969     }\r
2970 \r
2971     //\r
2972     // Get this module function address from ModulePeMapFile and add them into FvMap file\r
2973     //\r
2974 WritePeMap:\r
2975     //\r
2976     // Default use FileName as map file path\r
2977     //\r
2978     if (PdbPointer == NULL) {\r
2979       PdbPointer = FileName;\r
2980     }\r
2981 \r
2982     WriteMapFile (FvMapFile, PdbPointer, (EFI_GUID *) FfsFile, NewPe32BaseAddress, &OrigImageContext);\r
2983   }\r
2984 \r
2985   if (FfsFile->Type != EFI_FV_FILETYPE_SECURITY_CORE &&\r
2986       FfsFile->Type != EFI_FV_FILETYPE_PEI_CORE &&\r
2987       FfsFile->Type != EFI_FV_FILETYPE_PEIM &&\r
2988       FfsFile->Type != EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER\r
2989       ) {\r
2990     //\r
2991     // Only Peim code may have a TE section\r
2992     //\r
2993     return EFI_SUCCESS;\r
2994   }\r
2995   \r
2996   //\r
2997   // Now process TE sections\r
2998   //\r
2999   for (Index = 1;; Index++) {\r
3000     NewPe32BaseAddress = 0;\r
3001     \r
3002     //\r
3003     // Find Te Image\r
3004     //\r
3005     Status = GetSectionByType (FfsFile, EFI_SECTION_TE, Index, &CurrentPe32Section);\r
3006     if (EFI_ERROR (Status)) {\r
3007       break;\r
3008     }\r
3009     \r
3010     //\r
3011     // Calculate the TE base address, the FFS file base plus the offset of the TE section less the size stripped off\r
3012     // by GenTEImage\r
3013     //\r
3014     TEImageHeader = (EFI_TE_IMAGE_HEADER *) ((UINT8 *) CurrentPe32Section.Pe32Section + sizeof (EFI_COMMON_SECTION_HEADER));\r
3015 \r
3016     //\r
3017     // Initialize context, load image info.\r
3018     //\r
3019     memset (&ImageContext, 0, sizeof (ImageContext));\r
3020     ImageContext.Handle     = (VOID *) TEImageHeader;\r
3021     ImageContext.ImageRead  = (PE_COFF_LOADER_READ_FILE) FfsRebaseImageRead;\r
3022     Status                  = PeCoffLoaderGetImageInfo (&ImageContext);\r
3023     if (EFI_ERROR (Status)) {\r
3024       Error (NULL, 0, 3000, "Invalid TeImage", "The input file is %s and the return status is %x", FileName, (int) Status);\r
3025       return Status;\r
3026     }\r
3027 \r
3028     if (ImageContext.Machine == EFI_IMAGE_MACHINE_ARMT) {\r
3029       mArm = TRUE;\r
3030     }\r
3031 \r
3032     //\r
3033     // Keep Image Context for TE image in FV\r
3034     //\r
3035     memcpy (&OrigImageContext, &ImageContext, sizeof (ImageContext));\r
3036 \r
3037     //\r
3038     // Get File PdbPointer\r
3039     //\r
3040     PdbPointer = PeCoffLoaderGetPdbPointer (ImageContext.Handle);\r
3041     \r
3042     if ((Flags & REBASE_XIP_FILE) == 0) {\r
3043       //\r
3044       // For none XIP PEIM module, their map info also are collected.\r
3045       //\r
3046       goto WriteTeMap;\r
3047     }\r
3048 \r
3049     //\r
3050     // Set new rebased address.\r
3051     //\r
3052     NewPe32BaseAddress = XipBase + (UINTN) TEImageHeader + sizeof (EFI_TE_IMAGE_HEADER) \\r
3053                          - TEImageHeader->StrippedSize - (UINTN) FfsFile;\r
3054 \r
3055     //\r
3056     // if reloc is stripped, try to get the original efi image to get reloc info.\r
3057     //\r
3058     if (ImageContext.RelocationsStripped == TRUE) {\r
3059       //\r
3060       // Construct the original efi file name \r
3061       //\r
3062       strcpy (PeFileName, FileName);\r
3063       Cptr = PeFileName + strlen (PeFileName);\r
3064       while (*Cptr != '.') {\r
3065         Cptr --;\r
3066       }\r
3067 \r
3068       if (*Cptr != '.') {\r
3069         Error (NULL, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName);\r
3070         return EFI_ABORTED;\r
3071       } else {\r
3072         *(Cptr + 1) = 'e';\r
3073         *(Cptr + 2) = 'f';\r
3074         *(Cptr + 3) = 'i';\r
3075         *(Cptr + 4) = '\0';\r
3076       }\r
3077 \r
3078       PeFile = fopen (PeFileName, "rb");\r
3079       if (PeFile == NULL) {\r
3080         Warning (NULL, 0, 0, "Invalid", "The file %s has no .reloc section.", FileName);\r
3081         //Error (NULL, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName);\r
3082         //return EFI_ABORTED;\r
3083       } else {\r
3084         //\r
3085         // Get the file size\r
3086         //\r
3087         PeFileSize = _filelength (fileno (PeFile));\r
3088         PeFileBuffer = (UINT8 *) malloc (PeFileSize);\r
3089         if (PeFileBuffer == NULL) {\r
3090           Error (NULL, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName);\r
3091           return EFI_OUT_OF_RESOURCES;\r
3092         }\r
3093         //\r
3094         // Read Pe File\r
3095         //\r
3096         fread (PeFileBuffer, sizeof (UINT8), PeFileSize, PeFile);\r
3097         //\r
3098         // close file\r
3099         //\r
3100         fclose (PeFile);\r
3101         //\r
3102         // Append reloc section into TeImage\r
3103         //\r
3104         ImageContext.Handle = PeFileBuffer;\r
3105         Status              = PeCoffLoaderGetImageInfo (&ImageContext);\r
3106         if (EFI_ERROR (Status)) {\r
3107           Error (NULL, 0, 3000, "Invalid TeImage", "The input file is %s and the return status is %x", FileName, (int) Status);\r
3108           return Status;\r
3109         }\r
3110         ImageContext.RelocationsStripped = FALSE;\r
3111       }\r
3112     }\r
3113 \r
3114     //\r
3115     // Relocation exist and rebase\r
3116     //\r
3117     if (!ImageContext.RelocationsStripped) {\r
3118       //\r
3119       // Load and Relocate Image Data\r
3120       //\r
3121       MemoryImagePointer = (UINT8 *) malloc ((UINTN) ImageContext.ImageSize + ImageContext.SectionAlignment);\r
3122       if (MemoryImagePointer == NULL) {\r
3123         Error (NULL, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName);\r
3124         return EFI_OUT_OF_RESOURCES;\r
3125       }\r
3126       memset ((VOID *) MemoryImagePointer, 0, (UINTN) ImageContext.ImageSize + ImageContext.SectionAlignment);\r
3127       ImageContext.ImageAddress = ((UINTN) MemoryImagePointer + ImageContext.SectionAlignment - 1) & (~(ImageContext.SectionAlignment - 1));\r
3128   \r
3129       Status =  PeCoffLoaderLoadImage (&ImageContext);\r
3130       if (EFI_ERROR (Status)) {\r
3131         Error (NULL, 0, 3000, "Invalid", "LocateImage() call failed on rebase of %s", FileName);\r
3132         free ((VOID *) MemoryImagePointer);\r
3133         return Status;\r
3134       }\r
3135       //\r
3136       // Reloacate TeImage\r
3137       // \r
3138       ImageContext.DestinationAddress = NewPe32BaseAddress;\r
3139       Status                          = PeCoffLoaderRelocateImage (&ImageContext);\r
3140       if (EFI_ERROR (Status)) {\r
3141         Error (NULL, 0, 3000, "Invalid", "RelocateImage() call failed on rebase of TE image %s", FileName);\r
3142         free ((VOID *) MemoryImagePointer);\r
3143         return Status;\r
3144       }\r
3145       \r
3146       //\r
3147       // Copy the relocated image into raw image file.\r
3148       //\r
3149       SectionHeader = (EFI_IMAGE_SECTION_HEADER *) (TEImageHeader + 1);\r
3150       for (Index = 0; Index < TEImageHeader->NumberOfSections; Index ++, SectionHeader ++) {\r
3151         if (!ImageContext.IsTeImage) {\r
3152           CopyMem (\r
3153             (UINT8 *) TEImageHeader + sizeof (EFI_TE_IMAGE_HEADER) - TEImageHeader->StrippedSize + SectionHeader->PointerToRawData, \r
3154             (VOID*) (UINTN) (ImageContext.ImageAddress + SectionHeader->VirtualAddress), \r
3155             SectionHeader->SizeOfRawData\r
3156             );\r
3157         } else {\r
3158           CopyMem (\r
3159             (UINT8 *) TEImageHeader + sizeof (EFI_TE_IMAGE_HEADER) - TEImageHeader->StrippedSize + SectionHeader->PointerToRawData, \r
3160             (VOID*) (UINTN) (ImageContext.ImageAddress + sizeof (EFI_TE_IMAGE_HEADER) - TEImageHeader->StrippedSize + SectionHeader->VirtualAddress), \r
3161             SectionHeader->SizeOfRawData\r
3162             );\r
3163         }\r
3164       }\r
3165       \r
3166       //\r
3167       // Free the allocated memory resource\r
3168       //\r
3169       free ((VOID *) MemoryImagePointer);\r
3170       MemoryImagePointer = NULL;\r
3171       if (PeFileBuffer != NULL) {\r
3172         free (PeFileBuffer);\r
3173         PeFileBuffer = NULL;\r
3174       }\r
3175     }\r
3176     \r
3177     //\r
3178     // Update Image Base Address\r
3179     //\r
3180     TEImageHeader->ImageBase = NewPe32BaseAddress;\r
3181 \r
3182     //\r
3183     // Now update file checksum\r
3184     //\r
3185     if (FfsFile->Attributes & FFS_ATTRIB_CHECKSUM) {\r
3186       SavedState  = FfsFile->State;\r
3187       FfsFile->IntegrityCheck.Checksum.File = 0;\r
3188       FfsFile->State                        = 0;\r
3189       if (FfsFile->Attributes & FFS_ATTRIB_CHECKSUM) {\r
3190         FfsFile->IntegrityCheck.Checksum.File = CalculateChecksum8 (\r
3191                                                   (UINT8 *) FfsFile,\r
3192                                                   GetLength (FfsFile->Size)\r
3193                                                   );\r
3194       } else {\r
3195         FfsFile->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;\r
3196       }\r
3197 \r
3198       FfsFile->State = SavedState;\r
3199     }\r
3200     //\r
3201     // Get this module function address from ModulePeMapFile and add them into FvMap file\r
3202     //\r
3203 WriteTeMap:\r
3204     //\r
3205     // Default use FileName as map file path\r
3206     //\r
3207     if (PdbPointer == NULL) {\r
3208       PdbPointer = FileName;\r
3209     }\r
3210 \r
3211     WriteMapFile (\r
3212       FvMapFile, \r
3213       PdbPointer, \r
3214       (EFI_GUID *) FfsFile,\r
3215       NewPe32BaseAddress, \r
3216       &OrigImageContext\r
3217       );\r
3218   }\r
3219  \r
3220   return EFI_SUCCESS;\r
3221 }\r
3222 \r
3223 EFI_STATUS\r
3224 FindApResetVectorPosition (\r
3225   IN  MEMORY_FILE  *FvImage,\r
3226   OUT UINT8        **Pointer\r
3227   )\r
3228 /*++\r
3229 \r
3230 Routine Description:\r
3231 \r
3232   Find the position in this FvImage to place Ap reset vector.\r
3233 \r
3234 Arguments:\r
3235 \r
3236   FvImage       Memory file for the FV memory image.\r
3237   Pointer       Pointer to pointer to position.\r
3238 \r
3239 Returns:\r
3240 \r
3241   EFI_NOT_FOUND   - No satisfied position is found.\r
3242   EFI_SUCCESS     - The suitable position is return.\r
3243 \r
3244 --*/\r
3245 {\r
3246   EFI_FFS_FILE_HEADER   *PadFile;\r
3247   UINT32                Index;\r
3248   EFI_STATUS            Status;\r
3249   UINT8                 *FixPoint;\r
3250   UINT32                FileLength;\r
3251 \r
3252   for (Index = 1; ;Index ++) {\r
3253     //\r
3254     // Find Pad File to add ApResetVector info\r
3255     //\r
3256     Status = GetFileByType (EFI_FV_FILETYPE_FFS_PAD, Index, &PadFile);\r
3257     if (EFI_ERROR (Status) || (PadFile == NULL)) {\r
3258       //\r
3259       // No Pad file to be found.\r
3260       //\r
3261       break;\r
3262     }\r
3263     //\r
3264     // Get Pad file size.\r
3265     //\r
3266     FileLength = (*(UINT32 *)(PadFile->Size)) & 0x00FFFFFF;\r
3267     FileLength = (FileLength + EFI_FFS_FILE_HEADER_ALIGNMENT - 1) & ~(EFI_FFS_FILE_HEADER_ALIGNMENT - 1); \r
3268     //\r
3269     // FixPoint must be align on 0x1000 relative to FvImage Header\r
3270     //\r
3271     FixPoint = (UINT8*) PadFile + sizeof (EFI_FFS_FILE_HEADER);\r
3272     FixPoint = FixPoint + 0x1000 - (((UINTN) FixPoint - (UINTN) FvImage->FileImage) & 0xFFF);\r
3273     //\r
3274     // FixPoint be larger at the last place of one fv image.\r
3275     //\r
3276     while (((UINTN) FixPoint + SIZEOF_STARTUP_DATA_ARRAY - (UINTN) PadFile) <= FileLength) {\r
3277       FixPoint += 0x1000;\r
3278     }\r
3279     FixPoint -= 0x1000;\r
3280     \r
3281     if ((UINTN) FixPoint < ((UINTN) PadFile + sizeof (EFI_FFS_FILE_HEADER))) {\r
3282       //\r
3283       // No alignment FixPoint in this Pad File.\r
3284       //\r
3285       continue;\r
3286     }\r
3287 \r
3288     if ((UINTN) FvImage->Eof - (UINTN)FixPoint <= 0x20000) {    \r
3289       //\r
3290       // Find the position to place ApResetVector\r
3291       //\r
3292       *Pointer = FixPoint;\r
3293       return EFI_SUCCESS;\r
3294     }\r
3295   }\r
3296   \r
3297   return EFI_NOT_FOUND;\r
3298 }\r
3299 \r
3300 EFI_STATUS\r
3301 ParseCapInf (\r
3302   IN  MEMORY_FILE  *InfFile,\r
3303   OUT CAP_INFO     *CapInfo\r
3304   )\r
3305 /*++\r
3306 \r
3307 Routine Description:\r
3308 \r
3309   This function parses a Cap.INF file and copies info into a CAP_INFO structure.\r
3310 \r
3311 Arguments:\r
3312 \r
3313   InfFile        Memory file image.\r
3314   CapInfo        Information read from INF file.\r
3315 \r
3316 Returns:\r
3317 \r
3318   EFI_SUCCESS       INF file information successfully retrieved.\r
3319   EFI_ABORTED       INF file has an invalid format.\r
3320   EFI_NOT_FOUND     A required string was not found in the INF file.\r
3321 --*/\r
3322 {\r
3323   CHAR8       Value[_MAX_PATH];\r
3324   UINT64      Value64;\r
3325   UINTN       Index, Number;\r
3326   EFI_STATUS  Status;\r
3327 \r
3328   //\r
3329   // Initialize Cap info\r
3330   //\r
3331   // memset (CapInfo, 0, sizeof (CAP_INFO));\r
3332   //\r
3333 \r
3334   //\r
3335   // Read the Capsule Guid\r
3336   //\r
3337   Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_CAPSULE_GUID_STRING, 0, Value);\r
3338   if (Status == EFI_SUCCESS) {\r
3339     //\r
3340     // Get the Capsule Guid\r
3341     //\r
3342     Status = StringToGuid (Value, &CapInfo->CapGuid);\r
3343     if (EFI_ERROR (Status)) {\r
3344       Error (NULL, 0, 2000, "Invalid parameter", "%s = %s", EFI_CAPSULE_GUID_STRING, Value);\r
3345       return EFI_ABORTED;\r
3346     }\r
3347     DebugMsg (NULL, 0, 9, "Capsule Guid", "%s = %s", EFI_CAPSULE_GUID_STRING, Value);\r
3348   }\r
3349 \r
3350   //\r
3351   // Read the Capsule Header Size\r
3352   //\r
3353   Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_CAPSULE_HEADER_SIZE_STRING, 0, Value);\r
3354   if (Status == EFI_SUCCESS) {\r
3355     Status = AsciiStringToUint64 (Value, FALSE, &Value64);\r
3356     if (EFI_ERROR (Status)) {\r
3357       Error (NULL, 0, 2000, "Invalid parameter", "%s = %s", EFI_CAPSULE_HEADER_SIZE_STRING, Value);\r
3358       return EFI_ABORTED;\r
3359     }\r
3360     CapInfo->HeaderSize = (UINT32) Value64;\r
3361     DebugMsg (NULL, 0, 9, "Capsule Header size", "%s = %s", EFI_CAPSULE_HEADER_SIZE_STRING, Value);\r
3362   }\r
3363 \r
3364   //\r
3365   // Read the Capsule Flag\r
3366   //\r
3367   Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_CAPSULE_FLAGS_STRING, 0, Value);\r
3368   if (Status == EFI_SUCCESS) {\r
3369     if (strstr (Value, "PopulateSystemTable") != NULL) {\r
3370       CapInfo->Flags |= CAPSULE_FLAGS_PERSIST_ACROSS_RESET | CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE;\r
3371     } else if (strstr (Value, "PersistAcrossReset") != NULL) {\r
3372       CapInfo->Flags |= CAPSULE_FLAGS_PERSIST_ACROSS_RESET; \r
3373     } else {\r
3374       Error (NULL, 0, 2000, "Invalid parameter", "invalid Flag setting for %s.", EFI_CAPSULE_FLAGS_STRING);\r
3375       return EFI_ABORTED;\r
3376     }\r
3377     DebugMsg (NULL, 0, 9, "Capsule Flag", Value);\r
3378   }\r
3379 \r
3380   //\r
3381   // Read Capsule File name\r
3382   //\r
3383   Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_FILE_NAME_STRING, 0, Value);\r
3384   if (Status == EFI_SUCCESS) {\r
3385     //\r
3386     // Get output file name\r
3387     //\r
3388     strcpy (CapInfo->CapName, Value);\r
3389   }\r
3390 \r
3391   //\r
3392   // Read the Capsule FileImage\r
3393   //\r
3394   Number = 0;\r
3395   for (Index = 0; Index < MAX_NUMBER_OF_FILES_IN_CAP; Index++) {\r
3396     if (CapInfo->CapFiles[Index][0] != '\0') {\r
3397       continue;\r
3398     }\r
3399     //\r
3400     // Read the capsule file name\r
3401     //\r
3402     Status = FindToken (InfFile, FILES_SECTION_STRING, EFI_FILE_NAME_STRING, Number++, Value);\r
3403 \r
3404     if (Status == EFI_SUCCESS) {\r
3405       //\r
3406       // Add the file\r
3407       //\r
3408       strcpy (CapInfo->CapFiles[Index], Value);\r
3409       DebugMsg (NULL, 0, 9, "Capsule component file", "the %uth file name is %s", (unsigned) Index, CapInfo->CapFiles[Index]); \r
3410     } else {\r
3411       break;\r
3412     }\r
3413   }\r
3414   \r
3415   if (Index == 0) {\r
3416     Warning (NULL, 0, 0, "Capsule components are not specified.", NULL);\r
3417   }\r
3418 \r
3419   return EFI_SUCCESS;\r
3420 }\r
3421 \r
3422 EFI_STATUS\r
3423 GenerateCapImage (\r
3424   IN CHAR8                *InfFileImage,\r
3425   IN UINTN                InfFileSize,\r
3426   IN CHAR8                *CapFileName\r
3427   )\r
3428 /*++\r
3429 \r
3430 Routine Description:\r
3431 \r
3432   This is the main function which will be called from application to create UEFI Capsule image.\r
3433 \r
3434 Arguments:\r
3435 \r
3436   InfFileImage   Buffer containing the INF file contents.\r
3437   InfFileSize    Size of the contents of the InfFileImage buffer.\r
3438   CapFileName    Requested name for the Cap file.\r
3439 \r
3440 Returns:\r
3441 \r
3442   EFI_SUCCESS             Function completed successfully.\r
3443   EFI_OUT_OF_RESOURCES    Could not allocate required resources.\r
3444   EFI_ABORTED             Error encountered.\r
3445   EFI_INVALID_PARAMETER   A required parameter was NULL.\r
3446 \r
3447 --*/\r
3448 {\r
3449   UINT32                CapSize;\r
3450   UINT8                 *CapBuffer;\r
3451   EFI_CAPSULE_HEADER    *CapsuleHeader;\r
3452   MEMORY_FILE           InfMemoryFile;\r
3453   UINT32                FileSize;\r
3454   UINT32                Index;\r
3455   FILE                  *fpin, *fpout;\r
3456   EFI_STATUS            Status;\r
3457   \r
3458   if (InfFileImage != NULL) {\r
3459     //\r
3460     // Initialize file structures\r
3461     //\r
3462     InfMemoryFile.FileImage           = InfFileImage;\r
3463     InfMemoryFile.CurrentFilePointer  = InfFileImage;\r
3464     InfMemoryFile.Eof                 = InfFileImage + InfFileSize;\r
3465   \r
3466     //\r
3467     // Parse the Cap inf file for header information\r
3468     //\r
3469     Status = ParseCapInf (&InfMemoryFile, &mCapDataInfo);\r
3470     if (Status != EFI_SUCCESS) {\r
3471       return Status;\r
3472     }\r
3473   }\r
3474   \r
3475   if (mCapDataInfo.HeaderSize == 0) {\r
3476     //\r
3477     // make header size align 16 bytes.\r
3478     //\r
3479     mCapDataInfo.HeaderSize = sizeof (EFI_CAPSULE_HEADER);\r
3480     mCapDataInfo.HeaderSize = (mCapDataInfo.HeaderSize + 0xF) & ~0xF;\r
3481   }\r
3482 \r
3483   if (mCapDataInfo.HeaderSize < sizeof (EFI_CAPSULE_HEADER)) {\r
3484     Error (NULL, 0, 2000, "Invalid parameter", "The specified HeaderSize cannot be less than the size of EFI_CAPSULE_HEADER.");\r
3485     return EFI_INVALID_PARAMETER;\r
3486   }\r
3487   \r