Update GenFw and GenFv tool to support more features based on base tools spec.
[people/mcb30/basetools.git] / Source / C / GenFv / GenFvInternalLib.c
1 /*++\r
2 \r
3 Copyright (c) 2004, 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 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 <Common/UefiBaseTypes.h>\r
36 #include "GenFvInternalLib.h"\r
37 #include "CommonLib.h"\r
38 #include "EfiUtilityMsgs.h"\r
39 #include "WinNtInclude.h"\r
40 \r
41 EFI_STATUS\r
42 FindApResetVectorPosition (\r
43   IN  MEMORY_FILE  *FvImage,\r
44   OUT UINT8        **Pointer\r
45   ); \r
46 \r
47 EFI_STATUS\r
48 CalculateFvSize (\r
49   FV_INFO *FvInfoPtr\r
50   );\r
51 /*++\r
52 Routine Description:\r
53   Calculate the FV size and Update Fv Size based on the actual FFS files.\r
54   And Update FvInfo data.\r
55 \r
56 Arguments:\r
57   FvInfoPtr     - The pointer to FV_INFO structure.\r
58 \r
59 Returns:\r
60   EFI_ABORTED   - Ffs Image Error\r
61   EFI_SUCCESS   - Successfully update FvSize\r
62 --*/\r
63 \r
64 EFI_STATUS\r
65 FfsRebase ( \r
66   IN OUT  FV_INFO               *FvInfo, \r
67   IN      CHAR8                 *FileName,           \r
68   IN OUT  EFI_FFS_FILE_HEADER   *FfsFile,\r
69   IN      UINTN                 XipOffset\r
70   );\r
71 /*++\r
72 \r
73 Routine Description:\r
74 \r
75   This function determines if a file is XIP and should be rebased.  It will\r
76   rebase any PE32 sections found in the file using the base address.\r
77 \r
78 Arguments:\r
79   \r
80   FvInfo            A pointer to FV_INFO struture.\r
81   FileName          Ffs file Name\r
82   FfsFile           A pointer to Ffs file image.\r
83   XipOffset         The offset address to use for rebasing the XIP file image.\r
84 \r
85 Returns:\r
86 \r
87   EFI_SUCCESS             The image was properly rebased.\r
88   EFI_INVALID_PARAMETER   An input parameter is invalid.\r
89   EFI_ABORTED             An error occurred while rebasing the input file image.\r
90   EFI_OUT_OF_RESOURCES    Could not allocate a required resource.\r
91   EFI_NOT_FOUND           No compressed sections could be found.\r
92 \r
93 --*/\r
94 \r
95 static UINT32 MaxFfsAlignment = 0;\r
96 \r
97 EFI_GUID  gEfiFirmwareFileSystem2Guid = EFI_FIRMWARE_FILE_SYSTEM2_GUID;\r
98 EFI_GUID  gEfiFirmwareVolumeTopFileGuid = EFI_FFS_VOLUME_TOP_FILE_GUID;\r
99 \r
100 CHAR8      *FvbAttributeName[] = {\r
101   EFI_FVB2_READ_DISABLED_CAP_STRING, \r
102   EFI_FVB2_READ_ENABLED_CAP_STRING,  \r
103   EFI_FVB2_READ_STATUS_STRING,       \r
104   EFI_FVB2_WRITE_DISABLED_CAP_STRING,\r
105   EFI_FVB2_WRITE_ENABLED_CAP_STRING, \r
106   EFI_FVB2_WRITE_STATUS_STRING,      \r
107   EFI_FVB2_LOCK_CAP_STRING,          \r
108   EFI_FVB2_LOCK_STATUS_STRING,       \r
109   NULL,\r
110   EFI_FVB2_STICKY_WRITE_STRING,      \r
111   EFI_FVB2_MEMORY_MAPPED_STRING,     \r
112   EFI_FVB2_ERASE_POLARITY_STRING,    \r
113   EFI_FVB2_READ_LOCK_CAP_STRING,     \r
114   EFI_FVB2_READ_LOCK_STATUS_STRING,  \r
115   EFI_FVB2_WRITE_LOCK_CAP_STRING,    \r
116   EFI_FVB2_WRITE_LOCK_STATUS_STRING \r
117 };\r
118 \r
119 CHAR8      *FvbAlignmentName[] = {\r
120   EFI_FVB2_ALIGNMENT_1_STRING,   \r
121   EFI_FVB2_ALIGNMENT_2_STRING,   \r
122   EFI_FVB2_ALIGNMENT_4_STRING,   \r
123   EFI_FVB2_ALIGNMENT_8_STRING,   \r
124   EFI_FVB2_ALIGNMENT_16_STRING,  \r
125   EFI_FVB2_ALIGNMENT_32_STRING,  \r
126   EFI_FVB2_ALIGNMENT_64_STRING,  \r
127   EFI_FVB2_ALIGNMENT_128_STRING, \r
128   EFI_FVB2_ALIGNMENT_256_STRING, \r
129   EFI_FVB2_ALIGNMENT_512_STRING, \r
130   EFI_FVB2_ALIGNMENT_1K_STRING,  \r
131   EFI_FVB2_ALIGNMENT_2K_STRING,  \r
132   EFI_FVB2_ALIGNMENT_4K_STRING,  \r
133   EFI_FVB2_ALIGNMENT_8K_STRING,  \r
134   EFI_FVB2_ALIGNMENT_16K_STRING, \r
135   EFI_FVB2_ALIGNMENT_32K_STRING, \r
136   EFI_FVB2_ALIGNMENT_64K_STRING, \r
137   EFI_FVB2_ALIGNMENT_128K_STRING,\r
138   EFI_FVB2_ALIGNMENT_256K_STRING,\r
139   EFI_FVB2_ALIGNMNET_512K_STRING,\r
140   EFI_FVB2_ALIGNMENT_1M_STRING,  \r
141   EFI_FVB2_ALIGNMENT_2M_STRING,  \r
142   EFI_FVB2_ALIGNMENT_4M_STRING,  \r
143   EFI_FVB2_ALIGNMENT_8M_STRING,  \r
144   EFI_FVB2_ALIGNMENT_16M_STRING, \r
145   EFI_FVB2_ALIGNMENT_32M_STRING, \r
146   EFI_FVB2_ALIGNMENT_64M_STRING, \r
147   EFI_FVB2_ALIGNMENT_128M_STRING,\r
148   EFI_FVB2_ALIGNMENT_256M_STRING,\r
149   EFI_FVB2_ALIGNMENT_512M_STRING,\r
150   EFI_FVB2_ALIGNMENT_1G_STRING,  \r
151   EFI_FVB2_ALIGNMENT_2G_STRING\r
152 };\r
153 \r
154 //\r
155 // This data array will be located at the base of the Firmware Volume Header (FVH)\r
156 // in the boot block.  It must not exceed 14 bytes of code.  The last 2 bytes\r
157 // will be used to keep the FVH checksum consistent.\r
158 // This code will be run in response to a starutp IPI for HT-enabled systems.\r
159 //\r
160 #define SIZEOF_STARTUP_DATA_ARRAY 0x10\r
161 \r
162 UINT8                                   m128kRecoveryStartupApDataArray[SIZEOF_STARTUP_DATA_ARRAY] = {\r
163   //\r
164   // EA D0 FF 00 F0               ; far jmp F000:FFD0\r
165   // 0, 0, 0, 0, 0, 0, 0, 0, 0,   ; Reserved bytes\r
166   // 0, 0                         ; Checksum Padding\r
167   //\r
168   0xEA,\r
169   0xD0,\r
170   0xFF,\r
171   0x0,\r
172   0xF0,\r
173   0x00,\r
174   0x00,\r
175   0x00,\r
176   0x00,\r
177   0x00,\r
178   0x00,\r
179   0x00,\r
180   0x00,\r
181   0x00,\r
182   0x00,\r
183   0x00\r
184 };\r
185 \r
186 UINT8                                   m64kRecoveryStartupApDataArray[SIZEOF_STARTUP_DATA_ARRAY] = {\r
187   //\r
188   // EB CE                               ; jmp short ($-0x30)\r
189   // ; (from offset 0x0 to offset 0xFFD0)\r
190   // 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ; Reserved bytes\r
191   // 0, 0                                ; Checksum Padding\r
192   //\r
193   0xEB,\r
194   0xCE,\r
195   0x00,\r
196   0x00,\r
197   0x00,\r
198   0x00,\r
199   0x00,\r
200   0x00,\r
201   0x00,\r
202   0x00,\r
203   0x00,\r
204   0x00,\r
205   0x00,\r
206   0x00,\r
207   0x00,\r
208   0x00\r
209 };\r
210 \r
211 EFI_STATUS\r
212 ParseFvInf (\r
213   IN  MEMORY_FILE  *InfFile,\r
214   OUT FV_INFO      *FvInfo\r
215   )\r
216 /*++\r
217 \r
218 Routine Description:\r
219 \r
220   This function parses a FV.INF file and copies info into a FV_INFO structure.\r
221 \r
222 Arguments:\r
223 \r
224   InfFile         Memory file image.\r
225   FvInfo          Information read from INF file.\r
226 \r
227 Returns:\r
228 \r
229   EFI_SUCCESS       INF file information successfully retrieved.\r
230   EFI_ABORTED       INF file has an invalid format.\r
231   EFI_NOT_FOUND     A required string was not found in the INF file.\r
232 --*/\r
233 {\r
234   CHAR8       Value[_MAX_PATH];\r
235   UINT64      Value64;\r
236   UINTN       Index;\r
237   EFI_STATUS  Status;\r
238 \r
239   //\r
240   // Initialize FV info\r
241   //\r
242   memset (FvInfo, 0, sizeof (FV_INFO));\r
243   FvInfo->BaseAddress = -1;\r
244 \r
245   //\r
246   // Read the FV base address\r
247   //\r
248   Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_FV_BASE_ADDRESS_STRING, 0, Value);\r
249   if (Status == EFI_SUCCESS) {\r
250     //\r
251     // Get the base address\r
252     //\r
253     Status = AsciiStringToUint64 (Value, FALSE, &Value64);\r
254     if (EFI_ERROR (Status)) {\r
255       Error (NULL, 0, 0, EFI_FV_BASE_ADDRESS_STRING, "invalid value");\r
256       return EFI_ABORTED;\r
257     }\r
258 \r
259     FvInfo->BaseAddress = Value64;\r
260   }\r
261 \r
262   //\r
263   // Read the FV Guid\r
264   //\r
265   Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_FV_GUID_STRING, 0, Value);\r
266   if (Status == EFI_SUCCESS) {\r
267     //\r
268     // Get the guid value\r
269     //\r
270     Status = StringToGuid (Value, &FvInfo->FvGuid);\r
271     if (EFI_ERROR (Status)) {\r
272       memcpy (&FvInfo->FvGuid, &gEfiFirmwareFileSystem2Guid, sizeof (EFI_GUID));\r
273     }\r
274   } else {\r
275     memcpy (&FvInfo->FvGuid, &gEfiFirmwareFileSystem2Guid, sizeof (EFI_GUID));\r
276   }\r
277 \r
278   //\r
279   // Read the FV file name\r
280   //\r
281   Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_FV_FILE_NAME_STRING, 0, Value);\r
282   if (Status == EFI_SUCCESS) {\r
283     //\r
284     // copy the file name\r
285     //\r
286     strcpy (FvInfo->FvName, Value);\r
287   }\r
288   \r
289   //\r
290   // Read Fv Attribute\r
291   //\r
292   for (Index = 0; Index < sizeof (FvbAttributeName)/sizeof (char *); Index ++) {\r
293     if ((FvbAttributeName [Index] != NULL) && \\r
294         (FindToken (InfFile, ATTRIBUTES_SECTION_STRING, FvbAttributeName [Index], 0, Value) == EFI_SUCCESS)) {\r
295       if ((strcmp (Value, TRUE_STRING) == 0) || (strcmp (Value, ONE_STRING) == 0)) {\r
296         FvInfo->FvAttributes |= 1 << Index;\r
297       } else if ((strcmp (Value, FALSE_STRING) != 0) && (strcmp (Value, ZERO_STRING) != 0)) {\r
298         Error (NULL, 0, 0, FvbAttributeName [Index], "expected %s | %s", TRUE_STRING, FALSE_STRING);\r
299         return EFI_ABORTED;\r
300       }\r
301     }\r
302   }\r
303 \r
304   //\r
305   // Read Fv Alignment\r
306   //\r
307   for (Index = 0; Index < sizeof (FvbAlignmentName)/sizeof (char *); Index ++) {\r
308     if (FindToken (InfFile, ATTRIBUTES_SECTION_STRING, FvbAlignmentName [Index], 0, Value) == EFI_SUCCESS) {\r
309       if (strcmp (Value, TRUE_STRING) == 0) {\r
310         FvInfo->FvAttributes |= Index << 16;\r
311         break;\r
312       }\r
313     }\r
314   }\r
315 \r
316   //\r
317   // Read block maps\r
318   //\r
319   for (Index = 0; Index < MAX_NUMBER_OF_FV_BLOCKS; Index++) {\r
320     //\r
321     // Read block size\r
322     //\r
323     Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_BLOCK_SIZE_STRING, Index, Value);\r
324 \r
325     if (Status == EFI_SUCCESS) {\r
326       //\r
327       // Update the size of block\r
328       //\r
329       Status = AsciiStringToUint64 (Value, FALSE, &Value64);\r
330       if (EFI_ERROR (Status)) {\r
331         Error (NULL, 0, 0, Value, "invalid value for %s", EFI_BLOCK_SIZE_STRING);\r
332         return EFI_ABORTED;\r
333       }\r
334 \r
335       FvInfo->FvBlocks[Index].Length = (UINT32) Value64;\r
336     } else {\r
337       //\r
338       // If there is no blocks size, but there is the number of block, then we have a mismatched pair\r
339       // and should return an error.\r
340       //\r
341       Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_NUM_BLOCKS_STRING, Index, Value);\r
342       if (!EFI_ERROR (Status)) {\r
343         Error (NULL, 0, 0, "must specify both", "%s and %s", EFI_NUM_BLOCKS_STRING, EFI_BLOCK_SIZE_STRING);\r
344         return EFI_ABORTED;\r
345       } else {\r
346         //\r
347         // We are done\r
348         //\r
349         break;\r
350       }\r
351     }\r
352 \r
353     //\r
354     // Read blocks number\r
355     //\r
356     Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_NUM_BLOCKS_STRING, Index, Value);\r
357 \r
358     if (Status == EFI_SUCCESS) {\r
359       //\r
360       // Update the number of blocks\r
361       //\r
362       Status = AsciiStringToUint64 (Value, FALSE, &Value64);\r
363       if (EFI_ERROR (Status)) {\r
364         Error (NULL, 0, 0, Value, "invalid value specified for %s", EFI_NUM_BLOCKS_STRING);\r
365         return EFI_ABORTED;\r
366       }\r
367 \r
368       FvInfo->FvBlocks[Index].NumBlocks = (UINT32) Value64;\r
369     }\r
370   }\r
371 \r
372   if (Index == 0) {\r
373     Error (NULL, 0, 0, NULL, "at lease one block size must be specified.");\r
374     return EFI_ABORTED;\r
375   }\r
376 \r
377   //\r
378   // Read files\r
379   //\r
380   for (Index = 0; Index < MAX_NUMBER_OF_FILES_IN_FV; Index++) {\r
381     //\r
382     // Read the number of blocks\r
383     //\r
384     Status = FindToken (InfFile, FILES_SECTION_STRING, EFI_FILE_NAME_STRING, Index, Value);\r
385 \r
386     if (Status == EFI_SUCCESS) {\r
387       //\r
388       // Add the file\r
389       //\r
390       strcpy (FvInfo->FvFiles[Index], Value);\r
391     } else {\r
392       break;\r
393     }\r
394   }\r
395 \r
396   //\r
397   // Compute size for easy access later\r
398   //\r
399   FvInfo->Size = 0;\r
400   for (Index = 0; FvInfo->FvBlocks[Index].NumBlocks; Index++) {\r
401     FvInfo->Size += FvInfo->FvBlocks[Index].NumBlocks * FvInfo->FvBlocks[Index].Length;\r
402   }\r
403 \r
404   return EFI_SUCCESS;\r
405 }\r
406 \r
407 VOID\r
408 UpdateFfsFileState (\r
409   IN EFI_FFS_FILE_HEADER          *FfsFile,\r
410   IN EFI_FIRMWARE_VOLUME_HEADER   *FvHeader\r
411   )\r
412 /*++\r
413 \r
414 Routine Description:\r
415 \r
416   This function changes the FFS file attributes based on the erase polarity\r
417   of the FV. Update the reserved bits of State to EFI_FVB2_ERASE_POLARITY. \r
418 \r
419 Arguments:\r
420 \r
421   FfsFile   File header.\r
422   FvHeader  FV header.\r
423 \r
424 Returns:\r
425 \r
426   None\r
427 \r
428 --*/\r
429 {\r
430   if (FvHeader->Attributes & EFI_FVB2_ERASE_POLARITY) {\r
431     FfsFile->State = (UINT8)~(FfsFile->State);\r
432     // FfsFile->State |= ~(UINT8) EFI_FILE_ALL_STATE_BITS;\r
433   }\r
434 }\r
435 \r
436 EFI_STATUS\r
437 ReadFfsAlignment (\r
438   IN EFI_FFS_FILE_HEADER    *FfsFile,\r
439   IN OUT UINT32             *Alignment\r
440   )\r
441 /*++\r
442 \r
443 Routine Description:\r
444 \r
445   This function determines the alignment of the FFS input file from the file\r
446   attributes.\r
447 \r
448 Arguments:\r
449 \r
450   FfsFile       FFS file to parse\r
451   Alignment     The minimum required alignment offset of the FFS file\r
452 \r
453 Returns:\r
454 \r
455   EFI_SUCCESS              The function completed successfully.\r
456   EFI_INVALID_PARAMETER    One of the input parameters was invalid.\r
457   EFI_ABORTED              An error occurred.\r
458 \r
459 --*/\r
460 {\r
461   //\r
462   // Verify input parameters.\r
463   //\r
464   if (FfsFile == NULL || Alignment == NULL) {\r
465     return EFI_INVALID_PARAMETER;\r
466   }\r
467 \r
468   switch ((FfsFile->Attributes >> 3) & 0x07) {\r
469 \r
470   case 0:\r
471     //\r
472     // 8 byte alignment, mini alignment requirement for FFS file. \r
473     //\r
474     *Alignment = 3;\r
475     break;\r
476 \r
477   case 1:\r
478     //\r
479     // 16 byte alignment\r
480     //\r
481     *Alignment = 4;\r
482     break;\r
483 \r
484   case 2:\r
485     //\r
486     // 128 byte alignment\r
487     //\r
488     *Alignment = 7;\r
489     break;\r
490 \r
491   case 3:\r
492     //\r
493     // 512 byte alignment\r
494     //\r
495     *Alignment = 9;\r
496     break;\r
497 \r
498   case 4:\r
499     //\r
500     // 1K byte alignment\r
501     //\r
502     *Alignment = 10;\r
503     break;\r
504 \r
505   case 5:\r
506     //\r
507     // 4K byte alignment\r
508     //\r
509     *Alignment = 12;\r
510     break;\r
511 \r
512   case 6:\r
513     //\r
514     // 32K byte alignment\r
515     //\r
516     *Alignment = 15;\r
517     break;\r
518 \r
519   case 7:\r
520     //\r
521     // 64K byte alignment\r
522     //\r
523     *Alignment = 16;\r
524     break;\r
525 \r
526   default:\r
527     Error (NULL, 0, 0, "nvalid file attribute calculated, this is most likely a utility error", NULL);\r
528     return EFI_ABORTED;\r
529   }\r
530 \r
531   return EFI_SUCCESS;\r
532 }\r
533 \r
534 EFI_STATUS\r
535 AddPadFile (\r
536   IN OUT MEMORY_FILE  *FvImage,\r
537   IN UINT32           DataAlignment\r
538   )\r
539 /*++\r
540 \r
541 Routine Description:\r
542 \r
543   This function adds a pad file to the FV image if it required to align the\r
544   data of the next file.\r
545 \r
546 Arguments:\r
547 \r
548   FvImage         The memory image of the FV to add it to.  The current offset\r
549                   must be valid.\r
550   DataAlignment   The data alignment of the next FFS file.\r
551 \r
552 Returns:\r
553 \r
554   EFI_SUCCESS              The function completed successfully.\r
555   EFI_INVALID_PARAMETER    One of the input parameters was invalid.\r
556   EFI_OUT_OF_RESOURCES     Insufficient resources exist in the FV to complete\r
557                            the pad file add.\r
558 \r
559 --*/\r
560 {\r
561   EFI_FFS_FILE_HEADER *PadFile;\r
562   EFI_GUID            PadFileGuid;\r
563   UINTN               PadFileSize;\r
564 \r
565   //\r
566   // Verify input parameters.\r
567   //\r
568   if (FvImage == NULL) {\r
569     return EFI_INVALID_PARAMETER;\r
570   }\r
571 \r
572   //\r
573   // Check if a pad file is necessary\r
574   //\r
575   if (((UINTN) FvImage->CurrentFilePointer - (UINTN) FvImage->FileImage + sizeof (EFI_FFS_FILE_HEADER)) % DataAlignment == 0) {\r
576     return EFI_SUCCESS;\r
577   }\r
578 \r
579   //\r
580   // Write pad file header\r
581   //\r
582   PadFile = (EFI_FFS_FILE_HEADER *) FvImage->CurrentFilePointer;\r
583 \r
584   //\r
585   // Verify that we have enough space for the file header\r
586   //\r
587   if ((UINTN) (PadFile + sizeof (EFI_FFS_FILE_HEADER)) >= (UINTN) FvImage->Eof) {\r
588     return EFI_OUT_OF_RESOURCES;\r
589   }\r
590 \r
591 #ifdef __GNUC__\r
592   {\r
593     uuid_t tmp_id;\r
594     uuid_generate (tmp_id);\r
595     memcpy (&PadFileGuid, tmp_id, sizeof (EFI_GUID));\r
596   }\r
597 #else\r
598   UuidCreate (&PadFileGuid);\r
599 #endif\r
600   memset (PadFile, 0, sizeof (EFI_FFS_FILE_HEADER));\r
601   memcpy (&PadFile->Name, &PadFileGuid, sizeof (EFI_GUID));\r
602   PadFile->Type       = EFI_FV_FILETYPE_FFS_PAD;\r
603   PadFile->Attributes = 0;\r
604 \r
605   //\r
606   // Calculate the pad file size\r
607   //\r
608   //\r
609   // This is the earliest possible valid offset (current plus pad file header\r
610   // plus the next file header)\r
611   //\r
612   PadFileSize = (UINTN) FvImage->CurrentFilePointer - (UINTN) FvImage->FileImage + (sizeof (EFI_FFS_FILE_HEADER) * 2);\r
613 \r
614   //\r
615   // Add whatever it takes to get to the next aligned address\r
616   //\r
617   while ((PadFileSize % DataAlignment) != 0) {\r
618     PadFileSize++;\r
619   }\r
620   //\r
621   // Subtract the next file header size\r
622   //\r
623   PadFileSize -= sizeof (EFI_FFS_FILE_HEADER);\r
624 \r
625   //\r
626   // Subtract the starting offset to get size\r
627   //\r
628   PadFileSize -= (UINTN) FvImage->CurrentFilePointer - (UINTN) FvImage->FileImage;\r
629   \r
630   //\r
631   // Write pad file size (calculated size minus next file header size)\r
632   //\r
633   PadFile->Size[0]  = (UINT8) (PadFileSize & 0xFF);\r
634   PadFile->Size[1]  = (UINT8) ((PadFileSize >> 8) & 0xFF);\r
635   PadFile->Size[2]  = (UINT8) ((PadFileSize >> 16) & 0xFF);\r
636 \r
637   //\r
638   // Fill in checksums and state, they must be 0 for checksumming.\r
639   //\r
640   PadFile->IntegrityCheck.Checksum.Header = 0;\r
641   PadFile->IntegrityCheck.Checksum.File   = 0;\r
642   PadFile->State                          = 0;\r
643   PadFile->IntegrityCheck.Checksum.Header = CalculateChecksum8 ((UINT8 *) PadFile, sizeof (EFI_FFS_FILE_HEADER));\r
644   if (PadFile->Attributes & FFS_ATTRIB_CHECKSUM) {\r
645     PadFile->IntegrityCheck.Checksum.File = CalculateChecksum8 ((UINT8 *) PadFile, PadFileSize);\r
646   } else {\r
647     PadFile->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;\r
648   }\r
649 \r
650   PadFile->State = EFI_FILE_HEADER_CONSTRUCTION | EFI_FILE_HEADER_VALID | EFI_FILE_DATA_VALID;\r
651   UpdateFfsFileState (\r
652     (EFI_FFS_FILE_HEADER *) PadFile,\r
653     (EFI_FIRMWARE_VOLUME_HEADER *) FvImage->FileImage\r
654     );\r
655 \r
656   //\r
657   // Verify that we have enough space (including the padding\r
658   //\r
659   if ((UINTN) (PadFile + PadFileSize) >= (UINTN) FvImage->Eof) {\r
660     return EFI_OUT_OF_RESOURCES;\r
661   }\r
662   //\r
663   // Update the current FV pointer\r
664   //\r
665   FvImage->CurrentFilePointer += PadFileSize;\r
666 \r
667   return EFI_SUCCESS;\r
668 }\r
669 \r
670 BOOLEAN\r
671 IsVtfFile (\r
672   IN EFI_FFS_FILE_HEADER    *FileBuffer\r
673   )\r
674 /*++\r
675 \r
676 Routine Description:\r
677 \r
678   This function checks the header to validate if it is a VTF file\r
679 \r
680 Arguments:\r
681 \r
682   FileBuffer     Buffer in which content of a file has been read.\r
683 \r
684 Returns:\r
685 \r
686   TRUE    If this is a VTF file\r
687   FALSE   If this is not a VTF file\r
688 \r
689 --*/\r
690 {\r
691   if (!memcmp (&FileBuffer->Name, &gEfiFirmwareVolumeTopFileGuid, sizeof (EFI_GUID))) {\r
692     return TRUE;\r
693   } else {\r
694     return FALSE;\r
695   }\r
696 }\r
697 \r
698 EFI_STATUS\r
699 AddFile (\r
700   IN OUT MEMORY_FILE          *FvImage,\r
701   IN FV_INFO                  *FvInfo,\r
702   IN UINTN                    Index,\r
703   IN OUT EFI_FFS_FILE_HEADER  **VtfFileImage  \r
704   )\r
705 /*++\r
706 \r
707 Routine Description:\r
708 \r
709   This function adds a file to the FV image.  The file will pad to the\r
710   appropriate alignment if required.\r
711 \r
712 Arguments:\r
713 \r
714   FvImage       The memory image of the FV to add it to.  The current offset\r
715                 must be valid.\r
716   FvInfo        Pointer to information about the FV.\r
717   Index         The file in the FvInfo file list to add.\r
718   VtfFileImage  A pointer to the VTF file within the FvImage.  If this is equal\r
719                 to the end of the FvImage then no VTF previously found.\r
720 \r
721 Returns:\r
722 \r
723   EFI_SUCCESS              The function completed successfully.\r
724   EFI_INVALID_PARAMETER    One of the input parameters was invalid.\r
725   EFI_ABORTED              An error occurred.\r
726   EFI_OUT_OF_RESOURCES     Insufficient resources exist to complete the add.\r
727 \r
728 --*/\r
729 {\r
730   FILE                  *NewFile;\r
731   UINTN                 FileSize;\r
732   UINT8                 *FileBuffer;\r
733   UINTN                 NumBytesRead;\r
734   UINT32                CurrentFileAlignment;\r
735   EFI_STATUS            Status;\r
736   EFI_PHYSICAL_ADDRESS  CurrentFileBaseAddress;\r
737   UINT8                 VtfHeaderChecksum;\r
738   UINT8                 VtfFileChecksum;\r
739   UINT8                 FileState;\r
740   //\r
741   // Verify input parameters.\r
742   //\r
743   if (FvImage == NULL || FvInfo == NULL || FvInfo->FvFiles[Index][0] == 0 || VtfFileImage == NULL) {\r
744     return EFI_INVALID_PARAMETER;\r
745   }\r
746 \r
747   //\r
748   // Read the file to add\r
749   //\r
750   NewFile = fopen (FvInfo->FvFiles[Index], "rb");\r
751 \r
752   if (NewFile == NULL) {\r
753     Error (NULL, 0, 0, FvInfo->FvFiles[Index], "failed to open file for reading");\r
754     return EFI_ABORTED;\r
755   }\r
756 \r
757   //\r
758   // Get the file size\r
759   //\r
760   FileSize = _filelength (fileno (NewFile));\r
761 \r
762   //\r
763   // Read the file into a buffer\r
764   //\r
765   FileBuffer = malloc (FileSize);\r
766   if (FileBuffer == NULL) {\r
767     Error (NULL, 0, 0, "memory allocation failure", NULL);\r
768     return EFI_OUT_OF_RESOURCES;\r
769   }\r
770 \r
771   NumBytesRead = fread (FileBuffer, sizeof (UINT8), FileSize, NewFile);\r
772 \r
773   //\r
774   // Done with the file, from this point on we will just use the buffer read.\r
775   //\r
776   fclose (NewFile);\r
777   \r
778   //\r
779   // Verify read successful\r
780   //\r
781   if (NumBytesRead != sizeof (UINT8) * FileSize) {\r
782     free (FileBuffer);\r
783     Error (NULL, 0, 0, FvInfo->FvFiles[Index], "failed to read input file contents");\r
784     return EFI_ABORTED;\r
785   }\r
786   \r
787   //\r
788   // Verify Ffs file\r
789   //\r
790   Status = VerifyFfsFile (FileBuffer);\r
791   if (EFI_ERROR (Status)) {\r
792     Error (NULL, 0, 0, FvInfo->FvFiles[Index], "the invalid FFS file");\r
793     free (FileBuffer);\r
794     return EFI_INVALID_PARAMETER;\r
795   }\r
796 \r
797   //\r
798   // Verify space exists to add the file\r
799   //\r
800   if (FileSize > (UINTN) ((UINTN) *VtfFileImage - (UINTN) FvImage->CurrentFilePointer)) {\r
801     Error (NULL, 0, 0, FvInfo->FvFiles[Index], "insufficient space remains to add the file");\r
802     free (FileBuffer);\r
803     return EFI_OUT_OF_RESOURCES;\r
804   }\r
805 \r
806   //\r
807   // Update the file state based on polarity of the FV.\r
808   //\r
809   UpdateFfsFileState (\r
810     (EFI_FFS_FILE_HEADER *) FileBuffer,\r
811     (EFI_FIRMWARE_VOLUME_HEADER *) FvImage->FileImage\r
812     );\r
813 \r
814   //\r
815   // Check if alignment is required\r
816   //\r
817   ReadFfsAlignment ((EFI_FFS_FILE_HEADER *) FileBuffer, &CurrentFileAlignment);\r
818   \r
819   //\r
820   // Find the largest alignment of all the FFS files in the FV\r
821   //\r
822   if (CurrentFileAlignment > MaxFfsAlignment) {\r
823     MaxFfsAlignment = CurrentFileAlignment;\r
824   }\r
825   //\r
826   // If we have a VTF file, add it at the top.\r
827   //\r
828   if (IsVtfFile ((EFI_FFS_FILE_HEADER *) FileBuffer)) {\r
829     if ((UINTN) *VtfFileImage == (UINTN) FvImage->Eof) {\r
830       //\r
831       // No previous VTF, add this one.\r
832       //\r
833       *VtfFileImage = (EFI_FFS_FILE_HEADER *) (UINTN) ((UINTN) FvImage->FileImage + FvInfo->Size - FileSize);\r
834       //\r
835       // Sanity check. The file MUST align appropriately\r
836       //\r
837       if (((UINTN) *VtfFileImage + sizeof (EFI_FFS_FILE_HEADER) - (UINTN) FvImage->FileImage) % (1 << CurrentFileAlignment)) {\r
838         Error (NULL, 0, 0, NULL, "VTF file does not align on %d-byte boundary", 1 << CurrentFileAlignment);\r
839         free (FileBuffer);\r
840         return EFI_ABORTED;\r
841       }\r
842       //\r
843       // Rebase the PE or TE image in FileBuffer of FFS file for XIP \r
844       // Rebase for the debug genfvmap tool\r
845       //\r
846       FfsRebase (FvInfo, FvInfo->FvFiles[Index], (EFI_FFS_FILE_HEADER *) FileBuffer, (UINTN) *VtfFileImage - (UINTN) FvImage->FileImage);\r
847       //\r
848       // copy VTF File\r
849       //\r
850       memcpy (*VtfFileImage, FileBuffer, FileSize);\r
851       free (FileBuffer);\r
852       return EFI_SUCCESS;\r
853     } else {\r
854       //\r
855       // Already found a VTF file.\r
856       //\r
857       Error (NULL, 0, 0, "multiple VTF files are illegal in a single FV", NULL);\r
858       free (FileBuffer);\r
859       return EFI_ABORTED;\r
860     }\r
861   }\r
862 \r
863   //\r
864   // Add pad file if necessary\r
865   //\r
866   Status = AddPadFile (FvImage, 1 << CurrentFileAlignment);\r
867   if (EFI_ERROR (Status)) {\r
868     Error (NULL, 0, 0, NULL, "ERROR: Could not align the file data properly.");\r
869     free (FileBuffer);\r
870     return EFI_ABORTED;\r
871   }\r
872   //\r
873   // Add file\r
874   //\r
875   if ((FvImage->CurrentFilePointer + FileSize) < FvImage->Eof) {\r
876     //\r
877     // Rebase the PE or TE image in FileBuffer of FFS file for XIP. \r
878     // Rebase Bs and Rt drivers for the debug genfvmap tool.\r
879     //\r
880     FfsRebase (FvInfo, FvInfo->FvFiles[Index], (EFI_FFS_FILE_HEADER *) FileBuffer, (UINTN) FvImage->CurrentFilePointer - (UINTN) FvImage->FileImage);\r
881     //\r
882     // Copy the file\r
883     //\r
884     memcpy (FvImage->CurrentFilePointer, FileBuffer, FileSize);\r
885     FvImage->CurrentFilePointer += FileSize;\r
886   } else {\r
887     Error (NULL, 0, 0, NULL, "ERROR: The firmware volume is out of space, could not add file %s.\n", FvInfo->FvFiles[Index]);\r
888     free (FileBuffer);\r
889     return EFI_ABORTED;\r
890   }\r
891   //\r
892   // Make next file start at QWord Boundry\r
893   //\r
894   while (((UINTN) FvImage->CurrentFilePointer & (EFI_FFS_FILE_HEADER_ALIGNMENT - 1)) != 0) {\r
895     FvImage->CurrentFilePointer++;\r
896   }\r
897 \r
898   //\r
899   // Free allocated memory.\r
900   //\r
901   free (FileBuffer);\r
902 \r
903   return EFI_SUCCESS;\r
904 }\r
905 \r
906 EFI_STATUS\r
907 PadFvImage (\r
908   IN MEMORY_FILE          *FvImage,\r
909   IN EFI_FFS_FILE_HEADER  *VtfFileImage\r
910   )\r
911 /*++\r
912 \r
913 Routine Description:\r
914 \r
915   This function places a pad file between the last file in the FV and the VTF\r
916   file if the VTF file exists.\r
917 \r
918 Arguments:\r
919 \r
920   FvImage       Memory file for the FV memory image\r
921   VtfFileImage  The address of the VTF file.  If this is the end of the FV\r
922                 image, no VTF exists and no pad file is needed.\r
923 \r
924 Returns:\r
925 \r
926   EFI_SUCCESS             Completed successfully.\r
927   EFI_INVALID_PARAMETER   One of the input parameters was NULL.\r
928 \r
929 --*/\r
930 {\r
931   EFI_FFS_FILE_HEADER *PadFile;\r
932   UINTN               FileSize;\r
933   EFI_GUID            PadFileGuid;\r
934 \r
935   //\r
936   // If there is no VTF or the VTF naturally follows the previous file without a\r
937   // pad file, then there's nothing to do\r
938   //\r
939   if ((UINTN) VtfFileImage == (UINTN) FvImage->Eof || \\r
940       ((UINTN) VtfFileImage == (UINTN) FvImage->CurrentFilePointer)) {\r
941     return EFI_SUCCESS;\r
942   }\r
943 \r
944   //\r
945   // Pad file starts at beginning of free space\r
946   //\r
947   PadFile = (EFI_FFS_FILE_HEADER *) FvImage->CurrentFilePointer;\r
948 \r
949   //\r
950   // write header\r
951   //\r
952   memset (PadFile, 0, sizeof (EFI_FFS_FILE_HEADER));\r
953 #ifdef __GNUC__\r
954   {\r
955     uuid_t tmp_id;\r
956     uuid_generate (tmp_id);\r
957     memcpy (&PadFileGuid, tmp_id, sizeof (EFI_GUID));\r
958   }\r
959 #else\r
960   UuidCreate (&PadFileGuid);\r
961 #endif\r
962   memcpy (&PadFile->Name, &PadFileGuid, sizeof (EFI_GUID));\r
963   PadFile->Type       = EFI_FV_FILETYPE_FFS_PAD;\r
964   PadFile->Attributes = 0;\r
965 \r
966   //\r
967   // FileSize includes the EFI_FFS_FILE_HEADER\r
968   //\r
969   FileSize          = (UINTN) VtfFileImage - (UINTN) FvImage->CurrentFilePointer;\r
970   PadFile->Size[0]  = (UINT8) (FileSize & 0x000000FF);\r
971   PadFile->Size[1]  = (UINT8) ((FileSize & 0x0000FF00) >> 8);\r
972   PadFile->Size[2]  = (UINT8) ((FileSize & 0x00FF0000) >> 16);\r
973 \r
974   //\r
975   // Fill in checksums and state, must be zero during checksum calculation.\r
976   //\r
977   PadFile->IntegrityCheck.Checksum.Header = 0;\r
978   PadFile->IntegrityCheck.Checksum.File   = 0;\r
979   PadFile->State                          = 0;\r
980   PadFile->IntegrityCheck.Checksum.Header = CalculateChecksum8 ((UINT8 *) PadFile, sizeof (EFI_FFS_FILE_HEADER));\r
981   if (PadFile->Attributes & FFS_ATTRIB_CHECKSUM) {\r
982     PadFile->IntegrityCheck.Checksum.File = CalculateChecksum8 ((UINT8 *) PadFile, FileSize);\r
983   } else {\r
984     PadFile->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;\r
985   }\r
986 \r
987   PadFile->State = EFI_FILE_HEADER_CONSTRUCTION | EFI_FILE_HEADER_VALID | EFI_FILE_DATA_VALID;\r
988 \r
989   UpdateFfsFileState (\r
990     (EFI_FFS_FILE_HEADER *) PadFile,\r
991     (EFI_FIRMWARE_VOLUME_HEADER *) FvImage->FileImage\r
992     );\r
993   //\r
994   // Update the current FV pointer\r
995   //\r
996   FvImage->CurrentFilePointer = FvImage->Eof;\r
997 \r
998   return EFI_SUCCESS;\r
999 }\r
1000 \r
1001 EFI_STATUS\r
1002 UpdateResetVector (\r
1003   IN MEMORY_FILE            *FvImage,\r
1004   IN FV_INFO                *FvInfo,\r
1005   IN EFI_FFS_FILE_HEADER    *VtfFile\r
1006   )\r
1007 /*++\r
1008 \r
1009 Routine Description:\r
1010 \r
1011   This parses the FV looking for the PEI core and then plugs the address into\r
1012   the SALE_ENTRY point of the BSF/VTF for IPF and does BUGBUG TBD action to\r
1013   complete an IA32 Bootstrap FV.\r
1014 \r
1015 Arguments:\r
1016 \r
1017   FvImage       Memory file for the FV memory image\r
1018   FvInfo        Information read from INF file.\r
1019   VtfFile       Pointer to the VTF file in the FV image.\r
1020 \r
1021 Returns:\r
1022 \r
1023   EFI_SUCCESS             Function Completed successfully.\r
1024   EFI_ABORTED             Error encountered.\r
1025   EFI_INVALID_PARAMETER   A required parameter was NULL.\r
1026   EFI_NOT_FOUND           PEI Core file not found.\r
1027 \r
1028 --*/\r
1029 {\r
1030   EFI_FFS_FILE_HEADER       *PeiCoreFile;\r
1031   EFI_FFS_FILE_HEADER       *SecCoreFile;\r
1032   EFI_STATUS                Status;\r
1033   EFI_FILE_SECTION_POINTER  Pe32Section;\r
1034   UINT32                    EntryPoint;\r
1035   UINT32                    BaseOfCode;\r
1036   UINT16                    MachineType;\r
1037   EFI_PHYSICAL_ADDRESS      PeiCorePhysicalAddress;\r
1038   EFI_PHYSICAL_ADDRESS      SecCorePhysicalAddress;\r
1039   EFI_PHYSICAL_ADDRESS      *SecCoreEntryAddressPtr;\r
1040   INT32                     Ia32SecEntryOffset;\r
1041   UINT32                    *Ia32ResetAddressPtr;\r
1042   UINT8                     *BytePointer;\r
1043   UINT8                     *BytePointer2;\r
1044   UINT16                    *WordPointer;\r
1045   UINT16                    CheckSum;\r
1046   UINTN                     Index;\r
1047   EFI_FFS_FILE_STATE        SavedState;\r
1048   UINT64                    FitAddress;\r
1049   FIT_TABLE                 *FitTablePtr;\r
1050   UINT32                    IpiVector;\r
1051 \r
1052   //\r
1053   // Verify input parameters\r
1054   //\r
1055   if (FvImage == NULL || FvInfo == NULL || VtfFile == NULL) {\r
1056     return EFI_INVALID_PARAMETER;\r
1057   }\r
1058   //\r
1059   // Initialize FV library\r
1060   //\r
1061   InitializeFvLib (FvImage->FileImage, FvInfo->Size);\r
1062 \r
1063   //\r
1064   // Verify VTF file\r
1065   //\r
1066   Status = VerifyFfsFile (VtfFile);\r
1067   if (EFI_ERROR (Status)) {\r
1068     return EFI_INVALID_PARAMETER;\r
1069   }\r
1070 \r
1071   //\r
1072   // Find the Sec Core\r
1073   //\r
1074   Status = GetFileByType (EFI_FV_FILETYPE_SECURITY_CORE, 1, &SecCoreFile);\r
1075   if (EFI_ERROR (Status) || SecCoreFile == NULL) {\r
1076     Error (NULL, 0, 0, "could not find the Sec core in the FV", NULL);\r
1077     return EFI_ABORTED;\r
1078   }\r
1079   //\r
1080   // Sec Core found, now find PE32 section\r
1081   //\r
1082   Status = GetSectionByType (SecCoreFile, EFI_SECTION_PE32, 1, &Pe32Section);\r
1083   if (Status == EFI_NOT_FOUND) {\r
1084     Status = GetSectionByType (SecCoreFile, EFI_SECTION_TE, 1, &Pe32Section);\r
1085   }\r
1086 \r
1087   if (EFI_ERROR (Status)) {\r
1088     Error (NULL, 0, 0, "could not find PE32 section in SEC core file", NULL);\r
1089     return EFI_ABORTED;\r
1090   }\r
1091 \r
1092   Status = GetPe32Info (\r
1093             (VOID *) ((UINTN) Pe32Section.Pe32Section + sizeof (EFI_SECTION_PE32)),\r
1094             &EntryPoint,\r
1095             &BaseOfCode,\r
1096             &MachineType\r
1097             );\r
1098 \r
1099   if (EFI_ERROR (Status)) {\r
1100     Error (NULL, 0, 0, "could not get PE32 entry point for SEC core", NULL);\r
1101     return EFI_ABORTED;\r
1102   }\r
1103   //\r
1104   // Physical address is FV base + offset of PE32 + offset of the entry point\r
1105   //\r
1106   SecCorePhysicalAddress = FvInfo->BaseAddress;\r
1107   SecCorePhysicalAddress += (UINTN) Pe32Section.Pe32Section + sizeof (EFI_SECTION_PE32) - (UINTN) FvImage->FileImage;\r
1108   SecCorePhysicalAddress += EntryPoint;\r
1109 \r
1110   //\r
1111   // Find the PEI Core\r
1112   //\r
1113   Status = GetFileByType (EFI_FV_FILETYPE_PEI_CORE, 1, &PeiCoreFile);\r
1114   if (EFI_ERROR (Status) || PeiCoreFile == NULL) {\r
1115     Error (NULL, 0, 0, "could not find the PEI core in the FV", NULL);\r
1116     return EFI_ABORTED;\r
1117   }\r
1118   //\r
1119   // PEI Core found, now find PE32 or TE section\r
1120   //\r
1121   Status = GetSectionByType (PeiCoreFile, EFI_SECTION_PE32, 1, &Pe32Section);\r
1122   if (Status == EFI_NOT_FOUND) {\r
1123     Status = GetSectionByType (PeiCoreFile, EFI_SECTION_TE, 1, &Pe32Section);\r
1124   }\r
1125 \r
1126   if (EFI_ERROR (Status)) {\r
1127     Error (NULL, 0, 0, "could not find PE32 or TE section in PEI core file", NULL);\r
1128     return EFI_ABORTED;\r
1129   }\r
1130 \r
1131   Status = GetPe32Info (\r
1132             (VOID *) ((UINTN) Pe32Section.Pe32Section + sizeof (EFI_SECTION_PE32)),\r
1133             &EntryPoint,\r
1134             &BaseOfCode,\r
1135             &MachineType\r
1136             );\r
1137 \r
1138   if (EFI_ERROR (Status)) {\r
1139     Error (NULL, 0, 0, "could not get PE32 entry point for PEI core", NULL);\r
1140     return EFI_ABORTED;\r
1141   }\r
1142   //\r
1143   // Physical address is FV base + offset of PE32 + offset of the entry point\r
1144   //\r
1145   PeiCorePhysicalAddress = FvInfo->BaseAddress;\r
1146   PeiCorePhysicalAddress += (UINTN) Pe32Section.Pe32Section + sizeof (EFI_SECTION_PE32) - (UINTN) FvImage->FileImage;\r
1147   PeiCorePhysicalAddress += EntryPoint;\r
1148 \r
1149   if (MachineType == EFI_IMAGE_MACHINE_IA64) {\r
1150     //\r
1151     // Update PEI_CORE address\r
1152     //\r
1153     //\r
1154     // Set the uncached attribute bit in the physical address\r
1155     //\r
1156     PeiCorePhysicalAddress |= 0x8000000000000000ULL;\r
1157 \r
1158     //\r
1159     // Check if address is aligned on a 16 byte boundary\r
1160     //\r
1161     if (PeiCorePhysicalAddress & 0xF) {\r
1162       Error (NULL, 0, 0, NULL,\r
1163         "ERROR: PEI_CORE entry point is not aligned on a 16 byte boundary, address specified is %Xh.",\r
1164         PeiCorePhysicalAddress\r
1165         );\r
1166       return EFI_ABORTED;\r
1167     }\r
1168     //\r
1169     // First Get the FIT table address\r
1170     //\r
1171     FitAddress  = (*(UINT64 *) (FvImage->Eof - IPF_FIT_ADDRESS_OFFSET)) & 0xFFFFFFFF;\r
1172 \r
1173     FitTablePtr = (FIT_TABLE *) (FvImage->FileImage + (FitAddress - FvInfo->BaseAddress));\r
1174 \r
1175     Status      = UpdatePeiCoreEntryInFit (FitTablePtr, PeiCorePhysicalAddress);\r
1176 \r
1177     if (!EFI_ERROR (Status)) {\r
1178       UpdateFitCheckSum (FitTablePtr);\r
1179     }\r
1180 \r
1181     //\r
1182     // Update SEC_CORE address\r
1183     //\r
1184     //\r
1185     // Set the uncached attribute bit in the physical address\r
1186     //\r
1187     SecCorePhysicalAddress |= 0x8000000000000000ULL;\r
1188     //\r
1189     // Check if address is aligned on a 16 byte boundary\r
1190     //\r
1191     if (SecCorePhysicalAddress & 0xF) {\r
1192       Error (NULL, 0, 0, NULL, \r
1193         "ERROR: SALE_ENTRY entry point is not aligned on a 16 byte boundary, address specified is %Xh.",\r
1194         SecCorePhysicalAddress\r
1195         );\r
1196       return EFI_ABORTED;\r
1197     }\r
1198     //\r
1199     // Update the address\r
1200     //\r
1201     SecCoreEntryAddressPtr  = (EFI_PHYSICAL_ADDRESS *) ((UINTN) FvImage->Eof - IPF_SALE_ENTRY_ADDRESS_OFFSET);\r
1202     *SecCoreEntryAddressPtr = SecCorePhysicalAddress;\r
1203 \r
1204   } else if (MachineType == EFI_IMAGE_MACHINE_IA32) {\r
1205     //\r
1206     // Get the location to update\r
1207     //\r
1208     Ia32ResetAddressPtr  = (UINT32 *) ((UINTN) FvImage->Eof - IA32_PEI_CORE_ENTRY_OFFSET);\r
1209 \r
1210     //\r
1211     // Write lower 32 bits of physical address for Pei Core entry\r
1212     //\r
1213     *Ia32ResetAddressPtr = (UINT32) PeiCorePhysicalAddress;\r
1214     \r
1215     //\r
1216     // Write SecCore Entry point relative address into the jmp instruction in reset vector.\r
1217     // \r
1218     Ia32ResetAddressPtr  = (UINT32 *) ((UINTN) FvImage->Eof - IA32_SEC_CORE_ENTRY_OFFSET);\r
1219     \r
1220     Ia32SecEntryOffset   = SecCorePhysicalAddress - (FV_IMAGES_TOP_ADDRESS - IA32_SEC_CORE_ENTRY_OFFSET + 2);\r
1221     if (Ia32SecEntryOffset <= -65536) {\r
1222       Error (NULL, 0, 0, NULL, "The SEC EXE file size is too big");\r
1223       return STATUS_ERROR;\r
1224     }\r
1225     \r
1226     *(UINT16 *) Ia32ResetAddressPtr = (UINT16) Ia32SecEntryOffset;\r
1227 \r
1228     //\r
1229     // Update the BFV base address\r
1230     //\r
1231     Ia32ResetAddressPtr   = (UINT32 *) ((UINTN) FvImage->Eof - 4);\r
1232     *Ia32ResetAddressPtr  = (UINT32) (FvInfo->BaseAddress);\r
1233 \r
1234     //\r
1235     // Update the Startup AP in the FVH header block ZeroVector region.\r
1236     //\r
1237     BytePointer   = (UINT8 *) ((UINTN) FvImage->FileImage);\r
1238     if (FvInfo->Size == 0x10000) {\r
1239       BytePointer2 = m64kRecoveryStartupApDataArray;\r
1240     } else if (FvInfo->Size == 0x20000) {\r
1241       BytePointer2 = m128kRecoveryStartupApDataArray;\r
1242     } else if (FvInfo->Size > 0x20000) {\r
1243       BytePointer2 = m128kRecoveryStartupApDataArray;\r
1244       //\r
1245       // Find the position to place Ap reset vector, the offset\r
1246       // between the position and the end of Fvrecovery.fv file\r
1247       // should not exceed 128kB to prevent Ap reset vector from\r
1248       // outside legacy E and F segment\r
1249       //\r
1250       Status = FindApResetVectorPosition (FvImage, &BytePointer);\r
1251       if (EFI_ERROR (Status)) {\r
1252         Error (NULL, 0, 0, NULL, "Can't find the appropriate space in FvImage to add Ap reset vector!");\r
1253         return EFI_ABORTED;\r
1254       }\r
1255     }\r
1256 \r
1257     for (Index = 0; Index < SIZEOF_STARTUP_DATA_ARRAY; Index++) {\r
1258       BytePointer[Index] = BytePointer2[Index];\r
1259     }\r
1260     //\r
1261     // Calculate the checksum\r
1262     //\r
1263     CheckSum              = 0x0000;\r
1264     WordPointer = (UINT16 *) (BytePointer);\r
1265     for (Index = 0; Index < SIZEOF_STARTUP_DATA_ARRAY / 2; Index++) {\r
1266       CheckSum = (UINT16) (CheckSum + ((UINT16) *WordPointer));\r
1267       WordPointer++;\r
1268     }\r
1269     //\r
1270     // Update the checksum field\r
1271     //\r
1272     WordPointer   = (UINT16 *) (BytePointer + SIZEOF_STARTUP_DATA_ARRAY - 2);\r
1273     *WordPointer  = (UINT16) (0x10000 - (UINT32) CheckSum);\r
1274     \r
1275     //\r
1276     // IpiVector at the 4k aligned address in the top 2 blocks in the PEI FV. \r
1277     //\r
1278     IpiVector  = FV_IMAGES_TOP_ADDRESS - ((UINTN) FvImage->Eof - (UINTN) BytePointer);\r
1279     IpiVector  = IpiVector >> 12;\r
1280     IpiVector  = IpiVector & 0xFF;\r
1281 \r
1282     //\r
1283     // Write IPI Vector at Offset FvrecoveryFileSize - 8\r
1284     //\r
1285     Ia32ResetAddressPtr   = (UINT32 *) ((UINTN) FvImage->Eof - 8);\r
1286     *Ia32ResetAddressPtr  = IpiVector;\r
1287   } else {\r
1288     Error (NULL, 0, 0, "invalid machine type in PEI core", "machine type=0x%X", (UINT32) MachineType);\r
1289     return EFI_ABORTED;\r
1290   }\r
1291 \r
1292   //\r
1293   // Now update file checksum\r
1294   //\r
1295   SavedState  = VtfFile->State;\r
1296   VtfFile->IntegrityCheck.Checksum.File = 0;\r
1297   VtfFile->State                        = 0;\r
1298   if (VtfFile->Attributes & FFS_ATTRIB_CHECKSUM) {\r
1299     VtfFile->IntegrityCheck.Checksum.File = CalculateChecksum8 (\r
1300                                               (UINT8 *) VtfFile,\r
1301                                               GetLength (VtfFile->Size)\r
1302                                               );\r
1303   } else {\r
1304     VtfFile->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;\r
1305   }\r
1306 \r
1307   VtfFile->State = SavedState;\r
1308 \r
1309   return EFI_SUCCESS;\r
1310 }\r
1311 \r
1312 EFI_STATUS\r
1313 GetPe32Info (\r
1314   IN UINT8                  *Pe32,\r
1315   OUT UINT32                *EntryPoint,\r
1316   OUT UINT32                *BaseOfCode,\r
1317   OUT UINT16                *MachineType\r
1318   )\r
1319 /*++\r
1320 \r
1321 Routine Description:\r
1322 \r
1323   Retrieves the PE32 entry point offset and machine type from PE image or TeImage.  \r
1324   See EfiImage.h for machine types.  The entry point offset is from the beginning \r
1325   of the PE32 buffer passed in.\r
1326 \r
1327 Arguments:\r
1328 \r
1329   Pe32          Beginning of the PE32.\r
1330   EntryPoint    Offset from the beginning of the PE32 to the image entry point.\r
1331   BaseOfCode    Base address of code.\r
1332   MachineType   Magic number for the machine type.\r
1333 \r
1334 Returns:\r
1335 \r
1336   EFI_SUCCESS             Function completed successfully.\r
1337   EFI_ABORTED             Error encountered.\r
1338   EFI_INVALID_PARAMETER   A required parameter was NULL.\r
1339   EFI_UNSUPPORTED         The operation is unsupported.\r
1340 \r
1341 --*/\r
1342 {\r
1343   EFI_IMAGE_DOS_HEADER  *DosHeader;\r
1344   EFI_IMAGE_NT_HEADERS  *NtHeader;\r
1345   EFI_TE_IMAGE_HEADER   *TeHeader;\r
1346 \r
1347   //\r
1348   // Verify input parameters\r
1349   //\r
1350   if (Pe32 == NULL) {\r
1351     return EFI_INVALID_PARAMETER;\r
1352   }\r
1353 \r
1354   //\r
1355   // First check whether it is one TE Image.\r
1356   //\r
1357   TeHeader = (EFI_TE_IMAGE_HEADER *) Pe32;\r
1358   if (TeHeader->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {\r
1359     //\r
1360     // By TeImage Header to get output\r
1361     //\r
1362     *EntryPoint   = TeHeader->AddressOfEntryPoint + sizeof (EFI_TE_IMAGE_HEADER) - TeHeader->StrippedSize;\r
1363     *BaseOfCode   = TeHeader->BaseOfCode + sizeof (EFI_TE_IMAGE_HEADER) - TeHeader->StrippedSize;\r
1364     *MachineType  = TeHeader->Machine;\r
1365   } else {\r
1366   \r
1367     //\r
1368     // Then check whether \r
1369     // First is the DOS header\r
1370     //\r
1371     DosHeader = (EFI_IMAGE_DOS_HEADER *) Pe32;\r
1372   \r
1373     //\r
1374     // Verify DOS header is expected\r
1375     //\r
1376     if (DosHeader->e_magic != EFI_IMAGE_DOS_SIGNATURE) {\r
1377       Error (NULL, 0, 0, NULL, "ERROR: Unknown magic number in the DOS header, 0x%04X.", DosHeader->e_magic);\r
1378       return EFI_UNSUPPORTED;\r
1379     }\r
1380     //\r
1381     // Immediately following is the NT header.\r
1382     //\r
1383     NtHeader = (EFI_IMAGE_NT_HEADERS *) ((UINTN) Pe32 + DosHeader->e_lfanew);\r
1384   \r
1385     //\r
1386     // Verify NT header is expected\r
1387     //\r
1388     if (NtHeader->Signature != EFI_IMAGE_NT_SIGNATURE) {\r
1389       Error (NULL, 0, 0, NULL, "ERROR: Unrecognized image signature 0x%08X.", NtHeader->Signature);\r
1390       return EFI_UNSUPPORTED;\r
1391     }\r
1392     //\r
1393     // Get output\r
1394     //\r
1395     *EntryPoint   = NtHeader->OptionalHeader.AddressOfEntryPoint;\r
1396     *BaseOfCode   = NtHeader->OptionalHeader.BaseOfCode;\r
1397     *MachineType  = NtHeader->FileHeader.Machine;\r
1398   }\r
1399 \r
1400   //\r
1401   // Verify machine type is supported\r
1402   //\r
1403   if (*MachineType != EFI_IMAGE_MACHINE_IA32 && *MachineType != EFI_IMAGE_MACHINE_IA64 && *MachineType != EFI_IMAGE_MACHINE_X64 && *MachineType != EFI_IMAGE_MACHINE_EBC) {\r
1404     Error (NULL, 0, 0, NULL, "ERROR: Unrecognized machine type in the PE32 file.");\r
1405     return EFI_UNSUPPORTED;\r
1406   }\r
1407 \r
1408   return EFI_SUCCESS;\r
1409 }\r
1410 //\r
1411 // Exposed function implementations (prototypes are defined in GenFvImageLib.h)\r
1412 //\r
1413 EFI_STATUS\r
1414 GenerateFvImage (\r
1415   IN CHAR8                *InfFileImage,\r
1416   IN UINTN                InfFileSize,\r
1417   IN CHAR8                *FvFileName,\r
1418   IN EFI_PHYSICAL_ADDRESS XipBaseAddress\r
1419   )\r
1420 /*++\r
1421 \r
1422 Routine Description:\r
1423 \r
1424   This is the main function which will be called from application.\r
1425 \r
1426 Arguments:\r
1427 \r
1428   InfFileImage   Buffer containing the INF file contents.\r
1429   InfFileSize    Size of the contents of the InfFileImage buffer.\r
1430   FvFileName     Requested name for the FV file.\r
1431   XipBaseAddress BaseAddress is to be rebased.\r
1432 \r
1433 Returns:\r
1434 \r
1435   EFI_SUCCESS             Function completed successfully.\r
1436   EFI_OUT_OF_RESOURCES    Could not allocate required resources.\r
1437   EFI_ABORTED             Error encountered.\r
1438   EFI_INVALID_PARAMETER   A required parameter was NULL.\r
1439 \r
1440 --*/\r
1441 {\r
1442   EFI_STATUS                  Status;\r
1443   MEMORY_FILE                 InfMemoryFile;\r
1444   MEMORY_FILE                 FvImageMemoryFile;\r
1445   FV_INFO                     FvInfo;\r
1446   UINTN                       Index;\r
1447   EFI_FIRMWARE_VOLUME_HEADER  *FvHeader;\r
1448   EFI_FFS_FILE_HEADER         *VtfFileImage;\r
1449   UINT8                       *FvBufferHeader; // to make sure fvimage header 8 type alignment.\r
1450   UINT8                       *FvImage;\r
1451   UINTN                       FvImageSize;\r
1452   FILE                        *FvFile;\r
1453 \r
1454   FvBufferHeader = NULL;\r
1455   FvFile         = NULL;\r
1456   //\r
1457   // Check for invalid parameter\r
1458   //\r
1459   if (InfFileImage == NULL) {\r
1460     return EFI_INVALID_PARAMETER;\r
1461   }\r
1462 \r
1463   //\r
1464   // Initialize file structures\r
1465   //\r
1466   InfMemoryFile.FileImage           = InfFileImage;\r
1467   InfMemoryFile.CurrentFilePointer  = InfFileImage;\r
1468   InfMemoryFile.Eof                 = InfFileImage + InfFileSize;\r
1469 \r
1470   //\r
1471   // Parse the FV inf file for header information\r
1472   //\r
1473   Status = ParseFvInf (&InfMemoryFile, &FvInfo);\r
1474   if (EFI_ERROR (Status)) {\r
1475     Error (NULL, 0, 0, NULL, "ERROR: Could not parse the input INF file.");\r
1476     return Status;\r
1477   }\r
1478 \r
1479   //\r
1480   // Update the file name return values\r
1481   //\r
1482   if (FvFileName == NULL && FvInfo.FvName[0] != '\0') {\r
1483     FvFileName = FvInfo.FvName;\r
1484   }\r
1485   \r
1486   //\r
1487   // Update FvImage Base Address, XipBase not same to BtBase, RtBase address.\r
1488   //\r
1489   if (XipBaseAddress != -1) {\r
1490     FvInfo.BaseAddress = XipBaseAddress;\r
1491   }\r
1492 \r
1493   //\r
1494   // Calculate the FV size and Update Fv Size based on the actual FFS files.\r
1495   // And Update FvInfo data.\r
1496   //\r
1497   Status = CalculateFvSize (&FvInfo);\r
1498   if (EFI_ERROR (Status)) {\r
1499     return Status;    \r
1500   }\r
1501   \r
1502   //\r
1503   // support fv image and empty fv image\r
1504   //\r
1505   FvImageSize = FvInfo.Size;\r
1506 \r
1507   //\r
1508   // Allocate the FV, assure FvImage Header 8 byte alignment\r
1509   //\r
1510   FvBufferHeader = malloc (FvImageSize + 8);\r
1511   if (FvBufferHeader == NULL) {\r
1512     return EFI_OUT_OF_RESOURCES;\r
1513   }\r
1514   FvImage = (UINT8 *) (((UINTN) FvBufferHeader + 7) & ~7);\r
1515 \r
1516   //\r
1517   // Initialize the FV to the erase polarity\r
1518   //\r
1519   if (FvInfo.FvAttributes & EFI_FVB2_ERASE_POLARITY) {\r
1520     memset (FvImage, -1, FvImageSize);\r
1521   } else {\r
1522     memset (FvImage, 0, FvImageSize);\r
1523   }\r
1524 \r
1525   //\r
1526   // Initialize FV header\r
1527   //\r
1528   FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) FvImage;\r
1529 \r
1530   //\r
1531   // Initialize the zero vector to all zeros.\r
1532   //\r
1533   memset (FvHeader->ZeroVector, 0, 16);\r
1534 \r
1535   //\r
1536   // Copy the FFS GUID\r
1537   //\r
1538   memcpy (&FvHeader->FileSystemGuid, &FvInfo.FvGuid, sizeof (EFI_GUID));\r
1539 \r
1540   FvHeader->FvLength        = FvImageSize;\r
1541   FvHeader->Signature       = EFI_FVH_SIGNATURE;\r
1542   FvHeader->Attributes      = FvInfo.FvAttributes;\r
1543   FvHeader->Revision        = EFI_FVH_PI_REVISION;\r
1544   FvHeader->ExtHeaderOffset = 0;\r
1545   FvHeader->Reserved[0]     = 0;\r
1546   \r
1547   //\r
1548   // Copy firmware block map\r
1549   //\r
1550   for (Index = 0; FvInfo.FvBlocks[Index].Length != 0; Index++) {\r
1551     FvHeader->BlockMap[Index].NumBlocks   = FvInfo.FvBlocks[Index].NumBlocks;\r
1552     FvHeader->BlockMap[Index].Length      = FvInfo.FvBlocks[Index].Length;\r
1553   }\r
1554 \r
1555   //\r
1556   // Add block map terminator\r
1557   //\r
1558   FvHeader->BlockMap[Index].NumBlocks   = 0;\r
1559   FvHeader->BlockMap[Index].Length      = 0;\r
1560 \r
1561   //\r
1562   // Complete the header\r
1563   //\r
1564   FvHeader->HeaderLength  = (UINT16) (((UINTN) &(FvHeader->BlockMap[Index + 1])) - (UINTN) FvImage);\r
1565   FvHeader->Checksum      = 0;\r
1566   FvHeader->Checksum      = CalculateChecksum16 ((UINT16 *) FvHeader, FvHeader->HeaderLength / sizeof (UINT16));\r
1567 \r
1568   //\r
1569   // If there is no FFS file, generate one empty FV\r
1570   //\r
1571   if (FvInfo.FvFiles[0][0] == 0) {\r
1572     goto WriteFile;\r
1573   }\r
1574 \r
1575   //\r
1576   // Initialize our "file" view of the buffer\r
1577   //\r
1578   FvImageMemoryFile.FileImage           = FvImage;\r
1579   FvImageMemoryFile.CurrentFilePointer  = FvImage + FvHeader->HeaderLength;\r
1580   FvImageMemoryFile.Eof                 = FvImage + FvImageSize;\r
1581 \r
1582   //\r
1583   // Initialize the FV library.\r
1584   //\r
1585   InitializeFvLib (FvImageMemoryFile.FileImage, FvImageSize);\r
1586 \r
1587   //\r
1588   // Initialize the VTF file address.\r
1589   //\r
1590   VtfFileImage = (EFI_FFS_FILE_HEADER *) FvImageMemoryFile.Eof;\r
1591 \r
1592   //\r
1593   // Add files to FV\r
1594   //\r
1595   for (Index = 0; FvInfo.FvFiles[Index][0] != 0; Index++) {\r
1596     //\r
1597     // Add the file\r
1598     //\r
1599     Status = AddFile (&FvImageMemoryFile, &FvInfo, Index, &VtfFileImage);\r
1600 \r
1601     //\r
1602     // Exit if error detected while adding the file\r
1603     //\r
1604     if (EFI_ERROR (Status)) {\r
1605       Error (NULL, 0, 0, NULL, "ERROR: Could not add file %s.", FvInfo.FvFiles[Index]);\r
1606       goto Finish;\r
1607     }\r
1608   }\r
1609 \r
1610   //\r
1611   // If there is a VTF file, some special actions need to occur.\r
1612   //\r
1613   if ((UINTN) VtfFileImage != (UINTN) FvImageMemoryFile.Eof) {\r
1614     //\r
1615     // Pad from the end of the last file to the beginning of the VTF file.\r
1616     // If the left space is less than sizeof (EFI_FFS_FILE_HEADER)?\r
1617     //\r
1618     Status = PadFvImage (&FvImageMemoryFile, VtfFileImage);\r
1619     if (EFI_ERROR (Status)) {\r
1620       Error (NULL, 0, 0, NULL, "ERROR: Could not create the pad file between the last file and the VTF file.");\r
1621       goto Finish;\r
1622     }\r
1623     //\r
1624     // Update reset vector (SALE_ENTRY for IPF)\r
1625     // Now for IA32 and IA64 platform, the fv which has bsf file must have the \r
1626     // EndAddress of 0xFFFFFFFF. Thus, only this type fv needs to update the   \r
1627     // reset vector. If the PEI Core is found, the VTF file will probably get  \r
1628     // corrupted by updating the entry point.                                  \r
1629     //\r
1630     if ((FvInfo.BaseAddress + FvInfo.Size) == FV_IMAGES_TOP_ADDRESS) {       \r
1631       Status = UpdateResetVector (&FvImageMemoryFile, &FvInfo, VtfFileImage);\r
1632       if (EFI_ERROR(Status)) {                                               \r
1633         Error (NULL, 0, 0, NULL, "ERROR: Could not update the reset vector.");\r
1634         goto Finish;                                              \r
1635       }\r
1636     }\r
1637   } \r
1638   \r
1639   //\r
1640   // Update FV Alignment attribute to the largest alignment of all the FFS files in the FV\r
1641   //\r
1642   if ((((FvHeader->Attributes & EFI_FVB2_ALIGNMENT) >> 16)) < MaxFfsAlignment) {\r
1643     FvHeader->Attributes = ((MaxFfsAlignment << 16) | (FvHeader->Attributes & 0xFFFF));\r
1644     //\r
1645     // Update Checksum for FvHeader\r
1646     //\r
1647     FvHeader->Checksum      = 0;\r
1648     FvHeader->Checksum      = CalculateChecksum16 ((UINT16 *) FvHeader, FvHeader->HeaderLength / sizeof (UINT16));\r
1649   }\r
1650 \r
1651 WriteFile: \r
1652   //\r
1653   // Write fv file\r
1654   //\r
1655   if (FvFileName == NULL) {\r
1656     FvFile = stdout;\r
1657   } else {\r
1658     FvFile = fopen (FvFileName, "wb");\r
1659   }\r
1660 \r
1661   if (FvFile == NULL) {\r
1662     Error (NULL, 0, 0, FvFileName, "could not open output file");\r
1663     Status = EFI_ABORTED;\r
1664     goto Finish;\r
1665   }\r
1666 \r
1667   if (fwrite (FvImage, 1, FvImageSize, FvFile) != FvImageSize) {\r
1668     Error (NULL, 0, 0, FvFileName, "failed to write to output file");\r
1669     Status = EFI_ABORTED;\r
1670     goto Finish;\r
1671   }\r
1672 \r
1673 Finish:\r
1674   if (FvBufferHeader != NULL) {\r
1675     free (FvBufferHeader);\r
1676   }\r
1677   \r
1678   if (FvFile != NULL) {\r
1679     fclose (FvFile);\r
1680   }\r
1681 \r
1682   return Status;\r
1683 }\r
1684 \r
1685 EFI_STATUS\r
1686 UpdatePeiCoreEntryInFit (\r
1687   IN FIT_TABLE     *FitTablePtr,\r
1688   IN UINT64        PeiCorePhysicalAddress\r
1689   )\r
1690 /*++\r
1691 \r
1692 Routine Description:\r
1693 \r
1694   This function is used to update the Pei Core address in FIT, this can be used by Sec core to pass control from\r
1695   Sec to Pei Core\r
1696 \r
1697 Arguments:\r
1698 \r
1699   FitTablePtr             - The pointer of FIT_TABLE.\r
1700   PeiCorePhysicalAddress  - The address of Pei Core entry.\r
1701 \r
1702 Returns:\r
1703 \r
1704   EFI_SUCCESS             - The PEI_CORE FIT entry was updated successfully.\r
1705   EFI_NOT_FOUND           - Not found the PEI_CORE FIT entry.\r
1706 \r
1707 --*/\r
1708 {\r
1709   FIT_TABLE *TmpFitPtr;\r
1710   UINTN     Index;\r
1711   UINTN     NumFitComponents;\r
1712 \r
1713   TmpFitPtr         = FitTablePtr;\r
1714   NumFitComponents  = TmpFitPtr->CompSize;\r
1715 \r
1716   for (Index = 0; Index < NumFitComponents; Index++) {\r
1717     if ((TmpFitPtr->CvAndType & FIT_TYPE_MASK) == COMP_TYPE_FIT_PEICORE) {\r
1718       TmpFitPtr->CompAddress = PeiCorePhysicalAddress;\r
1719       return EFI_SUCCESS;\r
1720     }\r
1721 \r
1722     TmpFitPtr++;\r
1723   }\r
1724 \r
1725   return EFI_NOT_FOUND;\r
1726 }\r
1727 \r
1728 VOID\r
1729 UpdateFitCheckSum (\r
1730   IN FIT_TABLE   *FitTablePtr\r
1731   )\r
1732 /*++\r
1733 \r
1734 Routine Description:\r
1735 \r
1736   This function is used to update the checksum for FIT.\r
1737 \r
1738 \r
1739 Arguments:\r
1740 \r
1741   FitTablePtr             - The pointer of FIT_TABLE.\r
1742 \r
1743 Returns:\r
1744 \r
1745   None.\r
1746 \r
1747 --*/\r
1748 {\r
1749   if ((FitTablePtr->CvAndType & CHECKSUM_BIT_MASK) >> 7) {\r
1750     FitTablePtr->CheckSum = 0;\r
1751     FitTablePtr->CheckSum = CalculateChecksum8 ((UINT8 *) FitTablePtr, FitTablePtr->CompSize * 16);\r
1752   }\r
1753 }\r
1754 \r
1755 EFI_STATUS\r
1756 CalculateFvSize (\r
1757   FV_INFO *FvInfoPtr\r
1758   )\r
1759 /*++\r
1760 Routine Description:\r
1761   Calculate the FV size and Update Fv Size based on the actual FFS files.\r
1762   And Update FvInfo data.\r
1763 \r
1764 Arguments:\r
1765   FvInfoPtr     - The pointer to FV_INFO structure.\r
1766 \r
1767 Returns:\r
1768   EFI_ABORTED   - Ffs Image Error\r
1769   EFI_SUCCESS   - Successfully update FvSize\r
1770 --*/\r
1771 {\r
1772   UINTN               CurrentOffset;\r
1773   UINTN               Index;\r
1774   FILE                *fpin;\r
1775   UINTN               FfsFileSize;\r
1776   UINT32              FfsAlignment;\r
1777   EFI_FFS_FILE_HEADER FfsHeader;\r
1778   EFI_STATUS          Status;\r
1779   BOOLEAN             VtfFileFlag;\r
1780   \r
1781   VtfFileFlag = FALSE;\r
1782   fpin  = NULL;\r
1783   Index = 0;\r
1784   CurrentOffset = sizeof (EFI_FIRMWARE_VOLUME_HEADER);\r
1785   \r
1786   for (Index = 1;; Index ++) {\r
1787     CurrentOffset += sizeof (EFI_FV_BLOCK_MAP_ENTRY);\r
1788     if (FvInfoPtr->FvBlocks[Index].NumBlocks == 0 && FvInfoPtr->FvBlocks[Index].Length == 0) {\r
1789       break;\r
1790     }\r
1791   }\r
1792 \r
1793   //\r
1794   // Accumlate every FFS file size.\r
1795   //\r
1796   for (Index = 0; FvInfoPtr->FvFiles[Index][0] != 0; Index++) {\r
1797     //\r
1798     // Open FFS file\r
1799     //\r
1800     fpin = NULL;\r
1801     fpin = fopen (FvInfoPtr->FvFiles[Index], "rb");\r
1802     if (fpin == NULL) {\r
1803       Error (NULL, 0, 0, NULL, "%s could not open for reading", FvInfoPtr->FvFiles[Index]);\r
1804       return EFI_ABORTED;\r
1805     }\r
1806     //\r
1807     // Get the file size\r
1808     //\r
1809     FfsFileSize = _filelength (fileno (fpin));\r
1810     //\r
1811     // Read Ffs File header\r
1812     //\r
1813     fread (&FfsHeader, sizeof (UINT8), sizeof (EFI_FFS_FILE_HEADER), fpin);\r
1814     //\r
1815     // close file\r
1816     //\r
1817     fclose (fpin);\r
1818     //\r
1819     // Check whether this ffs file is vtf file\r
1820     //\r
1821     if (IsVtfFile (&FfsHeader)) {\r
1822       if (VtfFileFlag) {\r
1823         //\r
1824         // One Fv image can't have two vtf files.\r
1825         //\r
1826         return EFI_ABORTED;\r
1827       }\r
1828       VtfFileFlag = TRUE;\r
1829       //\r
1830       // The space between Vft File and the latest file must be able to contain \r
1831       // one ffs file header in order to add one pad file.\r
1832       //\r
1833       CurrentOffset += sizeof (EFI_FFS_FILE_HEADER);\r
1834     }\r
1835     //\r
1836     // Get the alignment of FFS file \r
1837     //\r
1838     ReadFfsAlignment (&FfsHeader, &FfsAlignment);\r
1839     FfsAlignment = 1 << FfsAlignment;\r
1840     //\r
1841     // Add Pad file\r
1842     //\r
1843     if (((CurrentOffset + sizeof (EFI_FFS_FILE_HEADER)) % FfsAlignment) != 0) {\r
1844       CurrentOffset = (CurrentOffset + sizeof (EFI_FFS_FILE_HEADER) * 2 + FfsAlignment - 1) & ~(FfsAlignment - 1);\r
1845       CurrentOffset -= sizeof (EFI_FFS_FILE_HEADER);\r
1846     }\r
1847     //\r
1848     // Add ffs file size\r
1849     //\r
1850     CurrentOffset += FfsFileSize;    \r
1851     //\r
1852     // Make next ffs file start at QWord Boundry\r
1853     //\r
1854     CurrentOffset = (CurrentOffset + EFI_FFS_FILE_HEADER_ALIGNMENT - 1) & ~(EFI_FFS_FILE_HEADER_ALIGNMENT - 1);\r
1855   }\r
1856   \r
1857   if (FvInfoPtr->Size < CurrentOffset) { \r
1858     //\r
1859     // Update FvInfo data\r
1860     //\r
1861     FvInfoPtr->FvBlocks[0].NumBlocks = CurrentOffset / FvInfoPtr->FvBlocks[0].Length + ((CurrentOffset % FvInfoPtr->FvBlocks[0].Length)?1:0);\r
1862     FvInfoPtr->Size = FvInfoPtr->FvBlocks[0].NumBlocks * FvInfoPtr->FvBlocks[0].Length;\r
1863     FvInfoPtr->FvBlocks[1].NumBlocks = 0;\r
1864     FvInfoPtr->FvBlocks[1].Length = 0;\r
1865   }\r
1866 \r
1867   return EFI_SUCCESS;\r
1868 }\r
1869 \r
1870 EFI_STATUS\r
1871 FfsRebaseImageRead (\r
1872   IN     VOID    *FileHandle,\r
1873   IN     UINTN   FileOffset,\r
1874   IN OUT UINT32  *ReadSize,\r
1875   OUT    VOID    *Buffer\r
1876   )\r
1877 /*++\r
1878 \r
1879 Routine Description:\r
1880 \r
1881   Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file\r
1882 \r
1883 Arguments:\r
1884 \r
1885   FileHandle - The handle to the PE/COFF file\r
1886 \r
1887   FileOffset - The offset, in bytes, into the file to read\r
1888 \r
1889   ReadSize   - The number of bytes to read from the file starting at FileOffset\r
1890 \r
1891   Buffer     - A pointer to the buffer to read the data into.\r
1892 \r
1893 Returns:\r
1894 \r
1895   EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset\r
1896 \r
1897 --*/\r
1898 {\r
1899   CHAR8   *Destination8;\r
1900   CHAR8   *Source8;\r
1901   UINT32  Length;\r
1902 \r
1903   Destination8  = Buffer;\r
1904   Source8       = (CHAR8 *) ((UINTN) FileHandle + FileOffset);\r
1905   Length        = *ReadSize;\r
1906   while (Length--) {\r
1907     *(Destination8++) = *(Source8++);\r
1908   }\r
1909 \r
1910   return EFI_SUCCESS;\r
1911 }\r
1912 \r
1913 EFI_STATUS\r
1914 FfsRebase ( \r
1915   IN OUT  FV_INFO               *FvInfo, \r
1916   IN      CHAR8                 *FileName,           \r
1917   IN OUT  EFI_FFS_FILE_HEADER   *FfsFile,\r
1918   IN      UINTN                 XipOffset\r
1919   )\r
1920 /*++\r
1921 \r
1922 Routine Description:\r
1923 \r
1924   This function determines if a file is XIP and should be rebased.  It will\r
1925   rebase any PE32 sections found in the file using the base address.\r
1926 \r
1927 Arguments:\r
1928   \r
1929   FvInfo            A pointer to FV_INFO struture.\r
1930   FfsFile           A pointer to Ffs file image.\r
1931   XipOffset         The offset address to use for rebasing the XIP file image.\r
1932 \r
1933 Returns:\r
1934 \r
1935   EFI_SUCCESS             The image was properly rebased.\r
1936   EFI_INVALID_PARAMETER   An input parameter is invalid.\r
1937   EFI_ABORTED             An error occurred while rebasing the input file image.\r
1938   EFI_OUT_OF_RESOURCES    Could not allocate a required resource.\r
1939   EFI_NOT_FOUND           No compressed sections could be found.\r
1940 \r
1941 --*/\r
1942 {\r
1943   EFI_STATUS                            Status;\r
1944   PE_COFF_LOADER_IMAGE_CONTEXT          ImageContext;\r
1945   EFI_PHYSICAL_ADDRESS                  XipBase;\r
1946   EFI_PHYSICAL_ADDRESS                  NewPe32BaseAddress;\r
1947   EFI_PHYSICAL_ADDRESS                  *BaseToUpdate;\r
1948   UINTN                                 Index;\r
1949   EFI_FILE_SECTION_POINTER              CurrentPe32Section;\r
1950   EFI_FFS_FILE_STATE                    SavedState;\r
1951   EFI_IMAGE_NT_HEADERS                  *PeHdr;\r
1952   EFI_IMAGE_OPTIONAL_HEADER32           *Optional32;\r
1953   EFI_IMAGE_OPTIONAL_HEADER64           *Optional64;\r
1954   EFI_TE_IMAGE_HEADER                   *TEImageHeader;\r
1955   UINT8                                 Flags;\r
1956   UINT8                                 *MemoryImagePointer;\r
1957   EFI_IMAGE_SECTION_HEADER              *SectionHeader;\r
1958 \r
1959   Index              = 0;  \r
1960   MemoryImagePointer = NULL;\r
1961   BaseToUpdate       = NULL;\r
1962   TEImageHeader      = NULL;\r
1963   PeHdr              = NULL;\r
1964   Optional32         = NULL;\r
1965   Optional64         = NULL;\r
1966   MemoryImagePointer = NULL;\r
1967   SectionHeader      = NULL;\r
1968   //\r
1969   // Check XipAddress, BootAddress and RuntimeAddress\r
1970   //\r
1971   Flags = 0;\r
1972 \r
1973   if (FvInfo->BaseAddress != -1) {\r
1974     Flags  |= REBASE_XIP_FILE;\r
1975     XipBase = FvInfo->BaseAddress + XipOffset;\r
1976   }\r
1977   if (FvInfo->BootBaseAddress != 0) {\r
1978     Flags  |= REBASE_BOOTTIME_FILE;\r
1979   }\r
1980   if (FvInfo->RuntimeBaseAddress != 0) {\r
1981     Flags  |= REBASE_RUNTIME_FILE;\r
1982   }\r
1983   //\r
1984   // Don't Rebase this FFS.\r
1985   //\r
1986   if (Flags == 0) {\r
1987     return EFI_SUCCESS;\r
1988   }\r
1989 \r
1990   //\r
1991   // We only process files potentially containing PE32 sections.\r
1992   //\r
1993   switch (FfsFile->Type) {\r
1994     case EFI_FV_FILETYPE_SECURITY_CORE:\r
1995     case EFI_FV_FILETYPE_PEI_CORE:\r
1996     case EFI_FV_FILETYPE_PEIM:\r
1997     case EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER:\r
1998     case EFI_FV_FILETYPE_DRIVER:\r
1999     case EFI_FV_FILETYPE_DXE_CORE:\r
2000       break;\r
2001     default:\r
2002       return EFI_SUCCESS;\r
2003   }\r
2004 \r
2005   //\r
2006   // Rebase each PE32 section\r
2007   //\r
2008   Status      = EFI_SUCCESS;\r
2009   for (Index = 1;; Index++) {\r
2010     Status = GetSectionByType (FfsFile, EFI_SECTION_PE32, Index, &CurrentPe32Section);\r
2011     if (EFI_ERROR (Status)) {\r
2012       break;\r
2013     }\r
2014 \r
2015     //\r
2016     // Initialize context\r
2017     //\r
2018     memset (&ImageContext, 0, sizeof (ImageContext));\r
2019     ImageContext.Handle     = (VOID *) ((UINTN) CurrentPe32Section.Pe32Section + sizeof (EFI_PE32_SECTION));\r
2020     ImageContext.ImageRead  = (PE_COFF_LOADER_READ_FILE) FfsRebaseImageRead;\r
2021     Status                  = PeCoffLoaderGetImageInfo (&ImageContext);\r
2022     if (EFI_ERROR (Status)) {\r
2023       Error (NULL, 0, 0, "GetImageInfo() call failed on rebase", FileName);\r
2024       return Status;\r
2025     }\r
2026 \r
2027     //\r
2028     // Don't Load PeImage, only to relocate current image.\r
2029     //\r
2030     ImageContext.ImageAddress = (UINTN) CurrentPe32Section.Pe32Section + sizeof (EFI_PE32_SECTION);\r
2031 \r
2032     //\r
2033     // Get PeHeader pointer\r
2034     //\r
2035     PeHdr = (EFI_IMAGE_NT_HEADERS *)((UINTN)ImageContext.ImageAddress + ImageContext.PeCoffHeaderOffset);\r
2036 \r
2037     //\r
2038     // Calculate the PE32 base address, based on file type\r
2039     //\r
2040     switch (FfsFile->Type) {\r
2041       case EFI_FV_FILETYPE_SECURITY_CORE:\r
2042       case EFI_FV_FILETYPE_PEI_CORE:\r
2043       case EFI_FV_FILETYPE_PEIM:\r
2044       case EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER:\r
2045         if ((Flags & REBASE_XIP_FILE) == 0) {\r
2046           //\r
2047           // We aren't relocating XIP code, so skip it.\r
2048           //\r
2049           return EFI_SUCCESS;\r
2050         }\r
2051         \r
2052         //\r
2053         // Check if section-alignment and file-alignment match or not\r
2054         //\r
2055         if ((PeHdr->OptionalHeader.SectionAlignment != PeHdr->OptionalHeader.FileAlignment)) {\r
2056           //\r
2057           // Xip module has the same section alignment and file alignment.\r
2058           //\r
2059           printf("Section-Alignment and File-Alignment does not match : %s\n", FileName);\r
2060           return EFI_ABORTED;\r
2061         }\r
2062 \r
2063         NewPe32BaseAddress =\r
2064           XipBase + (UINTN)ImageContext.ImageAddress - (UINTN)FfsFile;\r
2065         BaseToUpdate = &XipBase;\r
2066         break;\r
2067 \r
2068       case EFI_FV_FILETYPE_DRIVER:\r
2069         switch (PeHdr->OptionalHeader.Subsystem) {\r
2070           case EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER:\r
2071             if ((Flags & REBASE_RUNTIME_FILE) == 0) {\r
2072               //\r
2073               // RT drivers aren't supposed to be relocated\r
2074               //\r
2075               continue;\r
2076             }\r
2077 \r
2078             NewPe32BaseAddress = FvInfo->RuntimeBaseAddress;\r
2079             BaseToUpdate = &(FvInfo->RuntimeBaseAddress);\r
2080             break;\r
2081 \r
2082           default:\r
2083             //\r
2084             // We treat all other subsystems the same as BS_DRIVER\r
2085             //\r
2086             if ((Flags & REBASE_BOOTTIME_FILE) == 0) {\r
2087               //\r
2088               // Skip all BS_DRIVER's\r
2089               //\r
2090               continue;\r
2091             }\r
2092 \r
2093             NewPe32BaseAddress = FvInfo->BootBaseAddress;\r
2094             BaseToUpdate = &(FvInfo->BootBaseAddress);\r
2095             break;\r
2096         }\r
2097         break;\r
2098 \r
2099       case EFI_FV_FILETYPE_DXE_CORE:\r
2100         if ((Flags & REBASE_BOOTTIME_FILE) == 0) {\r
2101           //\r
2102           // Skip DXE core, DxeCore only contain one PE image.\r
2103           //\r
2104           return EFI_SUCCESS;\r
2105         }\r
2106 \r
2107         NewPe32BaseAddress = FvInfo->BootBaseAddress;\r
2108         BaseToUpdate = &(FvInfo->BootBaseAddress);\r
2109         break;\r
2110 \r
2111       default:\r
2112         //\r
2113         // Not supported file type\r
2114         //\r
2115         return EFI_SUCCESS;\r
2116     }\r
2117 \r
2118     //\r
2119     // Load and Relocate Image Data\r
2120     //\r
2121     MemoryImagePointer = (UINT8 *) malloc ((UINTN) ImageContext.ImageSize + ImageContext.SectionAlignment);\r
2122     if (MemoryImagePointer == NULL) {\r
2123       Error (NULL, 0, 0, "Can't allocate enough memory on rebase", FileName);\r
2124       return EFI_OUT_OF_RESOURCES;\r
2125     }\r
2126     memset ((VOID *) MemoryImagePointer, 0, (UINTN) ImageContext.ImageSize + ImageContext.SectionAlignment);\r
2127     ImageContext.ImageAddress = ((UINTN) MemoryImagePointer + ImageContext.SectionAlignment - 1) & (~(ImageContext.SectionAlignment - 1));\r
2128     \r
2129     Status =  PeCoffLoaderLoadImage (&ImageContext);\r
2130     if (EFI_ERROR (Status)) {\r
2131       Error (NULL, 0, 0, "LocateImage() call failed on rebase", FileName);\r
2132       free ((VOID *) MemoryImagePointer);\r
2133       return Status;\r
2134     }\r
2135          \r
2136     ImageContext.DestinationAddress = NewPe32BaseAddress;\r
2137     Status                          = PeCoffLoaderRelocateImage (&ImageContext);\r
2138     if (EFI_ERROR (Status)) {\r
2139       Error (NULL, 0, 0, "RelocateImage() call failed on rebase", FileName);\r
2140       free ((VOID *) MemoryImagePointer);\r
2141       return Status;\r
2142     }\r
2143 \r
2144     //\r
2145     // Copy Relocated data to raw image file.\r
2146     //\r
2147     if (PeHdr->FileHeader.Machine == EFI_IMAGE_MACHINE_IA32) {\r
2148       Optional32 = (EFI_IMAGE_OPTIONAL_HEADER32 *) &(PeHdr->OptionalHeader);\r
2149       Optional32->ImageBase     = (UINT32) NewPe32BaseAddress;\r
2150     } else if (PeHdr->FileHeader.Machine == EFI_IMAGE_MACHINE_IA64 || \r
2151                PeHdr->FileHeader.Machine == EFI_IMAGE_MACHINE_X64) {\r
2152       Optional64 = (EFI_IMAGE_OPTIONAL_HEADER64 *) &(PeHdr->OptionalHeader);\r
2153       Optional64->ImageBase     = NewPe32BaseAddress;\r
2154     } else {\r
2155       Error (\r
2156         NULL,\r
2157         0,\r
2158         0,\r
2159         "unknown machine type in PE32 image",\r
2160         "machine type=0x%X, file=%s",\r
2161         (UINT32) PeHdr->FileHeader.Machine,\r
2162         FileName\r
2163         );\r
2164       free ((VOID *) MemoryImagePointer);\r
2165       return EFI_ABORTED;\r
2166     }\r
2167 \r
2168     SectionHeader = (EFI_IMAGE_SECTION_HEADER *) (\r
2169                        (UINTN) ImageContext.ImageAddress +\r
2170                        ImageContext.PeCoffHeaderOffset +\r
2171                        sizeof (UINT32) + \r
2172                        sizeof (EFI_IMAGE_FILE_HEADER) +  \r
2173                        PeHdr->FileHeader.SizeOfOptionalHeader\r
2174                        );\r
2175     \r
2176     for (Index = 0; Index < PeHdr->FileHeader.NumberOfSections; Index ++, SectionHeader ++) {\r
2177       CopyMem (\r
2178         (UINT8 *) ImageContext.Handle + SectionHeader->PointerToRawData, \r
2179         (VOID*) (UINTN) (ImageContext.ImageAddress + SectionHeader->VirtualAddress), \r
2180         SectionHeader->SizeOfRawData\r
2181         );\r
2182     }\r
2183 \r
2184     free ((VOID *) MemoryImagePointer);\r
2185 \r
2186     //\r
2187     // Update BASE address\r
2188     //\r
2189     *BaseToUpdate += EFI_SIZE_TO_PAGES (ImageContext.ImageSize) * EFI_PAGE_SIZE;\r
2190 \r
2191     //\r
2192     // Now update file checksum\r
2193     //\r
2194     if (FfsFile->Attributes & FFS_ATTRIB_CHECKSUM) {\r
2195       SavedState  = FfsFile->State;\r
2196       FfsFile->IntegrityCheck.Checksum.File = 0;\r
2197       FfsFile->State                        = 0;\r
2198       if (FfsFile->Attributes & FFS_ATTRIB_CHECKSUM) {\r
2199         FfsFile->IntegrityCheck.Checksum.File = CalculateChecksum8 (\r
2200                                                   (UINT8 *) FfsFile,\r
2201                                                   GetLength (FfsFile->Size)\r
2202                                                   );\r
2203       } else {\r
2204         FfsFile->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;\r
2205       }\r
2206 \r
2207       FfsFile->State = SavedState;\r
2208     }\r
2209   }\r
2210 \r
2211   if ((Flags & 1) == 0 || (\r
2212       FfsFile->Type != EFI_FV_FILETYPE_SECURITY_CORE &&\r
2213       FfsFile->Type != EFI_FV_FILETYPE_PEI_CORE &&\r
2214 \r
2215       FfsFile->Type != EFI_FV_FILETYPE_PEIM &&\r
2216       FfsFile->Type != EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER\r
2217       )) {\r
2218     //\r
2219     // Only XIP code may have a TE section\r
2220     //\r
2221     return EFI_SUCCESS;\r
2222   }\r
2223   \r
2224   //\r
2225   // Now process TE sections\r
2226   //\r
2227   for (Index = 1;; Index++) {\r
2228     Status = GetSectionByType (FfsFile, EFI_SECTION_TE, Index, &CurrentPe32Section);\r
2229     if (EFI_ERROR (Status)) {\r
2230       break;\r
2231     }\r
2232 \r
2233     //\r
2234     // Calculate the TE base address, the FFS file base plus the offset of the TE section less the size stripped off\r
2235     // by GenTEImage\r
2236     //\r
2237     TEImageHeader = (EFI_TE_IMAGE_HEADER *) ((UINT8 *) CurrentPe32Section.Pe32Section + sizeof (EFI_COMMON_SECTION_HEADER));\r
2238 \r
2239     //\r
2240     // Initialize context, load image info.\r
2241     //\r
2242     memset (&ImageContext, 0, sizeof (ImageContext));\r
2243     ImageContext.Handle     = (VOID *) TEImageHeader;\r
2244     ImageContext.ImageRead  = (PE_COFF_LOADER_READ_FILE) FfsRebaseImageRead;\r
2245 \r
2246     Status                  = PeCoffLoaderGetImageInfo (&ImageContext);\r
2247 \r
2248     if (EFI_ERROR (Status)) {\r
2249       Error (NULL, 0, 0, "GetImageInfo() call failed on rebase of TE image", FileName);\r
2250       return Status;\r
2251     }\r
2252     //\r
2253     // Don't reload TeImage\r
2254     //\r
2255     ImageContext.ImageAddress = (UINTN) TEImageHeader;\r
2256 \r
2257     //\r
2258     // Reloacate TeImage\r
2259     // \r
2260     ImageContext.DestinationAddress = XipBase + (UINTN) TEImageHeader + sizeof (EFI_TE_IMAGE_HEADER) \\r
2261                                       - TEImageHeader->StrippedSize - (UINTN) FfsFile;\r
2262     Status                          = PeCoffLoaderRelocateImage (&ImageContext);\r
2263     if (EFI_ERROR (Status)) {\r
2264       Error (NULL, 0, 0, "RelocateImage() call failed on rebase of TE image", FileName);\r
2265       return Status;\r
2266     }\r
2267 \r
2268     //\r
2269     // Now update file checksum\r
2270     //\r
2271     if (FfsFile->Attributes & FFS_ATTRIB_CHECKSUM) {\r
2272       SavedState  = FfsFile->State;\r
2273       FfsFile->IntegrityCheck.Checksum.File = 0;\r
2274       FfsFile->State                        = 0;\r
2275       if (FfsFile->Attributes & FFS_ATTRIB_CHECKSUM) {\r
2276         FfsFile->IntegrityCheck.Checksum.File = CalculateChecksum8 (\r
2277                                                   (UINT8 *) FfsFile,\r
2278                                                   GetLength (FfsFile->Size)\r
2279                                                   );\r
2280       } else {\r
2281         FfsFile->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;\r
2282       }\r
2283 \r
2284       FfsFile->State = SavedState;\r
2285     }\r
2286   }\r
2287  \r
2288   return EFI_SUCCESS;\r
2289 }\r
2290 \r
2291 EFI_STATUS\r
2292 FindApResetVectorPosition (\r
2293   IN  MEMORY_FILE  *FvImage,\r
2294   OUT UINT8        **Pointer\r
2295   )\r
2296 {\r
2297   EFI_FFS_FILE_HEADER   *PadFile;\r
2298   UINT32                Index;\r
2299   EFI_STATUS            Status;\r
2300   UINT8                 *FixPoint;\r
2301   UINT32                FileLength;\r
2302 \r
2303   for (Index = 1; ;Index ++) {\r
2304     //\r
2305     // Find Pad File to add ApResetVector info\r
2306     //\r
2307     Status = GetFileByType (EFI_FV_FILETYPE_FFS_PAD, Index, &PadFile);\r
2308     if (EFI_ERROR (Status) || (PadFile == NULL)) {\r
2309       //\r
2310       // No Pad file to be found.\r
2311       //\r
2312       break;\r
2313     }\r
2314     //\r
2315     // Get Pad file size.\r
2316     //\r
2317     FileLength = (*(UINT32 *)(PadFile->Size)) & 0x00FFFFFF;\r
2318     FileLength = (FileLength + EFI_FFS_FILE_HEADER_ALIGNMENT - 1) & ~(EFI_FFS_FILE_HEADER_ALIGNMENT - 1); \r
2319     //\r
2320     // FixPoint must be align on 0x1000 relative to FvImage Header\r
2321     //\r
2322     FixPoint = (UINT8*) PadFile + sizeof (EFI_FFS_FILE_HEADER);\r
2323     FixPoint = FixPoint + 0x1000 - (((UINTN) FixPoint - (UINTN) FvImage->FileImage) & 0xFFF);\r
2324     //\r
2325     // FixPoint be larger at the last place of one fv image.\r
2326     //\r
2327     while (((UINTN) FixPoint + SIZEOF_STARTUP_DATA_ARRAY - (UINTN) PadFile) <= FileLength) {\r
2328       FixPoint += 0x1000;\r
2329     }\r
2330     FixPoint -= 0x1000;\r
2331     \r
2332     if ((UINTN) FixPoint < ((UINTN) PadFile + sizeof (EFI_FFS_FILE_HEADER))) {\r
2333       //\r
2334       // No alignment FixPoint in this Pad File.\r
2335       //\r
2336       continue;\r
2337     }\r
2338 \r
2339     if ((UINTN) FvImage->Eof - (UINTN)FixPoint <= 0x20000) {    \r
2340       //\r
2341       // Find the position to place ApResetVector\r
2342       //\r
2343       *Pointer = FixPoint;\r
2344       return EFI_SUCCESS;\r
2345     }\r
2346   }\r
2347   \r
2348   return EFI_NOT_FOUND;\r
2349 }\r
2350   \r
2351   \r
2352