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