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