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