Fix a bug that file name should be printed
[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   \r
723   //\r
724   // Init local variable\r
725   //\r
726   FunctionType = 0;\r
727   //\r
728   // Print FileGuid to string buffer. \r
729   //\r
730   PrintGuidToBuffer (FileGuidPtr, (UINT8 *)FileGuidName, MAX_LINE_LEN, TRUE);\r
731   \r
732   //\r
733   // Construct Map file Name \r
734   //\r
735   strcpy (PeMapFileName, FileName);\r
736   \r
737   //\r
738   // Change '\\' to '/', unified path format.\r
739   //\r
740   Cptr = PeMapFileName;\r
741   while (*Cptr != '\0') {\r
742     if (*Cptr == '\\') {\r
743       *Cptr = FILE_SEP_CHAR;\r
744     }\r
745     Cptr ++;\r
746   }\r
747   \r
748   //\r
749   // Get Map file\r
750   // \r
751   Cptr = PeMapFileName + strlen (PeMapFileName);\r
752   while ((*Cptr != '.') && (Cptr >= PeMapFileName)) {\r
753     Cptr --;\r
754   }\r
755   if (Cptr < PeMapFileName) {\r
756     return EFI_NOT_FOUND;\r
757   } else {\r
758     *(Cptr + 1) = 'm';\r
759     *(Cptr + 2) = 'a';\r
760     *(Cptr + 3) = 'p';\r
761     *(Cptr + 4) = '\0';\r
762   }\r
763 \r
764   //\r
765   // Get module Name\r
766   //\r
767   Cptr2 = Cptr;\r
768   while ((*Cptr != FILE_SEP_CHAR) && (Cptr >= PeMapFileName)) {\r
769     Cptr --;\r
770   }\r
771         *Cptr2 = '\0';\r
772         strcpy (KeyWord, Cptr + 1);\r
773         *Cptr2 = '.';\r
774 \r
775   //\r
776   // AddressOfEntryPoint and Offset in Image\r
777   //\r
778   if (!pImageContext->IsTeImage) {\r
779         ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *) ((UINT8 *) pImageContext->Handle + pImageContext->PeCoffHeaderOffset);\r
780         AddressOfEntryPoint = ImgHdr->Pe32.OptionalHeader.AddressOfEntryPoint;\r
781         Offset = 0;\r
782     SectionHeader = (EFI_IMAGE_SECTION_HEADER *) (\r
783                        (UINT8 *) ImgHdr +\r
784                        sizeof (UINT32) + \r
785                        sizeof (EFI_IMAGE_FILE_HEADER) +  \r
786                        ImgHdr->Pe32.FileHeader.SizeOfOptionalHeader\r
787                        );\r
788     Index = ImgHdr->Pe32.FileHeader.NumberOfSections;\r
789   } else {\r
790         TEImageHeader = (EFI_TE_IMAGE_HEADER *) pImageContext->Handle;\r
791     AddressOfEntryPoint = TEImageHeader->AddressOfEntryPoint;\r
792     Offset = TEImageHeader->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER);\r
793     SectionHeader = (EFI_IMAGE_SECTION_HEADER *) (TEImageHeader + 1);\r
794     Index = TEImageHeader->NumberOfSections;\r
795   }\r
796   \r
797   //\r
798   // module information output\r
799   //\r
800   if (ImageBaseAddress == 0) {\r
801     fprintf (FvMapFile, "%s (dummy) (", KeyWord);\r
802     fprintf (FvMapFile, "BaseAddress=%010llx, ", (unsigned long long) ImageBaseAddress);\r
803   } else {\r
804     fprintf (FvMapFile, "%s (Fixed Flash Address, ", KeyWord);\r
805     fprintf (FvMapFile, "BaseAddress=0x%010llx, ", (unsigned long long) (ImageBaseAddress + Offset));\r
806   }\r
807   fprintf (FvMapFile, "EntryPoint=0x%010llx", (unsigned long long) (ImageBaseAddress + AddressOfEntryPoint));\r
808   fprintf (FvMapFile, ")\n"); \r
809   \r
810   fprintf (FvMapFile, "(GUID=%s", FileGuidName);\r
811   for (; Index > 0; Index --, SectionHeader ++) {\r
812         if (stricmp ((CHAR8 *)SectionHeader->Name, ".text") == 0) {\r
813                 fprintf (FvMapFile, " .textbaseaddress=0x%010llx", (unsigned long long) (ImageBaseAddress + SectionHeader->VirtualAddress));\r
814         } else if (stricmp ((CHAR8 *)SectionHeader->Name, ".data") == 0) {\r
815           fprintf (FvMapFile, " .databaseaddress=0x%010llx", (unsigned long long) (ImageBaseAddress + SectionHeader->VirtualAddress));\r
816         }\r
817   }\r
818   fprintf (FvMapFile, ")\n\n"); \r
819    \r
820   //\r
821   // Open PeMapFile\r
822   //\r
823   PeMapFile = fopen (PeMapFileName, "r");\r
824   if (PeMapFile == NULL) {\r
825     // fprintf (stdout, "can't open %s file to reading\n", PeMapFileName);\r
826     return EFI_ABORTED;\r
827   }\r
828   VerboseMsg ("The map file is %s", PeMapFileName);\r
829   \r
830   //\r
831   // Output Functions information into Fv Map file\r
832   //\r
833   while (fgets (Line, MAX_LINE_LEN, PeMapFile) != NULL) {\r
834     //\r
835     // Skip blank line\r
836     //\r
837     if (Line[0] == 0x0a) {\r
838       FunctionType = 0;\r
839       continue;\r
840     }\r
841     //\r
842     // By Address and Static keyword\r
843     //  \r
844     if (FunctionType == 0) {\r
845       sscanf (Line, "%s", KeyWord);\r
846       if (stricmp (KeyWord, "Address") == 0) {\r
847         //\r
848         // function list\r
849         //\r
850         FunctionType = 1;\r
851         fgets (Line, MAX_LINE_LEN, PeMapFile);\r
852       } else if (stricmp (KeyWord, "Static") == 0) {\r
853         //\r
854         // static function list\r
855         //\r
856         FunctionType = 2;\r
857         fgets (Line, MAX_LINE_LEN, PeMapFile);\r
858       }\r
859       continue;\r
860     }\r
861     //\r
862     // Printf Function Information\r
863     //\r
864     if (FunctionType == 1) {\r
865       sscanf (Line, "%s %s %llx %s", KeyWord, FunctionName, &TempLongAddress, FunctionTypeName);\r
866       FunctionAddress = (UINT64) TempLongAddress;\r
867       if (FunctionTypeName [1] == '\0' && (FunctionTypeName [0] == 'f' || FunctionTypeName [0] == 'F')) {\r
868         fprintf (FvMapFile, "  0x%010llx    ", (unsigned long long) (ImageBaseAddress + FunctionAddress));\r
869         fprintf (FvMapFile, "%s\n", FunctionName);\r
870       }\r
871     } else if (FunctionType == 2) {\r
872       sscanf (Line, "%s %s %llx %s", KeyWord, FunctionName, &TempLongAddress, FunctionTypeName);\r
873       FunctionAddress = (UINT64) TempLongAddress;\r
874       if (FunctionTypeName [1] == '\0' && (FunctionTypeName [0] == 'f' || FunctionTypeName [0] == 'F')) {\r
875         fprintf (FvMapFile, "  0x%010llx    ", (unsigned long long) (ImageBaseAddress + FunctionAddress));\r
876         fprintf (FvMapFile, "%s\n", FunctionName);\r
877       }\r
878     }\r
879   }\r
880   //\r
881   // Close PeMap file\r
882   //\r
883   fprintf (FvMapFile, "\n\n");\r
884   fclose (PeMapFile);\r
885   \r
886   return EFI_SUCCESS;\r
887 }\r
888 \r
889 EFI_STATUS\r
890 AddFile (\r
891   IN OUT MEMORY_FILE          *FvImage,\r
892   IN FV_INFO                  *FvInfo,\r
893   IN UINTN                    Index,\r
894   IN OUT EFI_FFS_FILE_HEADER  **VtfFileImage,\r
895   IN FILE                     *FvMapFile,\r
896   IN FILE                     *FvReportFile\r
897   )\r
898 /*++\r
899 \r
900 Routine Description:\r
901 \r
902   This function adds a file to the FV image.  The file will pad to the\r
903   appropriate alignment if required.\r
904 \r
905 Arguments:\r
906 \r
907   FvImage       The memory image of the FV to add it to.  The current offset\r
908                 must be valid.\r
909   FvInfo        Pointer to information about the FV.\r
910   Index         The file in the FvInfo file list to add.\r
911   VtfFileImage  A pointer to the VTF file within the FvImage.  If this is equal\r
912                 to the end of the FvImage then no VTF previously found.\r
913   FvMapFile     Pointer to FvMap File\r
914   FvReportFile  Pointer to FvReport File\r
915 \r
916 Returns:\r
917 \r
918   EFI_SUCCESS              The function completed successfully.\r
919   EFI_INVALID_PARAMETER    One of the input parameters was invalid.\r
920   EFI_ABORTED              An error occurred.\r
921   EFI_OUT_OF_RESOURCES     Insufficient resources exist to complete the add.\r
922 \r
923 --*/\r
924 {\r
925   FILE                  *NewFile;\r
926   UINTN                 FileSize;\r
927   UINT8                 *FileBuffer;\r
928   UINTN                 NumBytesRead;\r
929   UINT32                CurrentFileAlignment;\r
930   EFI_STATUS            Status;\r
931   UINTN                 Index1;\r
932   UINT8                 FileGuidString[PRINTED_GUID_BUFFER_SIZE];\r
933   \r
934   Index1 = 0;\r
935   //\r
936   // Verify input parameters.\r
937   //\r
938   if (FvImage == NULL || FvInfo == NULL || FvInfo->FvFiles[Index][0] == 0 || VtfFileImage == NULL) {\r
939     return EFI_INVALID_PARAMETER;\r
940   }\r
941 \r
942   //\r
943   // Read the file to add\r
944   //\r
945   NewFile = fopen (FvInfo->FvFiles[Index], "rb");\r
946 \r
947   if (NewFile == NULL) {\r
948     Error (NULL, 0, 0001, "Error opening file", FvInfo->FvFiles[Index]);\r
949     return EFI_ABORTED;\r
950   }\r
951 \r
952   //\r
953   // Get the file size\r
954   //\r
955   FileSize = _filelength (fileno (NewFile));\r
956 \r
957   //\r
958   // Read the file into a buffer\r
959   //\r
960   FileBuffer = malloc (FileSize);\r
961   if (FileBuffer == NULL) {\r
962     Error (NULL, 0, 4001, "Resouce", "memory cannot be allocated!");\r
963     return EFI_OUT_OF_RESOURCES;\r
964   }\r
965 \r
966   NumBytesRead = fread (FileBuffer, sizeof (UINT8), FileSize, NewFile);\r
967 \r
968   //\r
969   // Done with the file, from this point on we will just use the buffer read.\r
970   //\r
971   fclose (NewFile);\r
972   \r
973   //\r
974   // Verify read successful\r
975   //\r
976   if (NumBytesRead != sizeof (UINT8) * FileSize) {\r
977     free  (FileBuffer);\r
978     Error (NULL, 0, 0004, "Error reading file", FvInfo->FvFiles[Index]);\r
979     return EFI_ABORTED;\r
980   }\r
981   \r
982   //\r
983   // For None PI Ffs file, directly add them into FvImage.\r
984   //\r
985   if (!FvInfo->IsPiFvImage) {\r
986     memcpy (FvImage->CurrentFilePointer, FileBuffer, FileSize);\r
987     if (FvInfo->SizeofFvFiles[Index] > FileSize) {\r
988         FvImage->CurrentFilePointer += FvInfo->SizeofFvFiles[Index];\r
989     } else {\r
990         FvImage->CurrentFilePointer += FileSize;\r
991     }\r
992     goto Done;\r
993   }\r
994   \r
995   //\r
996   // Verify Ffs file\r
997   //\r
998   Status = VerifyFfsFile ((EFI_FFS_FILE_HEADER *)FileBuffer);\r
999   if (EFI_ERROR (Status)) {\r
1000     free (FileBuffer);\r
1001     Error (NULL, 0, 3000, "Invalid", "%s is a FFS file.", FvInfo->FvFiles[Index]);\r
1002     return EFI_INVALID_PARAMETER;\r
1003   }\r
1004 \r
1005   //\r
1006   // Verify space exists to add the file\r
1007   //\r
1008   if (FileSize > (UINTN) ((UINTN) *VtfFileImage - (UINTN) FvImage->CurrentFilePointer)) {\r
1009     free (FileBuffer);\r
1010     Error (NULL, 0, 4002, "Resource", "FV space is full, not enough room to add file %s.", FvInfo->FvFiles[Index]);\r
1011     return EFI_OUT_OF_RESOURCES;\r
1012   }\r
1013 \r
1014   //\r
1015   // Verify the input file is the duplicated file in this Fv image\r
1016   //\r
1017   for (Index1 = 0; Index1 < Index; Index1 ++) {\r
1018     if (CompareGuid ((EFI_GUID *) FileBuffer, &mFileGuidArray [Index1]) == 0) {\r
1019       Error (NULL, 0, 2000, "Invalid parameter", "the %dth file and %uth file have the same file GUID.", (unsigned) Index1 + 1, (unsigned) Index + 1);\r
1020       PrintGuid ((EFI_GUID *) FileBuffer);\r
1021       return EFI_INVALID_PARAMETER;\r
1022     }\r
1023   }\r
1024   CopyMem (&mFileGuidArray [Index], FileBuffer, sizeof (EFI_GUID));\r
1025 \r
1026   //\r
1027   // Update the file state based on polarity of the FV.\r
1028   //\r
1029   UpdateFfsFileState (\r
1030     (EFI_FFS_FILE_HEADER *) FileBuffer,\r
1031     (EFI_FIRMWARE_VOLUME_HEADER *) FvImage->FileImage\r
1032     );\r
1033 \r
1034   //\r
1035   // Check if alignment is required\r
1036   //\r
1037   ReadFfsAlignment ((EFI_FFS_FILE_HEADER *) FileBuffer, &CurrentFileAlignment);\r
1038   \r
1039   //\r
1040   // Find the largest alignment of all the FFS files in the FV\r
1041   //\r
1042   if (CurrentFileAlignment > MaxFfsAlignment) {\r
1043     MaxFfsAlignment = CurrentFileAlignment;\r
1044   }\r
1045   //\r
1046   // If we have a VTF file, add it at the top.\r
1047   //\r
1048   if (IsVtfFile ((EFI_FFS_FILE_HEADER *) FileBuffer)) {\r
1049     if ((UINTN) *VtfFileImage == (UINTN) FvImage->Eof) {\r
1050       //\r
1051       // No previous VTF, add this one.\r
1052       //\r
1053       *VtfFileImage = (EFI_FFS_FILE_HEADER *) (UINTN) ((UINTN) FvImage->FileImage + FvInfo->Size - FileSize);\r
1054       //\r
1055       // Sanity check. The file MUST align appropriately\r
1056       //\r
1057       if (((UINTN) *VtfFileImage + sizeof (EFI_FFS_FILE_HEADER) - (UINTN) FvImage->FileImage) % (1 << CurrentFileAlignment)) {\r
1058         Error (NULL, 0, 3000, "Invalid", "VTF file cannot be aligned on a %u-byte boundary.", (unsigned) (1 << CurrentFileAlignment));\r
1059         free (FileBuffer);\r
1060         return EFI_ABORTED;\r
1061       }\r
1062       //\r
1063       // Rebase the PE or TE image in FileBuffer of FFS file for XIP \r
1064       // Rebase for the debug genfvmap tool\r
1065       //\r
1066       FfsRebase (FvInfo, FvInfo->FvFiles[Index], (EFI_FFS_FILE_HEADER *) FileBuffer, (UINTN) *VtfFileImage - (UINTN) FvImage->FileImage, FvMapFile);\r
1067       //\r
1068       // copy VTF File\r
1069       //\r
1070       memcpy (*VtfFileImage, FileBuffer, FileSize);\r
1071       free (FileBuffer);\r
1072       DebugMsg (NULL, 0, 9, "Add VTF FFS file in FV image", NULL);\r
1073       return EFI_SUCCESS;\r
1074     } else {\r
1075       //\r
1076       // Already found a VTF file.\r
1077       //\r
1078       Error (NULL, 0, 3000, "Invalid", "multiple VTF files are not permitted within a single FV.");\r
1079       free (FileBuffer);\r
1080       return EFI_ABORTED;\r
1081     }\r
1082   }\r
1083 \r
1084   //\r
1085   // Add pad file if necessary\r
1086   //\r
1087   Status = AddPadFile (FvImage, 1 << CurrentFileAlignment, *VtfFileImage, NULL);\r
1088   if (EFI_ERROR (Status)) {\r
1089     Error (NULL, 0, 4002, "Resource", "FV space is full, could not add pad file for data alignment property.");\r
1090     free (FileBuffer);\r
1091     return EFI_ABORTED;\r
1092   }\r
1093   //\r
1094   // Add file\r
1095   //\r
1096   if ((UINTN) (FvImage->CurrentFilePointer + FileSize) <= (UINTN) (*VtfFileImage)) {\r
1097     //\r
1098     // Rebase the PE or TE image in FileBuffer of FFS file for XIP. \r
1099     // Rebase Bs and Rt drivers for the debug genfvmap tool.\r
1100     //\r
1101     FfsRebase (FvInfo, FvInfo->FvFiles[Index], (EFI_FFS_FILE_HEADER *) FileBuffer, (UINTN) FvImage->CurrentFilePointer - (UINTN) FvImage->FileImage, FvMapFile);\r
1102     //\r
1103     // Copy the file\r
1104     //\r
1105     memcpy (FvImage->CurrentFilePointer, FileBuffer, FileSize);\r
1106     PrintGuidToBuffer ((EFI_GUID *) FileBuffer, FileGuidString, sizeof (FileGuidString), TRUE); \r
1107     fprintf (FvReportFile, "0x%08x %s\n", (unsigned) (FvImage->CurrentFilePointer - FvImage->FileImage), FileGuidString);\r
1108     FvImage->CurrentFilePointer += FileSize;\r
1109   } else {\r
1110     Error (NULL, 0, 4002, "Resource", "FV space is full, cannot add file %s.", FvInfo->FvFiles[Index]);\r
1111     free (FileBuffer);\r
1112     return EFI_ABORTED;\r
1113   }\r
1114   //\r
1115   // Make next file start at QWord Boundry\r
1116   //\r
1117   while (((UINTN) FvImage->CurrentFilePointer & (EFI_FFS_FILE_HEADER_ALIGNMENT - 1)) != 0) {\r
1118     FvImage->CurrentFilePointer++;\r
1119   }\r
1120 \r
1121 Done: \r
1122   //\r
1123   // Free allocated memory.\r
1124   //\r
1125   free (FileBuffer);\r
1126 \r
1127   return EFI_SUCCESS;\r
1128 }\r
1129 \r
1130 EFI_STATUS\r
1131 PadFvImage (\r
1132   IN MEMORY_FILE          *FvImage,\r
1133   IN EFI_FFS_FILE_HEADER  *VtfFileImage\r
1134   )\r
1135 /*++\r
1136 \r
1137 Routine Description:\r
1138 \r
1139   This function places a pad file between the last file in the FV and the VTF\r
1140   file if the VTF file exists.\r
1141 \r
1142 Arguments:\r
1143 \r
1144   FvImage       Memory file for the FV memory image\r
1145   VtfFileImage  The address of the VTF file.  If this is the end of the FV\r
1146                 image, no VTF exists and no pad file is needed.\r
1147 \r
1148 Returns:\r
1149 \r
1150   EFI_SUCCESS             Completed successfully.\r
1151   EFI_INVALID_PARAMETER   One of the input parameters was NULL.\r
1152 \r
1153 --*/\r
1154 {\r
1155   EFI_FFS_FILE_HEADER *PadFile;\r
1156   UINTN               FileSize;\r
1157 \r
1158   //\r
1159   // If there is no VTF or the VTF naturally follows the previous file without a\r
1160   // pad file, then there's nothing to do\r
1161   //\r
1162   if ((UINTN) VtfFileImage == (UINTN) FvImage->Eof || \\r
1163       ((UINTN) VtfFileImage == (UINTN) FvImage->CurrentFilePointer)) {\r
1164     return EFI_SUCCESS;\r
1165   }\r
1166 \r
1167   if ((UINTN) VtfFileImage < (UINTN) FvImage->CurrentFilePointer) {\r
1168     return EFI_INVALID_PARAMETER;\r
1169   }\r
1170 \r
1171   //\r
1172   // Pad file starts at beginning of free space\r
1173   //\r
1174   PadFile = (EFI_FFS_FILE_HEADER *) FvImage->CurrentFilePointer;\r
1175 \r
1176   //\r
1177   // write PadFile FFS header with PadType, don't need to set PAD file guid in its header. \r
1178   //\r
1179   PadFile->Type       = EFI_FV_FILETYPE_FFS_PAD;\r
1180   PadFile->Attributes = 0;\r
1181 \r
1182   //\r
1183   // FileSize includes the EFI_FFS_FILE_HEADER\r
1184   //\r
1185   FileSize          = (UINTN) VtfFileImage - (UINTN) FvImage->CurrentFilePointer;\r
1186   PadFile->Size[0]  = (UINT8) (FileSize & 0x000000FF);\r
1187   PadFile->Size[1]  = (UINT8) ((FileSize & 0x0000FF00) >> 8);\r
1188   PadFile->Size[2]  = (UINT8) ((FileSize & 0x00FF0000) >> 16);\r
1189 \r
1190   //\r
1191   // Fill in checksums and state, must be zero during checksum calculation.\r
1192   //\r
1193   PadFile->IntegrityCheck.Checksum.Header = 0;\r
1194   PadFile->IntegrityCheck.Checksum.File   = 0;\r
1195   PadFile->State                          = 0;\r
1196   PadFile->IntegrityCheck.Checksum.Header = CalculateChecksum8 ((UINT8 *) PadFile, sizeof (EFI_FFS_FILE_HEADER));\r
1197   PadFile->IntegrityCheck.Checksum.File   = FFS_FIXED_CHECKSUM;\r
1198 \r
1199   PadFile->State = EFI_FILE_HEADER_CONSTRUCTION | EFI_FILE_HEADER_VALID | EFI_FILE_DATA_VALID;\r
1200 \r
1201   UpdateFfsFileState (\r
1202     (EFI_FFS_FILE_HEADER *) PadFile,\r
1203     (EFI_FIRMWARE_VOLUME_HEADER *) FvImage->FileImage\r
1204     );\r
1205   //\r
1206   // Update the current FV pointer\r
1207   //\r
1208   FvImage->CurrentFilePointer = FvImage->Eof;\r
1209 \r
1210   return EFI_SUCCESS;\r
1211 }\r
1212 \r
1213 EFI_STATUS\r
1214 UpdateResetVector (\r
1215   IN MEMORY_FILE            *FvImage,\r
1216   IN FV_INFO                *FvInfo,\r
1217   IN EFI_FFS_FILE_HEADER    *VtfFile\r
1218   )\r
1219 /*++\r
1220 \r
1221 Routine Description:\r
1222 \r
1223   This parses the FV looking for the PEI core and then plugs the address into\r
1224   the SALE_ENTRY point of the BSF/VTF for IPF and does BUGBUG TBD action to\r
1225   complete an IA32 Bootstrap FV.\r
1226 \r
1227 Arguments:\r
1228 \r
1229   FvImage       Memory file for the FV memory image\r
1230   FvInfo        Information read from INF file.\r
1231   VtfFile       Pointer to the VTF file in the FV image.\r
1232 \r
1233 Returns:\r
1234 \r
1235   EFI_SUCCESS             Function Completed successfully.\r
1236   EFI_ABORTED             Error encountered.\r
1237   EFI_INVALID_PARAMETER   A required parameter was NULL.\r
1238   EFI_NOT_FOUND           PEI Core file not found.\r
1239 \r
1240 --*/\r
1241 {\r
1242   EFI_FFS_FILE_HEADER       *PeiCoreFile;\r
1243   EFI_FFS_FILE_HEADER       *SecCoreFile;\r
1244   EFI_STATUS                Status;\r
1245   EFI_FILE_SECTION_POINTER  Pe32Section;\r
1246   UINT32                    EntryPoint;\r
1247   UINT32                    BaseOfCode;\r
1248   UINT16                    MachineType;\r
1249   EFI_PHYSICAL_ADDRESS      PeiCorePhysicalAddress;\r
1250   EFI_PHYSICAL_ADDRESS      SecCorePhysicalAddress;\r
1251   EFI_PHYSICAL_ADDRESS      *SecCoreEntryAddressPtr;\r
1252   INT32                     Ia32SecEntryOffset;\r
1253   UINT32                    *Ia32ResetAddressPtr;\r
1254   UINT8                     *BytePointer;\r
1255   UINT8                     *BytePointer2;\r
1256   UINT16                    *WordPointer;\r
1257   UINT16                    CheckSum;\r
1258   UINT32                    IpiVector;\r
1259   UINTN                     Index;\r
1260   EFI_FFS_FILE_STATE        SavedState;\r
1261   UINT64                    FitAddress;\r
1262   FIT_TABLE                 *FitTablePtr;\r
1263   BOOLEAN                   Vtf0Detected;\r
1264 \r
1265   //\r
1266   // Verify input parameters\r
1267   //\r
1268   if (FvImage == NULL || FvInfo == NULL || VtfFile == NULL) {\r
1269     return EFI_INVALID_PARAMETER;\r
1270   }\r
1271   //\r
1272   // Initialize FV library\r
1273   //\r
1274   InitializeFvLib (FvImage->FileImage, FvInfo->Size);\r
1275 \r
1276   //\r
1277   // Verify VTF file\r
1278   //\r
1279   Status = VerifyFfsFile (VtfFile);\r
1280   if (EFI_ERROR (Status)) {\r
1281     return EFI_INVALID_PARAMETER;\r
1282   }\r
1283 \r
1284   if (\r
1285       (((UINTN)FvImage->Eof - (UINTN)FvImage->FileImage) >=\r
1286         IA32_X64_VTF_SIGNATURE_OFFSET) &&\r
1287       (*(UINT32 *)(VOID*)((UINTN) FvImage->Eof -\r
1288                                   IA32_X64_VTF_SIGNATURE_OFFSET) ==\r
1289         IA32_X64_VTF0_SIGNATURE)\r
1290      ) {\r
1291     Vtf0Detected = TRUE;\r
1292   } else {\r
1293     Vtf0Detected = FALSE;\r
1294   }\r
1295 \r
1296   //\r
1297   // Find the Sec Core\r
1298   //\r
1299   Status = GetFileByType (EFI_FV_FILETYPE_SECURITY_CORE, 1, &SecCoreFile);\r
1300   if (EFI_ERROR (Status) || SecCoreFile == NULL) {\r
1301     if (Vtf0Detected) {\r
1302       //\r
1303       // If the SEC core file is not found, but the VTF-0 signature\r
1304       // is found, we'll treat it as a VTF-0 'Volume Top File'.\r
1305       // This means no modifications are required to the VTF.\r
1306       //\r
1307       return EFI_SUCCESS;\r
1308     }\r
1309 \r
1310     Error (NULL, 0, 3000, "Invalid", "could not find the SEC core file in the FV.");\r
1311     return EFI_ABORTED;\r
1312   }\r
1313   //\r
1314   // Sec Core found, now find PE32 section\r
1315   //\r
1316   Status = GetSectionByType (SecCoreFile, EFI_SECTION_PE32, 1, &Pe32Section);\r
1317   if (Status == EFI_NOT_FOUND) {\r
1318     Status = GetSectionByType (SecCoreFile, EFI_SECTION_TE, 1, &Pe32Section);\r
1319   }\r
1320 \r
1321   if (EFI_ERROR (Status)) {\r
1322     Error (NULL, 0, 3000, "Invalid", "could not find a PE32 section in the SEC core file.");\r
1323     return EFI_ABORTED;\r
1324   }\r
1325 \r
1326   Status = GetPe32Info (\r
1327             (VOID *) ((UINTN) Pe32Section.Pe32Section + sizeof (EFI_SECTION_PE32)),\r
1328             &EntryPoint,\r
1329             &BaseOfCode,\r
1330             &MachineType\r
1331             );\r
1332 \r
1333   if (EFI_ERROR (Status)) {\r
1334     Error (NULL, 0, 3000, "Invalid", "could not get the PE32 entry point for the SEC core.");\r
1335     return EFI_ABORTED;\r
1336   }  \r
1337 \r
1338   if (\r
1339        Vtf0Detected &&\r
1340        (MachineType == EFI_IMAGE_MACHINE_IA32 ||\r
1341         MachineType == EFI_IMAGE_MACHINE_X64)\r
1342      ) {\r
1343     //\r
1344     // If the SEC core code is IA32 or X64 and the VTF-0 signature\r
1345     // is found, we'll treat it as a VTF-0 'Volume Top File'.\r
1346     // This means no modifications are required to the VTF.\r
1347     //\r
1348     return EFI_SUCCESS;\r
1349   }\r
1350 \r
1351   //\r
1352   // Physical address is FV base + offset of PE32 + offset of the entry point\r
1353   //\r
1354   SecCorePhysicalAddress = FvInfo->BaseAddress;\r
1355   SecCorePhysicalAddress += (UINTN) Pe32Section.Pe32Section + sizeof (EFI_SECTION_PE32) - (UINTN) FvImage->FileImage;\r
1356   SecCorePhysicalAddress += EntryPoint;\r
1357   DebugMsg (NULL, 0, 9, "SecCore physical entry point address", "Address = 0x%llX", (unsigned long long) SecCorePhysicalAddress); \r
1358 \r
1359   //\r
1360   // Find the PEI Core\r
1361   //\r
1362   Status = GetFileByType (EFI_FV_FILETYPE_PEI_CORE, 1, &PeiCoreFile);\r
1363   if (EFI_ERROR (Status) || PeiCoreFile == NULL) {\r
1364     Error (NULL, 0, 3000, "Invalid", "could not find the PEI core in the FV.");\r
1365     return EFI_ABORTED;\r
1366   }\r
1367   //\r
1368   // PEI Core found, now find PE32 or TE section\r
1369   //\r
1370   Status = GetSectionByType (PeiCoreFile, EFI_SECTION_PE32, 1, &Pe32Section);\r
1371   if (Status == EFI_NOT_FOUND) {\r
1372     Status = GetSectionByType (PeiCoreFile, EFI_SECTION_TE, 1, &Pe32Section);\r
1373   }\r
1374 \r
1375   if (EFI_ERROR (Status)) {\r
1376     Error (NULL, 0, 3000, "Invalid", "could not find either a PE32 or a TE section in PEI core file.");\r
1377     return EFI_ABORTED;\r
1378   }\r
1379 \r
1380   Status = GetPe32Info (\r
1381             (VOID *) ((UINTN) Pe32Section.Pe32Section + sizeof (EFI_SECTION_PE32)),\r
1382             &EntryPoint,\r
1383             &BaseOfCode,\r
1384             &MachineType\r
1385             );\r
1386 \r
1387   if (EFI_ERROR (Status)) {\r
1388     Error (NULL, 0, 3000, "Invalid", "could not get the PE32 entry point for the PEI core.");\r
1389     return EFI_ABORTED;\r
1390   }\r
1391   //\r
1392   // Physical address is FV base + offset of PE32 + offset of the entry point\r
1393   //\r
1394   PeiCorePhysicalAddress = FvInfo->BaseAddress;\r
1395   PeiCorePhysicalAddress += (UINTN) Pe32Section.Pe32Section + sizeof (EFI_SECTION_PE32) - (UINTN) FvImage->FileImage;\r
1396   PeiCorePhysicalAddress += EntryPoint;\r
1397   DebugMsg (NULL, 0, 9, "PeiCore physical entry point address", "Address = 0x%llX", (unsigned long long) PeiCorePhysicalAddress);\r
1398 \r
1399   if (MachineType == EFI_IMAGE_MACHINE_IA64) {\r
1400     //\r
1401     // Update PEI_CORE address\r
1402     //\r
1403     //\r
1404     // Set the uncached attribute bit in the physical address\r
1405     //\r
1406     PeiCorePhysicalAddress |= 0x8000000000000000ULL;\r
1407 \r
1408     //\r
1409     // Check if address is aligned on a 16 byte boundary\r
1410     //\r
1411     if (PeiCorePhysicalAddress & 0xF) {\r
1412       Error (NULL, 0, 3000, "Invalid",\r
1413         "PEI_CORE entry point is not aligned on a 16 byte boundary, address specified is %llXh.",\r
1414         (unsigned long long) PeiCorePhysicalAddress\r
1415         );\r
1416       return EFI_ABORTED;\r
1417     }\r
1418     //\r
1419     // First Get the FIT table address\r
1420     //\r
1421     FitAddress  = (*(UINT64 *) (FvImage->Eof - IPF_FIT_ADDRESS_OFFSET)) & 0xFFFFFFFF;\r
1422 \r
1423     FitTablePtr = (FIT_TABLE *) (FvImage->FileImage + (FitAddress - FvInfo->BaseAddress));\r
1424 \r
1425     Status      = UpdatePeiCoreEntryInFit (FitTablePtr, PeiCorePhysicalAddress);\r
1426 \r
1427     if (!EFI_ERROR (Status)) {\r
1428       UpdateFitCheckSum (FitTablePtr);\r
1429     }\r
1430 \r
1431     //\r
1432     // Update SEC_CORE address\r
1433     //\r
1434     //\r
1435     // Set the uncached attribute bit in the physical address\r
1436     //\r
1437     SecCorePhysicalAddress |= 0x8000000000000000ULL;\r
1438     //\r
1439     // Check if address is aligned on a 16 byte boundary\r
1440     //\r
1441     if (SecCorePhysicalAddress & 0xF) {\r
1442       Error (NULL, 0, 3000, "Invalid",\r
1443         "SALE_ENTRY entry point is not aligned on a 16 byte boundary, address specified is %llXh.",\r
1444         (unsigned long long) SecCorePhysicalAddress\r
1445         );\r
1446       return EFI_ABORTED;\r
1447     }\r
1448     //\r
1449     // Update the address\r
1450     //\r
1451     SecCoreEntryAddressPtr  = (EFI_PHYSICAL_ADDRESS *) ((UINTN) FvImage->Eof - IPF_SALE_ENTRY_ADDRESS_OFFSET);\r
1452     *SecCoreEntryAddressPtr = SecCorePhysicalAddress;\r
1453 \r
1454   } else if (MachineType == EFI_IMAGE_MACHINE_IA32 || MachineType == EFI_IMAGE_MACHINE_X64) {\r
1455     //\r
1456     // Get the location to update\r
1457     //\r
1458     Ia32ResetAddressPtr  = (UINT32 *) ((UINTN) FvImage->Eof - IA32_PEI_CORE_ENTRY_OFFSET);\r
1459 \r
1460     //\r
1461     // Write lower 32 bits of physical address for Pei Core entry\r
1462     //\r
1463     *Ia32ResetAddressPtr = (UINT32) PeiCorePhysicalAddress;\r
1464     \r
1465     //\r
1466     // Write SecCore Entry point relative address into the jmp instruction in reset vector.\r
1467     // \r
1468     Ia32ResetAddressPtr  = (UINT32 *) ((UINTN) FvImage->Eof - IA32_SEC_CORE_ENTRY_OFFSET);\r
1469     \r
1470     Ia32SecEntryOffset   = (INT32) (SecCorePhysicalAddress - (FV_IMAGES_TOP_ADDRESS - IA32_SEC_CORE_ENTRY_OFFSET + 2));\r
1471     if (Ia32SecEntryOffset <= -65536) {\r
1472       Error (NULL, 0, 3000, "Invalid", "The SEC EXE file size is too large, it must be less than 64K.");\r
1473       return STATUS_ERROR;\r
1474     }\r
1475     \r
1476     *(UINT16 *) Ia32ResetAddressPtr = (UINT16) Ia32SecEntryOffset;\r
1477 \r
1478     //\r
1479     // Update the BFV base address\r
1480     //\r
1481     Ia32ResetAddressPtr   = (UINT32 *) ((UINTN) FvImage->Eof - 4);\r
1482     *Ia32ResetAddressPtr  = (UINT32) (FvInfo->BaseAddress);\r
1483     DebugMsg (NULL, 0, 9, "update BFV base address in the top FV image", "BFV base address = 0x%llX.", (unsigned long long) FvInfo->BaseAddress);\r
1484 \r
1485     //\r
1486     // Update the Startup AP in the FVH header block ZeroVector region.\r
1487     //\r
1488     BytePointer   = (UINT8 *) ((UINTN) FvImage->FileImage);\r
1489     if (FvInfo->Size <= 0x10000) {\r
1490       BytePointer2 = m64kRecoveryStartupApDataArray;\r
1491     } else if (FvInfo->Size <= 0x20000) {\r
1492       BytePointer2 = m128kRecoveryStartupApDataArray;\r
1493     } else {\r
1494       BytePointer2 = m128kRecoveryStartupApDataArray;\r
1495       //\r
1496       // Find the position to place Ap reset vector, the offset\r
1497       // between the position and the end of Fvrecovery.fv file\r
1498       // should not exceed 128kB to prevent Ap reset vector from\r
1499       // outside legacy E and F segment\r
1500       //\r
1501       Status = FindApResetVectorPosition (FvImage, &BytePointer);\r
1502       if (EFI_ERROR (Status)) {\r
1503         Error (NULL, 0, 3000, "Invalid", "Cannot find the appropriate location in FvImage to add Ap reset vector!");\r
1504         return EFI_ABORTED;\r
1505       }\r
1506     }\r
1507 \r
1508     for (Index = 0; Index < SIZEOF_STARTUP_DATA_ARRAY; Index++) {\r
1509       BytePointer[Index] = BytePointer2[Index];\r
1510     }\r
1511     //\r
1512     // Calculate the checksum\r
1513     //\r
1514     CheckSum              = 0x0000;\r
1515     WordPointer = (UINT16 *) (BytePointer);\r
1516     for (Index = 0; Index < SIZEOF_STARTUP_DATA_ARRAY / 2; Index++) {\r
1517       CheckSum = (UINT16) (CheckSum + ((UINT16) *WordPointer));\r
1518       WordPointer++;\r
1519     }\r
1520     //\r
1521     // Update the checksum field\r
1522     //\r
1523     WordPointer   = (UINT16 *) (BytePointer + SIZEOF_STARTUP_DATA_ARRAY - 2);\r
1524     *WordPointer  = (UINT16) (0x10000 - (UINT32) CheckSum);\r
1525     \r
1526     //\r
1527     // IpiVector at the 4k aligned address in the top 2 blocks in the PEI FV. \r
1528     //\r
1529     IpiVector  = (UINT32) (FV_IMAGES_TOP_ADDRESS - ((UINTN) FvImage->Eof - (UINTN) BytePointer));\r
1530     DebugMsg (NULL, 0, 9, "Startup AP Vector address", "IpiVector at 0x%X", (unsigned) IpiVector);\r
1531     if ((IpiVector & 0xFFF) != 0) {\r
1532       Error (NULL, 0, 3000, "Invalid", "Startup AP Vector address are not 4K aligned, because the FV size is not 4K aligned");\r
1533       return EFI_ABORTED;\r
1534     }\r
1535     IpiVector  = IpiVector >> 12;\r
1536     IpiVector  = IpiVector & 0xFF;\r
1537 \r
1538     //\r
1539     // Write IPI Vector at Offset FvrecoveryFileSize - 8\r
1540     //\r
1541     Ia32ResetAddressPtr   = (UINT32 *) ((UINTN) FvImage->Eof - 8);\r
1542     *Ia32ResetAddressPtr  = IpiVector;\r
1543   } else if (MachineType == EFI_IMAGE_MACHINE_ARMT) {\r
1544     //\r
1545     // Since the ARM reset vector is in the FV Header you really don't need a\r
1546     // Volume Top File, but if you have one for some reason don't crash...\r
1547     //\r
1548   } else {\r
1549     Error (NULL, 0, 3000, "Invalid", "machine type=0x%X in PEI core.", MachineType);\r
1550     return EFI_ABORTED;\r
1551   }\r
1552 \r
1553   //\r
1554   // Now update file checksum\r
1555   //\r
1556   SavedState  = VtfFile->State;\r
1557   VtfFile->IntegrityCheck.Checksum.File = 0;\r
1558   VtfFile->State                        = 0;\r
1559   if (VtfFile->Attributes & FFS_ATTRIB_CHECKSUM) {\r
1560     VtfFile->IntegrityCheck.Checksum.File = CalculateChecksum8 (\r
1561                                               (UINT8 *) (VtfFile + 1),\r
1562                                               GetLength (VtfFile->Size) - sizeof (EFI_FFS_FILE_HEADER)\r
1563                                               );\r
1564   } else {\r
1565     VtfFile->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;\r
1566   }\r
1567 \r
1568   VtfFile->State = SavedState;\r
1569 \r
1570   return EFI_SUCCESS;\r
1571 }\r
1572 \r
1573 \r
1574 EFI_STATUS\r
1575 UpdateArmResetVectorIfNeeded (\r
1576   IN MEMORY_FILE            *FvImage,\r
1577   IN FV_INFO                *FvInfo\r
1578   )\r
1579 /*++\r
1580 \r
1581 Routine Description:\r
1582   This parses the FV looking for SEC and patches that address into the \r
1583   beginning of the FV header.\r
1584 \r
1585   For ARM the reset vector is at 0x00000000 or 0xFFFF0000.\r
1586   This would commonly map to the first entry in the ROM. \r
1587   ARM Exceptions:\r
1588   Reset            +0    \r
1589   Undefined        +4\r
1590   SWI              +8\r
1591   Prefetch Abort   +12\r
1592   Data Abort       +16\r
1593   IRQ              +20\r
1594   FIQ              +24\r
1595 \r
1596   We support two schemes on ARM.\r
1597   1) Beginning of the FV is the reset vector\r
1598   2) Reset vector is data bytes FDF file and that code branches to reset vector \r
1599     in the beginning of the FV (fixed size offset).\r
1600 \r
1601 \r
1602   Need to have the jump for the reset vector at location zero.\r
1603   We also need to store the address or PEI (if it exists).\r
1604   We stub out a return from interrupt in case the debugger \r
1605    is using SWI.\r
1606   The optional entry to the common exception handler is \r
1607    to support full featured exception handling from ROM and is currently \r
1608     not support by this tool.\r
1609 \r
1610 Arguments:\r
1611   FvImage       Memory file for the FV memory image\r
1612   FvInfo        Information read from INF file.\r
1613 \r
1614 Returns:\r
1615 \r
1616   EFI_SUCCESS             Function Completed successfully.\r
1617   EFI_ABORTED             Error encountered.\r
1618   EFI_INVALID_PARAMETER   A required parameter was NULL.\r
1619   EFI_NOT_FOUND           PEI Core file not found.\r
1620 \r
1621 --*/\r
1622 {\r
1623   EFI_FFS_FILE_HEADER       *PeiCoreFile;\r
1624   EFI_FFS_FILE_HEADER       *SecCoreFile;\r
1625   EFI_STATUS                Status;\r
1626   EFI_FILE_SECTION_POINTER  Pe32Section;\r
1627   UINT32                    EntryPoint;\r
1628   UINT32                    BaseOfCode;\r
1629   UINT16                    MachineType;\r
1630   EFI_PHYSICAL_ADDRESS      PeiCorePhysicalAddress;\r
1631   EFI_PHYSICAL_ADDRESS      SecCorePhysicalAddress;\r
1632   INT32                     ResetVector[4]; // 0 - is branch relative to SEC entry point\r
1633                                             // 1 - PEI Entry Point\r
1634                                             // 2 - movs pc,lr for a SWI handler\r
1635                                             // 3 - Place holder for Common Exception Handler\r
1636 \r
1637   //\r
1638   // Verify input parameters\r
1639   //\r
1640   if (FvImage == NULL || FvInfo == NULL) {\r
1641     return EFI_INVALID_PARAMETER;\r
1642   }\r
1643   //\r
1644   // Initialize FV library\r
1645   //\r
1646   InitializeFvLib (FvImage->FileImage, FvInfo->Size);\r
1647 \r
1648   //\r
1649   // Find the Sec Core\r
1650   //\r
1651   Status = GetFileByType (EFI_FV_FILETYPE_SECURITY_CORE, 1, &SecCoreFile);\r
1652   if (EFI_ERROR (Status) || SecCoreFile == NULL) {\r
1653     //\r
1654     // Maybe hardware does SEC job and we only have PEI Core?\r
1655     //\r
1656 \r
1657     //\r
1658     // Find the PEI Core. It may not exist if SEC loads DXE core directly\r
1659     //\r
1660     PeiCorePhysicalAddress = 0;\r
1661     Status = GetFileByType (EFI_FV_FILETYPE_PEI_CORE, 1, &PeiCoreFile);\r
1662     if (!EFI_ERROR (Status) && PeiCoreFile != NULL) {\r
1663       //\r
1664       // PEI Core found, now find PE32 or TE section\r
1665       //\r
1666       Status = GetSectionByType (PeiCoreFile, EFI_SECTION_PE32, 1, &Pe32Section);\r
1667       if (Status == EFI_NOT_FOUND) {\r
1668         Status = GetSectionByType (PeiCoreFile, EFI_SECTION_TE, 1, &Pe32Section);\r
1669       }\r
1670     \r
1671       if (EFI_ERROR (Status)) {\r
1672         Error (NULL, 0, 3000, "Invalid", "could not find either a PE32 or a TE section in PEI core file!");\r
1673         return EFI_ABORTED;\r
1674       }\r
1675     \r
1676       Status = GetPe32Info (\r
1677                 (VOID *) ((UINTN) Pe32Section.Pe32Section + sizeof (EFI_SECTION_PE32)),\r
1678                 &EntryPoint,\r
1679                 &BaseOfCode,\r
1680                 &MachineType\r
1681                 );\r
1682     \r
1683       if (EFI_ERROR (Status)) {\r
1684         Error (NULL, 0, 3000, "Invalid", "could not get the PE32 entry point for the PEI core!");\r
1685         return EFI_ABORTED;\r
1686       }\r
1687       //\r
1688       // Physical address is FV base + offset of PE32 + offset of the entry point\r
1689       //\r
1690       PeiCorePhysicalAddress = FvInfo->BaseAddress;\r
1691       PeiCorePhysicalAddress += (UINTN) Pe32Section.Pe32Section + sizeof (EFI_SECTION_PE32) - (UINTN) FvImage->FileImage;\r
1692       PeiCorePhysicalAddress += EntryPoint;\r
1693       DebugMsg (NULL, 0, 9, "PeiCore physical entry point address", "Address = 0x%llX", (unsigned long long) PeiCorePhysicalAddress);\r
1694 \r
1695       if (MachineType == EFI_IMAGE_MACHINE_ARMT) {\r
1696         memset (ResetVector, 0, sizeof (ResetVector));\r
1697         // Address of PEI Core, if we have one\r
1698         ResetVector[1] = (UINT32)PeiCorePhysicalAddress;\r
1699       }\r
1700       \r
1701       //\r
1702       // Copy to the beginning of the FV \r
1703       //\r
1704       memcpy ((UINT8 *) ((UINTN) FvImage->FileImage), ResetVector, sizeof (ResetVector));\r
1705 \r
1706     }\r
1707 \r
1708     return EFI_SUCCESS;\r
1709   }\r
1710   \r
1711   //\r
1712   // Sec Core found, now find PE32 section\r
1713   //\r
1714   Status = GetSectionByType (SecCoreFile, EFI_SECTION_PE32, 1, &Pe32Section);\r
1715   if (Status == EFI_NOT_FOUND) {\r
1716     Status = GetSectionByType (SecCoreFile, EFI_SECTION_TE, 1, &Pe32Section);\r
1717   }\r
1718 \r
1719   if (EFI_ERROR (Status)) {\r
1720     Error (NULL, 0, 3000, "Invalid", "could not find a PE32 section in the SEC core file.");\r
1721     return EFI_ABORTED;\r
1722   }\r
1723 \r
1724   Status = GetPe32Info (\r
1725             (VOID *) ((UINTN) Pe32Section.Pe32Section + sizeof (EFI_SECTION_PE32)),\r
1726             &EntryPoint,\r
1727             &BaseOfCode,\r
1728             &MachineType\r
1729             );\r
1730   if (EFI_ERROR (Status)) {\r
1731     Error (NULL, 0, 3000, "Invalid", "could not get the PE32 entry point for the SEC core.");\r
1732     return EFI_ABORTED;\r
1733   }\r
1734   \r
1735   if (MachineType != EFI_IMAGE_MACHINE_ARMT) {\r
1736     //\r
1737     // If SEC is not ARM we have nothing to do\r
1738     //\r
1739     return EFI_SUCCESS;\r
1740   }\r
1741   \r
1742   //\r
1743   // Physical address is FV base + offset of PE32 + offset of the entry point\r
1744   //\r
1745   SecCorePhysicalAddress = FvInfo->BaseAddress;\r
1746   SecCorePhysicalAddress += (UINTN) Pe32Section.Pe32Section + sizeof (EFI_SECTION_PE32) - (UINTN) FvImage->FileImage;\r
1747   SecCorePhysicalAddress += EntryPoint;\r
1748   DebugMsg (NULL, 0, 9, "SecCore physical entry point address", "Address = 0x%llX", (unsigned long long) SecCorePhysicalAddress); \r
1749 \r
1750   //\r
1751   // Find the PEI Core. It may not exist if SEC loads DXE core directly\r
1752   //\r
1753   PeiCorePhysicalAddress = 0;\r
1754   Status = GetFileByType (EFI_FV_FILETYPE_PEI_CORE, 1, &PeiCoreFile);\r
1755   if (!EFI_ERROR (Status) && PeiCoreFile != NULL) {\r
1756     //\r
1757     // PEI Core found, now find PE32 or TE section\r
1758     //\r
1759     Status = GetSectionByType (PeiCoreFile, EFI_SECTION_PE32, 1, &Pe32Section);\r
1760     if (Status == EFI_NOT_FOUND) {\r
1761       Status = GetSectionByType (PeiCoreFile, EFI_SECTION_TE, 1, &Pe32Section);\r
1762     }\r
1763   \r
1764     if (EFI_ERROR (Status)) {\r
1765       Error (NULL, 0, 3000, "Invalid", "could not find either a PE32 or a TE section in PEI core file!");\r
1766       return EFI_ABORTED;\r
1767     }\r
1768   \r
1769     Status = GetPe32Info (\r
1770               (VOID *) ((UINTN) Pe32Section.Pe32Section + sizeof (EFI_SECTION_PE32)),\r
1771               &EntryPoint,\r
1772               &BaseOfCode,\r
1773               &MachineType\r
1774               );\r
1775   \r
1776     if (EFI_ERROR (Status)) {\r
1777       Error (NULL, 0, 3000, "Invalid", "could not get the PE32 entry point for the PEI core!");\r
1778       return EFI_ABORTED;\r
1779     }\r
1780     //\r
1781     // Physical address is FV base + offset of PE32 + offset of the entry point\r
1782     //\r
1783     PeiCorePhysicalAddress = FvInfo->BaseAddress;\r
1784     PeiCorePhysicalAddress += (UINTN) Pe32Section.Pe32Section + sizeof (EFI_SECTION_PE32) - (UINTN) FvImage->FileImage;\r
1785     PeiCorePhysicalAddress += EntryPoint;\r
1786     DebugMsg (NULL, 0, 9, "PeiCore physical entry point address", "Address = 0x%llX", (unsigned long long) PeiCorePhysicalAddress);\r
1787   }\r
1788   \r
1789   \r
1790   // B SecEntryPoint - signed_immed_24 part +/-32MB offset\r
1791   // on ARM, the PC is always 8 ahead, so we're not really jumping from the base address, but from base address + 8\r
1792   ResetVector[0] = (INT32)(SecCorePhysicalAddress - FvInfo->BaseAddress - 8) >> 2;\r
1793   \r
1794   if (ResetVector[0] > 0x00FFFFFF) {\r
1795     Error (NULL, 0, 3000, "Invalid", "SEC Entry point must be within 32MB of the start of the FV");\r
1796     return EFI_ABORTED;    \r
1797   }\r
1798   \r
1799   // Add opcode for an uncondional branch with no link. AKA B SecEntryPoint\r
1800   ResetVector[0] |= 0xEA000000;\r
1801   \r
1802   \r
1803   // Address of PEI Core, if we have one\r
1804   ResetVector[1] = (UINT32)PeiCorePhysicalAddress;\r
1805   \r
1806   // SWI handler movs   pc,lr. Just in case a debugger uses SWI\r
1807   ResetVector[2] = 0xE1B0F07E;\r
1808   \r
1809   // Place holder to support a common interrupt handler from ROM. \r
1810   // Currently not suppprted. For this to be used the reset vector would not be in this FV\r
1811   // and the exception vectors would be hard coded in the ROM and just through this address \r
1812   // to find a common handler in the a module in the FV.\r
1813   ResetVector[3] = 0;\r
1814 \r
1815   //\r
1816   // Copy to the beginning of the FV \r
1817   //\r
1818   memcpy ((UINT8 *) ((UINTN) FvImage->FileImage), ResetVector, sizeof (ResetVector));\r
1819 \r
1820   DebugMsg (NULL, 0, 9, "Update Reset vector in FV Header", NULL);\r
1821 \r
1822   return EFI_SUCCESS;\r
1823 }\r
1824 \r
1825 EFI_STATUS\r
1826 GetPe32Info (\r
1827   IN UINT8                  *Pe32,\r
1828   OUT UINT32                *EntryPoint,\r
1829   OUT UINT32                *BaseOfCode,\r
1830   OUT UINT16                *MachineType\r
1831   )\r
1832 /*++\r
1833 \r
1834 Routine Description:\r
1835 \r
1836   Retrieves the PE32 entry point offset and machine type from PE image or TeImage.  \r
1837   See EfiImage.h for machine types.  The entry point offset is from the beginning \r
1838   of the PE32 buffer passed in.\r
1839 \r
1840 Arguments:\r
1841 \r
1842   Pe32          Beginning of the PE32.\r
1843   EntryPoint    Offset from the beginning of the PE32 to the image entry point.\r
1844   BaseOfCode    Base address of code.\r
1845   MachineType   Magic number for the machine type.\r
1846 \r
1847 Returns:\r
1848 \r
1849   EFI_SUCCESS             Function completed successfully.\r
1850   EFI_ABORTED             Error encountered.\r
1851   EFI_INVALID_PARAMETER   A required parameter was NULL.\r
1852   EFI_UNSUPPORTED         The operation is unsupported.\r
1853 \r
1854 --*/\r
1855 {\r
1856   EFI_IMAGE_DOS_HEADER             *DosHeader;\r
1857   EFI_IMAGE_OPTIONAL_HEADER_UNION  *ImgHdr;\r
1858   EFI_TE_IMAGE_HEADER              *TeHeader;\r
1859 \r
1860   //\r
1861   // Verify input parameters\r
1862   //\r
1863   if (Pe32 == NULL) {\r
1864     return EFI_INVALID_PARAMETER;\r
1865   }\r
1866 \r
1867   //\r
1868   // First check whether it is one TE Image.\r
1869   //\r
1870   TeHeader = (EFI_TE_IMAGE_HEADER *) Pe32;\r
1871   if (TeHeader->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {\r
1872     //\r
1873     // By TeImage Header to get output\r
1874     //\r
1875     *EntryPoint   = TeHeader->AddressOfEntryPoint + sizeof (EFI_TE_IMAGE_HEADER) - TeHeader->StrippedSize;\r
1876     *BaseOfCode   = TeHeader->BaseOfCode + sizeof (EFI_TE_IMAGE_HEADER) - TeHeader->StrippedSize;\r
1877     *MachineType  = TeHeader->Machine;\r
1878   } else {\r
1879   \r
1880     //\r
1881     // Then check whether \r
1882     // First is the DOS header\r
1883     //\r
1884     DosHeader = (EFI_IMAGE_DOS_HEADER *) Pe32;\r
1885   \r
1886     //\r
1887     // Verify DOS header is expected\r
1888     //\r
1889     if (DosHeader->e_magic != EFI_IMAGE_DOS_SIGNATURE) {\r
1890       Error (NULL, 0, 3000, "Invalid", "Unknown magic number in the DOS header, 0x%04X.", DosHeader->e_magic);\r
1891       return EFI_UNSUPPORTED;\r
1892     }\r
1893     //\r
1894     // Immediately following is the NT header.\r
1895     //\r
1896     ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *) ((UINTN) Pe32 + DosHeader->e_lfanew);\r
1897   \r
1898     //\r
1899     // Verify NT header is expected\r
1900     //\r
1901     if (ImgHdr->Pe32.Signature != EFI_IMAGE_NT_SIGNATURE) {\r
1902       Error (NULL, 0, 3000, "Invalid", "Unrecognized image signature 0x%08X.", (unsigned) ImgHdr->Pe32.Signature);\r
1903       return EFI_UNSUPPORTED;\r
1904     }\r
1905     //\r
1906     // Get output\r
1907     //\r
1908     *EntryPoint   = ImgHdr->Pe32.OptionalHeader.AddressOfEntryPoint;\r
1909     *BaseOfCode   = ImgHdr->Pe32.OptionalHeader.BaseOfCode;\r
1910     *MachineType  = ImgHdr->Pe32.FileHeader.Machine;\r
1911   }\r
1912 \r
1913   //\r
1914   // Verify machine type is supported\r
1915   //\r
1916   if (*MachineType != EFI_IMAGE_MACHINE_IA32 && *MachineType != EFI_IMAGE_MACHINE_IA64 && *MachineType != EFI_IMAGE_MACHINE_X64 && *MachineType != EFI_IMAGE_MACHINE_EBC && \r
1917       *MachineType != EFI_IMAGE_MACHINE_ARMT) {\r
1918     Error (NULL, 0, 3000, "Invalid", "Unrecognized machine type in the PE32 file.");\r
1919     return EFI_UNSUPPORTED;\r
1920   }\r
1921 \r
1922   return EFI_SUCCESS;\r
1923 }\r
1924 \r
1925 EFI_STATUS\r
1926 GenerateFvImage (\r
1927   IN CHAR8                *InfFileImage,\r
1928   IN UINTN                InfFileSize,\r
1929   IN CHAR8                *FvFileName,\r
1930   IN CHAR8                *MapFileName\r
1931   )\r
1932 /*++\r
1933 \r
1934 Routine Description:\r
1935 \r
1936   This is the main function which will be called from application.\r
1937 \r
1938 Arguments:\r
1939 \r
1940   InfFileImage   Buffer containing the INF file contents.\r
1941   InfFileSize    Size of the contents of the InfFileImage buffer.\r
1942   FvFileName     Requested name for the FV file.\r
1943   MapFileName    Fv map file to log fv driver information.\r
1944 \r
1945 Returns:\r
1946 \r
1947   EFI_SUCCESS             Function completed successfully.\r
1948   EFI_OUT_OF_RESOURCES    Could not allocate required resources.\r
1949   EFI_ABORTED             Error encountered.\r
1950   EFI_INVALID_PARAMETER   A required parameter was NULL.\r
1951 \r
1952 --*/\r
1953 {\r
1954   EFI_STATUS                      Status;\r
1955   MEMORY_FILE                     InfMemoryFile;\r
1956   MEMORY_FILE                     FvImageMemoryFile;\r
1957   UINTN                           Index;\r
1958   EFI_FIRMWARE_VOLUME_HEADER      *FvHeader;\r
1959   EFI_FFS_FILE_HEADER             *VtfFileImage;\r
1960   UINT8                           *FvBufferHeader; // to make sure fvimage header 8 type alignment.\r
1961   UINT8                           *FvImage;\r
1962   UINTN                           FvImageSize;\r
1963   FILE                            *FvFile;\r
1964   CHAR8                           FvMapName [_MAX_PATH];\r
1965   FILE                            *FvMapFile;\r
1966   EFI_FIRMWARE_VOLUME_EXT_HEADER  *FvExtHeader;\r
1967   FILE                            *FvExtHeaderFile;\r
1968   UINTN                           FileSize;\r
1969   CHAR8                           FvReportName[_MAX_PATH];\r
1970   FILE                            *FvReportFile;\r
1971 \r
1972   FvBufferHeader = NULL;\r
1973   FvFile         = NULL;\r
1974   FvMapFile      = NULL;\r
1975   FvReportFile   = NULL;\r
1976 \r
1977   if (InfFileImage != NULL) {\r
1978     //\r
1979     // Initialize file structures\r
1980     //\r
1981     InfMemoryFile.FileImage           = InfFileImage;\r
1982     InfMemoryFile.CurrentFilePointer  = InfFileImage;\r
1983     InfMemoryFile.Eof                 = InfFileImage + InfFileSize;\r
1984   \r
1985     //\r
1986     // Parse the FV inf file for header information\r
1987     //\r
1988     Status = ParseFvInf (&InfMemoryFile, &mFvDataInfo);\r
1989     if (EFI_ERROR (Status)) {\r
1990       Error (NULL, 0, 0003, "Error parsing file", "the input FV INF file.");\r
1991       return Status;\r
1992     }\r
1993   }\r
1994 \r
1995   //\r
1996   // Update the file name return values\r
1997   //\r
1998   if (FvFileName == NULL && mFvDataInfo.FvName[0] != '\0') {\r
1999     FvFileName = mFvDataInfo.FvName;\r
2000   }\r
2001 \r
2002   if (FvFileName == NULL) {\r
2003     Error (NULL, 0, 1001, "Missing option", "Output file name");\r
2004     return EFI_ABORTED;\r
2005   }\r
2006   \r
2007   if (mFvDataInfo.FvBlocks[0].Length == 0) {\r
2008     Error (NULL, 0, 1001, "Missing required argument", "Block Size");\r
2009     return EFI_ABORTED;\r
2010   }\r
2011   \r
2012   //\r
2013   // Debug message Fv File System Guid\r
2014   //\r
2015   if (mFvDataInfo.FvFileSystemGuidSet) {\r
2016     DebugMsg (NULL, 0, 9, "FV File System Guid", "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", \r
2017                   (unsigned) mFvDataInfo.FvFileSystemGuid.Data1,\r
2018                   mFvDataInfo.FvFileSystemGuid.Data2,\r
2019                   mFvDataInfo.FvFileSystemGuid.Data3,\r
2020                   mFvDataInfo.FvFileSystemGuid.Data4[0],\r
2021                   mFvDataInfo.FvFileSystemGuid.Data4[1],\r
2022                   mFvDataInfo.FvFileSystemGuid.Data4[2],\r
2023                   mFvDataInfo.FvFileSystemGuid.Data4[3],\r
2024                   mFvDataInfo.FvFileSystemGuid.Data4[4],\r
2025                   mFvDataInfo.FvFileSystemGuid.Data4[5],\r
2026                   mFvDataInfo.FvFileSystemGuid.Data4[6],\r
2027                   mFvDataInfo.FvFileSystemGuid.Data4[7]);\r
2028   }\r
2029 \r
2030   //\r
2031   // Add PI FV extension header\r
2032   //\r
2033   FvExtHeader = NULL;\r
2034   FvExtHeaderFile = NULL;\r
2035   if (mFvDataInfo.FvExtHeaderFile[0] != 0) {\r
2036     //\r
2037     // Open the FV Extension Header file\r
2038     //\r
2039     FvExtHeaderFile = fopen (mFvDataInfo.FvExtHeaderFile, "rb");\r
2040 \r
2041     //\r
2042     // Get the file size\r
2043     //\r
2044     FileSize = _filelength (fileno (FvExtHeaderFile));\r
2045 \r
2046     //\r
2047     // Allocate a buffer for the FV Extension Header\r
2048     //\r
2049     FvExtHeader = malloc(FileSize);\r
2050     if (FvExtHeader == NULL) {\r
2051       fclose (FvExtHeaderFile);\r
2052       return EFI_OUT_OF_RESOURCES;\r
2053     }\r
2054 \r
2055     //\r
2056     // Read the FV Extension Header\r
2057     //\r
2058     fread (FvExtHeader, sizeof (UINT8), FileSize, FvExtHeaderFile);\r
2059     fclose (FvExtHeaderFile);\r
2060 \r
2061     //\r
2062     // See if there is an override for the FV Name GUID\r
2063     //\r
2064     if (mFvDataInfo.FvNameGuidSet) {\r
2065       memcpy (&FvExtHeader->FvName, &mFvDataInfo.FvNameGuid, sizeof (EFI_GUID));\r
2066     }\r
2067     memcpy (&mFvDataInfo.FvNameGuid, &FvExtHeader->FvName, sizeof (EFI_GUID));\r
2068     mFvDataInfo.FvNameGuidSet = TRUE;\r
2069   } else if (mFvDataInfo.FvNameGuidSet) {\r
2070     //\r
2071     // Allocate a buffer for the FV Extension Header\r
2072     //\r
2073     FvExtHeader = malloc(sizeof (EFI_FIRMWARE_VOLUME_EXT_HEADER));\r
2074     if (FvExtHeader == NULL) {\r
2075       return EFI_OUT_OF_RESOURCES;\r
2076     }\r
2077     memcpy (&FvExtHeader->FvName, &mFvDataInfo.FvNameGuid, sizeof (EFI_GUID));\r
2078     FvExtHeader->ExtHeaderSize = sizeof (EFI_FIRMWARE_VOLUME_EXT_HEADER);\r
2079   }\r
2080 \r
2081   //\r
2082   // Debug message Fv Name Guid\r
2083   //\r
2084   if (mFvDataInfo.FvNameGuidSet) {\r
2085       DebugMsg (NULL, 0, 9, "FV Name Guid", "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", \r
2086                   (unsigned) mFvDataInfo.FvNameGuid.Data1,\r
2087                   mFvDataInfo.FvNameGuid.Data2,\r
2088                   mFvDataInfo.FvNameGuid.Data3,\r
2089                   mFvDataInfo.FvNameGuid.Data4[0],\r
2090                   mFvDataInfo.FvNameGuid.Data4[1],\r
2091                   mFvDataInfo.FvNameGuid.Data4[2],\r
2092                   mFvDataInfo.FvNameGuid.Data4[3],\r
2093                   mFvDataInfo.FvNameGuid.Data4[4],\r
2094                   mFvDataInfo.FvNameGuid.Data4[5],\r
2095                   mFvDataInfo.FvNameGuid.Data4[6],\r
2096                   mFvDataInfo.FvNameGuid.Data4[7]);\r
2097   }\r
2098 \r
2099   if (CompareGuid (&mFvDataInfo.FvFileSystemGuid, &mEfiFirmwareFileSystem2Guid) == 0) {\r
2100     mFvDataInfo.IsPiFvImage = TRUE;\r
2101   }\r
2102 \r
2103   //\r
2104   // FvMap file to log the function address of all modules in one Fvimage\r
2105   //\r
2106   if (MapFileName != NULL) {\r
2107     strcpy (FvMapName, MapFileName);\r
2108   } else {\r
2109     strcpy (FvMapName, FvFileName);\r
2110     strcat (FvMapName, ".map");\r
2111   }\r
2112   VerboseMsg ("FV Map file name is %s", FvMapName);\r
2113 \r
2114   //\r
2115   // FvReport file to log the FV information in one Fvimage\r
2116   //\r
2117   strcpy (FvReportName, FvFileName);\r
2118   strcat (FvReportName, ".txt");\r
2119 \r
2120   //\r
2121   // Calculate the FV size and Update Fv Size based on the actual FFS files.\r
2122   // And Update mFvDataInfo data.\r
2123   //\r
2124   Status = CalculateFvSize (&mFvDataInfo);\r
2125   if (EFI_ERROR (Status)) {\r
2126     return Status;    \r
2127   }\r
2128   VerboseMsg ("the generated FV image size is %u bytes", (unsigned) mFvDataInfo.Size);\r
2129   \r
2130   //\r
2131   // support fv image and empty fv image\r
2132   //\r
2133   FvImageSize = mFvDataInfo.Size;\r
2134 \r
2135   //\r
2136   // Allocate the FV, assure FvImage Header 8 byte alignment\r
2137   //\r
2138   FvBufferHeader = malloc (FvImageSize + sizeof (UINT64));\r
2139   if (FvBufferHeader == NULL) {\r
2140     return EFI_OUT_OF_RESOURCES;\r
2141   }\r
2142   FvImage = (UINT8 *) (((UINTN) FvBufferHeader + 7) & ~7);\r
2143 \r
2144   //\r
2145   // Initialize the FV to the erase polarity\r
2146   //\r
2147   if (mFvDataInfo.FvAttributes == 0) {\r
2148     //\r
2149     // Set Default Fv Attribute \r
2150     //\r
2151     mFvDataInfo.FvAttributes = FV_DEFAULT_ATTRIBUTE;\r
2152   }\r
2153   if (mFvDataInfo.FvAttributes & EFI_FVB2_ERASE_POLARITY) {\r
2154     memset (FvImage, -1, FvImageSize);\r
2155   } else {\r
2156     memset (FvImage, 0, FvImageSize);\r
2157   }\r
2158 \r
2159   //\r
2160   // Initialize FV header\r
2161   //\r
2162   FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) FvImage;\r
2163 \r
2164   //\r
2165   // Initialize the zero vector to all zeros.\r
2166   //\r
2167   memset (FvHeader->ZeroVector, 0, 16);\r
2168 \r
2169   //\r
2170   // Copy the Fv file system GUID\r
2171   //\r
2172   memcpy (&FvHeader->FileSystemGuid, &mFvDataInfo.FvFileSystemGuid, sizeof (EFI_GUID));\r
2173 \r
2174   FvHeader->FvLength        = FvImageSize;\r
2175   FvHeader->Signature       = EFI_FVH_SIGNATURE;\r
2176   FvHeader->Attributes      = mFvDataInfo.FvAttributes;\r
2177   FvHeader->Revision        = EFI_FVH_REVISION;\r
2178   FvHeader->ExtHeaderOffset = 0;\r
2179   FvHeader->Reserved[0]     = 0;\r
2180   \r
2181   //\r
2182   // Copy firmware block map\r
2183   //\r
2184   for (Index = 0; mFvDataInfo.FvBlocks[Index].Length != 0; Index++) {\r
2185     FvHeader->BlockMap[Index].NumBlocks   = mFvDataInfo.FvBlocks[Index].NumBlocks;\r
2186     FvHeader->BlockMap[Index].Length      = mFvDataInfo.FvBlocks[Index].Length;\r
2187   }\r
2188 \r
2189   //\r
2190   // Add block map terminator\r
2191   //\r
2192   FvHeader->BlockMap[Index].NumBlocks   = 0;\r
2193   FvHeader->BlockMap[Index].Length      = 0;\r
2194 \r
2195   //\r
2196   // Complete the header\r
2197   //\r
2198   FvHeader->HeaderLength  = (UINT16) (((UINTN) &(FvHeader->BlockMap[Index + 1])) - (UINTN) FvImage);\r
2199   FvHeader->Checksum      = 0;\r
2200   FvHeader->Checksum      = CalculateChecksum16 ((UINT16 *) FvHeader, FvHeader->HeaderLength / sizeof (UINT16));\r
2201 \r
2202   //\r
2203   // If there is no FFS file, generate one empty FV\r
2204   //\r
2205   if (mFvDataInfo.FvFiles[0][0] == 0 && !mFvDataInfo.FvNameGuidSet) {\r
2206     goto WriteFile;\r
2207   }\r
2208 \r
2209   //\r
2210   // Initialize our "file" view of the buffer\r
2211   //\r
2212   FvImageMemoryFile.FileImage           = (CHAR8 *)FvImage;\r
2213   FvImageMemoryFile.CurrentFilePointer  = (CHAR8 *)FvImage + FvHeader->HeaderLength;\r
2214   FvImageMemoryFile.Eof                 = (CHAR8 *)FvImage + FvImageSize;\r
2215 \r
2216   //\r
2217   // Initialize the FV library.\r
2218   //\r
2219   InitializeFvLib (FvImageMemoryFile.FileImage, FvImageSize);\r
2220 \r
2221   //\r
2222   // Initialize the VTF file address.\r
2223   //\r
2224   VtfFileImage = (EFI_FFS_FILE_HEADER *) FvImageMemoryFile.Eof;\r
2225 \r
2226   //\r
2227   // Open FvMap file\r
2228   //\r
2229   FvMapFile = fopen (FvMapName, "w");\r
2230   if (FvMapFile == NULL) {\r
2231     Error (NULL, 0, 0001, "Error opening file", FvMapName);\r
2232     return EFI_ABORTED;\r
2233   }\r
2234   \r
2235   //\r
2236   // Open FvReport file\r
2237   //\r
2238   FvReportFile = fopen(FvReportName, "w");\r
2239   if (FvReportFile == NULL) {\r
2240     Error (NULL, 0, 0001, "Error opening file", FvReportName);\r
2241     return EFI_ABORTED;\r
2242   }\r
2243   //\r
2244   // record FV size information into FvMap file.\r
2245   //\r
2246   if (mFvTotalSize != 0) {\r
2247     fprintf (FvMapFile, EFI_FV_TOTAL_SIZE_STRING);\r
2248     fprintf (FvMapFile, " = 0x%x\n", (unsigned) mFvTotalSize);\r
2249   }\r
2250   if (mFvTakenSize != 0) {\r
2251     fprintf (FvMapFile, EFI_FV_TAKEN_SIZE_STRING);\r
2252     fprintf (FvMapFile, " = 0x%x\n", (unsigned) mFvTakenSize);\r
2253   }\r
2254   if (mFvTotalSize != 0 && mFvTakenSize != 0) {\r
2255     fprintf (FvMapFile, EFI_FV_SPACE_SIZE_STRING);\r
2256     fprintf (FvMapFile, " = 0x%x\n\n", (unsigned) (mFvTotalSize - mFvTakenSize));\r
2257   }\r
2258 \r
2259   //\r
2260   // record FV size information to FvReportFile.\r
2261   //\r
2262   fprintf (FvReportFile, "%s = 0x%x\n", EFI_FV_TOTAL_SIZE_STRING, (unsigned) mFvTotalSize);\r
2263   fprintf (FvReportFile, "%s = 0x%x\n", EFI_FV_TAKEN_SIZE_STRING, (unsigned) mFvTakenSize);\r
2264 \r
2265   //\r
2266   // Add PI FV extension header\r
2267   //\r
2268   if (FvExtHeader != NULL) {\r
2269     //\r
2270     // Add FV Extended Header contents to the FV as a PAD file\r
2271     //\r
2272     AddPadFile (&FvImageMemoryFile, 4, VtfFileImage, FvExtHeader);\r
2273 \r
2274     //\r
2275     // Fv Extension header change update Fv Header Check sum\r
2276     //\r
2277     FvHeader->Checksum      = 0;\r
2278     FvHeader->Checksum      = CalculateChecksum16 ((UINT16 *) FvHeader, FvHeader->HeaderLength / sizeof (UINT16));\r
2279   }\r
2280 \r
2281   //\r
2282   // Add files to FV\r
2283   //\r
2284   for (Index = 0; mFvDataInfo.FvFiles[Index][0] != 0; Index++) {\r
2285     //\r
2286     // Add the file\r
2287     //\r
2288     Status = AddFile (&FvImageMemoryFile, &mFvDataInfo, Index, &VtfFileImage, FvMapFile, FvReportFile);\r
2289 \r
2290     //\r
2291     // Exit if error detected while adding the file\r
2292     //\r
2293     if (EFI_ERROR (Status)) {\r
2294       goto Finish;\r
2295     }\r
2296   }\r
2297 \r
2298   //\r
2299   // If there is a VTF file, some special actions need to occur.\r
2300   //\r
2301   if ((UINTN) VtfFileImage != (UINTN) FvImageMemoryFile.Eof) {\r
2302     //\r
2303     // Pad from the end of the last file to the beginning of the VTF file.\r
2304     // If the left space is less than sizeof (EFI_FFS_FILE_HEADER)?\r
2305     //\r
2306     Status = PadFvImage (&FvImageMemoryFile, VtfFileImage);\r
2307     if (EFI_ERROR (Status)) {\r
2308       Error (NULL, 0, 4002, "Resource", "FV space is full, cannot add pad file between the last file and the VTF file.");\r
2309       goto Finish;\r
2310     }\r
2311     if (!mArm) {\r
2312       //\r
2313       // Update reset vector (SALE_ENTRY for IPF)\r
2314       // Now for IA32 and IA64 platform, the fv which has bsf file must have the \r
2315       // EndAddress of 0xFFFFFFFF. Thus, only this type fv needs to update the   \r
2316       // reset vector. If the PEI Core is found, the VTF file will probably get  \r
2317       // corrupted by updating the entry point.                                  \r
2318       //\r
2319       if ((mFvDataInfo.BaseAddress + mFvDataInfo.Size) == FV_IMAGES_TOP_ADDRESS) {       \r
2320         Status = UpdateResetVector (&FvImageMemoryFile, &mFvDataInfo, VtfFileImage);\r
2321         if (EFI_ERROR(Status)) {                                               \r
2322           Error (NULL, 0, 3000, "Invalid", "Could not update the reset vector.");\r
2323           goto Finish;                                              \r
2324         }\r
2325         DebugMsg (NULL, 0, 9, "Update Reset vector in VTF file", NULL);\r
2326       }\r
2327     }\r
2328   } \r
2329 \r
2330   if (mArm) {\r
2331     Status = UpdateArmResetVectorIfNeeded (&FvImageMemoryFile, &mFvDataInfo);\r
2332     if (EFI_ERROR (Status)) {                                               \r
2333       Error (NULL, 0, 3000, "Invalid", "Could not update the reset vector.");\r
2334       goto Finish;                                              \r
2335     }  \r
2336     \r
2337     //\r
2338     // Update Checksum for FvHeader\r
2339     //\r
2340     FvHeader->Checksum = 0;\r
2341     FvHeader->Checksum = CalculateChecksum16 ((UINT16 *) FvHeader, FvHeader->HeaderLength / sizeof (UINT16));\r
2342   }\r
2343   \r
2344   //\r
2345   // Update FV Alignment attribute to the largest alignment of all the FFS files in the FV\r
2346   //\r
2347   if ((((FvHeader->Attributes & EFI_FVB2_ALIGNMENT) >> 16)) < MaxFfsAlignment) {\r
2348     FvHeader->Attributes = ((MaxFfsAlignment << 16) | (FvHeader->Attributes & 0xFFFF));\r
2349     //\r
2350     // Update Checksum for FvHeader\r
2351     //\r
2352     FvHeader->Checksum      = 0;\r
2353     FvHeader->Checksum      = CalculateChecksum16 ((UINT16 *) FvHeader, FvHeader->HeaderLength / sizeof (UINT16));\r
2354   }\r
2355 \r
2356 WriteFile: \r
2357   //\r
2358   // Write fv file\r
2359   //\r
2360   FvFile = fopen (FvFileName, "wb");\r
2361   if (FvFile == NULL) {\r
2362     Error (NULL, 0, 0001, "Error opening file", FvFileName);\r
2363     Status = EFI_ABORTED;\r
2364     goto Finish;\r
2365   }\r
2366 \r
2367   if (fwrite (FvImage, 1, FvImageSize, FvFile) != FvImageSize) {\r
2368     Error (NULL, 0, 0002, "Error writing file", FvFileName);\r
2369     Status = EFI_ABORTED;\r
2370     goto Finish;\r
2371   }\r
2372 \r
2373 Finish:\r
2374   if (FvBufferHeader != NULL) {\r
2375     free (FvBufferHeader);\r
2376   }\r
2377 \r
2378   if (FvExtHeader != NULL) {\r
2379     free (FvExtHeader);\r
2380   }\r
2381   \r
2382   if (FvFile != NULL) {\r
2383     fclose (FvFile);\r
2384   }\r
2385   \r
2386   if (FvMapFile != NULL) {\r
2387     fclose (FvMapFile);\r
2388   }\r
2389 \r
2390   if (FvReportFile != NULL) {\r
2391     fclose (FvReportFile);\r
2392   }\r
2393   return Status;\r
2394 }\r
2395 \r
2396 EFI_STATUS\r
2397 UpdatePeiCoreEntryInFit (\r
2398   IN FIT_TABLE     *FitTablePtr,\r
2399   IN UINT64        PeiCorePhysicalAddress\r
2400   )\r
2401 /*++\r
2402 \r
2403 Routine Description:\r
2404 \r
2405   This function is used to update the Pei Core address in FIT, this can be used by Sec core to pass control from\r
2406   Sec to Pei Core\r
2407 \r
2408 Arguments:\r
2409 \r
2410   FitTablePtr             - The pointer of FIT_TABLE.\r
2411   PeiCorePhysicalAddress  - The address of Pei Core entry.\r
2412 \r
2413 Returns:\r
2414 \r
2415   EFI_SUCCESS             - The PEI_CORE FIT entry was updated successfully.\r
2416   EFI_NOT_FOUND           - Not found the PEI_CORE FIT entry.\r
2417 \r
2418 --*/\r
2419 {\r
2420   FIT_TABLE *TmpFitPtr;\r
2421   UINTN     Index;\r
2422   UINTN     NumFitComponents;\r
2423 \r
2424   TmpFitPtr         = FitTablePtr;\r
2425   NumFitComponents  = TmpFitPtr->CompSize;\r
2426 \r
2427   for (Index = 0; Index < NumFitComponents; Index++) {\r
2428     if ((TmpFitPtr->CvAndType & FIT_TYPE_MASK) == COMP_TYPE_FIT_PEICORE) {\r
2429       TmpFitPtr->CompAddress = PeiCorePhysicalAddress;\r
2430       return EFI_SUCCESS;\r
2431     }\r
2432 \r
2433     TmpFitPtr++;\r
2434   }\r
2435 \r
2436   return EFI_NOT_FOUND;\r
2437 }\r
2438 \r
2439 VOID\r
2440 UpdateFitCheckSum (\r
2441   IN FIT_TABLE   *FitTablePtr\r
2442   )\r
2443 /*++\r
2444 \r
2445 Routine Description:\r
2446 \r
2447   This function is used to update the checksum for FIT.\r
2448 \r
2449 \r
2450 Arguments:\r
2451 \r
2452   FitTablePtr             - The pointer of FIT_TABLE.\r
2453 \r
2454 Returns:\r
2455 \r
2456   None.\r
2457 \r
2458 --*/\r
2459 {\r
2460   if ((FitTablePtr->CvAndType & CHECKSUM_BIT_MASK) >> 7) {\r
2461     FitTablePtr->CheckSum = 0;\r
2462     FitTablePtr->CheckSum = CalculateChecksum8 ((UINT8 *) FitTablePtr, FitTablePtr->CompSize * 16);\r
2463   }\r
2464 }\r
2465 \r
2466 EFI_STATUS\r
2467 CalculateFvSize (\r
2468   FV_INFO *FvInfoPtr\r
2469   )\r
2470 /*++\r
2471 Routine Description:\r
2472   Calculate the FV size and Update Fv Size based on the actual FFS files.\r
2473   And Update FvInfo data.\r
2474 \r
2475 Arguments:\r
2476   FvInfoPtr     - The pointer to FV_INFO structure.\r
2477 \r
2478 Returns:\r
2479   EFI_ABORTED   - Ffs Image Error\r
2480   EFI_SUCCESS   - Successfully update FvSize\r
2481 --*/\r
2482 {\r
2483   UINTN               CurrentOffset;\r
2484   UINTN               Index;\r
2485   FILE                *fpin;\r
2486   UINTN               FfsFileSize;\r
2487   UINTN               FvExtendHeaderSize;\r
2488   UINT32              FfsAlignment;\r
2489   EFI_FFS_FILE_HEADER FfsHeader;\r
2490   BOOLEAN             VtfFileFlag;\r
2491   UINTN               VtfFileSize;\r
2492   \r
2493   FvExtendHeaderSize = 0;\r
2494   VtfFileSize = 0;\r
2495   VtfFileFlag = FALSE;\r
2496   fpin  = NULL;\r
2497   Index = 0;\r
2498 \r
2499   //\r
2500   // Compute size for easy access later\r
2501   //\r
2502   FvInfoPtr->Size = 0;\r
2503   for (Index = 0; FvInfoPtr->FvBlocks[Index].NumBlocks > 0 && FvInfoPtr->FvBlocks[Index].Length > 0; Index++) {\r
2504     FvInfoPtr->Size += FvInfoPtr->FvBlocks[Index].NumBlocks * FvInfoPtr->FvBlocks[Index].Length;\r
2505   }\r
2506   \r
2507   //\r
2508   // Caculate the required sizes for all FFS files.\r
2509   //\r
2510   CurrentOffset = sizeof (EFI_FIRMWARE_VOLUME_HEADER);\r
2511   \r
2512   for (Index = 1;; Index ++) {\r
2513     CurrentOffset += sizeof (EFI_FV_BLOCK_MAP_ENTRY);\r
2514     if (FvInfoPtr->FvBlocks[Index].NumBlocks == 0 || FvInfoPtr->FvBlocks[Index].Length == 0) {\r
2515       break;\r
2516     }\r
2517   }\r
2518   \r
2519   //\r
2520   // Calculate PI extension header\r
2521   //\r
2522   if (mFvDataInfo.FvExtHeaderFile[0] != '\0') {\r
2523     fpin = fopen (mFvDataInfo.FvExtHeaderFile, "rb");\r
2524     if (fpin == NULL) {\r
2525       Error (NULL, 0, 0001, "Error opening file", mFvDataInfo.FvExtHeaderFile);\r
2526       return EFI_ABORTED;\r
2527     }\r
2528     FvExtendHeaderSize = _filelength (fileno (fpin));\r
2529     fclose (fpin);\r
2530     CurrentOffset += sizeof (EFI_FFS_FILE_HEADER) + FvExtendHeaderSize;\r
2531     CurrentOffset = (CurrentOffset + 7) & (~7);\r
2532   } else if (mFvDataInfo.FvNameGuidSet) {\r
2533     CurrentOffset += sizeof (EFI_FFS_FILE_HEADER) + sizeof (EFI_FIRMWARE_VOLUME_EXT_HEADER);\r
2534     CurrentOffset = (CurrentOffset + 7) & (~7);\r
2535   }\r
2536 \r
2537   //\r
2538   // Accumlate every FFS file size.\r
2539   //\r
2540   for (Index = 0; FvInfoPtr->FvFiles[Index][0] != 0; Index++) {\r
2541     //\r
2542     // Open FFS file\r
2543     //\r
2544     fpin = NULL;\r
2545     fpin = fopen (FvInfoPtr->FvFiles[Index], "rb");\r
2546     if (fpin == NULL) {\r
2547       Error (NULL, 0, 0001, "Error opening file", FvInfoPtr->FvFiles[Index]);\r
2548       return EFI_ABORTED;\r
2549     }\r
2550     //\r
2551     // Get the file size\r
2552     //\r
2553     FfsFileSize = _filelength (fileno (fpin));\r
2554     //\r
2555     // Read Ffs File header\r
2556     //\r
2557     fread (&FfsHeader, sizeof (UINT8), sizeof (EFI_FFS_FILE_HEADER), fpin);\r
2558     //\r
2559     // close file\r
2560     //\r
2561     fclose (fpin);\r
2562     \r
2563     if (FvInfoPtr->IsPiFvImage) {\r
2564             //\r
2565             // Check whether this ffs file is vtf file\r
2566             //\r
2567             if (IsVtfFile (&FfsHeader)) {\r
2568               if (VtfFileFlag) {\r
2569                 //\r
2570                 // One Fv image can't have two vtf files.\r
2571                 //\r
2572                 return EFI_ABORTED;\r
2573               }\r
2574               VtfFileFlag = TRUE;\r
2575         VtfFileSize = FfsFileSize;\r
2576         continue;\r
2577       }\r
2578 \r
2579       //\r
2580       // Get the alignment of FFS file \r
2581       //\r
2582       ReadFfsAlignment (&FfsHeader, &FfsAlignment);\r
2583       FfsAlignment = 1 << FfsAlignment;\r
2584       //\r
2585       // Add Pad file\r
2586       //\r
2587       if (((CurrentOffset + sizeof (EFI_FFS_FILE_HEADER)) % FfsAlignment) != 0) {\r
2588         CurrentOffset = (CurrentOffset + sizeof (EFI_FFS_FILE_HEADER) * 2 + FfsAlignment - 1) & ~(FfsAlignment - 1);\r
2589         CurrentOffset -= sizeof (EFI_FFS_FILE_HEADER);\r
2590       }\r
2591           }\r
2592 \r
2593     //\r
2594     // Add ffs file size\r
2595     //\r
2596     if (FvInfoPtr->SizeofFvFiles[Index] > FfsFileSize) {\r
2597         CurrentOffset += FvInfoPtr->SizeofFvFiles[Index];\r
2598     } else {\r
2599         CurrentOffset += FfsFileSize;\r
2600     }\r
2601         \r
2602     //\r
2603     // Make next ffs file start at QWord Boundry\r
2604     //\r
2605     if (FvInfoPtr->IsPiFvImage) {\r
2606         CurrentOffset = (CurrentOffset + EFI_FFS_FILE_HEADER_ALIGNMENT - 1) & ~(EFI_FFS_FILE_HEADER_ALIGNMENT - 1);\r
2607     }\r
2608   }\r
2609   CurrentOffset += VtfFileSize;\r
2610   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
2611   \r
2612   if (FvInfoPtr->Size == 0) { \r
2613     //\r
2614     // Update FvInfo data\r
2615     //\r
2616     FvInfoPtr->FvBlocks[0].NumBlocks = CurrentOffset / FvInfoPtr->FvBlocks[0].Length + ((CurrentOffset % FvInfoPtr->FvBlocks[0].Length)?1:0);\r
2617     FvInfoPtr->Size = FvInfoPtr->FvBlocks[0].NumBlocks * FvInfoPtr->FvBlocks[0].Length;\r
2618     FvInfoPtr->FvBlocks[1].NumBlocks = 0;\r
2619     FvInfoPtr->FvBlocks[1].Length = 0;\r
2620   } else if (FvInfoPtr->Size < CurrentOffset) {\r
2621     //\r
2622     // Not invalid\r
2623     //\r
2624     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
2625     return EFI_INVALID_PARAMETER;\r
2626   }\r
2627   \r
2628   //\r
2629   // Set Fv Size Information\r
2630   //\r
2631   mFvTotalSize = FvInfoPtr->Size;\r
2632   mFvTakenSize = CurrentOffset;\r
2633 \r
2634   return EFI_SUCCESS;\r
2635 }\r
2636 \r
2637 EFI_STATUS\r
2638 FfsRebaseImageRead (\r
2639   IN     VOID    *FileHandle,\r
2640   IN     UINTN   FileOffset,\r
2641   IN OUT UINT32  *ReadSize,\r
2642   OUT    VOID    *Buffer\r
2643   )\r
2644 /*++\r
2645 \r
2646 Routine Description:\r
2647 \r
2648   Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file\r
2649 \r
2650 Arguments:\r
2651 \r
2652   FileHandle - The handle to the PE/COFF file\r
2653 \r
2654   FileOffset - The offset, in bytes, into the file to read\r
2655 \r
2656   ReadSize   - The number of bytes to read from the file starting at FileOffset\r
2657 \r
2658   Buffer     - A pointer to the buffer to read the data into.\r
2659 \r
2660 Returns:\r
2661 \r
2662   EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset\r
2663 \r
2664 --*/\r
2665 {\r
2666   CHAR8   *Destination8;\r
2667   CHAR8   *Source8;\r
2668   UINT32  Length;\r
2669 \r
2670   Destination8  = Buffer;\r
2671   Source8       = (CHAR8 *) ((UINTN) FileHandle + FileOffset);\r
2672   Length        = *ReadSize;\r
2673   while (Length--) {\r
2674     *(Destination8++) = *(Source8++);\r
2675   }\r
2676 \r
2677   return EFI_SUCCESS;\r
2678 }\r
2679 \r
2680 EFI_STATUS\r
2681 GetChildFvFromFfs (\r
2682   IN      FV_INFO               *FvInfo, \r
2683   IN      EFI_FFS_FILE_HEADER   *FfsFile,\r
2684   IN      UINTN                 XipOffset\r
2685   )\r
2686 /*++\r
2687 \r
2688 Routine Description:\r
2689 \r
2690   This function gets all child FvImages in the input FfsFile, and records\r
2691   their base address to the parent image.\r
2692 \r
2693 Arguments:\r
2694   FvInfo            A pointer to FV_INFO struture.\r
2695   FfsFile           A pointer to Ffs file image that may contain FvImage.\r
2696   XipOffset         The offset address to the parent FvImage base.\r
2697 \r
2698 Returns:\r
2699 \r
2700   EFI_SUCCESS        Base address of child Fv image is recorded.\r
2701 --*/\r
2702 {\r
2703   EFI_STATUS                          Status;\r
2704   UINTN                               Index;\r
2705   EFI_FILE_SECTION_POINTER            SubFvSection;\r
2706   EFI_FIRMWARE_VOLUME_HEADER          *SubFvImageHeader;\r
2707   EFI_PHYSICAL_ADDRESS                SubFvBaseAddress;\r
2708 \r
2709   for (Index = 1;; Index++) {\r
2710     //\r
2711     // Find FV section \r
2712     //\r
2713     Status = GetSectionByType (FfsFile, EFI_SECTION_FIRMWARE_VOLUME_IMAGE, Index, &SubFvSection);\r
2714     if (EFI_ERROR (Status)) {\r
2715       break;\r
2716     }\r
2717     SubFvImageHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINT8 *) SubFvSection.FVImageSection + sizeof (EFI_FIRMWARE_VOLUME_IMAGE_SECTION));\r
2718     //\r
2719     // Rebase on Flash\r
2720     //\r
2721     SubFvBaseAddress = FvInfo->BaseAddress + (UINTN) SubFvImageHeader - (UINTN) FfsFile + XipOffset;\r
2722     mFvBaseAddress[mFvBaseAddressNumber ++ ] = SubFvBaseAddress;\r
2723   }\r
2724 \r
2725   return EFI_SUCCESS;\r
2726 }\r
2727 \r
2728 EFI_STATUS\r
2729 FfsRebase ( \r
2730   IN OUT  FV_INFO               *FvInfo, \r
2731   IN      CHAR8                 *FileName,           \r
2732   IN OUT  EFI_FFS_FILE_HEADER   *FfsFile,\r
2733   IN      UINTN                 XipOffset,\r
2734   IN      FILE                  *FvMapFile\r
2735   )\r
2736 /*++\r
2737 \r
2738 Routine Description:\r
2739 \r
2740   This function determines if a file is XIP and should be rebased.  It will\r
2741   rebase any PE32 sections found in the file using the base address.\r
2742 \r
2743 Arguments:\r
2744   \r
2745   FvInfo            A pointer to FV_INFO struture.\r
2746   FileName          Ffs File PathName\r
2747   FfsFile           A pointer to Ffs file image.\r
2748   XipOffset         The offset address to use for rebasing the XIP file image.\r
2749   FvMapFile         FvMapFile to record the function address in one Fvimage\r
2750 \r
2751 Returns:\r
2752 \r
2753   EFI_SUCCESS             The image was properly rebased.\r
2754   EFI_INVALID_PARAMETER   An input parameter is invalid.\r
2755   EFI_ABORTED             An error occurred while rebasing the input file image.\r
2756   EFI_OUT_OF_RESOURCES    Could not allocate a required resource.\r
2757   EFI_NOT_FOUND           No compressed sections could be found.\r
2758 \r
2759 --*/\r
2760 {\r
2761   EFI_STATUS                            Status;\r
2762   PE_COFF_LOADER_IMAGE_CONTEXT          ImageContext;\r
2763   PE_COFF_LOADER_IMAGE_CONTEXT          OrigImageContext;  \r
2764   EFI_PHYSICAL_ADDRESS                  XipBase;\r
2765   EFI_PHYSICAL_ADDRESS                  NewPe32BaseAddress;\r
2766   EFI_PHYSICAL_ADDRESS                  *BaseToUpdate;\r
2767   UINTN                                 Index;\r
2768   EFI_FILE_SECTION_POINTER              CurrentPe32Section;\r
2769   EFI_FFS_FILE_STATE                    SavedState;\r
2770   EFI_IMAGE_OPTIONAL_HEADER_UNION       *ImgHdr;\r
2771   EFI_TE_IMAGE_HEADER                   *TEImageHeader;\r
2772   UINT8                                 *MemoryImagePointer;\r
2773   EFI_IMAGE_SECTION_HEADER              *SectionHeader;\r
2774   CHAR8                                 PeFileName [_MAX_PATH];\r
2775   CHAR8                                 *Cptr;\r
2776   FILE                                  *PeFile;\r
2777   UINT8                                 *PeFileBuffer;\r
2778   UINT32                                PeFileSize;\r
2779   CHAR8                                 *PdbPointer;\r
2780 \r
2781   Index              = 0;  \r
2782   MemoryImagePointer = NULL;\r
2783   BaseToUpdate       = NULL;\r
2784   TEImageHeader      = NULL;\r
2785   ImgHdr             = NULL;\r
2786   SectionHeader      = NULL;\r
2787   Cptr               = NULL;\r
2788   PeFile             = NULL;\r
2789   PeFileBuffer       = NULL;\r
2790 \r
2791   //\r
2792   // Don't need to relocate image when BaseAddress is not set.\r
2793   //\r
2794   if (FvInfo->BaseAddress == 0) {\r
2795     return EFI_SUCCESS;\r
2796   }\r
2797   XipBase = FvInfo->BaseAddress + XipOffset;\r
2798 \r
2799   //\r
2800   // We only process files potentially containing PE32 sections.\r
2801   //\r
2802   switch (FfsFile->Type) {\r
2803     case EFI_FV_FILETYPE_SECURITY_CORE:\r
2804     case EFI_FV_FILETYPE_PEI_CORE:\r
2805     case EFI_FV_FILETYPE_PEIM:\r
2806     case EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER:\r
2807     case EFI_FV_FILETYPE_DRIVER:\r
2808     case EFI_FV_FILETYPE_DXE_CORE:\r
2809       break;\r
2810     case EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE:\r
2811       //\r
2812       // Rebase the inside FvImage.\r
2813       //\r
2814       GetChildFvFromFfs (FvInfo, FfsFile, XipOffset);\r
2815 \r
2816       //\r
2817       // Search PE/TE section in FV sectin.\r
2818       //\r
2819       break;\r
2820     default:\r
2821       return EFI_SUCCESS;\r
2822   }\r
2823   //\r
2824   // Rebase each PE32 section\r
2825   //\r
2826   Status      = EFI_SUCCESS;\r
2827   for (Index = 1;; Index++) {\r
2828     //\r
2829     // Init Value\r
2830     //\r
2831     NewPe32BaseAddress = 0;\r
2832     \r
2833     //\r
2834     // Find Pe Image\r
2835     //\r
2836     Status = GetSectionByType (FfsFile, EFI_SECTION_PE32, Index, &CurrentPe32Section);\r
2837     if (EFI_ERROR (Status)) {\r
2838       break;\r
2839     }\r
2840 \r
2841     //\r
2842     // Initialize context\r
2843     //\r
2844     memset (&ImageContext, 0, sizeof (ImageContext));\r
2845     ImageContext.Handle     = (VOID *) ((UINTN) CurrentPe32Section.Pe32Section + sizeof (EFI_PE32_SECTION));\r
2846     ImageContext.ImageRead  = (PE_COFF_LOADER_READ_FILE) FfsRebaseImageRead;\r
2847     Status                  = PeCoffLoaderGetImageInfo (&ImageContext);\r
2848     if (EFI_ERROR (Status)) {\r
2849       Error (NULL, 0, 3000, "Invalid PeImage", "The input file is %s and the return status is %x", FileName, (int) Status);\r
2850       return Status;\r
2851     }\r
2852 \r
2853     if (ImageContext.Machine == EFI_IMAGE_MACHINE_ARMT) {\r
2854       mArm = TRUE;\r
2855     }\r
2856 \r
2857     //\r
2858     // Keep Image Context for PE image in FV\r
2859     //\r
2860     memcpy (&OrigImageContext, &ImageContext, sizeof (ImageContext));\r
2861     \r
2862     //\r
2863     // Get File PdbPointer\r
2864     //\r
2865     PdbPointer = PeCoffLoaderGetPdbPointer (ImageContext.Handle);\r
2866 \r
2867     //\r
2868     // Get PeHeader pointer\r
2869     //\r
2870     ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((UINTN) CurrentPe32Section.Pe32Section + sizeof (EFI_PE32_SECTION) + ImageContext.PeCoffHeaderOffset);\r
2871 \r
2872     //\r
2873     // Calculate the PE32 base address, based on file type\r
2874     //\r
2875     switch (FfsFile->Type) {\r
2876       case EFI_FV_FILETYPE_SECURITY_CORE:\r
2877       case EFI_FV_FILETYPE_PEI_CORE:\r
2878       case EFI_FV_FILETYPE_PEIM:\r
2879       case EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER:\r
2880         //\r
2881         // Check if section-alignment and file-alignment match or not\r
2882         //\r
2883         if ((ImgHdr->Pe32.OptionalHeader.SectionAlignment != ImgHdr->Pe32.OptionalHeader.FileAlignment)) {\r
2884           //\r
2885           // Xip module has the same section alignment and file alignment.\r
2886           //\r
2887           Error (NULL, 0, 3000, "Invalid", "Section-Alignment and File-Alignment do not match : %s.", FileName);\r
2888           return EFI_ABORTED;\r
2889         }\r
2890         //\r
2891         // PeImage has no reloc section. It will try to get reloc data from the original EFI image. \r
2892         //\r
2893         if (ImageContext.RelocationsStripped) {\r
2894           //\r
2895           // Construct the original efi file Name \r
2896           //\r
2897           strcpy (PeFileName, FileName);\r
2898           Cptr = PeFileName + strlen (PeFileName);\r
2899           while (*Cptr != '.') {\r
2900             Cptr --;\r
2901           }\r
2902           if (*Cptr != '.') {\r
2903             Error (NULL, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName);\r
2904             return EFI_ABORTED;\r
2905           } else {\r
2906             *(Cptr + 1) = 'e';\r
2907             *(Cptr + 2) = 'f';\r
2908             *(Cptr + 3) = 'i';\r
2909             *(Cptr + 4) = '\0';\r
2910           }\r
2911           PeFile = fopen (PeFileName, "rb");\r
2912           if (PeFile == NULL) {\r
2913             Warning (NULL, 0, 0, "Invalid", "The file %s has no .reloc section.", FileName);\r
2914             //Error (NULL, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName);\r
2915             //return EFI_ABORTED;\r
2916             break;\r
2917           }\r
2918           //\r
2919           // Get the file size\r
2920           //\r
2921           PeFileSize = _filelength (fileno (PeFile));\r
2922           PeFileBuffer = (UINT8 *) malloc (PeFileSize);\r
2923           if (PeFileBuffer == NULL) {\r
2924             Error (NULL, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName);\r
2925             return EFI_OUT_OF_RESOURCES;\r
2926           }\r
2927           //\r
2928           // Read Pe File\r
2929           //\r
2930           fread (PeFileBuffer, sizeof (UINT8), PeFileSize, PeFile);\r
2931           //\r
2932           // close file\r
2933           //\r
2934           fclose (PeFile);\r
2935           //\r
2936           // Handle pointer to the original efi image.\r
2937           //\r
2938           ImageContext.Handle = PeFileBuffer;\r
2939           Status              = PeCoffLoaderGetImageInfo (&ImageContext);\r
2940           if (EFI_ERROR (Status)) {\r
2941             Error (NULL, 0, 3000, "Invalid PeImage", "The input file is %s and the return status is %x", FileName, (int) Status);\r
2942             return Status;\r
2943           }\r
2944           ImageContext.RelocationsStripped = FALSE;\r
2945         }\r
2946 \r
2947         NewPe32BaseAddress = XipBase + (UINTN) CurrentPe32Section.Pe32Section + sizeof (EFI_PE32_SECTION) - (UINTN)FfsFile;\r
2948         BaseToUpdate = &XipBase;\r
2949         break;\r
2950 \r
2951       case EFI_FV_FILETYPE_DRIVER:\r
2952       case EFI_FV_FILETYPE_DXE_CORE:\r
2953         //\r
2954         // Check if section-alignment and file-alignment match or not\r
2955         //\r
2956         if ((ImgHdr->Pe32.OptionalHeader.SectionAlignment != ImgHdr->Pe32.OptionalHeader.FileAlignment)) {\r
2957           //\r
2958           // Xip module has the same section alignment and file alignment.\r
2959           //\r
2960           Error (NULL, 0, 3000, "Invalid", "Section-Alignment and File-Alignment do not match : %s.", FileName);\r
2961           return EFI_ABORTED;\r
2962         }\r
2963         NewPe32BaseAddress = XipBase + (UINTN) CurrentPe32Section.Pe32Section + sizeof (EFI_PE32_SECTION) - (UINTN)FfsFile;\r
2964         BaseToUpdate = &XipBase;                        \r
2965         break;\r
2966 \r
2967       default:\r
2968         //\r
2969         // Not supported file type\r
2970         //\r
2971         return EFI_SUCCESS;\r
2972     }\r
2973     \r
2974     //\r
2975     // Relocation doesn't exist\r
2976     //\r
2977     if (ImageContext.RelocationsStripped) {\r
2978       Warning (NULL, 0, 0, "Invalid", "The file %s has no .reloc section.", FileName);\r
2979       continue;\r
2980     }\r
2981 \r
2982     //\r
2983     // Relocation exist and rebase\r
2984     //\r
2985     //\r
2986     // Load and Relocate Image Data\r
2987     //\r
2988     MemoryImagePointer = (UINT8 *) malloc ((UINTN) ImageContext.ImageSize + ImageContext.SectionAlignment);\r
2989     if (MemoryImagePointer == NULL) {\r
2990       Error (NULL, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName);\r
2991       return EFI_OUT_OF_RESOURCES;\r
2992     }\r
2993     memset ((VOID *) MemoryImagePointer, 0, (UINTN) ImageContext.ImageSize + ImageContext.SectionAlignment);\r
2994     ImageContext.ImageAddress = ((UINTN) MemoryImagePointer + ImageContext.SectionAlignment - 1) & (~((INT64)ImageContext.SectionAlignment - 1));\r
2995     \r
2996     Status =  PeCoffLoaderLoadImage (&ImageContext);\r
2997     if (EFI_ERROR (Status)) {\r
2998       Error (NULL, 0, 3000, "Invalid", "LocateImage() call failed on rebase of %s", FileName);\r
2999       free ((VOID *) MemoryImagePointer);\r
3000       return Status;\r
3001     }\r
3002          \r
3003     ImageContext.DestinationAddress = NewPe32BaseAddress;\r
3004     Status                          = PeCoffLoaderRelocateImage (&ImageContext);\r
3005     if (EFI_ERROR (Status)) {\r
3006       Error (NULL, 0, 3000, "Invalid", "RelocateImage() call failed on rebase of %s", FileName);\r
3007       free ((VOID *) MemoryImagePointer);\r
3008       return Status;\r
3009     }\r
3010 \r
3011     //\r
3012     // Copy Relocated data to raw image file.\r
3013     //\r
3014     SectionHeader = (EFI_IMAGE_SECTION_HEADER *) (\r
3015                        (UINTN) ImgHdr +\r
3016                        sizeof (UINT32) + \r
3017                        sizeof (EFI_IMAGE_FILE_HEADER) +  \r
3018                        ImgHdr->Pe32.FileHeader.SizeOfOptionalHeader\r
3019                        );\r
3020     \r
3021     for (Index = 0; Index < ImgHdr->Pe32.FileHeader.NumberOfSections; Index ++, SectionHeader ++) {\r
3022       CopyMem (\r
3023         (UINT8 *) CurrentPe32Section.Pe32Section + sizeof (EFI_COMMON_SECTION_HEADER) + SectionHeader->PointerToRawData, \r
3024         (VOID*) (UINTN) (ImageContext.ImageAddress + SectionHeader->VirtualAddress), \r
3025         SectionHeader->SizeOfRawData\r
3026         );\r
3027     }\r
3028 \r
3029     free ((VOID *) MemoryImagePointer);\r
3030     MemoryImagePointer = NULL;\r
3031     if (PeFileBuffer != NULL) {\r
3032       free (PeFileBuffer);\r
3033       PeFileBuffer = NULL;\r
3034     }\r
3035     \r
3036     //\r
3037     // Update Image Base Address\r
3038     //\r
3039     if (ImgHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
3040       ImgHdr->Pe32.OptionalHeader.ImageBase = (UINT32) NewPe32BaseAddress;\r
3041     } else if (ImgHdr->Pe32Plus.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {\r
3042       ImgHdr->Pe32Plus.OptionalHeader.ImageBase = NewPe32BaseAddress;\r
3043     } else {\r
3044       Error (NULL, 0, 3000, "Invalid", "unknown PE magic signature %X in PE32 image %s",\r
3045         ImgHdr->Pe32.OptionalHeader.Magic,\r
3046         FileName\r
3047         );\r
3048       return EFI_ABORTED;\r
3049     }\r
3050 \r
3051     //\r
3052     // Now update file checksum\r
3053     //\r
3054     if (FfsFile->Attributes & FFS_ATTRIB_CHECKSUM) {\r
3055       SavedState  = FfsFile->State;\r
3056       FfsFile->IntegrityCheck.Checksum.File = 0;\r
3057       FfsFile->State                        = 0;\r
3058       FfsFile->IntegrityCheck.Checksum.File = CalculateChecksum8 (\r
3059                                                 (UINT8 *) (FfsFile + 1),\r
3060                                                 GetLength (FfsFile->Size) - sizeof (EFI_FFS_FILE_HEADER)\r
3061                                                 );\r
3062       FfsFile->State = SavedState;\r
3063     }\r
3064 \r
3065     //\r
3066     // Get this module function address from ModulePeMapFile and add them into FvMap file\r
3067     //\r
3068 \r
3069     //\r
3070     // Default use FileName as map file path\r
3071     //\r
3072     if (PdbPointer == NULL) {\r
3073       PdbPointer = FileName;\r
3074     }\r
3075 \r
3076     WriteMapFile (FvMapFile, PdbPointer, (EFI_GUID *) FfsFile, NewPe32BaseAddress, &OrigImageContext);\r
3077   }\r
3078 \r
3079   if (FfsFile->Type != EFI_FV_FILETYPE_SECURITY_CORE &&\r
3080       FfsFile->Type != EFI_FV_FILETYPE_PEI_CORE &&\r
3081       FfsFile->Type != EFI_FV_FILETYPE_PEIM &&\r
3082       FfsFile->Type != EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER &&\r
3083       FfsFile->Type != EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE\r
3084       ) {\r
3085     //\r
3086     // Only Peim code may have a TE section\r
3087     //\r
3088     return EFI_SUCCESS;\r
3089   }\r
3090   \r
3091   //\r
3092   // Now process TE sections\r
3093   //\r
3094   for (Index = 1;; Index++) {\r
3095     NewPe32BaseAddress = 0;\r
3096     \r
3097     //\r
3098     // Find Te Image\r
3099     //\r
3100     Status = GetSectionByType (FfsFile, EFI_SECTION_TE, Index, &CurrentPe32Section);\r
3101     if (EFI_ERROR (Status)) {\r
3102       break;\r
3103     }\r
3104     \r
3105     //\r
3106     // Calculate the TE base address, the FFS file base plus the offset of the TE section less the size stripped off\r
3107     // by GenTEImage\r
3108     //\r
3109     TEImageHeader = (EFI_TE_IMAGE_HEADER *) ((UINT8 *) CurrentPe32Section.Pe32Section + sizeof (EFI_COMMON_SECTION_HEADER));\r
3110 \r
3111     //\r
3112     // Initialize context, load image info.\r
3113     //\r
3114     memset (&ImageContext, 0, sizeof (ImageContext));\r
3115     ImageContext.Handle     = (VOID *) TEImageHeader;\r
3116     ImageContext.ImageRead  = (PE_COFF_LOADER_READ_FILE) FfsRebaseImageRead;\r
3117     Status                  = PeCoffLoaderGetImageInfo (&ImageContext);\r
3118     if (EFI_ERROR (Status)) {\r
3119       Error (NULL, 0, 3000, "Invalid TeImage", "The input file is %s and the return status is %x", FileName, (int) Status);\r
3120       return Status;\r
3121     }\r
3122 \r
3123     if (ImageContext.Machine == EFI_IMAGE_MACHINE_ARMT) {\r
3124       mArm = TRUE;\r
3125     }\r
3126 \r
3127     //\r
3128     // Keep Image Context for TE image in FV\r
3129     //\r
3130     memcpy (&OrigImageContext, &ImageContext, sizeof (ImageContext));\r
3131 \r
3132     //\r
3133     // Get File PdbPointer\r
3134     //\r
3135     PdbPointer = PeCoffLoaderGetPdbPointer (ImageContext.Handle);\r
3136 \r
3137     //\r
3138     // Set new rebased address.\r
3139     //\r
3140     NewPe32BaseAddress = XipBase + (UINTN) TEImageHeader + sizeof (EFI_TE_IMAGE_HEADER) \\r
3141                          - TEImageHeader->StrippedSize - (UINTN) FfsFile;\r
3142 \r
3143     //\r
3144     // if reloc is stripped, try to get the original efi image to get reloc info.\r
3145     //\r
3146     if (ImageContext.RelocationsStripped) {\r
3147       //\r
3148       // Construct the original efi file name \r
3149       //\r
3150       strcpy (PeFileName, FileName);\r
3151       Cptr = PeFileName + strlen (PeFileName);\r
3152       while (*Cptr != '.') {\r
3153         Cptr --;\r
3154       }\r
3155 \r
3156       if (*Cptr != '.') {\r
3157         Error (NULL, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName);\r
3158         return EFI_ABORTED;\r
3159       } else {\r
3160         *(Cptr + 1) = 'e';\r
3161         *(Cptr + 2) = 'f';\r
3162         *(Cptr + 3) = 'i';\r
3163         *(Cptr + 4) = '\0';\r
3164       }\r
3165 \r
3166       PeFile = fopen (PeFileName, "rb");\r
3167       if (PeFile == NULL) {\r
3168         Warning (NULL, 0, 0, "Invalid", "The file %s has no .reloc section.", FileName);\r
3169         //Error (NULL, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName);\r
3170         //return EFI_ABORTED;\r
3171       } else {\r
3172         //\r
3173         // Get the file size\r
3174         //\r
3175         PeFileSize = _filelength (fileno (PeFile));\r
3176         PeFileBuffer = (UINT8 *) malloc (PeFileSize);\r
3177         if (PeFileBuffer == NULL) {\r
3178           Error (NULL, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName);\r
3179           return EFI_OUT_OF_RESOURCES;\r
3180         }\r
3181         //\r
3182         // Read Pe File\r
3183         //\r
3184         fread (PeFileBuffer, sizeof (UINT8), PeFileSize, PeFile);\r
3185         //\r
3186         // close file\r
3187         //\r
3188         fclose (PeFile);\r
3189         //\r
3190         // Append reloc section into TeImage\r
3191         //\r
3192         ImageContext.Handle = PeFileBuffer;\r
3193         Status              = PeCoffLoaderGetImageInfo (&ImageContext);\r
3194         if (EFI_ERROR (Status)) {\r
3195           Error (NULL, 0, 3000, "Invalid TeImage", "The input file is %s and the return status is %x", FileName, (int) Status);\r
3196           return Status;\r
3197         }\r
3198         ImageContext.RelocationsStripped = FALSE;\r
3199       }\r
3200     }\r
3201     //\r
3202     // Relocation doesn't exist\r
3203     //\r
3204     if (ImageContext.RelocationsStripped) {\r
3205       Warning (NULL, 0, 0, "Invalid", "The file %s has no .reloc section.", FileName);\r
3206       continue;\r
3207     }\r
3208 \r
3209     //\r
3210     // Relocation exist and rebase\r
3211     //\r
3212     //\r
3213     // Load and Relocate Image Data\r
3214     //\r
3215     MemoryImagePointer = (UINT8 *) malloc ((UINTN) ImageContext.ImageSize + ImageContext.SectionAlignment);\r
3216     if (MemoryImagePointer == NULL) {\r
3217       Error (NULL, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName);\r
3218       return EFI_OUT_OF_RESOURCES;\r
3219     }\r
3220     memset ((VOID *) MemoryImagePointer, 0, (UINTN) ImageContext.ImageSize + ImageContext.SectionAlignment);\r
3221     ImageContext.ImageAddress = ((UINTN) MemoryImagePointer + ImageContext.SectionAlignment - 1) & (~(ImageContext.SectionAlignment - 1));\r
3222 \r
3223     Status =  PeCoffLoaderLoadImage (&ImageContext);\r
3224     if (EFI_ERROR (Status)) {\r
3225       Error (NULL, 0, 3000, "Invalid", "LocateImage() call failed on rebase of %s", FileName);\r
3226       free ((VOID *) MemoryImagePointer);\r
3227       return Status;\r
3228     }\r
3229     //\r
3230     // Reloacate TeImage\r
3231     // \r
3232     ImageContext.DestinationAddress = NewPe32BaseAddress;\r
3233     Status                          = PeCoffLoaderRelocateImage (&ImageContext);\r
3234     if (EFI_ERROR (Status)) {\r
3235       Error (NULL, 0, 3000, "Invalid", "RelocateImage() call failed on rebase of TE image %s", FileName);\r
3236       free ((VOID *) MemoryImagePointer);\r
3237       return Status;\r
3238     }\r
3239     \r
3240     //\r
3241     // Copy the relocated image into raw image file.\r
3242     //\r
3243     SectionHeader = (EFI_IMAGE_SECTION_HEADER *) (TEImageHeader + 1);\r
3244     for (Index = 0; Index < TEImageHeader->NumberOfSections; Index ++, SectionHeader ++) {\r
3245       if (!ImageContext.IsTeImage) {\r
3246         CopyMem (\r
3247           (UINT8 *) TEImageHeader + sizeof (EFI_TE_IMAGE_HEADER) - TEImageHeader->StrippedSize + SectionHeader->PointerToRawData, \r
3248           (VOID*) (UINTN) (ImageContext.ImageAddress + SectionHeader->VirtualAddress), \r
3249           SectionHeader->SizeOfRawData\r
3250           );\r
3251       } else {\r
3252         CopyMem (\r
3253           (UINT8 *) TEImageHeader + sizeof (EFI_TE_IMAGE_HEADER) - TEImageHeader->StrippedSize + SectionHeader->PointerToRawData, \r
3254           (VOID*) (UINTN) (ImageContext.ImageAddress + sizeof (EFI_TE_IMAGE_HEADER) - TEImageHeader->StrippedSize + SectionHeader->VirtualAddress), \r
3255           SectionHeader->SizeOfRawData\r
3256           );\r
3257       }\r
3258     }\r
3259     \r
3260     //\r
3261     // Free the allocated memory resource\r
3262     //\r
3263     free ((VOID *) MemoryImagePointer);\r
3264     MemoryImagePointer = NULL;\r
3265     if (PeFileBuffer != NULL) {\r
3266       free (PeFileBuffer);\r
3267       PeFileBuffer = NULL;\r
3268     }\r
3269     \r
3270     //\r
3271     // Update Image Base Address\r
3272     //\r
3273     TEImageHeader->ImageBase = NewPe32BaseAddress;\r
3274 \r
3275     //\r
3276     // Now update file checksum\r
3277     //\r
3278     if (FfsFile->Attributes & FFS_ATTRIB_CHECKSUM) {\r
3279       SavedState  = FfsFile->State;\r
3280       FfsFile->IntegrityCheck.Checksum.File = 0;\r
3281       FfsFile->State                        = 0;\r
3282       FfsFile->IntegrityCheck.Checksum.File = CalculateChecksum8 (\r
3283                                                 (UINT8 *)(FfsFile + 1),\r
3284                                                 GetLength (FfsFile->Size) - sizeof (EFI_FFS_FILE_HEADER)\r
3285                                                 );\r
3286       FfsFile->State = SavedState;\r
3287     }\r
3288     //\r
3289     // Get this module function address from ModulePeMapFile and add them into FvMap file\r
3290     //\r
3291 \r
3292     //\r
3293     // Default use FileName as map file path\r
3294     //\r
3295     if (PdbPointer == NULL) {\r
3296       PdbPointer = FileName;\r
3297     }\r
3298 \r
3299     WriteMapFile (\r
3300       FvMapFile, \r
3301       PdbPointer, \r
3302       (EFI_GUID *) FfsFile,\r
3303       NewPe32BaseAddress, \r
3304       &OrigImageContext\r
3305       );\r
3306   }\r
3307  \r
3308   return EFI_SUCCESS;\r
3309 }\r
3310 \r
3311 EFI_STATUS\r
3312 FindApResetVectorPosition (\r
3313   IN  MEMORY_FILE  *FvImage,\r
3314   OUT UINT8        **Pointer\r
3315   )\r
3316 /*++\r
3317 \r
3318 Routine Description:\r
3319 \r
3320   Find the position in this FvImage to place Ap reset vector.\r
3321 \r
3322 Arguments:\r
3323 \r
3324   FvImage       Memory file for the FV memory image.\r
3325   Pointer       Pointer to pointer to position.\r
3326 \r
3327 Returns:\r
3328 \r
3329   EFI_NOT_FOUND   - No satisfied position is found.\r
3330   EFI_SUCCESS     - The suitable position is return.\r
3331 \r
3332 --*/\r
3333 {\r
3334   EFI_FFS_FILE_HEADER   *PadFile;\r
3335   UINT32                Index;\r
3336   EFI_STATUS            Status;\r
3337   UINT8                 *FixPoint;\r
3338   UINT32                FileLength;\r
3339 \r
3340   for (Index = 1; ;Index ++) {\r
3341     //\r
3342     // Find Pad File to add ApResetVector info\r
3343     //\r
3344     Status = GetFileByType (EFI_FV_FILETYPE_FFS_PAD, Index, &PadFile);\r
3345     if (EFI_ERROR (Status) || (PadFile == NULL)) {\r
3346       //\r
3347       // No Pad file to be found.\r
3348       //\r
3349       break;\r
3350     }\r
3351     //\r
3352     // Get Pad file size.\r
3353     //\r
3354     FileLength = (*(UINT32 *)(PadFile->Size)) & 0x00FFFFFF;\r
3355     FileLength = (FileLength + EFI_FFS_FILE_HEADER_ALIGNMENT - 1) & ~(EFI_FFS_FILE_HEADER_ALIGNMENT - 1); \r
3356     //\r
3357     // FixPoint must be align on 0x1000 relative to FvImage Header\r
3358     //\r
3359     FixPoint = (UINT8*) PadFile + sizeof (EFI_FFS_FILE_HEADER);\r
3360     FixPoint = FixPoint + 0x1000 - (((UINTN) FixPoint - (UINTN) FvImage->FileImage) & 0xFFF);\r
3361     //\r
3362     // FixPoint be larger at the last place of one fv image.\r
3363     //\r
3364     while (((UINTN) FixPoint + SIZEOF_STARTUP_DATA_ARRAY - (UINTN) PadFile) <= FileLength) {\r
3365       FixPoint += 0x1000;\r
3366     }\r
3367     FixPoint -= 0x1000;\r
3368     \r
3369     if ((UINTN) FixPoint < ((UINTN) PadFile + sizeof (EFI_FFS_FILE_HEADER))) {\r
3370       //\r
3371       // No alignment FixPoint in this Pad File.\r
3372       //\r
3373       continue;\r
3374     }\r
3375 \r
3376     if ((UINTN) FvImage->Eof - (UINTN)FixPoint <= 0x20000) {    \r
3377       //\r
3378       // Find the position to place ApResetVector\r
3379       //\r
3380       *Pointer = FixPoint;\r
3381       return EFI_SUCCESS;\r
3382     }\r
3383   }\r
3384   \r
3385   return EFI_NOT_FOUND;\r
3386 }\r
3387 \r
3388 EFI_STATUS\r
3389 ParseCapInf (\r
3390   IN  MEMORY_FILE  *InfFile,\r
3391   OUT CAP_INFO     *CapInfo\r
3392   )\r
3393 /*++\r
3394 \r
3395 Routine Description:\r
3396 \r
3397   This function parses a Cap.INF file and copies info into a CAP_INFO structure.\r
3398 \r
3399 Arguments:\r
3400 \r
3401   InfFile        Memory file image.\r
3402   CapInfo        Information read from INF file.\r
3403 \r
3404 Returns:\r
3405 \r
3406   EFI_SUCCESS       INF file information successfully retrieved.\r
3407   EFI_ABORTED       INF file has an invalid format.\r
3408   EFI_NOT_FOUND     A required string was not found in the INF file.\r
3409 --*/\r
3410 {\r
3411   CHAR8       Value[_MAX_PATH];\r
3412   UINT64      Value64;\r
3413   UINTN       Index, Number;\r
3414   EFI_STATUS  Status;\r
3415 \r
3416   //\r
3417   // Initialize Cap info\r
3418   //\r
3419   // memset (CapInfo, 0, sizeof (CAP_INFO));\r
3420   //\r
3421 \r
3422   //\r
3423   // Read the Capsule Guid\r
3424   //\r
3425   Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_CAPSULE_GUID_STRING, 0, Value);\r
3426   if (Status == EFI_SUCCESS) {\r
3427     //\r
3428     // Get the Capsule Guid\r
3429     //\r
3430     Status = StringToGuid (Value, &CapInfo->CapGuid);\r
3431     if (EFI_ERROR (Status)) {\r
3432       Error (NULL, 0, 2000, "Invalid parameter", "%s = %s", EFI_CAPSULE_GUID_STRING, Value);\r
3433       return EFI_ABORTED;\r
3434     }\r
3435     DebugMsg (NULL, 0, 9, "Capsule Guid", "%s = %s", EFI_CAPSULE_GUID_STRING, Value);\r
3436   }\r
3437 \r
3438   //\r
3439   // Read the Capsule Header Size\r
3440   //\r
3441   Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_CAPSULE_HEADER_SIZE_STRING, 0, Value);\r
3442   if (Status == EFI_SUCCESS) {\r
3443     Status = AsciiStringToUint64 (Value, FALSE, &Value64);\r
3444     if (EFI_ERROR (Status)) {\r
3445       Error (NULL, 0, 2000, "Invalid parameter", "%s = %s", EFI_CAPSULE_HEADER_SIZE_STRING, Value);\r
3446       return EFI_ABORTED;\r
3447     }\r
3448     CapInfo->HeaderSize = (UINT32) Value64;\r
3449     DebugMsg (NULL, 0, 9, "Capsule Header size", "%s = %s", EFI_CAPSULE_HEADER_SIZE_STRING, Value);\r
3450   }\r
3451 \r
3452   //\r
3453   // Read the Capsule Flag\r
3454   //\r
3455   Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_CAPSULE_FLAGS_STRING, 0, Value);\r
3456   if (Status == EFI_SUCCESS) {\r
3457     if (strstr (Value, "PopulateSystemTable") != NULL) {\r
3458       CapInfo->Flags |= CAPSULE_FLAGS_PERSIST_ACROSS_RESET | CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE;\r
3459       if (strstr (Value, "InitiateReset") != NULL) {\r
3460         CapInfo->Flags |= CAPSULE_FLAGS_INITIATE_RESET;\r
3461       }\r
3462     } else if (strstr (Value, "PersistAcrossReset") != NULL) {\r
3463       CapInfo->Flags |= CAPSULE_FLAGS_PERSIST_ACROSS_RESET; \r
3464       if (strstr (Value, "InitiateReset") != NULL) {\r
3465         CapInfo->Flags |= CAPSULE_FLAGS_INITIATE_RESET;\r
3466       }\r
3467     } else {\r
3468       Error (NULL, 0, 2000, "Invalid parameter", "invalid Flag setting for %s.", EFI_CAPSULE_FLAGS_STRING);\r
3469       return EFI_ABORTED;\r
3470     }\r
3471     DebugMsg (NULL, 0, 9, "Capsule Flag", Value);\r
3472   }\r
3473 \r
3474   //\r
3475   // Read Capsule File name\r
3476   //\r
3477   Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_FILE_NAME_STRING, 0, Value);\r
3478   if (Status == EFI_SUCCESS) {\r
3479     //\r
3480     // Get output file name\r
3481     //\r
3482     strcpy (CapInfo->CapName, Value);\r
3483   }\r
3484 \r
3485   //\r
3486   // Read the Capsule FileImage\r
3487   //\r
3488   Number = 0;\r
3489   for (Index = 0; Index < MAX_NUMBER_OF_FILES_IN_CAP; Index++) {\r
3490     if (CapInfo->CapFiles[Index][0] != '\0') {\r
3491       continue;\r
3492     }\r
3493     //\r
3494     // Read the capsule file name\r
3495     //\r
3496     Status = FindToken (InfFile, FILES_SECTION_STRING, EFI_FILE_NAME_STRING, Number++, Value);\r
3497 \r
3498     if (Status == EFI_SUCCESS) {\r
3499       //\r
3500       // Add the file\r
3501       //\r
3502       strcpy (CapInfo->CapFiles[Index], Value);\r
3503       DebugMsg (NULL, 0, 9, "Capsule component file", "the %uth file name is %s", (unsigned) Index, CapInfo->CapFiles[Index]); \r
3504     } else {\r
3505       break;\r
3506     }\r
3507   }\r
3508   \r
3509   if (Index == 0) {\r
3510     Warning (NULL, 0, 0, "Capsule components are not specified.", NULL);\r
3511   }\r
3512 \r
3513   return EFI_SUCCESS;\r
3514 }\r
3515 \r
3516 EFI_STATUS\r
3517 GenerateCapImage (\r
3518   IN CHAR8                *InfFileImage,\r
3519   IN UINTN                InfFileSize,\r
3520   IN CHAR8                *CapFileName\r
3521   )\r