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