90aa1e8708888cea3bc3e28476d3a9e4876568ea
[people/mcb30/basetools.git] / Source / C / GenFv / GenFvInternalLib.c
1 /** @file\r
2 \r
3 Copyright (c) 2004 - 2008, Intel Corporation                                                         \r
4 All rights reserved. This program and the accompanying materials                          \r
5 are licensed and made available under the terms and conditions of the BSD License         \r
6 which accompanies this distribution.  The full text of the license may be found at        \r
7 http://opensource.org/licenses/bsd-license.php                                            \r
8                                                                                           \r
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     \r
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             \r
11 \r
12 Module Name:\r
13 \r
14   GenFvInternalLib.c\r
15 \r
16 Abstract:\r
17 \r
18   This file contains the internal functions required to generate a Firmware Volume.\r
19 \r
20 **/\r
21 \r
22 //\r
23 // Include files\r
24 //\r
25 #ifdef __GNUC__\r
26 #include <uuid/uuid.h>\r
27 #include <sys/stat.h>\r
28 #endif\r
29 #include <string.h>\r
30 #ifndef __GNUC__\r
31 #include <io.h>\r
32 #endif\r
33 #include <assert.h>\r
34 \r
35 #include "GenFvInternalLib.h"\r
36 #include "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 parameter", "%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", "both %s and %s must be specified.", 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 a 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 enough room to add file %s.", 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 have the same file GUID.", Index1 + 1, Index + 1);\r
771       PrintGuid ((EFI_GUID *) FileBuffer);\r
772       return EFI_INVALID_PARAMETER;\r
773     }\r
774   }\r
775   CopyMem (&mFileGuidArray [Index], FileBuffer, sizeof (EFI_GUID));\r
776 \r
777   //\r
778   // Update the file state based on polarity of the FV.\r
779   //\r
780   UpdateFfsFileState (\r
781     (EFI_FFS_FILE_HEADER *) FileBuffer,\r
782     (EFI_FIRMWARE_VOLUME_HEADER *) FvImage->FileImage\r
783     );\r
784 \r
785   //\r
786   // Check if alignment is required\r
787   //\r
788   ReadFfsAlignment ((EFI_FFS_FILE_HEADER *) FileBuffer, &CurrentFileAlignment);\r
789   \r
790   //\r
791   // Find the largest alignment of all the FFS files in the FV\r
792   //\r
793   if (CurrentFileAlignment > MaxFfsAlignment) {\r
794     MaxFfsAlignment = CurrentFileAlignment;\r
795   }\r
796   //\r
797   // If we have a VTF file, add it at the top.\r
798   //\r
799   if (IsVtfFile ((EFI_FFS_FILE_HEADER *) FileBuffer)) {\r
800     if ((UINTN) *VtfFileImage == (UINTN) FvImage->Eof) {\r
801       //\r
802       // No previous VTF, add this one.\r
803       //\r
804       *VtfFileImage = (EFI_FFS_FILE_HEADER *) (UINTN) ((UINTN) FvImage->FileImage + FvInfo->Size - FileSize);\r
805       //\r
806       // Sanity check. The file MUST align appropriately\r
807       //\r
808       if (((UINTN) *VtfFileImage + sizeof (EFI_FFS_FILE_HEADER) - (UINTN) FvImage->FileImage) % (1 << CurrentFileAlignment)) {\r
809         Error (NULL, 0, 3000, "Invalid", "VTF file cannot be aligned on a %d-byte boundary.", 1 << CurrentFileAlignment);\r
810         free (FileBuffer);\r
811         return EFI_ABORTED;\r
812       }\r
813       //\r
814       // Rebase the PE or TE image in FileBuffer of FFS file for XIP \r
815       // Rebase for the debug genfvmap tool\r
816       //\r
817       FfsRebase (FvInfo, FvInfo->FvFiles[Index], (EFI_FFS_FILE_HEADER *) FileBuffer, (UINTN) *VtfFileImage - (UINTN) FvImage->FileImage, FvMapFile);\r
818       //\r
819       // copy VTF File\r
820       //\r
821       memcpy (*VtfFileImage, FileBuffer, FileSize);\r
822       free (FileBuffer);\r
823       DebugMsg (NULL, 0, 9, "Add VTF FFS file in FV image", NULL);\r
824       return EFI_SUCCESS;\r
825     } else {\r
826       //\r
827       // Already found a VTF file.\r
828       //\r
829       Error (NULL, 0, 3000, "Invalid", "multiple VTF files are not permitted within a single FV.");\r
830       free (FileBuffer);\r
831       return EFI_ABORTED;\r
832     }\r
833   }\r
834 \r
835   //\r
836   // Add pad file if necessary\r
837   //\r
838   Status = AddPadFile (FvImage, 1 << CurrentFileAlignment);\r
839   if (EFI_ERROR (Status)) {\r
840     Error (NULL, 0, 4002, "Resource", "FV space is full, could not add pad file for data alignment property.");\r
841     free (FileBuffer);\r
842     return EFI_ABORTED;\r
843   }\r
844   //\r
845   // Add file\r
846   //\r
847   if ((FvImage->CurrentFilePointer + FileSize) < FvImage->Eof) {\r
848     //\r
849     // Rebase the PE or TE image in FileBuffer of FFS file for XIP. \r
850     // Rebase Bs and Rt drivers for the debug genfvmap tool.\r
851     //\r
852     FfsRebase (FvInfo, FvInfo->FvFiles[Index], (EFI_FFS_FILE_HEADER *) FileBuffer, (UINTN) FvImage->CurrentFilePointer - (UINTN) FvImage->FileImage, FvMapFile);\r
853     //\r
854     // Copy the file\r
855     //\r
856     memcpy (FvImage->CurrentFilePointer, FileBuffer, FileSize);\r
857     FvImage->CurrentFilePointer += FileSize;\r
858   } else {\r
859     Error (NULL, 0, 4002, "Resource", "FV space is full, cannot add file %s.", FvInfo->FvFiles[Index]);\r
860     free (FileBuffer);\r
861     return EFI_ABORTED;\r
862   }\r
863   //\r
864   // Make next file start at QWord Boundry\r
865   //\r
866   while (((UINTN) FvImage->CurrentFilePointer & (EFI_FFS_FILE_HEADER_ALIGNMENT - 1)) != 0) {\r
867     FvImage->CurrentFilePointer++;\r
868   }\r
869 \r
870   //\r
871   // Free allocated memory.\r
872   //\r
873   free (FileBuffer);\r
874 \r
875   return EFI_SUCCESS;\r
876 }\r
877 \r
878 EFI_STATUS\r
879 PadFvImage (\r
880   IN MEMORY_FILE          *FvImage,\r
881   IN EFI_FFS_FILE_HEADER  *VtfFileImage\r
882   )\r
883 /*++\r
884 \r
885 Routine Description:\r
886 \r
887   This function places a pad file between the last file in the FV and the VTF\r
888   file if the VTF file exists.\r
889 \r
890 Arguments:\r
891 \r
892   FvImage       Memory file for the FV memory image\r
893   VtfFileImage  The address of the VTF file.  If this is the end of the FV\r
894                 image, no VTF exists and no pad file is needed.\r
895 \r
896 Returns:\r
897 \r
898   EFI_SUCCESS             Completed successfully.\r
899   EFI_INVALID_PARAMETER   One of the input parameters was NULL.\r
900 \r
901 --*/\r
902 {\r
903   EFI_FFS_FILE_HEADER *PadFile;\r
904   UINTN               FileSize;\r
905 \r
906   //\r
907   // If there is no VTF or the VTF naturally follows the previous file without a\r
908   // pad file, then there's nothing to do\r
909   //\r
910   if ((UINTN) VtfFileImage == (UINTN) FvImage->Eof || \\r
911       ((UINTN) VtfFileImage == (UINTN) FvImage->CurrentFilePointer)) {\r
912     return EFI_SUCCESS;\r
913   }\r
914 \r
915   //\r
916   // Pad file starts at beginning of free space\r
917   //\r
918   PadFile = (EFI_FFS_FILE_HEADER *) FvImage->CurrentFilePointer;\r
919 \r
920   //\r
921   // write PadFile FFS header with PadType, don't need to set PAD file guid in its header. \r
922   //\r
923   PadFile->Type       = EFI_FV_FILETYPE_FFS_PAD;\r
924   PadFile->Attributes = 0;\r
925 \r
926   //\r
927   // FileSize includes the EFI_FFS_FILE_HEADER\r
928   //\r
929   FileSize          = (UINTN) VtfFileImage - (UINTN) FvImage->CurrentFilePointer;\r
930   PadFile->Size[0]  = (UINT8) (FileSize & 0x000000FF);\r
931   PadFile->Size[1]  = (UINT8) ((FileSize & 0x0000FF00) >> 8);\r
932   PadFile->Size[2]  = (UINT8) ((FileSize & 0x00FF0000) >> 16);\r
933 \r
934   //\r
935   // Fill in checksums and state, must be zero during checksum calculation.\r
936   //\r
937   PadFile->IntegrityCheck.Checksum.Header = 0;\r
938   PadFile->IntegrityCheck.Checksum.File   = 0;\r
939   PadFile->State                          = 0;\r
940   PadFile->IntegrityCheck.Checksum.Header = CalculateChecksum8 ((UINT8 *) PadFile, sizeof (EFI_FFS_FILE_HEADER));\r
941   if (PadFile->Attributes & FFS_ATTRIB_CHECKSUM) {\r
942     PadFile->IntegrityCheck.Checksum.File = CalculateChecksum8 ((UINT8 *) PadFile, FileSize);\r
943   } else {\r
944     PadFile->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;\r
945   }\r
946 \r
947   PadFile->State = EFI_FILE_HEADER_CONSTRUCTION | EFI_FILE_HEADER_VALID | EFI_FILE_DATA_VALID;\r
948 \r
949   UpdateFfsFileState (\r
950     (EFI_FFS_FILE_HEADER *) PadFile,\r
951     (EFI_FIRMWARE_VOLUME_HEADER *) FvImage->FileImage\r
952     );\r
953   //\r
954   // Update the current FV pointer\r
955   //\r
956   FvImage->CurrentFilePointer = FvImage->Eof;\r
957 \r
958   return EFI_SUCCESS;\r
959 }\r
960 \r
961 EFI_STATUS\r
962 UpdateResetVector (\r
963   IN MEMORY_FILE            *FvImage,\r
964   IN FV_INFO                *FvInfo,\r
965   IN EFI_FFS_FILE_HEADER    *VtfFile\r
966   )\r
967 /*++\r
968 \r
969 Routine Description:\r
970 \r
971   This parses the FV looking for the PEI core and then plugs the address into\r
972   the SALE_ENTRY point of the BSF/VTF for IPF and does BUGBUG TBD action to\r
973   complete an IA32 Bootstrap FV.\r
974 \r
975 Arguments:\r
976 \r
977   FvImage       Memory file for the FV memory image\r
978   FvInfo        Information read from INF file.\r
979   VtfFile       Pointer to the VTF file in the FV image.\r
980 \r
981 Returns:\r
982 \r
983   EFI_SUCCESS             Function Completed successfully.\r
984   EFI_ABORTED             Error encountered.\r
985   EFI_INVALID_PARAMETER   A required parameter was NULL.\r
986   EFI_NOT_FOUND           PEI Core file not found.\r
987 \r
988 --*/\r
989 {\r
990   EFI_FFS_FILE_HEADER       *PeiCoreFile;\r
991   EFI_FFS_FILE_HEADER       *SecCoreFile;\r
992   EFI_STATUS                Status;\r
993   EFI_FILE_SECTION_POINTER  Pe32Section;\r
994   UINT32                    EntryPoint;\r
995   UINT32                    BaseOfCode;\r
996   UINT16                    MachineType;\r
997   EFI_PHYSICAL_ADDRESS      PeiCorePhysicalAddress;\r
998   EFI_PHYSICAL_ADDRESS      SecCorePhysicalAddress;\r
999   EFI_PHYSICAL_ADDRESS      *SecCoreEntryAddressPtr;\r
1000   INT32                     Ia32SecEntryOffset;\r
1001   UINT32                    *Ia32ResetAddressPtr;\r
1002   UINT8                     *BytePointer;\r
1003   UINT8                     *BytePointer2;\r
1004   UINT16                    *WordPointer;\r
1005   UINT16                    CheckSum;\r
1006   UINTN                     Index;\r
1007   EFI_FFS_FILE_STATE        SavedState;\r
1008   UINT64                    FitAddress;\r
1009   FIT_TABLE                 *FitTablePtr;\r
1010   UINT32                    IpiVector;\r
1011 \r
1012   //\r
1013   // Verify input parameters\r
1014   //\r
1015   if (FvImage == NULL || FvInfo == NULL || VtfFile == NULL) {\r
1016     return EFI_INVALID_PARAMETER;\r
1017   }\r
1018   //\r
1019   // Initialize FV library\r
1020   //\r
1021   InitializeFvLib (FvImage->FileImage, FvInfo->Size);\r
1022 \r
1023   //\r
1024   // Verify VTF file\r
1025   //\r
1026   Status = VerifyFfsFile (VtfFile);\r
1027   if (EFI_ERROR (Status)) {\r
1028     return EFI_INVALID_PARAMETER;\r
1029   }\r
1030 \r
1031   //\r
1032   // Find the Sec Core\r
1033   //\r
1034   Status = GetFileByType (EFI_FV_FILETYPE_SECURITY_CORE, 1, &SecCoreFile);\r
1035   if (EFI_ERROR (Status) || SecCoreFile == NULL) {\r
1036     Error (NULL, 0, 3000, "Invalid", "could not find the SEC core file in the FV.");\r
1037     return EFI_ABORTED;\r
1038   }\r
1039   //\r
1040   // Sec Core found, now find PE32 section\r
1041   //\r
1042   Status = GetSectionByType (SecCoreFile, EFI_SECTION_PE32, 1, &Pe32Section);\r
1043   if (Status == EFI_NOT_FOUND) {\r
1044     Status = GetSectionByType (SecCoreFile, EFI_SECTION_TE, 1, &Pe32Section);\r
1045   }\r
1046 \r
1047   if (EFI_ERROR (Status)) {\r
1048     Error (NULL, 0, 3000, "Invalid", "could not find a PE32 section in the SEC core file.");\r
1049     return EFI_ABORTED;\r
1050   }\r
1051 \r
1052   Status = GetPe32Info (\r
1053             (VOID *) ((UINTN) Pe32Section.Pe32Section + sizeof (EFI_SECTION_PE32)),\r
1054             &EntryPoint,\r
1055             &BaseOfCode,\r
1056             &MachineType\r
1057             );\r
1058 \r
1059   if (EFI_ERROR (Status)) {\r
1060     Error (NULL, 0, 3000, "Invalid", "could not get the PE32 entry point for the SEC core.");\r
1061     return EFI_ABORTED;\r
1062   }\r
1063   //\r
1064   // Physical address is FV base + offset of PE32 + offset of the entry point\r
1065   //\r
1066   SecCorePhysicalAddress = FvInfo->BaseAddress;\r
1067   SecCorePhysicalAddress += (UINTN) Pe32Section.Pe32Section + sizeof (EFI_SECTION_PE32) - (UINTN) FvImage->FileImage;\r
1068   SecCorePhysicalAddress += EntryPoint;\r
1069   DebugMsg (NULL, 0, 9, "SecCore physical entry point address", "Address = 0x%X", SecCorePhysicalAddress); \r
1070 \r
1071   //\r
1072   // Find the PEI Core\r
1073   //\r
1074   Status = GetFileByType (EFI_FV_FILETYPE_PEI_CORE, 1, &PeiCoreFile);\r
1075   if (EFI_ERROR (Status) || PeiCoreFile == NULL) {\r
1076     Error (NULL, 0, 3000, "Invalid", "could not find the PEI core in the FV.");\r
1077     return EFI_ABORTED;\r
1078   }\r
1079   //\r
1080   // PEI Core found, now find PE32 or TE section\r
1081   //\r
1082   Status = GetSectionByType (PeiCoreFile, EFI_SECTION_PE32, 1, &Pe32Section);\r
1083   if (Status == EFI_NOT_FOUND) {\r
1084     Status = GetSectionByType (PeiCoreFile, EFI_SECTION_TE, 1, &Pe32Section);\r
1085   }\r
1086 \r
1087   if (EFI_ERROR (Status)) {\r
1088     Error (NULL, 0, 3000, "Invalid", "could not find either a PE32 or a TE section in PEI core file.");\r
1089     return EFI_ABORTED;\r
1090   }\r
1091 \r
1092   Status = GetPe32Info (\r
1093             (VOID *) ((UINTN) Pe32Section.Pe32Section + sizeof (EFI_SECTION_PE32)),\r
1094             &EntryPoint,\r
1095             &BaseOfCode,\r
1096             &MachineType\r
1097             );\r
1098 \r
1099   if (EFI_ERROR (Status)) {\r
1100     Error (NULL, 0, 3000, "Invalid", "could not get the PE32 entry point for the PEI core.");\r
1101     return EFI_ABORTED;\r
1102   }\r
1103   //\r
1104   // Physical address is FV base + offset of PE32 + offset of the entry point\r
1105   //\r
1106   PeiCorePhysicalAddress = FvInfo->BaseAddress;\r
1107   PeiCorePhysicalAddress += (UINTN) Pe32Section.Pe32Section + sizeof (EFI_SECTION_PE32) - (UINTN) FvImage->FileImage;\r
1108   PeiCorePhysicalAddress += EntryPoint;\r
1109   DebugMsg (NULL, 0, 9, "PeiCore physical entry point address", "Address = 0x%X", PeiCorePhysicalAddress);\r
1110 \r
1111   if (MachineType == EFI_IMAGE_MACHINE_IA64) {\r
1112     //\r
1113     // Update PEI_CORE address\r
1114     //\r
1115     //\r
1116     // Set the uncached attribute bit in the physical address\r
1117     //\r
1118     PeiCorePhysicalAddress |= 0x8000000000000000ULL;\r
1119 \r
1120     //\r
1121     // Check if address is aligned on a 16 byte boundary\r
1122     //\r
1123     if (PeiCorePhysicalAddress & 0xF) {\r
1124       Error (NULL, 0, 3000, "Invalid",\r
1125         "PEI_CORE entry point is not aligned on a 16 byte boundary, address specified is %Xh.",\r
1126         PeiCorePhysicalAddress\r
1127         );\r
1128       return EFI_ABORTED;\r
1129     }\r
1130     //\r
1131     // First Get the FIT table address\r
1132     //\r
1133     FitAddress  = (*(UINT64 *) (FvImage->Eof - IPF_FIT_ADDRESS_OFFSET)) & 0xFFFFFFFF;\r
1134 \r
1135     FitTablePtr = (FIT_TABLE *) (FvImage->FileImage + (FitAddress - FvInfo->BaseAddress));\r
1136 \r
1137     Status      = UpdatePeiCoreEntryInFit (FitTablePtr, PeiCorePhysicalAddress);\r
1138 \r
1139     if (!EFI_ERROR (Status)) {\r
1140       UpdateFitCheckSum (FitTablePtr);\r
1141     }\r
1142 \r
1143     //\r
1144     // Update SEC_CORE address\r
1145     //\r
1146     //\r
1147     // Set the uncached attribute bit in the physical address\r
1148     //\r
1149     SecCorePhysicalAddress |= 0x8000000000000000ULL;\r
1150     //\r
1151     // Check if address is aligned on a 16 byte boundary\r
1152     //\r
1153     if (SecCorePhysicalAddress & 0xF) {\r
1154       Error (NULL, 0, 3000, "Invalid",\r
1155         "SALE_ENTRY entry point is not aligned on a 16 byte boundary, address specified is %Xh.",\r
1156         SecCorePhysicalAddress\r
1157         );\r
1158       return EFI_ABORTED;\r
1159     }\r
1160     //\r
1161     // Update the address\r
1162     //\r
1163     SecCoreEntryAddressPtr  = (EFI_PHYSICAL_ADDRESS *) ((UINTN) FvImage->Eof - IPF_SALE_ENTRY_ADDRESS_OFFSET);\r
1164     *SecCoreEntryAddressPtr = SecCorePhysicalAddress;\r
1165 \r
1166   } else if (MachineType == EFI_IMAGE_MACHINE_IA32) {\r
1167     //\r
1168     // Get the location to update\r
1169     //\r
1170     Ia32ResetAddressPtr  = (UINT32 *) ((UINTN) FvImage->Eof - IA32_PEI_CORE_ENTRY_OFFSET);\r
1171 \r
1172     //\r
1173     // Write lower 32 bits of physical address for Pei Core entry\r
1174     //\r
1175     *Ia32ResetAddressPtr = (UINT32) PeiCorePhysicalAddress;\r
1176     \r
1177     //\r
1178     // Write SecCore Entry point relative address into the jmp instruction in reset vector.\r
1179     // \r
1180     Ia32ResetAddressPtr  = (UINT32 *) ((UINTN) FvImage->Eof - IA32_SEC_CORE_ENTRY_OFFSET);\r
1181     \r
1182     Ia32SecEntryOffset   = SecCorePhysicalAddress - (FV_IMAGES_TOP_ADDRESS - IA32_SEC_CORE_ENTRY_OFFSET + 2);\r
1183     if (Ia32SecEntryOffset <= -65536) {\r
1184       Error (NULL, 0, 3000, "Invalid", "The SEC EXE file size is too large, it must be less than 64K.");\r
1185       return STATUS_ERROR;\r
1186     }\r
1187     \r
1188     *(UINT16 *) Ia32ResetAddressPtr = (UINT16) Ia32SecEntryOffset;\r
1189 \r
1190     //\r
1191     // Update the BFV base address\r
1192     //\r
1193     Ia32ResetAddressPtr   = (UINT32 *) ((UINTN) FvImage->Eof - 4);\r
1194     *Ia32ResetAddressPtr  = (UINT32) (FvInfo->BaseAddress);\r
1195     DebugMsg (NULL, 0, 9, "update BFV base address in the top FV image", "BFV base address = 0x%X.", FvInfo->BaseAddress);\r
1196 \r
1197     //\r
1198     // Update the Startup AP in the FVH header block ZeroVector region.\r
1199     //\r
1200     BytePointer   = (UINT8 *) ((UINTN) FvImage->FileImage);\r
1201     if (FvInfo->Size == 0x10000) {\r
1202       BytePointer2 = m64kRecoveryStartupApDataArray;\r
1203     } else if (FvInfo->Size == 0x20000) {\r
1204       BytePointer2 = m128kRecoveryStartupApDataArray;\r
1205     } else if (FvInfo->Size > 0x20000) {\r
1206       BytePointer2 = m128kRecoveryStartupApDataArray;\r
1207       //\r
1208       // Find the position to place Ap reset vector, the offset\r
1209       // between the position and the end of Fvrecovery.fv file\r
1210       // should not exceed 128kB to prevent Ap reset vector from\r
1211       // outside legacy E and F segment\r
1212       //\r
1213       Status = FindApResetVectorPosition (FvImage, &BytePointer);\r
1214       if (EFI_ERROR (Status)) {\r
1215         Error (NULL, 0, 3000, "Invalid", "Cannot find the appropriate location in FvImage to add Ap reset vector!");\r
1216         return EFI_ABORTED;\r
1217       }\r
1218     }\r
1219 \r
1220     for (Index = 0; Index < SIZEOF_STARTUP_DATA_ARRAY; Index++) {\r
1221       BytePointer[Index] = BytePointer2[Index];\r
1222     }\r
1223     //\r
1224     // Calculate the checksum\r
1225     //\r
1226     CheckSum              = 0x0000;\r
1227     WordPointer = (UINT16 *) (BytePointer);\r
1228     for (Index = 0; Index < SIZEOF_STARTUP_DATA_ARRAY / 2; Index++) {\r
1229       CheckSum = (UINT16) (CheckSum + ((UINT16) *WordPointer));\r
1230       WordPointer++;\r
1231     }\r
1232     //\r
1233     // Update the checksum field\r
1234     //\r
1235     WordPointer   = (UINT16 *) (BytePointer + SIZEOF_STARTUP_DATA_ARRAY - 2);\r
1236     *WordPointer  = (UINT16) (0x10000 - (UINT32) CheckSum);\r
1237     \r
1238     //\r
1239     // IpiVector at the 4k aligned address in the top 2 blocks in the PEI FV. \r
1240     //\r
1241     IpiVector  = FV_IMAGES_TOP_ADDRESS - ((UINTN) FvImage->Eof - (UINTN) BytePointer);\r
1242     DebugMsg (NULL, 0, 9, "Startup AP Vector address", "IpiVector at 0x%X", IpiVector);\r
1243     IpiVector  = IpiVector >> 12;\r
1244     IpiVector  = IpiVector & 0xFF;\r
1245 \r
1246     //\r
1247     // Write IPI Vector at Offset FvrecoveryFileSize - 8\r
1248     //\r
1249     Ia32ResetAddressPtr   = (UINT32 *) ((UINTN) FvImage->Eof - 8);\r
1250     *Ia32ResetAddressPtr  = IpiVector;\r
1251   } else {\r
1252     Error (NULL, 0, 3000, "Invalid", "machine type=0x%X in PEI core.", (UINT32) MachineType);\r
1253     return EFI_ABORTED;\r
1254   }\r
1255 \r
1256   //\r
1257   // Now update file checksum\r
1258   //\r
1259   SavedState  = VtfFile->State;\r
1260   VtfFile->IntegrityCheck.Checksum.File = 0;\r
1261   VtfFile->State                        = 0;\r
1262   if (VtfFile->Attributes & FFS_ATTRIB_CHECKSUM) {\r
1263     VtfFile->IntegrityCheck.Checksum.File = CalculateChecksum8 (\r
1264                                               (UINT8 *) VtfFile,\r
1265                                               GetLength (VtfFile->Size)\r
1266                                               );\r
1267   } else {\r
1268     VtfFile->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;\r
1269   }\r
1270 \r
1271   VtfFile->State = SavedState;\r
1272 \r
1273   return EFI_SUCCESS;\r
1274 }\r
1275 \r
1276 EFI_STATUS\r
1277 GetPe32Info (\r
1278   IN UINT8                  *Pe32,\r
1279   OUT UINT32                *EntryPoint,\r
1280   OUT UINT32                *BaseOfCode,\r
1281   OUT UINT16                *MachineType\r
1282   )\r
1283 /*++\r
1284 \r
1285 Routine Description:\r
1286 \r
1287   Retrieves the PE32 entry point offset and machine type from PE image or TeImage.  \r
1288   See EfiImage.h for machine types.  The entry point offset is from the beginning \r
1289   of the PE32 buffer passed in.\r
1290 \r
1291 Arguments:\r
1292 \r
1293   Pe32          Beginning of the PE32.\r
1294   EntryPoint    Offset from the beginning of the PE32 to the image entry point.\r
1295   BaseOfCode    Base address of code.\r
1296   MachineType   Magic number for the machine type.\r
1297 \r
1298 Returns:\r
1299 \r
1300   EFI_SUCCESS             Function completed successfully.\r
1301   EFI_ABORTED             Error encountered.\r
1302   EFI_INVALID_PARAMETER   A required parameter was NULL.\r
1303   EFI_UNSUPPORTED         The operation is unsupported.\r
1304 \r
1305 --*/\r
1306 {\r
1307   EFI_IMAGE_DOS_HEADER  *DosHeader;\r
1308   EFI_IMAGE_NT_HEADERS  *NtHeader;\r
1309   EFI_TE_IMAGE_HEADER   *TeHeader;\r
1310 \r
1311   //\r
1312   // Verify input parameters\r
1313   //\r
1314   if (Pe32 == NULL) {\r
1315     return EFI_INVALID_PARAMETER;\r
1316   }\r
1317 \r
1318   //\r
1319   // First check whether it is one TE Image.\r
1320   //\r
1321   TeHeader = (EFI_TE_IMAGE_HEADER *) Pe32;\r
1322   if (TeHeader->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {\r
1323     //\r
1324     // By TeImage Header to get output\r
1325     //\r
1326     *EntryPoint   = TeHeader->AddressOfEntryPoint + sizeof (EFI_TE_IMAGE_HEADER) - TeHeader->StrippedSize;\r
1327     *BaseOfCode   = TeHeader->BaseOfCode + sizeof (EFI_TE_IMAGE_HEADER) - TeHeader->StrippedSize;\r
1328     *MachineType  = TeHeader->Machine;\r
1329   } else {\r
1330   \r
1331     //\r
1332     // Then check whether \r
1333     // First is the DOS header\r
1334     //\r
1335     DosHeader = (EFI_IMAGE_DOS_HEADER *) Pe32;\r
1336   \r
1337     //\r
1338     // Verify DOS header is expected\r
1339     //\r
1340     if (DosHeader->e_magic != EFI_IMAGE_DOS_SIGNATURE) {\r
1341       Error (NULL, 0, 3000, "Invalid", "Unknown magic number in the DOS header, 0x%04X.", DosHeader->e_magic);\r
1342       return EFI_UNSUPPORTED;\r
1343     }\r
1344     //\r
1345     // Immediately following is the NT header.\r
1346     //\r
1347     NtHeader = (EFI_IMAGE_NT_HEADERS *) ((UINTN) Pe32 + DosHeader->e_lfanew);\r
1348   \r
1349     //\r
1350     // Verify NT header is expected\r
1351     //\r
1352     if (NtHeader->Signature != EFI_IMAGE_NT_SIGNATURE) {\r
1353       Error (NULL, 0, 3000, "Invalid", "Unrecognized image signature 0x%08X.", NtHeader->Signature);\r
1354       return EFI_UNSUPPORTED;\r
1355     }\r
1356     //\r
1357     // Get output\r
1358     //\r
1359     *EntryPoint   = NtHeader->OptionalHeader.AddressOfEntryPoint;\r
1360     *BaseOfCode   = NtHeader->OptionalHeader.BaseOfCode;\r
1361     *MachineType  = NtHeader->FileHeader.Machine;\r
1362   }\r
1363 \r
1364   //\r
1365   // Verify machine type is supported\r
1366   //\r
1367   if (*MachineType != EFI_IMAGE_MACHINE_IA32 && *MachineType != EFI_IMAGE_MACHINE_IA64 && *MachineType != EFI_IMAGE_MACHINE_X64 && *MachineType != EFI_IMAGE_MACHINE_EBC) {\r
1368     Error (NULL, 0, 3000, "Invalid", "Unrecognized machine type in the PE32 file.");\r
1369     return EFI_UNSUPPORTED;\r
1370   }\r
1371 \r
1372   return EFI_SUCCESS;\r
1373 }\r
1374 \r
1375 EFI_STATUS\r
1376 GenerateFvImage (\r
1377   IN CHAR8                *InfFileImage,\r
1378   IN UINTN                InfFileSize,\r
1379   IN CHAR8                *FvFileName,\r
1380   IN CHAR8                *MapFileName,\r
1381   IN EFI_PHYSICAL_ADDRESS XipBaseAddress,\r
1382   IN EFI_PHYSICAL_ADDRESS *BtBaseAddress,\r
1383   IN EFI_PHYSICAL_ADDRESS *RtBaseAddress\r
1384   )\r
1385 /*++\r
1386 \r
1387 Routine Description:\r
1388 \r
1389   This is the main function which will be called from application.\r
1390 \r
1391 Arguments:\r
1392 \r
1393   InfFileImage   Buffer containing the INF file contents.\r
1394   InfFileSize    Size of the contents of the InfFileImage buffer.\r
1395   FvFileName     Requested name for the FV file.\r
1396   MapFileName    Fv map file to log fv driver information.\r
1397   XipBaseAddress BaseAddress is to be rebased.\r
1398   BtBaseAddress  Pointer to BaseAddress is to set the prefer loaded image start address for boot drivers.\r
1399   RtBaseAddress  Pointer to BaseAddress is to set the prefer loaded image start address for runtime drivers.\r
1400 \r
1401 Returns:\r
1402 \r
1403   EFI_SUCCESS             Function completed successfully.\r
1404   EFI_OUT_OF_RESOURCES    Could not allocate required resources.\r
1405   EFI_ABORTED             Error encountered.\r
1406   EFI_INVALID_PARAMETER   A required parameter was NULL.\r
1407 \r
1408 --*/\r
1409 {\r
1410   EFI_STATUS                  Status;\r
1411   MEMORY_FILE                 InfMemoryFile;\r
1412   MEMORY_FILE                 FvImageMemoryFile;\r
1413   FV_INFO                     FvInfo;\r
1414   UINTN                       Index;\r
1415   EFI_FIRMWARE_VOLUME_HEADER  *FvHeader;\r
1416   EFI_FFS_FILE_HEADER         *VtfFileImage;\r
1417   UINT8                       *FvBufferHeader; // to make sure fvimage header 8 type alignment.\r
1418   UINT8                       *FvImage;\r
1419   UINTN                       FvImageSize;\r
1420   FILE                        *FvFile;\r
1421   CHAR8                       FvMapName [_MAX_PATH];\r
1422   FILE                        *FvMapFile;\r
1423 \r
1424   FvBufferHeader = NULL;\r
1425   FvFile         = NULL;\r
1426   FvMapFile      = NULL;\r
1427   //\r
1428   // Check for invalid parameter\r
1429   //\r
1430   if (InfFileImage == NULL) {\r
1431     return EFI_INVALID_PARAMETER;\r
1432   }\r
1433 \r
1434   //\r
1435   // Initialize file structures\r
1436   //\r
1437   InfMemoryFile.FileImage           = InfFileImage;\r
1438   InfMemoryFile.CurrentFilePointer  = InfFileImage;\r
1439   InfMemoryFile.Eof                 = InfFileImage + InfFileSize;\r
1440 \r
1441   //\r
1442   // Parse the FV inf file for header information\r
1443   //\r
1444   Status = ParseFvInf (&InfMemoryFile, &FvInfo);\r
1445   if (EFI_ERROR (Status)) {\r
1446     Error (NULL, 0, 0003, "Error parsing file", "the input INF file.");\r
1447     return Status;\r
1448   }\r
1449 \r
1450   //\r
1451   // Update the file name return values\r
1452   //\r
1453   if (FvFileName == NULL && FvInfo.FvName[0] != '\0') {\r
1454     FvFileName = FvInfo.FvName;\r
1455   }\r
1456 \r
1457   if (FvFileName == NULL) {\r
1458     Error (NULL, 0, 1001, "Missing option", "Output file name");\r
1459     return EFI_ABORTED;\r
1460   }\r
1461   \r
1462   //\r
1463   // FvMap file to log the function address of all modules in one Fvimage\r
1464   //\r
1465   if (MapFileName != NULL) {\r
1466     strcpy (FvMapName, MapFileName);\r
1467   } else {\r
1468     strcpy (FvMapName, FvFileName);\r
1469     strcat (FvMapName, ".map");\r
1470   }\r
1471   VerboseMsg ("FV Map file name is %s", FvMapName);\r
1472 \r
1473   FvMapFile = fopen (FvMapName, "w");\r
1474   if (FvMapFile == NULL) {\r
1475     Error (NULL, 0, 0001, "Error opening file", FvMapName);\r
1476     return EFI_ABORTED;\r
1477   }\r
1478   \r
1479   //\r
1480   // Update FvImage Base Address, XipBase not same to BtBase, RtBase address.\r
1481   //\r
1482   if (XipBaseAddress != 0) {\r
1483     FvInfo.BaseAddress = XipBaseAddress;\r
1484   }\r
1485   if (*BtBaseAddress != 0) {\r
1486     FvInfo.BootBaseAddress = *BtBaseAddress;\r
1487   }\r
1488   if (*RtBaseAddress != 0) {\r
1489     FvInfo.RuntimeBaseAddress = *RtBaseAddress;\r
1490   }\r
1491 \r
1492   //\r
1493   // Calculate the FV size and Update Fv Size based on the actual FFS files.\r
1494   // And Update FvInfo data.\r
1495   //\r
1496   Status = CalculateFvSize (&FvInfo);\r
1497   if (EFI_ERROR (Status)) {\r
1498     return Status;    \r
1499   }\r
1500   VerboseMsg ("the generated FV image size is %d bytes", FvInfo.Size);\r
1501   \r
1502   //\r
1503   // support fv image and empty fv image\r
1504   //\r
1505   FvImageSize = FvInfo.Size;\r
1506 \r
1507   //\r
1508   // Allocate the FV, assure FvImage Header 8 byte alignment\r
1509   //\r
1510   FvBufferHeader = malloc (FvImageSize + sizeof (UINT64));\r
1511   if (FvBufferHeader == NULL) {\r
1512     return EFI_OUT_OF_RESOURCES;\r
1513   }\r
1514   FvImage = (UINT8 *) (((UINTN) FvBufferHeader + 7) & ~7);\r
1515 \r
1516   //\r
1517   // Initialize the FV to the erase polarity\r
1518   //\r
1519   if (FvInfo.FvAttributes & EFI_FVB2_ERASE_POLARITY) {\r
1520     memset (FvImage, -1, FvImageSize);\r
1521   } else {\r
1522     memset (FvImage, 0, FvImageSize);\r
1523   }\r
1524 \r
1525   //\r
1526   // Initialize FV header\r
1527   //\r
1528   FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) FvImage;\r
1529 \r
1530   //\r
1531   // Initialize the zero vector to all zeros.\r
1532   //\r
1533   memset (FvHeader->ZeroVector, 0, 16);\r
1534 \r
1535   //\r
1536   // Copy the FFS GUID\r
1537   //\r
1538   memcpy (&FvHeader->FileSystemGuid, &FvInfo.FvGuid, sizeof (EFI_GUID));\r
1539 \r
1540   FvHeader->FvLength        = FvImageSize;\r
1541   FvHeader->Signature       = EFI_FVH_SIGNATURE;\r
1542   FvHeader->Attributes      = FvInfo.FvAttributes;\r
1543   FvHeader->Revision        = EFI_FVH_REVISION;\r
1544   FvHeader->ExtHeaderOffset = 0;\r
1545   FvHeader->Reserved[0]     = 0;\r
1546   \r
1547   //\r
1548   // Copy firmware block map\r
1549   //\r
1550   for (Index = 0; FvInfo.FvBlocks[Index].Length != 0; Index++) {\r
1551     FvHeader->BlockMap[Index].NumBlocks   = FvInfo.FvBlocks[Index].NumBlocks;\r
1552     FvHeader->BlockMap[Index].Length      = FvInfo.FvBlocks[Index].Length;\r
1553   }\r
1554 \r
1555   //\r
1556   // Add block map terminator\r
1557   //\r
1558   FvHeader->BlockMap[Index].NumBlocks   = 0;\r
1559   FvHeader->BlockMap[Index].Length      = 0;\r
1560 \r
1561   //\r
1562   // Complete the header\r
1563   //\r
1564   FvHeader->HeaderLength  = (UINT16) (((UINTN) &(FvHeader->BlockMap[Index + 1])) - (UINTN) FvImage);\r
1565   FvHeader->Checksum      = 0;\r
1566   FvHeader->Checksum      = CalculateChecksum16 ((UINT16 *) FvHeader, FvHeader->HeaderLength / sizeof (UINT16));\r
1567 \r
1568   //\r
1569   // If there is no FFS file, generate one empty FV\r
1570   //\r
1571   if (FvInfo.FvFiles[0][0] == 0) {\r
1572     goto WriteFile;\r
1573   }\r
1574 \r
1575   //\r
1576   // Initialize our "file" view of the buffer\r
1577   //\r
1578   FvImageMemoryFile.FileImage           = FvImage;\r
1579   FvImageMemoryFile.CurrentFilePointer  = FvImage + FvHeader->HeaderLength;\r
1580   FvImageMemoryFile.Eof                 = FvImage + FvImageSize;\r
1581 \r
1582   //\r
1583   // Initialize the FV library.\r
1584   //\r
1585   InitializeFvLib (FvImageMemoryFile.FileImage, FvImageSize);\r
1586 \r
1587   //\r
1588   // Initialize the VTF file address.\r
1589   //\r
1590   VtfFileImage = (EFI_FFS_FILE_HEADER *) FvImageMemoryFile.Eof;\r
1591 \r
1592   //\r
1593   // Add files to FV\r
1594   //\r
1595   for (Index = 0; FvInfo.FvFiles[Index][0] != 0; Index++) {\r
1596     //\r
1597     // Add the file\r
1598     //\r
1599     Status = AddFile (&FvImageMemoryFile, &FvInfo, Index, &VtfFileImage, FvMapFile);\r
1600 \r
1601     //\r
1602     // Exit if error detected while adding the file\r
1603     //\r
1604     if (EFI_ERROR (Status)) {\r
1605       goto Finish;\r
1606     }\r
1607   }\r
1608 \r
1609   //\r
1610   // If there is a VTF file, some special actions need to occur.\r
1611   //\r
1612   if ((UINTN) VtfFileImage != (UINTN) FvImageMemoryFile.Eof) {\r
1613     //\r
1614     // Pad from the end of the last file to the beginning of the VTF file.\r
1615     // If the left space is less than sizeof (EFI_FFS_FILE_HEADER)?\r
1616     //\r
1617     Status = PadFvImage (&FvImageMemoryFile, VtfFileImage);\r
1618     if (EFI_ERROR (Status)) {\r
1619       Error (NULL, 0, 4002, "Resource", "FV space is full, cannot add pad file between the last file and the VTF file.");\r
1620       goto Finish;\r
1621     }\r
1622     //\r
1623     // Update reset vector (SALE_ENTRY for IPF)\r
1624     // Now for IA32 and IA64 platform, the fv which has bsf file must have the \r
1625     // EndAddress of 0xFFFFFFFF. Thus, only this type fv needs to update the   \r
1626     // reset vector. If the PEI Core is found, the VTF file will probably get  \r
1627     // corrupted by updating the entry point.                                  \r
1628     //\r
1629     if ((FvInfo.BaseAddress + FvInfo.Size) == FV_IMAGES_TOP_ADDRESS) {       \r
1630       Status = UpdateResetVector (&FvImageMemoryFile, &FvInfo, VtfFileImage);\r
1631       if (EFI_ERROR(Status)) {                                               \r
1632         Error (NULL, 0, 3000, "Invalid", "Could not update the reset vector.");\r
1633         goto Finish;                                              \r
1634       }\r
1635       DebugMsg (NULL, 0, 9, "Update Reset vector in VTF file", NULL);\r
1636     }\r
1637   } \r
1638   \r
1639   //\r
1640   // Update FV Alignment attribute to the largest alignment of all the FFS files in the FV\r
1641   //\r
1642   if ((((FvHeader->Attributes & EFI_FVB2_ALIGNMENT) >> 16)) < MaxFfsAlignment) {\r
1643     FvHeader->Attributes = ((MaxFfsAlignment << 16) | (FvHeader->Attributes & 0xFFFF));\r
1644     //\r
1645     // Update Checksum for FvHeader\r
1646     //\r
1647     FvHeader->Checksum      = 0;\r
1648     FvHeader->Checksum      = CalculateChecksum16 ((UINT16 *) FvHeader, FvHeader->HeaderLength / sizeof (UINT16));\r
1649   }\r
1650 \r
1651 WriteFile: \r
1652   //\r
1653   // Write fv file\r
1654   //\r
1655   FvFile = fopen (FvFileName, "wb");\r
1656   if (FvFile == NULL) {\r
1657     Error (NULL, 0, 0001, "Error opening file", FvFileName);\r
1658     Status = EFI_ABORTED;\r
1659     goto Finish;\r
1660   }\r
1661 \r
1662   if (fwrite (FvImage, 1, FvImageSize, FvFile) != FvImageSize) {\r
1663     Error (NULL, 0, 0002, "Error writing file", FvFileName);\r
1664     Status = EFI_ABORTED;\r
1665     goto Finish;\r
1666   }\r
1667 \r
1668 Finish:\r
1669   if (FvBufferHeader != NULL) {\r
1670     free (FvBufferHeader);\r
1671   }\r
1672   \r
1673   if (FvFile != NULL) {\r
1674     fclose (FvFile);\r
1675   }\r
1676   \r
1677   if (FvMapFile != NULL) {\r
1678     fclose (FvMapFile);\r
1679   }\r
1680 \r
1681   //\r
1682   // Update BootAddress and RuntimeAddress\r
1683   //\r
1684   *BtBaseAddress = FvInfo.BootBaseAddress;\r
1685   *RtBaseAddress = FvInfo.RuntimeBaseAddress;\r
1686 \r
1687   return Status;\r
1688 }\r
1689 \r
1690 EFI_STATUS\r
1691 UpdatePeiCoreEntryInFit (\r
1692   IN FIT_TABLE     *FitTablePtr,\r
1693   IN UINT64        PeiCorePhysicalAddress\r
1694   )\r
1695 /*++\r
1696 \r
1697 Routine Description:\r
1698 \r
1699   This function is used to update the Pei Core address in FIT, this can be used by Sec core to pass control from\r
1700   Sec to Pei Core\r
1701 \r
1702 Arguments:\r
1703 \r
1704   FitTablePtr             - The pointer of FIT_TABLE.\r
1705   PeiCorePhysicalAddress  - The address of Pei Core entry.\r
1706 \r
1707 Returns:\r
1708 \r
1709   EFI_SUCCESS             - The PEI_CORE FIT entry was updated successfully.\r
1710   EFI_NOT_FOUND           - Not found the PEI_CORE FIT entry.\r
1711 \r
1712 --*/\r
1713 {\r
1714   FIT_TABLE *TmpFitPtr;\r
1715   UINTN     Index;\r
1716   UINTN     NumFitComponents;\r
1717 \r
1718   TmpFitPtr         = FitTablePtr;\r
1719   NumFitComponents  = TmpFitPtr->CompSize;\r
1720 \r
1721   for (Index = 0; Index < NumFitComponents; Index++) {\r
1722     if ((TmpFitPtr->CvAndType & FIT_TYPE_MASK) == COMP_TYPE_FIT_PEICORE) {\r
1723       TmpFitPtr->CompAddress = PeiCorePhysicalAddress;\r
1724       return EFI_SUCCESS;\r
1725     }\r
1726 \r
1727     TmpFitPtr++;\r
1728   }\r
1729 \r
1730   return EFI_NOT_FOUND;\r
1731 }\r
1732 \r
1733 VOID\r
1734 UpdateFitCheckSum (\r
1735   IN FIT_TABLE   *FitTablePtr\r
1736   )\r
1737 /*++\r
1738 \r
1739 Routine Description:\r
1740 \r
1741   This function is used to update the checksum for FIT.\r
1742 \r
1743 \r
1744 Arguments:\r
1745 \r
1746   FitTablePtr             - The pointer of FIT_TABLE.\r
1747 \r
1748 Returns:\r
1749 \r
1750   None.\r
1751 \r
1752 --*/\r
1753 {\r
1754   if ((FitTablePtr->CvAndType & CHECKSUM_BIT_MASK) >> 7) {\r
1755     FitTablePtr->CheckSum = 0;\r
1756     FitTablePtr->CheckSum = CalculateChecksum8 ((UINT8 *) FitTablePtr, FitTablePtr->CompSize * 16);\r
1757   }\r
1758 }\r
1759 \r
1760 EFI_STATUS\r
1761 CalculateFvSize (\r
1762   FV_INFO *FvInfoPtr\r
1763   )\r
1764 /*++\r
1765 Routine Description:\r
1766   Calculate the FV size and Update Fv Size based on the actual FFS files.\r
1767   And Update FvInfo data.\r
1768 \r
1769 Arguments:\r
1770   FvInfoPtr     - The pointer to FV_INFO structure.\r
1771 \r
1772 Returns:\r
1773   EFI_ABORTED   - Ffs Image Error\r
1774   EFI_SUCCESS   - Successfully update FvSize\r
1775 --*/\r
1776 {\r
1777   UINTN               CurrentOffset;\r
1778   UINTN               Index;\r
1779   FILE                *fpin;\r
1780   UINTN               FfsFileSize;\r
1781   UINT32              FfsAlignment;\r
1782   EFI_FFS_FILE_HEADER FfsHeader;\r
1783   EFI_STATUS          Status;\r
1784   BOOLEAN             VtfFileFlag;\r
1785   \r
1786   VtfFileFlag = FALSE;\r
1787   fpin  = NULL;\r
1788   Index = 0;\r
1789   CurrentOffset = sizeof (EFI_FIRMWARE_VOLUME_HEADER);\r
1790   \r
1791   for (Index = 1;; Index ++) {\r
1792     CurrentOffset += sizeof (EFI_FV_BLOCK_MAP_ENTRY);\r
1793     if (FvInfoPtr->FvBlocks[Index].NumBlocks == 0 && FvInfoPtr->FvBlocks[Index].Length == 0) {\r
1794       break;\r
1795     }\r
1796   }\r
1797 \r
1798   //\r
1799   // Accumlate every FFS file size.\r
1800   //\r
1801   for (Index = 0; FvInfoPtr->FvFiles[Index][0] != 0; Index++) {\r
1802     //\r
1803     // Open FFS file\r
1804     //\r
1805     fpin = NULL;\r
1806     fpin = fopen (FvInfoPtr->FvFiles[Index], "rb");\r
1807     if (fpin == NULL) {\r
1808       Error (NULL, 0, 0001, "Error opening file", FvInfoPtr->FvFiles[Index]);\r
1809       return EFI_ABORTED;\r
1810     }\r
1811     //\r
1812     // Get the file size\r
1813     //\r
1814     FfsFileSize = _filelength (fileno (fpin));\r
1815     //\r
1816     // Read Ffs File header\r
1817     //\r
1818     fread (&FfsHeader, sizeof (UINT8), sizeof (EFI_FFS_FILE_HEADER), fpin);\r
1819     //\r
1820     // close file\r
1821     //\r
1822     fclose (fpin);\r
1823     //\r
1824     // Check whether this ffs file is vtf file\r
1825     //\r
1826     if (IsVtfFile (&FfsHeader)) {\r
1827       if (VtfFileFlag) {\r
1828         //\r
1829         // One Fv image can't have two vtf files.\r
1830         //\r
1831         return EFI_ABORTED;\r
1832       }\r
1833       VtfFileFlag = TRUE;\r
1834       //\r
1835       // The space between Vft File and the latest file must be able to contain \r
1836       // one ffs file header in order to add one pad file.\r
1837       //\r
1838       CurrentOffset += sizeof (EFI_FFS_FILE_HEADER);\r
1839     }\r
1840     //\r
1841     // Get the alignment of FFS file \r
1842     //\r
1843     ReadFfsAlignment (&FfsHeader, &FfsAlignment);\r
1844     FfsAlignment = 1 << FfsAlignment;\r
1845     //\r
1846     // Add Pad file\r
1847     //\r
1848     if (((CurrentOffset + sizeof (EFI_FFS_FILE_HEADER)) % FfsAlignment) != 0) {\r
1849       CurrentOffset = (CurrentOffset + sizeof (EFI_FFS_FILE_HEADER) * 2 + FfsAlignment - 1) & ~(FfsAlignment - 1);\r
1850       CurrentOffset -= sizeof (EFI_FFS_FILE_HEADER);\r
1851     }\r
1852     //\r
1853     // Add ffs file size\r
1854     //\r
1855     CurrentOffset += FfsFileSize;    \r
1856     //\r
1857     // Make next ffs file start at QWord Boundry\r
1858     //\r
1859     CurrentOffset = (CurrentOffset + EFI_FFS_FILE_HEADER_ALIGNMENT - 1) & ~(EFI_FFS_FILE_HEADER_ALIGNMENT - 1);\r
1860   }\r
1861   \r
1862   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
1863   \r
1864   if (FvInfoPtr->Size < CurrentOffset) { \r
1865     //\r
1866     // Update FvInfo data\r
1867     //\r
1868     FvInfoPtr->FvBlocks[0].NumBlocks = CurrentOffset / FvInfoPtr->FvBlocks[0].Length + ((CurrentOffset % FvInfoPtr->FvBlocks[0].Length)?1:0);\r
1869     FvInfoPtr->Size = FvInfoPtr->FvBlocks[0].NumBlocks * FvInfoPtr->FvBlocks[0].Length;\r
1870     FvInfoPtr->FvBlocks[1].NumBlocks = 0;\r
1871     FvInfoPtr->FvBlocks[1].Length = 0;\r
1872   }\r
1873 \r
1874   return EFI_SUCCESS;\r
1875 }\r
1876 \r
1877 EFI_STATUS\r
1878 FfsRebaseImageRead (\r
1879   IN     VOID    *FileHandle,\r
1880   IN     UINTN   FileOffset,\r
1881   IN OUT UINT32  *ReadSize,\r
1882   OUT    VOID    *Buffer\r
1883   )\r
1884 /*++\r
1885 \r
1886 Routine Description:\r
1887 \r
1888   Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file\r
1889 \r
1890 Arguments:\r
1891 \r
1892   FileHandle - The handle to the PE/COFF file\r
1893 \r
1894   FileOffset - The offset, in bytes, into the file to read\r
1895 \r
1896   ReadSize   - The number of bytes to read from the file starting at FileOffset\r
1897 \r
1898   Buffer     - A pointer to the buffer to read the data into.\r
1899 \r
1900 Returns:\r
1901 \r
1902   EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset\r
1903 \r
1904 --*/\r
1905 {\r
1906   CHAR8   *Destination8;\r
1907   CHAR8   *Source8;\r
1908   UINT32  Length;\r
1909 \r
1910   Destination8  = Buffer;\r
1911   Source8       = (CHAR8 *) ((UINTN) FileHandle + FileOffset);\r
1912   Length        = *ReadSize;\r
1913   while (Length--) {\r
1914     *(Destination8++) = *(Source8++);\r
1915   }\r
1916 \r
1917   return EFI_SUCCESS;\r
1918 }\r
1919 \r
1920 EFI_STATUS\r
1921 FfsRebase ( \r
1922   IN OUT  FV_INFO               *FvInfo, \r
1923   IN      CHAR8                 *FileName,           \r
1924   IN OUT  EFI_FFS_FILE_HEADER   *FfsFile,\r
1925   IN      UINTN                 XipOffset,\r
1926   IN      FILE                  *FvMapFile\r
1927   )\r
1928 /*++\r
1929 \r
1930 Routine Description:\r
1931 \r
1932   This function determines if a file is XIP and should be rebased.  It will\r
1933   rebase any PE32 sections found in the file using the base address.\r
1934 \r
1935 Arguments:\r
1936   \r
1937   FvInfo            A pointer to FV_INFO struture.\r
1938   FileName          Ffs File PathName\r
1939   FfsFile           A pointer to Ffs file image.\r
1940   XipOffset         The offset address to use for rebasing the XIP file image.\r
1941   FvMapFile         FvMapFile to record the function address in one Fvimage\r
1942 \r
1943 Returns:\r
1944 \r
1945   EFI_SUCCESS             The image was properly rebased.\r
1946   EFI_INVALID_PARAMETER   An input parameter is invalid.\r
1947   EFI_ABORTED             An error occurred while rebasing the input file image.\r
1948   EFI_OUT_OF_RESOURCES    Could not allocate a required resource.\r
1949   EFI_NOT_FOUND           No compressed sections could be found.\r
1950 \r
1951 --*/\r
1952 {\r
1953   EFI_STATUS                            Status;\r
1954   PE_COFF_LOADER_IMAGE_CONTEXT          ImageContext;\r
1955   EFI_PHYSICAL_ADDRESS                  XipBase;\r
1956   EFI_PHYSICAL_ADDRESS                  NewPe32BaseAddress;\r
1957   EFI_PHYSICAL_ADDRESS                  *BaseToUpdate;\r
1958   UINTN                                 Index;\r
1959   EFI_FILE_SECTION_POINTER              CurrentPe32Section;\r
1960   EFI_FFS_FILE_STATE                    SavedState;\r
1961   EFI_IMAGE_NT_HEADERS                  *PeHdr;\r
1962   EFI_IMAGE_OPTIONAL_HEADER32           *Optional32;\r
1963   EFI_IMAGE_OPTIONAL_HEADER64           *Optional64;\r
1964   EFI_TE_IMAGE_HEADER                   *TEImageHeader;\r
1965   UINT8                                 Flags;\r
1966   UINT8                                 *MemoryImagePointer;\r
1967   EFI_IMAGE_SECTION_HEADER              *SectionHeader;\r
1968   CHAR8                                 PeFileName [_MAX_PATH];\r
1969   CHAR8                                 *Cptr;\r
1970   FILE                                  *PeFile;\r
1971   UINT8                                 *PeFileBuffer;\r
1972   UINT32                                PeFileSize;\r
1973 \r
1974   Index              = 0;  \r
1975   MemoryImagePointer = NULL;\r
1976   BaseToUpdate       = NULL;\r
1977   TEImageHeader      = NULL;\r
1978   PeHdr              = NULL;\r
1979   Optional32         = NULL;\r
1980   Optional64         = NULL;\r
1981   SectionHeader      = NULL;\r
1982   Cptr               = NULL;\r
1983   PeFile             = NULL;\r
1984   PeFileBuffer       = NULL;\r
1985   //\r
1986   // Check XipAddress, BootAddress and RuntimeAddress\r
1987   //\r
1988   Flags = 0;\r
1989 \r
1990   if (FvInfo->BaseAddress != 0) {\r
1991     Flags  |= REBASE_XIP_FILE;\r
1992     XipBase = FvInfo->BaseAddress + XipOffset;\r
1993   }\r
1994   if (FvInfo->BootBaseAddress != 0) {\r
1995     Flags  |= REBASE_BOOTTIME_FILE;\r
1996   }\r
1997   if (FvInfo->RuntimeBaseAddress != 0) {\r
1998     Flags  |= REBASE_RUNTIME_FILE;\r
1999   }\r
2000 \r
2001   //\r
2002   //  Don't Rebase this FFS.\r
2003   //  Only copy the original map file into the FvMap file \r
2004   //  for the image that is not required to be relocated.\r
2005   //\r
2006 \r
2007   //\r
2008   // We only process files potentially containing PE32 sections.\r
2009   //\r
2010   switch (FfsFile->Type) {\r
2011     case EFI_FV_FILETYPE_SECURITY_CORE:\r
2012     case EFI_FV_FILETYPE_PEI_CORE:\r
2013     case EFI_FV_FILETYPE_PEIM:\r
2014     case EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER:\r
2015     case EFI_FV_FILETYPE_DRIVER:\r
2016     case EFI_FV_FILETYPE_DXE_CORE:\r
2017       break;\r
2018     default:\r
2019       return EFI_SUCCESS;\r
2020   }\r
2021 \r
2022   //\r
2023   // Rebase each PE32 section\r
2024   //\r
2025   Status      = EFI_SUCCESS;\r
2026   for (Index = 1;; Index++) {\r
2027     Status = GetSectionByType (FfsFile, EFI_SECTION_PE32, Index, &CurrentPe32Section);\r
2028     if (EFI_ERROR (Status)) {\r
2029       break;\r
2030     }\r
2031 \r
2032     //\r
2033     // Initialize context\r
2034     //\r
2035     memset (&ImageContext, 0, sizeof (ImageContext));\r
2036     ImageContext.Handle     = (VOID *) ((UINTN) CurrentPe32Section.Pe32Section + sizeof (EFI_PE32_SECTION));\r
2037     ImageContext.ImageRead  = (PE_COFF_LOADER_READ_FILE) FfsRebaseImageRead;\r
2038     Status                  = PeCoffLoaderGetImageInfo (&ImageContext);\r
2039     if (EFI_ERROR (Status)) {\r
2040       Error (NULL, 0, 3000, "Invalid", "GetImageInfo() call failed on rebase %s.", FileName);\r
2041       return Status;\r
2042     }\r
2043 \r
2044     //\r
2045     // Get PeHeader pointer\r
2046     //\r
2047     PeHdr = (EFI_IMAGE_NT_HEADERS *)((UINTN) CurrentPe32Section.Pe32Section + sizeof (EFI_PE32_SECTION) + ImageContext.PeCoffHeaderOffset);\r
2048 \r
2049     //\r
2050     // Calculate the PE32 base address, based on file type\r
2051     //\r
2052     switch (FfsFile->Type) {\r
2053       case EFI_FV_FILETYPE_SECURITY_CORE:\r
2054       case EFI_FV_FILETYPE_PEI_CORE:\r
2055       case EFI_FV_FILETYPE_PEIM:\r
2056       case EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER:\r
2057         if ((Flags & REBASE_XIP_FILE) == 0) {\r
2058           //\r
2059           // We aren't relocating XIP code, so skip it.\r
2060           //\r
2061           goto WritePeMap;\r
2062         }\r
2063         \r
2064         //\r
2065         // Check if section-alignment and file-alignment match or not\r
2066         //\r
2067         if ((PeHdr->OptionalHeader.SectionAlignment != PeHdr->OptionalHeader.FileAlignment)) {\r
2068           //\r
2069           // Xip module has the same section alignment and file alignment.\r
2070           //\r
2071           Error (NULL, 0, 3000, "Invalid", "Section-Alignment and File-Alignment do not match : %s.", FileName);\r
2072           return EFI_ABORTED;\r
2073         }\r
2074         //\r
2075         // PeImage has no reloc section. It will try to get reloc data from the original EFI image. \r
2076         //\r
2077         if (ImageContext.RelocationsStripped) {\r
2078           //\r
2079           // Construct the original efi file Name \r
2080           //\r
2081           strcpy (PeFileName, FileName);\r
2082           Cptr = PeFileName + strlen (PeFileName);\r
2083           while (*Cptr != '.') {\r
2084             Cptr --;\r
2085           }\r
2086           if (*Cptr != '.') {\r
2087             Error (NULL, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName);\r
2088             return EFI_ABORTED;\r
2089           } else {\r
2090             *(Cptr + 1) = 'e';\r
2091             *(Cptr + 2) = 'f';\r
2092             *(Cptr + 3) = 'i';\r
2093             *(Cptr + 4) = '\0';\r
2094           }\r
2095           PeFile = fopen (PeFileName, "rb");\r
2096           if (PeFile == NULL) {\r
2097             Error (NULL, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName);\r
2098             return EFI_ABORTED;\r
2099           }\r
2100           //\r
2101           // Get the file size\r
2102           //\r
2103           PeFileSize = _filelength (fileno (PeFile));\r
2104           PeFileBuffer = (UINT8 *) malloc (PeFileSize);\r
2105           if (PeFileBuffer == NULL) {\r
2106             Error (NULL, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName);\r
2107             return EFI_OUT_OF_RESOURCES;\r
2108           }\r
2109           //\r
2110           // Read Pe File\r
2111           //\r
2112           fread (PeFileBuffer, sizeof (UINT8), PeFileSize, PeFile);\r
2113           //\r
2114           // close file\r
2115           //\r
2116           fclose (PeFile);\r
2117           //\r
2118           // Handle pointer to the original efi image.\r
2119           //\r
2120           ImageContext.Handle = PeFileBuffer;\r
2121           Status              = PeCoffLoaderGetImageInfo (&ImageContext);\r
2122           if (EFI_ERROR (Status)) {\r
2123             Error (NULL, 0, 3000, "Invalid", "GetImageInfo() call failed on rebase of %s", FileName);\r
2124             return Status;\r
2125           }\r
2126           ImageContext.RelocationsStripped = FALSE;\r
2127         }\r
2128 \r
2129         NewPe32BaseAddress = XipBase + (UINTN) CurrentPe32Section.Pe32Section + sizeof (EFI_PE32_SECTION) - (UINTN)FfsFile;\r
2130         BaseToUpdate = &XipBase;\r
2131         break;\r
2132 \r
2133       case EFI_FV_FILETYPE_DRIVER:\r
2134         switch (PeHdr->OptionalHeader.Subsystem) {\r
2135           case EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER:\r
2136             if ((Flags & REBASE_RUNTIME_FILE) == 0) {\r
2137               //\r
2138               // RT drivers aren't supposed to be relocated\r
2139               //\r
2140               goto WritePeMap;\r
2141             }\r
2142             //\r
2143             // make sure image base address at the section alignment\r
2144             //\r
2145             FvInfo->RuntimeBaseAddress = (FvInfo->RuntimeBaseAddress - ImageContext.ImageSize) & (~(ImageContext.SectionAlignment - 1));\r
2146             FvInfo->RuntimeBaseAddress = FvInfo->RuntimeBaseAddress & (~(EFI_PAGE_SIZE - 1));\r
2147             NewPe32BaseAddress = FvInfo->RuntimeBaseAddress;\r
2148             BaseToUpdate = &(FvInfo->RuntimeBaseAddress);\r
2149             break;\r
2150 \r
2151           default:\r
2152             //\r
2153             // We treat all other subsystems the same as BS_DRIVER\r
2154             //\r
2155             if ((Flags & REBASE_BOOTTIME_FILE) == 0) {\r
2156               //\r
2157               // Skip all BS_DRIVER's\r
2158               //\r
2159               goto WritePeMap;\r
2160             }\r
2161             //\r
2162             // make sure image base address at the Section and Page alignment\r
2163             //\r
2164             FvInfo->BootBaseAddress = (FvInfo->BootBaseAddress - ImageContext.ImageSize) & (~(ImageContext.SectionAlignment - 1));\r
2165             FvInfo->BootBaseAddress = FvInfo->BootBaseAddress & (~(EFI_PAGE_SIZE - 1));\r
2166             NewPe32BaseAddress = FvInfo->BootBaseAddress;\r
2167             BaseToUpdate = &(FvInfo->BootBaseAddress);\r
2168             break;\r
2169         }\r
2170         break;\r
2171 \r
2172       case EFI_FV_FILETYPE_DXE_CORE:\r
2173         if ((Flags & REBASE_BOOTTIME_FILE) == 0) {\r
2174           //\r
2175           // Skip DXE core, DxeCore only contain one PE image.\r
2176           //\r
2177           goto WritePeMap;\r
2178         }\r
2179         //\r
2180         // make sure image base address at the Section and Page alignment\r
2181         //\r
2182         FvInfo->BootBaseAddress = (FvInfo->BootBaseAddress - ImageContext.ImageSize) & (~(ImageContext.SectionAlignment - 1));\r
2183         FvInfo->BootBaseAddress = FvInfo->BootBaseAddress & (~(EFI_PAGE_SIZE - 1));\r
2184         NewPe32BaseAddress = FvInfo->BootBaseAddress;\r
2185         BaseToUpdate = &(FvInfo->BootBaseAddress);\r
2186         break;\r
2187 \r
2188       default:\r
2189         //\r
2190         // Not supported file type\r
2191         //\r
2192         return EFI_SUCCESS;\r
2193     }\r
2194 \r
2195     //\r
2196     // Load and Relocate Image Data\r
2197     //\r
2198     MemoryImagePointer = (UINT8 *) malloc ((UINTN) ImageContext.ImageSize + ImageContext.SectionAlignment);\r
2199     if (MemoryImagePointer == NULL) {\r
2200       Error (NULL, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName);\r
2201       return EFI_OUT_OF_RESOURCES;\r
2202     }\r
2203     memset ((VOID *) MemoryImagePointer, 0, (UINTN) ImageContext.ImageSize + ImageContext.SectionAlignment);\r
2204     ImageContext.ImageAddress = ((UINTN) MemoryImagePointer + ImageContext.SectionAlignment - 1) & (~(ImageContext.SectionAlignment - 1));\r
2205     \r
2206     Status =  PeCoffLoaderLoadImage (&ImageContext);\r
2207     if (EFI_ERROR (Status)) {\r
2208       Error (NULL, 0, 3000, "Invalid", "LocateImage() call failed on rebase of %s", FileName);\r
2209       free ((VOID *) MemoryImagePointer);\r
2210       return Status;\r
2211     }\r
2212          \r
2213     ImageContext.DestinationAddress = NewPe32BaseAddress;\r
2214     Status                          = PeCoffLoaderRelocateImage (&ImageContext);\r
2215     if (EFI_ERROR (Status)) {\r
2216       Error (NULL, 0, 3000, "Invalid", "RelocateImage() call failed on rebase of %s", FileName);\r
2217       free ((VOID *) MemoryImagePointer);\r
2218       return Status;\r
2219     }\r
2220 \r
2221     //\r
2222     // Copy Relocated data to raw image file.\r
2223     //\r
2224     if (PeHdr->FileHeader.Machine == EFI_IMAGE_MACHINE_IA32) {\r
2225       Optional32 = (EFI_IMAGE_OPTIONAL_HEADER32 *) &(PeHdr->OptionalHeader);\r
2226       Optional32->ImageBase     = (UINT32) NewPe32BaseAddress;\r
2227     } else if (PeHdr->FileHeader.Machine == EFI_IMAGE_MACHINE_IA64 || \r
2228                PeHdr->FileHeader.Machine == EFI_IMAGE_MACHINE_X64) {\r
2229       Optional64 = (EFI_IMAGE_OPTIONAL_HEADER64 *) &(PeHdr->OptionalHeader);\r
2230       Optional64->ImageBase     = NewPe32BaseAddress;\r
2231     } else {\r
2232       Error (NULL, 0, 3000, "Invalid", "unknown machine type %X in PE32 image %s", \r
2233         (UINT32) PeHdr->FileHeader.Machine,\r
2234         FileName\r
2235         );\r
2236       free ((VOID *) MemoryImagePointer);\r
2237       return EFI_ABORTED;\r
2238     }\r
2239 \r
2240     SectionHeader = (EFI_IMAGE_SECTION_HEADER *) (\r
2241                        (UINTN) PeHdr +\r
2242                        sizeof (UINT32) + \r
2243                        sizeof (EFI_IMAGE_FILE_HEADER) +  \r
2244                        PeHdr->FileHeader.SizeOfOptionalHeader\r
2245                        );\r
2246     \r
2247     for (Index = 0; Index < PeHdr->FileHeader.NumberOfSections; Index ++, SectionHeader ++) {\r
2248       CopyMem (\r
2249         (UINT8 *) CurrentPe32Section.Pe32Section + sizeof (EFI_COMMON_SECTION_HEADER) + SectionHeader->PointerToRawData, \r
2250         (VOID*) (UINTN) (ImageContext.ImageAddress + SectionHeader->VirtualAddress), \r
2251         SectionHeader->SizeOfRawData\r
2252         );\r
2253     }\r
2254 \r
2255     free ((VOID *) MemoryImagePointer);\r
2256     MemoryImagePointer = NULL;\r
2257     if (PeFileBuffer != NULL) {\r
2258       free (PeFileBuffer);\r
2259       PeFileBuffer = NULL;\r
2260     }\r
2261 \r
2262     //\r
2263     // Update BASE address by add one page size.\r
2264     //\r
2265     *BaseToUpdate -= EFI_PAGE_SIZE;\r
2266 \r
2267     //\r
2268     // Now update file checksum\r
2269     //\r
2270     if (FfsFile->Attributes & FFS_ATTRIB_CHECKSUM) {\r
2271       SavedState  = FfsFile->State;\r
2272       FfsFile->IntegrityCheck.Checksum.File = 0;\r
2273       FfsFile->State                        = 0;\r
2274       if (FfsFile->Attributes & FFS_ATTRIB_CHECKSUM) {\r
2275         FfsFile->IntegrityCheck.Checksum.File = CalculateChecksum8 (\r
2276                                                   (UINT8 *) FfsFile,\r
2277                                                   GetLength (FfsFile->Size)\r
2278                                                   );\r
2279       } else {\r
2280         FfsFile->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;\r
2281       }\r
2282 \r
2283       FfsFile->State = SavedState;\r
2284     }\r
2285 \r
2286     //\r
2287     // Get this module function address from ModulePeMapFile and add them into FvMap file\r
2288     //\r
2289 WritePeMap:\r
2290     WriteMapFile (FvMapFile, FileName, ImageContext.DestinationAddress, PeHdr->OptionalHeader.AddressOfEntryPoint, 0);\r
2291   }\r
2292 \r
2293   if (FfsFile->Type != EFI_FV_FILETYPE_SECURITY_CORE &&\r
2294       FfsFile->Type != EFI_FV_FILETYPE_PEI_CORE &&\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 Peim 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 ((Flags & REBASE_XIP_FILE) == 0) {\r
2334       //\r
2335       // For none XIP PEIM module, their map info also are collected.\r
2336       //\r
2337       goto WriteTeMap;\r
2338     }\r
2339     //\r
2340     // if reloc is stripped, try to get the original efi image to get reloc info.\r
2341     //\r
2342     if (ImageContext.RelocationsStripped == TRUE) {\r
2343       //\r
2344       // Construct the original efi file name \r
2345       //\r
2346       strcpy (PeFileName, FileName);\r
2347       Cptr = PeFileName + strlen (PeFileName);\r
2348       while (*Cptr != '.') {\r
2349         Cptr --;\r
2350       }\r
2351       if (*Cptr != '.') {\r
2352         Error (NULL, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName);\r
2353         return EFI_ABORTED;\r
2354       } else {\r
2355         *(Cptr + 1) = 'e';\r
2356         *(Cptr + 2) = 'f';\r
2357         *(Cptr + 3) = 'i';\r
2358         *(Cptr + 4) = '\0';\r
2359       }\r
2360       PeFile = fopen (PeFileName, "rb");\r
2361       if (PeFile == NULL) {\r
2362         Error (NULL, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName);\r
2363         return EFI_ABORTED;\r
2364       }\r
2365       //\r
2366       // Get the file size\r
2367       //\r
2368       PeFileSize = _filelength (fileno (PeFile));\r
2369       PeFileBuffer = (UINT8 *) malloc (PeFileSize);\r
2370       if (PeFileBuffer == NULL) {\r
2371         Error (NULL, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName);\r
2372         return EFI_OUT_OF_RESOURCES;\r
2373       }\r
2374       //\r
2375       // Read Pe File\r
2376       //\r
2377       fread (PeFileBuffer, sizeof (UINT8), PeFileSize, PeFile);\r
2378       //\r
2379       // close file\r
2380       //\r
2381       fclose (PeFile);\r
2382       //\r
2383       // Append reloc section into TeImage\r
2384       //\r
2385       ImageContext.Handle = PeFileBuffer;\r
2386       Status              = PeCoffLoaderGetImageInfo (&ImageContext);\r
2387       if (EFI_ERROR (Status)) {\r
2388         Error (NULL, 0, 3000, "Invalid", "GetImageInfo() call failed on rebase of TE image %s", FileName);\r
2389         return Status;\r
2390       }\r
2391       ImageContext.RelocationsStripped = FALSE;\r
2392     }\r
2393 \r
2394     //\r
2395     // Load and Relocate Image Data\r
2396     //\r
2397     MemoryImagePointer = (UINT8 *) malloc ((UINTN) ImageContext.ImageSize + ImageContext.SectionAlignment);\r
2398     if (MemoryImagePointer == NULL) {\r
2399       Error (NULL, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName);\r
2400       return EFI_OUT_OF_RESOURCES;\r
2401     }\r
2402     memset ((VOID *) MemoryImagePointer, 0, (UINTN) ImageContext.ImageSize + ImageContext.SectionAlignment);\r
2403     ImageContext.ImageAddress = ((UINTN) MemoryImagePointer + ImageContext.SectionAlignment - 1) & (~(ImageContext.SectionAlignment - 1));\r
2404 \r
2405     Status =  PeCoffLoaderLoadImage (&ImageContext);\r
2406     if (EFI_ERROR (Status)) {\r
2407       Error (NULL, 0, 3000, "Invalid", "LocateImage() call failed on rebase of %s", FileName);\r
2408       free ((VOID *) MemoryImagePointer);\r
2409       return Status;\r
2410     }\r
2411     //\r
2412     // Reloacate TeImage\r
2413     // \r
2414     ImageContext.DestinationAddress = XipBase + (UINTN) TEImageHeader + sizeof (EFI_TE_IMAGE_HEADER) \\r
2415                                       - TEImageHeader->StrippedSize - (UINTN) FfsFile;\r
2416     Status                          = PeCoffLoaderRelocateImage (&ImageContext);\r
2417     if (EFI_ERROR (Status)) {\r
2418       Error (NULL, 0, 3000, "Invalid", "RelocateImage() call failed on rebase of TE image %s", FileName);\r
2419       free ((VOID *) MemoryImagePointer);\r
2420       return Status;\r
2421     }\r
2422     \r
2423     //\r
2424     // Copy the relocated image into raw image file.\r
2425     //\r
2426     TEImageHeader->ImageBase = ImageContext.DestinationAddress;\r
2427     SectionHeader = (EFI_IMAGE_SECTION_HEADER *) (TEImageHeader + 1);\r
2428     for (Index = 0; Index < TEImageHeader->NumberOfSections; Index ++, SectionHeader ++) {\r
2429       if (!ImageContext.IsTeImage) {\r
2430         CopyMem (\r
2431           (UINT8 *) TEImageHeader + sizeof (EFI_TE_IMAGE_HEADER) - TEImageHeader->StrippedSize + SectionHeader->PointerToRawData, \r
2432           (VOID*) (UINTN) (ImageContext.ImageAddress + SectionHeader->VirtualAddress), \r
2433           SectionHeader->SizeOfRawData\r
2434           );\r
2435       } else {\r
2436         CopyMem (\r
2437           (UINT8 *) TEImageHeader + sizeof (EFI_TE_IMAGE_HEADER) - TEImageHeader->StrippedSize + SectionHeader->PointerToRawData, \r
2438           (VOID*) (UINTN) (ImageContext.ImageAddress + sizeof (EFI_TE_IMAGE_HEADER) - TEImageHeader->StrippedSize + SectionHeader->VirtualAddress), \r
2439           SectionHeader->SizeOfRawData\r
2440           );\r
2441       }\r
2442     }\r
2443     \r
2444     //\r
2445     // Free the allocated memory resource\r
2446     //\r
2447     free ((VOID *) MemoryImagePointer);\r
2448     MemoryImagePointer = NULL;\r
2449     if (PeFileBuffer != NULL) {\r
2450       free (PeFileBuffer);\r
2451       PeFileBuffer = NULL;\r
2452     }\r
2453 \r
2454     //\r
2455     // Now update file checksum\r
2456     //\r
2457     if (FfsFile->Attributes & FFS_ATTRIB_CHECKSUM) {\r
2458       SavedState  = FfsFile->State;\r
2459       FfsFile->IntegrityCheck.Checksum.File = 0;\r
2460       FfsFile->State                        = 0;\r
2461       if (FfsFile->Attributes & FFS_ATTRIB_CHECKSUM) {\r
2462         FfsFile->IntegrityCheck.Checksum.File = CalculateChecksum8 (\r
2463                                                   (UINT8 *) FfsFile,\r
2464                                                   GetLength (FfsFile->Size)\r
2465                                                   );\r
2466       } else {\r
2467         FfsFile->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;\r
2468       }\r
2469 \r
2470       FfsFile->State = SavedState;\r
2471     }\r
2472     //\r
2473     // Get this module function address from ModulePeMapFile and add them into FvMap file\r
2474     //\r
2475 WriteTeMap:\r
2476     WriteMapFile (\r
2477       FvMapFile, \r
2478       FileName, \r
2479       ImageContext.DestinationAddress, \r
2480       TEImageHeader->AddressOfEntryPoint, \r
2481       TEImageHeader->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER)\r
2482       );  \r
2483   }\r
2484  \r
2485   return EFI_SUCCESS;\r
2486 }\r
2487 \r
2488 EFI_STATUS\r
2489 FindApResetVectorPosition (\r
2490   IN  MEMORY_FILE  *FvImage,\r
2491   OUT UINT8        **Pointer\r
2492   )\r
2493 /*++\r
2494 \r
2495 Routine Description:\r
2496 \r
2497   Find the position in this FvImage to place Ap reset vector.\r
2498 \r
2499 Arguments:\r
2500 \r
2501   FvImage       Memory file for the FV memory image.\r
2502   Pointer       Pointer to pointer to position.\r
2503 \r
2504 Returns:\r
2505 \r
2506   EFI_NOT_FOUND   - No satisfied position is found.\r
2507   EFI_SUCCESS     - The suitable position is return.\r
2508 \r
2509 --*/\r
2510 {\r
2511   EFI_FFS_FILE_HEADER   *PadFile;\r
2512   UINT32                Index;\r
2513   EFI_STATUS            Status;\r
2514   UINT8                 *FixPoint;\r
2515   UINT32                FileLength;\r
2516 \r
2517   for (Index = 1; ;Index ++) {\r
2518     //\r
2519     // Find Pad File to add ApResetVector info\r
2520     //\r
2521     Status = GetFileByType (EFI_FV_FILETYPE_FFS_PAD, Index, &PadFile);\r
2522     if (EFI_ERROR (Status) || (PadFile == NULL)) {\r
2523       //\r
2524       // No Pad file to be found.\r
2525       //\r
2526       break;\r
2527     }\r
2528     //\r
2529     // Get Pad file size.\r
2530     //\r
2531     FileLength = (*(UINT32 *)(PadFile->Size)) & 0x00FFFFFF;\r
2532     FileLength = (FileLength + EFI_FFS_FILE_HEADER_ALIGNMENT - 1) & ~(EFI_FFS_FILE_HEADER_ALIGNMENT - 1); \r
2533     //\r
2534     // FixPoint must be align on 0x1000 relative to FvImage Header\r
2535     //\r
2536     FixPoint = (UINT8*) PadFile + sizeof (EFI_FFS_FILE_HEADER);\r
2537     FixPoint = FixPoint + 0x1000 - (((UINTN) FixPoint - (UINTN) FvImage->FileImage) & 0xFFF);\r
2538     //\r
2539     // FixPoint be larger at the last place of one fv image.\r
2540     //\r
2541     while (((UINTN) FixPoint + SIZEOF_STARTUP_DATA_ARRAY - (UINTN) PadFile) <= FileLength) {\r
2542       FixPoint += 0x1000;\r
2543     }\r
2544     FixPoint -= 0x1000;\r
2545     \r
2546     if ((UINTN) FixPoint < ((UINTN) PadFile + sizeof (EFI_FFS_FILE_HEADER))) {\r
2547       //\r
2548       // No alignment FixPoint in this Pad File.\r
2549       //\r
2550       continue;\r
2551     }\r
2552 \r
2553     if ((UINTN) FvImage->Eof - (UINTN)FixPoint <= 0x20000) {    \r
2554       //\r
2555       // Find the position to place ApResetVector\r
2556       //\r
2557       *Pointer = FixPoint;\r
2558       return EFI_SUCCESS;\r
2559     }\r
2560   }\r
2561   \r
2562   return EFI_NOT_FOUND;\r
2563 }\r
2564 \r
2565 EFI_STATUS\r
2566 WriteMapFile (\r
2567   IN OUT FILE                  *FvMapFile,\r
2568   IN     CHAR8                 *FileName, \r
2569   IN     EFI_PHYSICAL_ADDRESS  ImageBaseAddress,\r
2570   IN     UINT32                AddressOfEntryPoint,\r
2571   IN     UINT32                Offset\r
2572   )\r
2573 /*++\r
2574 \r
2575 Routine Description:\r
2576 \r
2577   This function abstracts Pe Map file information and add them into FvMap file for Debug.\r
2578 \r
2579 Arguments:\r
2580 \r
2581   FvMapFile             A pointer to FvMap File\r
2582   FileName              Ffs File PathName\r
2583   ImageBaseAddress      PeImage Base Address.\r
2584   AddressOfEntryPoint   EntryPoint address relative to PeBase Address\r
2585   Offset                Offset between TeImage address and original PeImage.\r
2586 \r
2587 Returns:\r
2588 \r
2589   EFI_SUCCESS           Added required map information.\r
2590 \r
2591 --*/\r
2592 {\r
2593   CHAR8           PeMapFileName [_MAX_PATH];\r
2594   CHAR8           *Cptr;\r
2595   CHAR8           *FileGuidName;\r
2596   EFI_GUID        FileGuidValue;\r
2597   FILE            *PeMapFile;\r
2598   CHAR8           Line [MAX_LINE_LEN];\r
2599   CHAR8           KeyWord [MAX_LINE_LEN];\r
2600   CHAR8                 FunctionName [MAX_LINE_LEN];\r
2601   EFI_PHYSICAL_ADDRESS  FunctionAddress;\r
2602   UINT32                FunctionType;\r
2603   CHAR8                 FunctionTypeName [MAX_LINE_LEN];\r
2604   \r
2605   //\r
2606   // Init local variable\r
2607   //\r
2608   FunctionType = 0;\r
2609   \r
2610   //\r
2611   // Construct Map file Name \r
2612   //\r
2613   strcpy (PeMapFileName, FileName);\r
2614   Cptr = PeMapFileName + strlen (PeMapFileName);\r
2615   while (*Cptr != '.') {\r
2616     Cptr --;\r
2617   }\r
2618   if (*Cptr != '.') {\r
2619     return EFI_NOT_FOUND;\r
2620   } else {\r
2621     *(Cptr + 1) = 'm';\r
2622     *(Cptr + 2) = 'a';\r
2623     *(Cptr + 3) = 'p';\r
2624     *(Cptr + 4) = '\0';\r
2625   }\r
2626   //\r
2627   // Open PeMapFile\r
2628   //\r
2629   PeMapFile = fopen (PeMapFileName, "r");\r
2630   if (PeMapFile == NULL) {\r
2631     // fprintf (stdout, "can't open %s file to reading\n", PeMapFileName);\r
2632     return EFI_ABORTED;\r
2633   }\r
2634   //\r
2635   // Get Module Guid from FileName\r
2636   //\r
2637   *Cptr = '\0';\r
2638   while ((*Cptr != FILE_SEP_CHAR) && (Cptr >= PeMapFileName)) {\r
2639     Cptr --;\r
2640   }\r
2641   if (*Cptr == FILE_SEP_CHAR) {\r
2642     FileGuidName = Cptr + 1;\r
2643     if (StringToGuid (FileGuidName, &FileGuidValue) != EFI_SUCCESS) {\r
2644       FileGuidName = NULL;\r
2645     }\r
2646   }\r
2647   //\r
2648   // Output Functions information into Fv Map file\r
2649   //\r
2650   fgets (Line, MAX_LINE_LEN, PeMapFile);\r
2651   sscanf (Line, "%s", KeyWord);\r
2652   //\r
2653   // module information output\r
2654   //\r
2655   if (ImageBaseAddress == 0) {\r
2656     fprintf (FvMapFile, "%s (dummy) (", KeyWord);\r
2657     fprintf (FvMapFile, "BaseAddress=%08lx, ", ImageBaseAddress);\r
2658   } else {\r
2659     fprintf (FvMapFile, "%s (", KeyWord);\r
2660     fprintf (FvMapFile, "BaseAddress=%08lx, ", ImageBaseAddress + Offset);\r
2661   }\r
2662   fprintf (FvMapFile, "EntryPoint=%08lx, ", ImageBaseAddress + AddressOfEntryPoint);\r
2663   if (FileGuidName != NULL) {\r
2664     fprintf (FvMapFile, "GUID=%s", FileGuidName);\r
2665   }\r
2666   fprintf (FvMapFile, ")\n\n");\r
2667 \r
2668   while (fgets (Line, MAX_LINE_LEN, PeMapFile) != NULL) {\r
2669     //\r
2670     // Skip blank line\r
2671     //\r
2672     if (Line[0] == 0x0a) {\r
2673       FunctionType = 0;\r
2674       continue;\r
2675     }\r
2676     //\r
2677     // By Address and Static keyword\r
2678     //  \r
2679     if (FunctionType == 0) {\r
2680       sscanf (Line, "%s", KeyWord);\r
2681       if (stricmp (KeyWord, "Address") == 0) {\r
2682         //\r
2683         // function list\r
2684         //\r
2685         FunctionType = 1;\r
2686         fgets (Line, MAX_LINE_LEN, PeMapFile);\r
2687       } else if (stricmp (KeyWord, "Static") == 0) {\r
2688         //\r
2689         // static function list\r
2690         //\r
2691         FunctionType = 2;\r
2692         fgets (Line, MAX_LINE_LEN, PeMapFile);\r
2693       }\r
2694       continue;\r
2695     }\r
2696     //\r
2697     // Printf Function Information\r
2698     //\r
2699     if (FunctionType == 1) {\r
2700       sscanf (Line, "%s %s %lx %s", KeyWord, FunctionName, &FunctionAddress, FunctionTypeName);\r
2701       if (FunctionTypeName [1] == '\0' && (FunctionTypeName [0] == 'f' || FunctionTypeName [0] == 'F')) {\r
2702         fprintf (FvMapFile, "  %016lx ", ImageBaseAddress + FunctionAddress);\r
2703         fprintf (FvMapFile, "(%08lx) F  ", FunctionAddress - Offset);\r
2704         fprintf (FvMapFile, "%s\n", FunctionName);\r
2705     } else {\r
2706         fprintf (FvMapFile, "  %016lx ", ImageBaseAddress + FunctionAddress);\r
2707         fprintf (FvMapFile, "(%08lx)    ", FunctionAddress - Offset);\r
2708         fprintf (FvMapFile, "%s\n", FunctionName);\r
2709       }\r
2710     } else if (FunctionType == 2) {\r
2711       sscanf (Line, "%s %s %lx %s", KeyWord, FunctionName, &FunctionAddress, FunctionTypeName);\r
2712       if (FunctionTypeName [1] == '\0' && (FunctionTypeName [0] == 'f' || FunctionTypeName [0] == 'F')) {\r
2713         fprintf (FvMapFile, "  %016lx ", ImageBaseAddress + FunctionAddress);\r
2714         fprintf (FvMapFile, "(%08lx) FS ", FunctionAddress - Offset);\r
2715         fprintf (FvMapFile, "%s\n", FunctionName);\r
2716       } else {\r
2717         fprintf (FvMapFile, "  %016lx ", ImageBaseAddress + FunctionAddress);\r
2718         fprintf (FvMapFile, "(%08lx)    ", FunctionAddress - Offset);\r
2719         fprintf (FvMapFile, "%s\n", FunctionName);\r
2720       }\r
2721     }\r
2722   }\r
2723   //\r
2724   // Close PeMap file\r
2725   //\r
2726   fprintf (FvMapFile, "\n\n");\r
2727   fclose (PeMapFile);\r
2728   \r
2729   return EFI_SUCCESS;\r
2730 }\r
2731 \r
2732 EFI_STATUS\r
2733 ParseCapInf (\r
2734   IN  MEMORY_FILE  *InfFile,\r
2735   OUT CAP_INFO     *CapInfo\r
2736   )\r
2737 /*++\r
2738 \r
2739 Routine Description:\r
2740 \r
2741   This function parses a Cap.INF file and copies info into a CAP_INFO structure.\r
2742 \r
2743 Arguments:\r
2744 \r
2745   InfFile        Memory file image.\r
2746   CapInfo        Information read from INF file.\r
2747 \r
2748 Returns:\r
2749 \r
2750   EFI_SUCCESS       INF file information successfully retrieved.\r
2751   EFI_ABORTED       INF file has an invalid format.\r
2752   EFI_NOT_FOUND     A required string was not found in the INF file.\r
2753 --*/\r
2754 {\r
2755   CHAR8       Value[_MAX_PATH];\r
2756   UINT64      Value64;\r
2757   UINTN       Index;\r
2758   EFI_STATUS  Status;\r
2759 \r
2760   //\r
2761   // Initialize Cap info\r
2762   //\r
2763   memset (CapInfo, 0, sizeof (CAP_INFO));\r
2764 \r
2765   //\r
2766   // Read the Capsule Guid\r
2767   //\r
2768   Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_CAPSULE_GUID_STRING, 0, Value);\r
2769   if (Status == EFI_SUCCESS) {\r
2770     //\r
2771     // Get the Capsule Guid\r
2772     //\r
2773     Status = StringToGuid (Value, &CapInfo->CapGuid);\r
2774     if (EFI_ERROR (Status)) {\r
2775       Error (NULL, 0, 2000, "Invalid parameter", "%s = %s", EFI_CAPSULE_GUID_STRING, Value);\r
2776       return EFI_ABORTED;\r
2777     }\r
2778     DebugMsg (NULL, 0, 9, "Capsule Guid", "%s = %s", EFI_CAPSULE_GUID_STRING, Value);\r
2779   } else {\r
2780     Error (NULL, 0, 2001, "Missing required argument", EFI_CAPSULE_GUID_STRING);\r
2781     return EFI_ABORTED;\r
2782   }\r
2783 \r
2784   //\r
2785   // Read the Capsule Header Size\r
2786   //\r
2787   Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_CAPSULE_HEADER_SIZE_STRING, 0, Value);\r
2788   if (Status == EFI_SUCCESS) {\r
2789     Status = AsciiStringToUint64 (Value, FALSE, &Value64);\r
2790     if (EFI_ERROR (Status)) {\r
2791       Error (NULL, 0, 2000, "Invalid parameter", "%s = %s", EFI_CAPSULE_HEADER_SIZE_STRING, Value);\r
2792       return EFI_ABORTED;\r
2793     }\r
2794     CapInfo->HeaderSize = (UINT32) Value64;\r
2795     DebugMsg (NULL, 0, 9, "Capsule Header size", "%s = %s", EFI_CAPSULE_HEADER_SIZE_STRING, Value);\r
2796   }\r
2797 \r
2798   //\r
2799   // Read the Capsule Flag\r
2800   //\r
2801   Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_CAPSULE_FLAGS_STRING, 0, Value);\r
2802   if (Status == EFI_SUCCESS) {\r
2803     if (strstr (Value, "PopulateSystemTable") != NULL) {\r
2804       CapInfo->Flags |= CAPSULE_FLAGS_PERSIST_ACROSS_RESET | CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE;\r
2805     } else if (strstr (Value, "PersistAcrossReset") != NULL) {\r
2806       CapInfo->Flags |= CAPSULE_FLAGS_PERSIST_ACROSS_RESET; \r
2807     } else {\r
2808       Error (NULL, 0, 2000, "Invalid parameter", "invalid Flag setting for %s.", EFI_CAPSULE_FLAGS_STRING);\r
2809       return EFI_ABORTED;\r
2810     }\r
2811     DebugMsg (NULL, 0, 9, "Capsule Flag", Value);\r
2812   }\r
2813 \r
2814   //\r
2815   // Read Capsule File name\r
2816   //\r
2817   Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_FILE_NAME_STRING, 0, Value);\r
2818   if (Status == EFI_SUCCESS) {\r
2819     //\r
2820     // Get output file name\r
2821     //\r
2822     strcpy (CapInfo->CapName, Value);\r
2823   }\r
2824 \r
2825   //\r
2826   // Read the Capsule FileImage\r
2827   //\r
2828   for (Index = 0; Index < MAX_NUMBER_OF_FILES_IN_CAP; Index++) {\r
2829     //\r
2830     // Read the capsule file name\r
2831     //\r
2832     Status = FindToken (InfFile, FILES_SECTION_STRING, EFI_FILE_NAME_STRING, Index, Value);\r
2833 \r
2834     if (Status == EFI_SUCCESS) {\r
2835       //\r
2836       // Add the file\r
2837       //\r
2838       strcpy (CapInfo->CapFiles[Index], Value);\r
2839       DebugMsg (NULL, 0, 9, "Capsule component file", "the %dth file name is %s", Index, CapInfo->CapFiles[Index]); \r
2840     } else {\r
2841       break;\r
2842     }\r
2843   }\r
2844   \r
2845   if (Index == 0) {\r
2846     Warning (NULL, 0, 0, "Capsule components are not specified.", NULL);\r
2847   }\r
2848 \r
2849   return EFI_SUCCESS;\r
2850 }\r
2851 \r
2852 EFI_STATUS\r
2853 GenerateCapImage (\r
2854   IN CHAR8                *InfFileImage,\r
2855   IN UINTN                InfFileSize,\r
2856   IN CHAR8                *CapFileName\r
2857   )\r
2858 /*++\r
2859 \r
2860 Routine Description:\r
2861 \r
2862   This is the main function which will be called from application to create UEFI Capsule image.\r
2863 \r
2864 Arguments:\r
2865 \r
2866   InfFileImage   Buffer containing the INF file contents.\r
2867   InfFileSize    Size of the contents of the InfFileImage buffer.\r
2868   CapFileName    Requested name for the Cap file.\r
2869 \r
2870 Returns:\r
2871 \r
2872   EFI_SUCCESS             Function completed successfully.\r
2873   EFI_OUT_OF_RESOURCES    Could not allocate required resources.\r
2874   EFI_ABORTED             Error encountered.\r
2875   EFI_INVALID_PARAMETER   A required parameter was NULL.\r
2876 \r
2877 --*/\r
2878 {\r
2879   UINT32                CapSize;\r
2880   UINT8                 *CapBuffer;\r
2881   EFI_CAPSULE_HEADER    *CapsuleHeader;\r
2882   MEMORY_FILE           InfMemoryFile;\r
2883   UINT32                FileSize;\r
2884   UINT32                Index;\r
2885   FILE                  *fpin, *fpout;\r
2886   EFI_STATUS            Status;\r
2887   CAP_INFO              CapInfo;\r
2888 \r
2889   //\r
2890   // Initialize file structures\r
2891   //\r
2892   InfMemoryFile.FileImage           = InfFileImage;\r
2893   InfMemoryFile.CurrentFilePointer  = InfFileImage;\r
2894   InfMemoryFile.Eof                 = InfFileImage + InfFileSize;\r
2895 \r
2896   //\r
2897   // Parse the Cap inf file for header information\r
2898   //\r
2899   Status = ParseCapInf (&InfMemoryFile, &CapInfo);\r
2900   if (Status != EFI_SUCCESS) {\r
2901     return Status;\r
2902   }\r
2903   \r
2904   if (CapInfo.HeaderSize == 0) {\r
2905     CapInfo.HeaderSize = sizeof (EFI_CAPSULE_HEADER);\r
2906   }\r
2907 \r
2908   if (CapInfo.HeaderSize < sizeof (EFI_CAPSULE_HEADER)) {\r
2909     Error (NULL, 0, 2000, "Invalid parameter", "The specified HeaderSize cannot be less than the size of EFI_CAPSULE_HEADER.");\r
2910     return EFI_INVALID_PARAMETER;\r
2911   }\r
2912   \r
2913   if (CapFileName == NULL && CapInfo.CapName[0] != '\0') {\r
2914     CapFileName = CapInfo.CapName;\r
2915   }\r
2916   \r
2917   if (CapFileName == NULL) {\r
2918     Error (NULL, 0, 2001, "Missing required argument", "Output Capsule file name");\r
2919     return EFI_INVALID_PARAMETER;\r
2920   }\r
2921 \r
2922   //\r
2923   // Calculate the size of capsule image.\r
2924   //\r
2925   Index    = 0;\r
2926   FileSize = 0;\r
2927   CapSize  = CapInfo.HeaderSize;\r
2928   while (CapInfo.CapFiles [Index][0] != '\0') {\r
2929     fpin = fopen (CapInfo.CapFiles[Index], "rb");\r
2930     if (fpin == NULL) {\r
2931       Error (NULL, 0, 0001, "Error opening file", CapInfo.CapFiles[Index]);\r
2932       return EFI_ABORTED;\r
2933     }\r
2934     FileSize  = _filelength (fileno (fpin));\r
2935     CapSize  += FileSize;\r
2936     fclose (fpin);\r
2937     Index ++;\r
2938   }\r
2939 \r
2940   //\r
2941   // Allocate buffer for capsule image.\r
2942   //\r
2943   CapBuffer = (UINT8 *) malloc (CapSize);\r
2944   if (CapBuffer == NULL) {\r
2945     Error (NULL, 0, 4001, "Resource", "memory cannot be allocated for creating the capsule.");\r
2946     return EFI_OUT_OF_RESOURCES;\r
2947   }\r
2948 \r
2949   //\r
2950   // Initialize the capsule header to zero\r
2951   //\r
2952   memset (CapBuffer, 0, CapInfo.HeaderSize);\r
2953   \r
2954   //\r
2955   // create capsule header and get capsule body\r
2956   //\r
2957   CapsuleHeader = (EFI_CAPSULE_HEADER *) CapBuffer;\r
2958   memcpy (&CapsuleHeader->CapsuleGuid, &CapInfo.CapGuid, sizeof (EFI_GUID));\r
2959   CapsuleHeader->HeaderSize       = CapInfo.HeaderSize;\r
2960   CapsuleHeader->Flags            = CapInfo.Flags;\r
2961   CapsuleHeader->CapsuleImageSize = CapSize;\r
2962 \r
2963   Index    = 0;\r
2964   FileSize = 0;\r
2965   CapSize  = CapsuleHeader->HeaderSize;\r
2966   while (CapInfo.CapFiles [Index][0] != '\0') {\r
2967     fpin = fopen (CapInfo.CapFiles[Index], "rb");\r
2968     if (fpin == NULL) {\r
2969       Error (NULL, 0, 0001, "Error opening file", CapInfo.CapFiles[Index]);\r
2970       free (CapBuffer);\r
2971       return EFI_ABORTED;\r
2972     }\r
2973     FileSize = _filelength (fileno (fpin));\r
2974     fread (CapBuffer + CapSize, 1, FileSize, fpin);\r
2975     fclose (fpin);\r
2976     Index ++;\r
2977     CapSize += FileSize;\r
2978   }\r
2979   \r
2980   //\r
2981   // write capsule data into the output file\r
2982   //\r
2983   fpout = fopen (CapFileName, "wb");\r
2984   if (fpout == NULL) {\r
2985     Error (NULL, 0, 0001, "Error opening file", CapFileName);\r
2986     free (CapBuffer);\r
2987     return EFI_ABORTED;\r
2988   }\r
2989 \r
2990   fwrite (CapBuffer, 1, CapSize, fpout);\r
2991   fclose (fpout);\r
2992   \r
2993   VerboseMsg ("The size of the generated capsule image is %d bytes", CapSize);\r
2994 \r
2995   return EFI_SUCCESS;\r
2996 }\r