8da3295097fd43e6e0445caaef524282105e1775
[people/mcb30/basetools.git] / Source / C / GenFv / GenFvInternalLib.c
1 /*++\r
2 \r
3 Copyright (c) 2004, 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 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 <Common/UefiBaseTypes.h>\r
36 #include "GenFvInternalLib.h"\r
37 #include "CommonLib.h"\r
38 #include "EfiUtilityMsgs.h"\r
39 #include "WinNtInclude.h"\r
40 \r
41 EFI_STATUS\r
42 CalculateFvSize (\r
43   FV_INFO *FvInfoPtr\r
44   );\r
45 /*++\r
46 Routine Description:\r
47   Calculate the FV size and Update Fv Size based on the actual FFS files.\r
48   And Update FvInfo data.\r
49 \r
50 Arguments:\r
51   FvInfoPtr     - The pointer to FV_INFO structure.\r
52 \r
53 Returns:\r
54   EFI_ABORTED   - Ffs Image Error\r
55   EFI_SUCCESS   - Successfully update FvSize\r
56 --*/\r
57 \r
58 EFI_STATUS\r
59 FfsRebase ( \r
60   IN OUT  FV_INFO               *FvInfo, \r
61   IN      CHAR8                 *FileName,           \r
62   IN OUT  EFI_FFS_FILE_HEADER   *FfsFile,\r
63   IN      UINTN                 XipOffset\r
64   );\r
65 /*++\r
66 \r
67 Routine Description:\r
68 \r
69   This function determines if a file is XIP and should be rebased.  It will\r
70   rebase any PE32 sections found in the file using the base address.\r
71 \r
72 Arguments:\r
73   \r
74   FvInfo            A pointer to FV_INFO struture.\r
75   FileName          Ffs file Name\r
76   FfsFile           A pointer to Ffs file image.\r
77   XipOffset         The offset address to use for rebasing the XIP file image.\r
78 \r
79 Returns:\r
80 \r
81   EFI_SUCCESS             The image was properly rebased.\r
82   EFI_INVALID_PARAMETER   An input parameter is invalid.\r
83   EFI_ABORTED             An error occurred while rebasing the input file image.\r
84   EFI_OUT_OF_RESOURCES    Could not allocate a required resource.\r
85   EFI_NOT_FOUND           No compressed sections could be found.\r
86 \r
87 --*/\r
88 \r
89 static UINT32 MaxFfsAlignment = 0;\r
90 \r
91 EFI_GUID  gEfiFirmwareFileSystem2Guid = EFI_FIRMWARE_FILE_SYSTEM2_GUID;\r
92 EFI_GUID  gEfiFirmwareVolumeTopFileGuid = EFI_FFS_VOLUME_TOP_FILE_GUID;\r
93 \r
94 CHAR8      *FvbAttributeName[] = {\r
95   EFI_FVB2_READ_DISABLED_CAP_STRING, \r
96   EFI_FVB2_READ_ENABLED_CAP_STRING,  \r
97   EFI_FVB2_READ_STATUS_STRING,       \r
98   EFI_FVB2_WRITE_DISABLED_CAP_STRING,\r
99   EFI_FVB2_WRITE_ENABLED_CAP_STRING, \r
100   EFI_FVB2_WRITE_STATUS_STRING,      \r
101   EFI_FVB2_LOCK_CAP_STRING,          \r
102   EFI_FVB2_LOCK_STATUS_STRING,       \r
103   NULL,\r
104   EFI_FVB2_STICKY_WRITE_STRING,      \r
105   EFI_FVB2_MEMORY_MAPPED_STRING,     \r
106   EFI_FVB2_ERASE_POLARITY_STRING,    \r
107   EFI_FVB2_READ_LOCK_CAP_STRING,     \r
108   EFI_FVB2_READ_LOCK_STATUS_STRING,  \r
109   EFI_FVB2_WRITE_LOCK_CAP_STRING,    \r
110   EFI_FVB2_WRITE_LOCK_STATUS_STRING \r
111 };\r
112 \r
113 CHAR8      *FvbAlignmentName[] = {\r
114   EFI_FVB2_ALIGNMENT_1_STRING,   \r
115   EFI_FVB2_ALIGNMENT_2_STRING,   \r
116   EFI_FVB2_ALIGNMENT_4_STRING,   \r
117   EFI_FVB2_ALIGNMENT_8_STRING,   \r
118   EFI_FVB2_ALIGNMENT_16_STRING,  \r
119   EFI_FVB2_ALIGNMENT_32_STRING,  \r
120   EFI_FVB2_ALIGNMENT_64_STRING,  \r
121   EFI_FVB2_ALIGNMENT_128_STRING, \r
122   EFI_FVB2_ALIGNMENT_256_STRING, \r
123   EFI_FVB2_ALIGNMENT_512_STRING, \r
124   EFI_FVB2_ALIGNMENT_1K_STRING,  \r
125   EFI_FVB2_ALIGNMENT_2K_STRING,  \r
126   EFI_FVB2_ALIGNMENT_4K_STRING,  \r
127   EFI_FVB2_ALIGNMENT_8K_STRING,  \r
128   EFI_FVB2_ALIGNMENT_16K_STRING, \r
129   EFI_FVB2_ALIGNMENT_32K_STRING, \r
130   EFI_FVB2_ALIGNMENT_64K_STRING, \r
131   EFI_FVB2_ALIGNMENT_128K_STRING,\r
132   EFI_FVB2_ALIGNMENT_256K_STRING,\r
133   EFI_FVB2_ALIGNMNET_512K_STRING,\r
134   EFI_FVB2_ALIGNMENT_1M_STRING,  \r
135   EFI_FVB2_ALIGNMENT_2M_STRING,  \r
136   EFI_FVB2_ALIGNMENT_4M_STRING,  \r
137   EFI_FVB2_ALIGNMENT_8M_STRING,  \r
138   EFI_FVB2_ALIGNMENT_16M_STRING, \r
139   EFI_FVB2_ALIGNMENT_32M_STRING, \r
140   EFI_FVB2_ALIGNMENT_64M_STRING, \r
141   EFI_FVB2_ALIGNMENT_128M_STRING,\r
142   EFI_FVB2_ALIGNMENT_256M_STRING,\r
143   EFI_FVB2_ALIGNMENT_512M_STRING,\r
144   EFI_FVB2_ALIGNMENT_1G_STRING,  \r
145   EFI_FVB2_ALIGNMENT_2G_STRING\r
146 };\r
147 \r
148 //\r
149 // This data array will be located at the base of the Firmware Volume Header (FVH)\r
150 // in the boot block.  It must not exceed 14 bytes of code.  The last 2 bytes\r
151 // will be used to keep the FVH checksum consistent.\r
152 // This code will be run in response to a starutp IPI for HT-enabled systems.\r
153 //\r
154 #define SIZEOF_STARTUP_DATA_ARRAY 0x10\r
155 \r
156 UINT8                                   m128kRecoveryStartupApDataArray[SIZEOF_STARTUP_DATA_ARRAY] = {\r
157   //\r
158   // EA D0 FF 00 F0               ; far jmp F000:FFD0\r
159   // 0, 0, 0, 0, 0, 0, 0, 0, 0,   ; Reserved bytes\r
160   // 0, 0                         ; Checksum Padding\r
161   //\r
162   0xEA,\r
163   0xD0,\r
164   0xFF,\r
165   0x0,\r
166   0xF0,\r
167   0x00,\r
168   0x00,\r
169   0x00,\r
170   0x00,\r
171   0x00,\r
172   0x00,\r
173   0x00,\r
174   0x00,\r
175   0x00,\r
176   0x00,\r
177   0x00\r
178 };\r
179 \r
180 UINT8                                   m64kRecoveryStartupApDataArray[SIZEOF_STARTUP_DATA_ARRAY] = {\r
181   //\r
182   // EB CE                               ; jmp short ($-0x30)\r
183   // ; (from offset 0x0 to offset 0xFFD0)\r
184   // 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ; Reserved bytes\r
185   // 0, 0                                ; Checksum Padding\r
186   //\r
187   0xEB,\r
188   0xCE,\r
189   0x00,\r
190   0x00,\r
191   0x00,\r
192   0x00,\r
193   0x00,\r
194   0x00,\r
195   0x00,\r
196   0x00,\r
197   0x00,\r
198   0x00,\r
199   0x00,\r
200   0x00,\r
201   0x00,\r
202   0x00\r
203 };\r
204 \r
205 EFI_STATUS\r
206 ParseFvInf (\r
207   IN  MEMORY_FILE  *InfFile,\r
208   OUT FV_INFO      *FvInfo\r
209   )\r
210 /*++\r
211 \r
212 Routine Description:\r
213 \r
214   This function parses a FV.INF file and copies info into a FV_INFO structure.\r
215 \r
216 Arguments:\r
217 \r
218   InfFile         Memory file image.\r
219   FvInfo          Information read from INF file.\r
220 \r
221 Returns:\r
222 \r
223   EFI_SUCCESS       INF file information successfully retrieved.\r
224   EFI_ABORTED       INF file has an invalid format.\r
225   EFI_NOT_FOUND     A required string was not found in the INF file.\r
226 --*/\r
227 {\r
228   CHAR8       Value[_MAX_PATH];\r
229   UINT64      Value64;\r
230   UINTN       Index;\r
231   EFI_STATUS  Status;\r
232 \r
233   //\r
234   // Initialize FV info\r
235   //\r
236   memset (FvInfo, 0, sizeof (FV_INFO));\r
237   FvInfo->BaseAddress = -1;\r
238 \r
239   //\r
240   // Read the FV base address\r
241   //\r
242   Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_FV_BASE_ADDRESS_STRING, 0, Value);\r
243   if (Status == EFI_SUCCESS) {\r
244     //\r
245     // Get the base address\r
246     //\r
247     Status = AsciiStringToUint64 (Value, FALSE, &Value64);\r
248     if (EFI_ERROR (Status)) {\r
249       Error (NULL, 0, 0, EFI_FV_BASE_ADDRESS_STRING, "invalid value");\r
250       return EFI_ABORTED;\r
251     }\r
252 \r
253     FvInfo->BaseAddress = Value64;\r
254   }\r
255 \r
256   //\r
257   // Read the FV Guid\r
258   //\r
259   Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_FV_GUID_STRING, 0, Value);\r
260   if (Status == EFI_SUCCESS) {\r
261     //\r
262     // Get the guid value\r
263     //\r
264     Status = StringToGuid (Value, &FvInfo->FvGuid);\r
265     if (EFI_ERROR (Status)) {\r
266       memcpy (&FvInfo->FvGuid, &gEfiFirmwareFileSystem2Guid, sizeof (EFI_GUID));\r
267     }\r
268   } else {\r
269     memcpy (&FvInfo->FvGuid, &gEfiFirmwareFileSystem2Guid, sizeof (EFI_GUID));\r
270   }\r
271 \r
272   //\r
273   // Read the FV file name\r
274   //\r
275   Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_FV_FILE_NAME_STRING, 0, Value);\r
276   if (Status == EFI_SUCCESS) {\r
277     //\r
278     // copy the file name\r
279     //\r
280     strcpy (FvInfo->FvName, Value);\r
281   }\r
282   \r
283   //\r
284   // Read Fv Attribute\r
285   //\r
286   for (Index = 0; Index < sizeof (FvbAttributeName)/sizeof (char *); Index ++) {\r
287     if ((FvbAttributeName [Index] != NULL) && \\r
288         (FindToken (InfFile, ATTRIBUTES_SECTION_STRING, FvbAttributeName [Index], 0, Value) == EFI_SUCCESS)) {\r
289       if ((strcmp (Value, TRUE_STRING) == 0) || (strcmp (Value, ONE_STRING) == 0)) {\r
290         FvInfo->FvAttributes |= 1 << Index;\r
291       } else if ((strcmp (Value, FALSE_STRING) != 0) && (strcmp (Value, ZERO_STRING) != 0)) {\r
292         Error (NULL, 0, 0, FvbAttributeName [Index], "expected %s | %s", TRUE_STRING, FALSE_STRING);\r
293         return EFI_ABORTED;\r
294       }\r
295     }\r
296   }\r
297 \r
298   //\r
299   // Read Fv Alignment\r
300   //\r
301   for (Index = 0; Index < sizeof (FvbAlignmentName)/sizeof (char *); Index ++) {\r
302     if (FindToken (InfFile, ATTRIBUTES_SECTION_STRING, FvbAlignmentName [Index], 0, Value) == EFI_SUCCESS) {\r
303       if (strcmp (Value, TRUE_STRING) == 0) {\r
304         FvInfo->FvAttributes |= Index << 16;\r
305         break;\r
306       }\r
307     }\r
308   }\r
309 \r
310   //\r
311   // Read block maps\r
312   //\r
313   for (Index = 0; Index < MAX_NUMBER_OF_FV_BLOCKS; Index++) {\r
314     //\r
315     // Read block size\r
316     //\r
317     Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_BLOCK_SIZE_STRING, Index, Value);\r
318 \r
319     if (Status == EFI_SUCCESS) {\r
320       //\r
321       // Update the size of block\r
322       //\r
323       Status = AsciiStringToUint64 (Value, FALSE, &Value64);\r
324       if (EFI_ERROR (Status)) {\r
325         Error (NULL, 0, 0, Value, "invalid value for %s", EFI_BLOCK_SIZE_STRING);\r
326         return EFI_ABORTED;\r
327       }\r
328 \r
329       FvInfo->FvBlocks[Index].Length = (UINT32) Value64;\r
330     } else {\r
331       //\r
332       // If there is no blocks size, but there is the number of block, then we have a mismatched pair\r
333       // and should return an error.\r
334       //\r
335       Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_NUM_BLOCKS_STRING, Index, Value);\r
336       if (!EFI_ERROR (Status)) {\r
337         Error (NULL, 0, 0, "must specify both", "%s and %s", EFI_NUM_BLOCKS_STRING, EFI_BLOCK_SIZE_STRING);\r
338         return EFI_ABORTED;\r
339       } else {\r
340         //\r
341         // We are done\r
342         //\r
343         break;\r
344       }\r
345     }\r
346 \r
347     //\r
348     // Read blocks number\r
349     //\r
350     Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_NUM_BLOCKS_STRING, Index, Value);\r
351 \r
352     if (Status == EFI_SUCCESS) {\r
353       //\r
354       // Update the number of blocks\r
355       //\r
356       Status = AsciiStringToUint64 (Value, FALSE, &Value64);\r
357       if (EFI_ERROR (Status)) {\r
358         Error (NULL, 0, 0, Value, "invalid value specified for %s", EFI_NUM_BLOCKS_STRING);\r
359         return EFI_ABORTED;\r
360       }\r
361 \r
362       FvInfo->FvBlocks[Index].NumBlocks = (UINT32) Value64;\r
363     }\r
364   }\r
365 \r
366   if (Index == 0) {\r
367     Error (NULL, 0, 0, NULL, "at lease one block size must be specified.");\r
368     return EFI_ABORTED;\r
369   }\r
370 \r
371   //\r
372   // Read files\r
373   //\r
374   for (Index = 0; Index < MAX_NUMBER_OF_FILES_IN_FV; Index++) {\r
375     //\r
376     // Read the number of blocks\r
377     //\r
378     Status = FindToken (InfFile, FILES_SECTION_STRING, EFI_FILE_NAME_STRING, Index, Value);\r
379 \r
380     if (Status == EFI_SUCCESS) {\r
381       //\r
382       // Add the file\r
383       //\r
384       strcpy (FvInfo->FvFiles[Index], Value);\r
385     } else {\r
386       break;\r
387     }\r
388   }\r
389 \r
390   //\r
391   // Compute size for easy access later\r
392   //\r
393   FvInfo->Size = 0;\r
394   for (Index = 0; FvInfo->FvBlocks[Index].NumBlocks; Index++) {\r
395     FvInfo->Size += FvInfo->FvBlocks[Index].NumBlocks * FvInfo->FvBlocks[Index].Length;\r
396   }\r
397 \r
398   return EFI_SUCCESS;\r
399 }\r
400 \r
401 VOID\r
402 UpdateFfsFileState (\r
403   IN EFI_FFS_FILE_HEADER          *FfsFile,\r
404   IN EFI_FIRMWARE_VOLUME_HEADER   *FvHeader\r
405   )\r
406 /*++\r
407 \r
408 Routine Description:\r
409 \r
410   This function changes the FFS file attributes based on the erase polarity\r
411   of the FV. Update the reserved bits of State to EFI_FVB2_ERASE_POLARITY. \r
412 \r
413 Arguments:\r
414 \r
415   FfsFile   File header.\r
416   FvHeader  FV header.\r
417 \r
418 Returns:\r
419 \r
420   None\r
421 \r
422 --*/\r
423 {\r
424   if (FvHeader->Attributes & EFI_FVB2_ERASE_POLARITY) {\r
425     FfsFile->State = (UINT8)~(FfsFile->State);\r
426     // FfsFile->State |= ~(UINT8) EFI_FILE_ALL_STATE_BITS;\r
427   }\r
428 }\r
429 \r
430 EFI_STATUS\r
431 ReadFfsAlignment (\r
432   IN EFI_FFS_FILE_HEADER    *FfsFile,\r
433   IN OUT UINT32             *Alignment\r
434   )\r
435 /*++\r
436 \r
437 Routine Description:\r
438 \r
439   This function determines the alignment of the FFS input file from the file\r
440   attributes.\r
441 \r
442 Arguments:\r
443 \r
444   FfsFile       FFS file to parse\r
445   Alignment     The minimum required alignment offset of the FFS file\r
446 \r
447 Returns:\r
448 \r
449   EFI_SUCCESS              The function completed successfully.\r
450   EFI_INVALID_PARAMETER    One of the input parameters was invalid.\r
451   EFI_ABORTED              An error occurred.\r
452 \r
453 --*/\r
454 {\r
455   //\r
456   // Verify input parameters.\r
457   //\r
458   if (FfsFile == NULL || Alignment == NULL) {\r
459     return EFI_INVALID_PARAMETER;\r
460   }\r
461 \r
462   switch ((FfsFile->Attributes >> 3) & 0x07) {\r
463 \r
464   case 0:\r
465     //\r
466     // 8 byte alignment, mini alignment requirement for FFS file. \r
467     //\r
468     *Alignment = 3;\r
469     break;\r
470 \r
471   case 1:\r
472     //\r
473     // 16 byte alignment\r
474     //\r
475     *Alignment = 4;\r
476     break;\r
477 \r
478   case 2:\r
479     //\r
480     // 128 byte alignment\r
481     //\r
482     *Alignment = 7;\r
483     break;\r
484 \r
485   case 3:\r
486     //\r
487     // 512 byte alignment\r
488     //\r
489     *Alignment = 9;\r
490     break;\r
491 \r
492   case 4:\r
493     //\r
494     // 1K byte alignment\r
495     //\r
496     *Alignment = 10;\r
497     break;\r
498 \r
499   case 5:\r
500     //\r
501     // 4K byte alignment\r
502     //\r
503     *Alignment = 12;\r
504     break;\r
505 \r
506   case 6:\r
507     //\r
508     // 32K byte alignment\r
509     //\r
510     *Alignment = 15;\r
511     break;\r
512 \r
513   case 7:\r
514     //\r
515     // 64K byte alignment\r
516     //\r
517     *Alignment = 16;\r
518     break;\r
519 \r
520   default:\r
521     Error (NULL, 0, 0, "nvalid file attribute calculated, this is most likely a utility error", NULL);\r
522     return EFI_ABORTED;\r
523   }\r
524 \r
525   return EFI_SUCCESS;\r
526 }\r
527 \r
528 EFI_STATUS\r
529 AddPadFile (\r
530   IN OUT MEMORY_FILE  *FvImage,\r
531   IN UINT32           DataAlignment\r
532   )\r
533 /*++\r
534 \r
535 Routine Description:\r
536 \r
537   This function adds a pad file to the FV image if it required to align the\r
538   data of the next file.\r
539 \r
540 Arguments:\r
541 \r
542   FvImage         The memory image of the FV to add it to.  The current offset\r
543                   must be valid.\r
544   DataAlignment   The data alignment of the next FFS file.\r
545 \r
546 Returns:\r
547 \r
548   EFI_SUCCESS              The function completed successfully.\r
549   EFI_INVALID_PARAMETER    One of the input parameters was invalid.\r
550   EFI_OUT_OF_RESOURCES     Insufficient resources exist in the FV to complete\r
551                            the pad file add.\r
552 \r
553 --*/\r
554 {\r
555   EFI_FFS_FILE_HEADER *PadFile;\r
556   EFI_GUID            PadFileGuid;\r
557   UINTN               PadFileSize;\r
558 \r
559   //\r
560   // Verify input parameters.\r
561   //\r
562   if (FvImage == NULL) {\r
563     return EFI_INVALID_PARAMETER;\r
564   }\r
565 \r
566   //\r
567   // Check if a pad file is necessary\r
568   //\r
569   if (((UINTN) FvImage->CurrentFilePointer - (UINTN) FvImage->FileImage + sizeof (EFI_FFS_FILE_HEADER)) % DataAlignment == 0) {\r
570     return EFI_SUCCESS;\r
571   }\r
572 \r
573   //\r
574   // Write pad file header\r
575   //\r
576   PadFile = (EFI_FFS_FILE_HEADER *) FvImage->CurrentFilePointer;\r
577 \r
578   //\r
579   // Verify that we have enough space for the file header\r
580   //\r
581   if ((UINTN) (PadFile + sizeof (EFI_FFS_FILE_HEADER)) >= (UINTN) FvImage->Eof) {\r
582     return EFI_OUT_OF_RESOURCES;\r
583   }\r
584 \r
585 #ifdef __GNUC__\r
586   {\r
587     uuid_t tmp_id;\r
588     uuid_generate (tmp_id);\r
589     memcpy (&PadFileGuid, tmp_id, sizeof (EFI_GUID));\r
590   }\r
591 #else\r
592   UuidCreate (&PadFileGuid);\r
593 #endif\r
594   memset (PadFile, 0, sizeof (EFI_FFS_FILE_HEADER));\r
595   memcpy (&PadFile->Name, &PadFileGuid, sizeof (EFI_GUID));\r
596   PadFile->Type       = EFI_FV_FILETYPE_FFS_PAD;\r
597   PadFile->Attributes = 0;\r
598 \r
599   //\r
600   // Calculate the pad file size\r
601   //\r
602   //\r
603   // This is the earliest possible valid offset (current plus pad file header\r
604   // plus the next file header)\r
605   //\r
606   PadFileSize = (UINTN) FvImage->CurrentFilePointer - (UINTN) FvImage->FileImage + (sizeof (EFI_FFS_FILE_HEADER) * 2);\r
607 \r
608   //\r
609   // Add whatever it takes to get to the next aligned address\r
610   //\r
611   while ((PadFileSize % DataAlignment) != 0) {\r
612     PadFileSize++;\r
613   }\r
614   //\r
615   // Subtract the next file header size\r
616   //\r
617   PadFileSize -= sizeof (EFI_FFS_FILE_HEADER);\r
618 \r
619   //\r
620   // Subtract the starting offset to get size\r
621   //\r
622   PadFileSize -= (UINTN) FvImage->CurrentFilePointer - (UINTN) FvImage->FileImage;\r
623 \r
624   //\r
625   // Write pad file size (calculated size minus next file header size)\r
626   //\r
627   PadFile->Size[0]  = (UINT8) (PadFileSize & 0xFF);\r
628   PadFile->Size[1]  = (UINT8) ((PadFileSize >> 8) & 0xFF);\r
629   PadFile->Size[2]  = (UINT8) ((PadFileSize >> 16) & 0xFF);\r
630 \r
631   //\r
632   // Fill in checksums and state, they must be 0 for checksumming.\r
633   //\r
634   PadFile->IntegrityCheck.Checksum.Header = 0;\r
635   PadFile->IntegrityCheck.Checksum.File   = 0;\r
636   PadFile->State                          = 0;\r
637   PadFile->IntegrityCheck.Checksum.Header = CalculateChecksum8 ((UINT8 *) PadFile, sizeof (EFI_FFS_FILE_HEADER));\r
638   if (PadFile->Attributes & FFS_ATTRIB_CHECKSUM) {\r
639     PadFile->IntegrityCheck.Checksum.File = CalculateChecksum8 ((UINT8 *) PadFile, PadFileSize);\r
640   } else {\r
641     PadFile->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;\r
642   }\r
643 \r
644   PadFile->State = EFI_FILE_HEADER_CONSTRUCTION | EFI_FILE_HEADER_VALID | EFI_FILE_DATA_VALID;\r
645   UpdateFfsFileState (\r
646     (EFI_FFS_FILE_HEADER *) PadFile,\r
647     (EFI_FIRMWARE_VOLUME_HEADER *) FvImage->FileImage\r
648     );\r
649 \r
650   //\r
651   // Verify that we have enough space (including the padding\r
652   //\r
653   if ((UINTN) (PadFile + PadFileSize) >= (UINTN) FvImage->Eof) {\r
654     return EFI_OUT_OF_RESOURCES;\r
655   }\r
656   //\r
657   // Update the current FV pointer\r
658   //\r
659   FvImage->CurrentFilePointer += PadFileSize;\r
660 \r
661   return EFI_SUCCESS;\r
662 }\r
663 \r
664 BOOLEAN\r
665 IsVtfFile (\r
666   IN EFI_FFS_FILE_HEADER    *FileBuffer\r
667   )\r
668 /*++\r
669 \r
670 Routine Description:\r
671 \r
672   This function checks the header to validate if it is a VTF file\r
673 \r
674 Arguments:\r
675 \r
676   FileBuffer     Buffer in which content of a file has been read.\r
677 \r
678 Returns:\r
679 \r
680   TRUE    If this is a VTF file\r
681   FALSE   If this is not a VTF file\r
682 \r
683 --*/\r
684 {\r
685   if (!memcmp (&FileBuffer->Name, &gEfiFirmwareVolumeTopFileGuid, sizeof (EFI_GUID))) {\r
686     return TRUE;\r
687   } else {\r
688     return FALSE;\r
689   }\r
690 }\r
691 \r
692 EFI_STATUS\r
693 AddFile (\r
694   IN OUT MEMORY_FILE          *FvImage,\r
695   IN FV_INFO                  *FvInfo,\r
696   IN UINTN                    Index,\r
697   IN OUT EFI_FFS_FILE_HEADER  **VtfFileImage  \r
698   )\r
699 /*++\r
700 \r
701 Routine Description:\r
702 \r
703   This function adds a file to the FV image.  The file will pad to the\r
704   appropriate alignment if required.\r
705 \r
706 Arguments:\r
707 \r
708   FvImage       The memory image of the FV to add it to.  The current offset\r
709                 must be valid.\r
710   FvInfo        Pointer to information about the FV.\r
711   Index         The file in the FvInfo file list to add.\r
712   VtfFileImage  A pointer to the VTF file within the FvImage.  If this is equal\r
713                 to the end of the FvImage then no VTF previously found.\r
714 \r
715 Returns:\r
716 \r
717   EFI_SUCCESS              The function completed successfully.\r
718   EFI_INVALID_PARAMETER    One of the input parameters was invalid.\r
719   EFI_ABORTED              An error occurred.\r
720   EFI_OUT_OF_RESOURCES     Insufficient resources exist to complete the add.\r
721 \r
722 --*/\r
723 {\r
724   FILE                  *NewFile;\r
725   UINTN                 FileSize;\r
726   UINT8                 *FileBuffer;\r
727   UINTN                 NumBytesRead;\r
728   UINT32                CurrentFileAlignment;\r
729   EFI_STATUS            Status;\r
730   EFI_PHYSICAL_ADDRESS  CurrentFileBaseAddress;\r
731   UINT8                 VtfHeaderChecksum;\r
732   UINT8                 VtfFileChecksum;\r
733   UINT8                 FileState;\r
734   //\r
735   // Verify input parameters.\r
736   //\r
737   if (FvImage == NULL || FvInfo == NULL || FvInfo->FvFiles[Index][0] == 0 || VtfFileImage == NULL) {\r
738     return EFI_INVALID_PARAMETER;\r
739   }\r
740 \r
741   //\r
742   // Read the file to add\r
743   //\r
744   NewFile = fopen (FvInfo->FvFiles[Index], "rb");\r
745 \r
746   if (NewFile == NULL) {\r
747     Error (NULL, 0, 0, FvInfo->FvFiles[Index], "failed to open file for reading");\r
748     return EFI_ABORTED;\r
749   }\r
750 \r
751   //\r
752   // Get the file size\r
753   //\r
754   FileSize = _filelength (fileno (NewFile));\r
755 \r
756   //\r
757   // Read the file into a buffer\r
758   //\r
759   FileBuffer = malloc (FileSize);\r
760   if (FileBuffer == NULL) {\r
761     Error (NULL, 0, 0, "memory allocation failure", NULL);\r
762     return EFI_OUT_OF_RESOURCES;\r
763   }\r
764 \r
765   NumBytesRead = fread (FileBuffer, sizeof (UINT8), FileSize, NewFile);\r
766 \r
767   //\r
768   // Done with the file, from this point on we will just use the buffer read.\r
769   //\r
770   fclose (NewFile);\r
771   \r
772   //\r
773   // Verify read successful\r
774   //\r
775   if (NumBytesRead != sizeof (UINT8) * FileSize) {\r
776     free (FileBuffer);\r
777     Error (NULL, 0, 0, FvInfo->FvFiles[Index], "failed to read input file contents");\r
778     return EFI_ABORTED;\r
779   }\r
780   \r
781   //\r
782   // Verify Ffs file\r
783   //\r
784   Status = VerifyFfsFile (FileBuffer);\r
785   if (EFI_ERROR (Status)) {\r
786     Error (NULL, 0, 0, FvInfo->FvFiles[Index], "the invalid FFS file");\r
787     free (FileBuffer);\r
788     return EFI_INVALID_PARAMETER;\r
789   }\r
790 \r
791   //\r
792   // Verify space exists to add the file\r
793   //\r
794   if (FileSize > (UINTN) ((UINTN) *VtfFileImage - (UINTN) FvImage->CurrentFilePointer)) {\r
795     Error (NULL, 0, 0, FvInfo->FvFiles[Index], "insufficient space remains to add the file");\r
796     free (FileBuffer);\r
797     return EFI_OUT_OF_RESOURCES;\r
798   }\r
799 \r
800   //\r
801   // Update the file state based on polarity of the FV.\r
802   //\r
803   UpdateFfsFileState (\r
804     (EFI_FFS_FILE_HEADER *) FileBuffer,\r
805     (EFI_FIRMWARE_VOLUME_HEADER *) FvImage->FileImage\r
806     );\r
807 \r
808   //\r
809   // Check if alignment is required\r
810   //\r
811   ReadFfsAlignment ((EFI_FFS_FILE_HEADER *) FileBuffer, &CurrentFileAlignment);\r
812   \r
813   //\r
814   // Find the largest alignment of all the FFS files in the FV\r
815   //\r
816   if (CurrentFileAlignment > MaxFfsAlignment) {\r
817     MaxFfsAlignment = CurrentFileAlignment;\r
818   }\r
819   //\r
820   // If we have a VTF file, add it at the top.\r
821   //\r
822   if (IsVtfFile ((EFI_FFS_FILE_HEADER *) FileBuffer)) {\r
823     if ((UINTN) *VtfFileImage == (UINTN) FvImage->Eof) {\r
824       //\r
825       // No previous VTF, add this one.\r
826       //\r
827       *VtfFileImage = (EFI_FFS_FILE_HEADER *) (UINTN) ((UINTN) FvImage->FileImage + FvInfo->Size - FileSize);\r
828       //\r
829       // Sanity check. The file MUST align appropriately\r
830       //\r
831       if (((UINTN) *VtfFileImage + sizeof (EFI_FFS_FILE_HEADER) - (UINTN) FvImage->FileImage) % (1 << CurrentFileAlignment)) {\r
832         Error (NULL, 0, 0, NULL, "VTF file does not align on %d-byte boundary", 1 << CurrentFileAlignment);\r
833         free (FileBuffer);\r
834         return EFI_ABORTED;\r
835       }\r
836       //\r
837       // Rebase the PE or TE image in FileBuffer of FFS file for XIP \r
838       // Rebase for the debug genfvmap tool\r
839       //\r
840       FfsRebase (FvInfo, FvInfo->FvFiles[Index], (EFI_FFS_FILE_HEADER *) FileBuffer, (UINTN) *VtfFileImage - (UINTN) FvImage->FileImage);\r
841       //\r
842       // copy VTF File\r
843       //\r
844       memcpy (*VtfFileImage, FileBuffer, FileSize);\r
845       free (FileBuffer);\r
846       return EFI_SUCCESS;\r
847     } else {\r
848       //\r
849       // Already found a VTF file.\r
850       //\r
851       Error (NULL, 0, 0, "multiple VTF files are illegal in a single FV", NULL);\r
852       free (FileBuffer);\r
853       return EFI_ABORTED;\r
854     }\r
855   }\r
856 \r
857   //\r
858   // Add pad file if necessary\r
859   //\r
860   Status = AddPadFile (FvImage, 1 << CurrentFileAlignment);\r
861   if (EFI_ERROR (Status)) {\r
862     Error (NULL, 0, 0, NULL, "ERROR: Could not align the file data properly.");\r
863     free (FileBuffer);\r
864     return EFI_ABORTED;\r
865   }\r
866   //\r
867   // Add file\r
868   //\r
869   if ((FvImage->CurrentFilePointer + FileSize) < FvImage->Eof) {\r
870     //\r
871     // Rebase the PE or TE image in FileBuffer of FFS file for XIP. \r
872     // Rebase Bs and Rt drivers for the debug genfvmap tool.\r
873     //\r
874     FfsRebase (FvInfo, FvInfo->FvFiles[Index], (EFI_FFS_FILE_HEADER *) FileBuffer, (UINTN) FvImage->CurrentFilePointer - (UINTN) FvImage->FileImage);\r
875     //\r
876     // Copy the file\r
877     //\r
878     memcpy (FvImage->CurrentFilePointer, FileBuffer, FileSize);\r
879     FvImage->CurrentFilePointer += FileSize;\r
880   } else {\r
881     Error (NULL, 0, 0, NULL, "ERROR: The firmware volume is out of space, could not add file %s.\n", FvInfo->FvFiles[Index]);\r
882     free (FileBuffer);\r
883     return EFI_ABORTED;\r
884   }\r
885   //\r
886   // Make next file start at QWord Boundry\r
887   //\r
888   while (((UINTN) FvImage->CurrentFilePointer & (EFI_FFS_FILE_HEADER_ALIGNMENT - 1)) != 0) {\r
889     FvImage->CurrentFilePointer++;\r
890   }\r
891 \r
892   //\r
893   // Free allocated memory.\r
894   //\r
895   free (FileBuffer);\r
896 \r
897   return EFI_SUCCESS;\r
898 }\r
899 \r
900 EFI_STATUS\r
901 PadFvImage (\r
902   IN MEMORY_FILE          *FvImage,\r
903   IN EFI_FFS_FILE_HEADER  *VtfFileImage\r
904   )\r
905 /*++\r
906 \r
907 Routine Description:\r
908 \r
909   This function places a pad file between the last file in the FV and the VTF\r
910   file if the VTF file exists.\r
911 \r
912 Arguments:\r
913 \r
914   FvImage       Memory file for the FV memory image\r
915   VtfFileImage  The address of the VTF file.  If this is the end of the FV\r
916                 image, no VTF exists and no pad file is needed.\r
917 \r
918 Returns:\r
919 \r
920   EFI_SUCCESS             Completed successfully.\r
921   EFI_INVALID_PARAMETER   One of the input parameters was NULL.\r
922 \r
923 --*/\r
924 {\r
925   EFI_FFS_FILE_HEADER *PadFile;\r
926   UINTN               FileSize;\r
927   EFI_GUID            PadFileGuid;\r
928 \r
929   //\r
930   // If there is no VTF or the VTF naturally follows the previous file without a\r
931   // pad file, then there's nothing to do\r
932   //\r
933   if ((UINTN) VtfFileImage == (UINTN) FvImage->Eof || \\r
934       ((UINTN) VtfFileImage == (UINTN) FvImage->CurrentFilePointer)) {\r
935     return EFI_SUCCESS;\r
936   }\r
937 \r
938   //\r
939   // Pad file starts at beginning of free space\r
940   //\r
941   PadFile = (EFI_FFS_FILE_HEADER *) FvImage->CurrentFilePointer;\r
942 \r
943   //\r
944   // write header\r
945   //\r
946   memset (PadFile, 0, sizeof (EFI_FFS_FILE_HEADER));\r
947 #ifdef __GNUC__\r
948   {\r
949     uuid_t tmp_id;\r
950     uuid_generate (tmp_id);\r
951     memcpy (&PadFileGuid, tmp_id, sizeof (EFI_GUID));\r
952   }\r
953 #else\r
954   UuidCreate (&PadFileGuid);\r
955 #endif\r
956   memcpy (&PadFile->Name, &PadFileGuid, sizeof (EFI_GUID));\r
957   PadFile->Type       = EFI_FV_FILETYPE_FFS_PAD;\r
958   PadFile->Attributes = 0;\r
959 \r
960   //\r
961   // FileSize includes the EFI_FFS_FILE_HEADER\r
962   //\r
963   FileSize          = (UINTN) VtfFileImage - (UINTN) FvImage->CurrentFilePointer;\r
964   PadFile->Size[0]  = (UINT8) (FileSize & 0x000000FF);\r
965   PadFile->Size[1]  = (UINT8) ((FileSize & 0x0000FF00) >> 8);\r
966   PadFile->Size[2]  = (UINT8) ((FileSize & 0x00FF0000) >> 16);\r
967 \r
968   //\r
969   // Fill in checksums and state, must be zero during checksum calculation.\r
970   //\r
971   PadFile->IntegrityCheck.Checksum.Header = 0;\r
972   PadFile->IntegrityCheck.Checksum.File   = 0;\r
973   PadFile->State                          = 0;\r
974   PadFile->IntegrityCheck.Checksum.Header = CalculateChecksum8 ((UINT8 *) PadFile, sizeof (EFI_FFS_FILE_HEADER));\r
975   if (PadFile->Attributes & FFS_ATTRIB_CHECKSUM) {\r
976     PadFile->IntegrityCheck.Checksum.File = CalculateChecksum8 ((UINT8 *) PadFile, FileSize);\r
977   } else {\r
978     PadFile->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;\r
979   }\r
980 \r
981   PadFile->State = EFI_FILE_HEADER_CONSTRUCTION | EFI_FILE_HEADER_VALID | EFI_FILE_DATA_VALID;\r
982 \r
983   UpdateFfsFileState (\r
984     (EFI_FFS_FILE_HEADER *) PadFile,\r
985     (EFI_FIRMWARE_VOLUME_HEADER *) FvImage->FileImage\r
986     );\r
987   //\r
988   // Update the current FV pointer\r
989   //\r
990   FvImage->CurrentFilePointer = FvImage->Eof;\r
991 \r
992   return EFI_SUCCESS;\r
993 }\r
994 \r
995 EFI_STATUS\r
996 UpdateResetVector (\r
997   IN MEMORY_FILE            *FvImage,\r
998   IN FV_INFO                *FvInfo,\r
999   IN EFI_FFS_FILE_HEADER    *VtfFile\r
1000   )\r
1001 /*++\r
1002 \r
1003 Routine Description:\r
1004 \r
1005   This parses the FV looking for the PEI core and then plugs the address into\r
1006   the SALE_ENTRY point of the BSF/VTF for IPF and does BUGBUG TBD action to\r
1007   complete an IA32 Bootstrap FV.\r
1008 \r
1009 Arguments:\r
1010 \r
1011   FvImage       Memory file for the FV memory image\r
1012   FvInfo        Information read from INF file.\r
1013   VtfFile       Pointer to the VTF file in the FV image.\r
1014 \r
1015 Returns:\r
1016 \r
1017   EFI_SUCCESS             Function Completed successfully.\r
1018   EFI_ABORTED             Error encountered.\r
1019   EFI_INVALID_PARAMETER   A required parameter was NULL.\r
1020   EFI_NOT_FOUND           PEI Core file not found.\r
1021 \r
1022 --*/\r
1023 {\r
1024   EFI_FFS_FILE_HEADER       *PeiCoreFile;\r
1025   EFI_FFS_FILE_HEADER       *SecCoreFile;\r
1026   EFI_STATUS                Status;\r
1027   EFI_FILE_SECTION_POINTER  Pe32Section;\r
1028   UINT32                    EntryPoint;\r
1029   UINT32                    BaseOfCode;\r
1030   UINT16                    MachineType;\r
1031   EFI_PHYSICAL_ADDRESS      PeiCorePhysicalAddress;\r
1032   EFI_PHYSICAL_ADDRESS      SecCorePhysicalAddress;\r
1033   EFI_PHYSICAL_ADDRESS      *SecCoreEntryAddressPtr;\r
1034   UINT32                    *Ia32ResetAddressPtr;\r
1035   UINT8                     *BytePointer;\r
1036   UINT8                     *BytePointer2;\r
1037   UINT16                    *WordPointer;\r
1038   UINT16                    CheckSum;\r
1039   UINTN                     Index;\r
1040   EFI_FFS_FILE_STATE        SavedState;\r
1041   UINT64                    FitAddress;\r
1042   FIT_TABLE                 *FitTablePtr;\r
1043 \r
1044   //\r
1045   // Verify input parameters\r
1046   //\r
1047   if (FvImage == NULL || FvInfo == NULL || VtfFile == NULL) {\r
1048     return EFI_INVALID_PARAMETER;\r
1049   }\r
1050   //\r
1051   // Initialize FV library\r
1052   //\r
1053   InitializeFvLib (FvImage->FileImage, FvInfo->Size);\r
1054 \r
1055   //\r
1056   // Verify VTF file\r
1057   //\r
1058   Status = VerifyFfsFile (VtfFile);\r
1059   if (EFI_ERROR (Status)) {\r
1060     return EFI_INVALID_PARAMETER;\r
1061   }\r
1062   //\r
1063   // Find the PEI Core\r
1064   //\r
1065   Status = GetFileByType (EFI_FV_FILETYPE_PEI_CORE, 1, &PeiCoreFile);\r
1066   if (EFI_ERROR (Status) || PeiCoreFile == NULL) {\r
1067     Error (NULL, 0, 0, "could not find the PEI core in the FV", NULL);\r
1068     return EFI_ABORTED;\r
1069   }\r
1070 \r
1071   //\r
1072   // PEI Core found, now find PE32 or TE section\r
1073   //\r
1074   Status = GetSectionByType (PeiCoreFile, EFI_SECTION_PE32, 1, &Pe32Section);\r
1075   if (Status == EFI_NOT_FOUND) {\r
1076     Status = GetSectionByType (PeiCoreFile, EFI_SECTION_TE, 1, &Pe32Section);\r
1077   }\r
1078 \r
1079   if (EFI_ERROR (Status)) {\r
1080     Error (NULL, 0, 0, "could not find PE32 or TE section in PEI core file", NULL);\r
1081     return EFI_ABORTED;\r
1082   }\r
1083 \r
1084   Status = GetPe32Info (\r
1085             (VOID *) ((UINTN) Pe32Section.Pe32Section + sizeof (EFI_SECTION_PE32)),\r
1086             &EntryPoint,\r
1087             &BaseOfCode,\r
1088             &MachineType\r
1089             );\r
1090 \r
1091   if (EFI_ERROR (Status)) {\r
1092     Error (NULL, 0, 0, "could not get PE32 entry point for PEI core", NULL);\r
1093     return EFI_ABORTED;\r
1094   }\r
1095   //\r
1096   // Physical address is FV base + offset of PE32 + offset of the entry point\r
1097   //\r
1098   PeiCorePhysicalAddress = FvInfo->BaseAddress;\r
1099   PeiCorePhysicalAddress += (UINTN) Pe32Section.Pe32Section + sizeof (EFI_SECTION_PE32) - (UINTN) FvImage->FileImage;\r
1100   PeiCorePhysicalAddress += EntryPoint;\r
1101 \r
1102   if (MachineType == EFI_IMAGE_MACHINE_IA64) {\r
1103     //\r
1104     // Update PEI_CORE address\r
1105     //\r
1106     //\r
1107     // Set the uncached attribute bit in the physical address\r
1108     //\r
1109     PeiCorePhysicalAddress |= 0x8000000000000000ULL;\r
1110 \r
1111     //\r
1112     // Check if address is aligned on a 16 byte boundary\r
1113     //\r
1114     if (PeiCorePhysicalAddress & 0xF) {\r
1115       Error (NULL, 0, 0, NULL,\r
1116         "ERROR: PEI_CORE entry point is not aligned on a 16 byte boundary, address specified is %Xh.",\r
1117         PeiCorePhysicalAddress\r
1118         );\r
1119       return EFI_ABORTED;\r
1120     }\r
1121     //\r
1122     // First Get the FIT table address\r
1123     //\r
1124     FitAddress  = (*(UINT64 *) (FvImage->Eof - IPF_FIT_ADDRESS_OFFSET)) & 0xFFFFFFFF;\r
1125 \r
1126     FitTablePtr = (FIT_TABLE *) (FvImage->FileImage + (FitAddress - FvInfo->BaseAddress));\r
1127 \r
1128     Status      = UpdatePeiCoreEntryInFit (FitTablePtr, PeiCorePhysicalAddress);\r
1129 \r
1130     if (!EFI_ERROR (Status)) {\r
1131       UpdateFitCheckSum (FitTablePtr);\r
1132     }\r
1133     //\r
1134     // Find the Sec Core\r
1135     //\r
1136     Status = GetFileByType (EFI_FV_FILETYPE_SECURITY_CORE, 1, &SecCoreFile);\r
1137     if (EFI_ERROR (Status) || SecCoreFile == NULL) {\r
1138       Error (NULL, 0, 0, "could not find the Sec core in the FV", NULL);\r
1139       return EFI_ABORTED;\r
1140     }\r
1141     //\r
1142     // Sec Core found, now find PE32 section\r
1143     //\r
1144     Status = GetSectionByType (SecCoreFile, EFI_SECTION_PE32, 1, &Pe32Section);\r
1145     if (EFI_ERROR (Status)) {\r
1146       Error (NULL, 0, 0, "could not find PE32 section in SEC core file", NULL);\r
1147       return EFI_ABORTED;\r
1148     }\r
1149 \r
1150     Status = GetPe32Info (\r
1151               (VOID *) ((UINTN) Pe32Section.Pe32Section + sizeof (EFI_SECTION_PE32)),\r
1152               &EntryPoint,\r
1153               &BaseOfCode,\r
1154               &MachineType\r
1155               );\r
1156     if (EFI_ERROR (Status)) {\r
1157       Error (NULL, 0, 0, "could not get PE32 entry point for SEC core", NULL);\r
1158       return EFI_ABORTED;\r
1159     }\r
1160     //\r
1161     // Physical address is FV base + offset of PE32 + offset of the entry point\r
1162     //\r
1163     SecCorePhysicalAddress = FvInfo->BaseAddress;\r
1164     SecCorePhysicalAddress += (UINTN) Pe32Section.Pe32Section + sizeof (EFI_SECTION_PE32) - (UINTN) FvImage->FileImage;\r
1165     SecCorePhysicalAddress += EntryPoint;\r
1166 \r
1167     //\r
1168     // Update SEC_CORE address\r
1169     //\r
1170     //\r
1171     // Set the uncached attribute bit in the physical address\r
1172     //\r
1173     SecCorePhysicalAddress |= 0x8000000000000000ULL;\r
1174     //\r
1175     // Check if address is aligned on a 16 byte boundary\r
1176     //\r
1177     if (SecCorePhysicalAddress & 0xF) {\r
1178       Error (NULL, 0, 0, NULL, \r
1179         "ERROR: SALE_ENTRY entry point is not aligned on a 16 byte boundary, address specified is %Xh.",\r
1180         SecCorePhysicalAddress\r
1181         );\r
1182       return EFI_ABORTED;\r
1183     }\r
1184     //\r
1185     // Update the address\r
1186     //\r
1187     SecCoreEntryAddressPtr  = (EFI_PHYSICAL_ADDRESS *) ((UINTN) FvImage->Eof - IPF_SALE_ENTRY_ADDRESS_OFFSET);\r
1188     *SecCoreEntryAddressPtr = SecCorePhysicalAddress;\r
1189 \r
1190   } else if (MachineType == EFI_IMAGE_MACHINE_IA32) {\r
1191     //\r
1192     // Get the location to update\r
1193     //\r
1194     Ia32ResetAddressPtr = (UINT32 *) ((UINTN) FvImage->Eof - IA32_PEI_CORE_ENTRY_OFFSET);\r
1195 \r
1196     //\r
1197     // Write lower 32 bits of physical address\r
1198     //\r
1199     *Ia32ResetAddressPtr = (UINT32) PeiCorePhysicalAddress;\r
1200 \r
1201     //\r
1202     // Update the BFV base address\r
1203     //\r
1204     Ia32ResetAddressPtr   = (UINT32 *) ((UINTN) FvImage->Eof - 4);\r
1205     *Ia32ResetAddressPtr  = (UINT32) (FvInfo->BaseAddress);\r
1206 \r
1207     CheckSum              = 0x0000;\r
1208 \r
1209     //\r
1210     // Update the Startup AP in the FVH header block ZeroVector region.\r
1211     //\r
1212     BytePointer   = (UINT8 *) ((UINTN) FvImage->FileImage);\r
1213     BytePointer2  = (FvInfo->Size == 0x10000) ? m64kRecoveryStartupApDataArray : m128kRecoveryStartupApDataArray;\r
1214     for (Index = 0; Index < SIZEOF_STARTUP_DATA_ARRAY; Index++) {\r
1215       *BytePointer++ = *BytePointer2++;\r
1216     }\r
1217     //\r
1218     // Calculate the checksum\r
1219     //\r
1220     WordPointer = (UINT16 *) ((UINTN) FvImage->FileImage);\r
1221     for (Index = 0; Index < SIZEOF_STARTUP_DATA_ARRAY / 2; Index++) {\r
1222       CheckSum = (UINT16) (CheckSum + ((UINT16) *WordPointer));\r
1223       WordPointer++;\r
1224     }\r
1225     //\r
1226     // Update the checksum field\r
1227     //\r
1228     BytePointer = (UINT8 *) ((UINTN) FvImage->FileImage);\r
1229     BytePointer += (SIZEOF_STARTUP_DATA_ARRAY - 2);\r
1230     WordPointer   = (UINT16 *) BytePointer;\r
1231     *WordPointer  = (UINT16) (0x10000 - (UINT32) CheckSum);\r
1232   } else {\r
1233     Error (NULL, 0, 0, "invalid machine type in PEI core", "machine type=0x%X", (UINT32) MachineType);\r
1234     return EFI_ABORTED;\r
1235   }\r
1236 \r
1237   //\r
1238   // Now update file checksum\r
1239   //\r
1240   SavedState  = VtfFile->State;\r
1241   VtfFile->IntegrityCheck.Checksum.File = 0;\r
1242   VtfFile->State                        = 0;\r
1243   if (VtfFile->Attributes & FFS_ATTRIB_CHECKSUM) {\r
1244     VtfFile->IntegrityCheck.Checksum.File = CalculateChecksum8 (\r
1245                                               (UINT8 *) VtfFile,\r
1246                                               GetLength (VtfFile->Size)\r
1247                                               );\r
1248   } else {\r
1249     VtfFile->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;\r
1250   }\r
1251 \r
1252   VtfFile->State = SavedState;\r
1253 \r
1254   return EFI_SUCCESS;\r
1255 }\r
1256 \r
1257 EFI_STATUS\r
1258 GetPe32Info (\r
1259   IN UINT8                  *Pe32,\r
1260   OUT UINT32                *EntryPoint,\r
1261   OUT UINT32                *BaseOfCode,\r
1262   OUT UINT16                *MachineType\r
1263   )\r
1264 /*++\r
1265 \r
1266 Routine Description:\r
1267 \r
1268   Retrieves the PE32 entry point offset and machine type from PE image or TeImage.  \r
1269   See EfiImage.h for machine types.  The entry point offset is from the beginning \r
1270   of the PE32 buffer passed in.\r
1271 \r
1272 Arguments:\r
1273 \r
1274   Pe32          Beginning of the PE32.\r
1275   EntryPoint    Offset from the beginning of the PE32 to the image entry point.\r
1276   BaseOfCode    Base address of code.\r
1277   MachineType   Magic number for the machine type.\r
1278 \r
1279 Returns:\r
1280 \r
1281   EFI_SUCCESS             Function completed successfully.\r
1282   EFI_ABORTED             Error encountered.\r
1283   EFI_INVALID_PARAMETER   A required parameter was NULL.\r
1284   EFI_UNSUPPORTED         The operation is unsupported.\r
1285 \r
1286 --*/\r
1287 {\r
1288   EFI_IMAGE_DOS_HEADER  *DosHeader;\r
1289   EFI_IMAGE_NT_HEADERS  *NtHeader;\r
1290   EFI_TE_IMAGE_HEADER   *TeHeader;\r
1291 \r
1292   //\r
1293   // Verify input parameters\r
1294   //\r
1295   if (Pe32 == NULL) {\r
1296     return EFI_INVALID_PARAMETER;\r
1297   }\r
1298 \r
1299   //\r
1300   // First check whether it is one TE Image.\r
1301   //\r
1302   TeHeader = (EFI_TE_IMAGE_HEADER *) Pe32;\r
1303   if (TeHeader->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {\r
1304     //\r
1305     // By TeImage Header to get output\r
1306     //\r
1307     *EntryPoint   = TeHeader->AddressOfEntryPoint + sizeof (EFI_TE_IMAGE_HEADER) - TeHeader->StrippedSize;\r
1308     *BaseOfCode   = TeHeader->BaseOfCode + sizeof (EFI_TE_IMAGE_HEADER) - TeHeader->StrippedSize;\r
1309     *MachineType  = TeHeader->Machine;\r
1310   } else {\r
1311   \r
1312     //\r
1313     // Then check whether \r
1314     // First is the DOS header\r
1315     //\r
1316     DosHeader = (EFI_IMAGE_DOS_HEADER *) Pe32;\r
1317   \r
1318     //\r
1319     // Verify DOS header is expected\r
1320     //\r
1321     if (DosHeader->e_magic != EFI_IMAGE_DOS_SIGNATURE) {\r
1322       Error (NULL, 0, 0, NULL, "ERROR: Unknown magic number in the DOS header, 0x%04X.", DosHeader->e_magic);\r
1323       return EFI_UNSUPPORTED;\r
1324     }\r
1325     //\r
1326     // Immediately following is the NT header.\r
1327     //\r
1328     NtHeader = (EFI_IMAGE_NT_HEADERS *) ((UINTN) Pe32 + DosHeader->e_lfanew);\r
1329   \r
1330     //\r
1331     // Verify NT header is expected\r
1332     //\r
1333     if (NtHeader->Signature != EFI_IMAGE_NT_SIGNATURE) {\r
1334       Error (NULL, 0, 0, NULL, "ERROR: Unrecognized image signature 0x%08X.", NtHeader->Signature);\r
1335       return EFI_UNSUPPORTED;\r
1336     }\r
1337     //\r
1338     // Get output\r
1339     //\r
1340     *EntryPoint   = NtHeader->OptionalHeader.AddressOfEntryPoint;\r
1341     *BaseOfCode   = NtHeader->OptionalHeader.BaseOfCode;\r
1342     *MachineType  = NtHeader->FileHeader.Machine;\r
1343   }\r
1344 \r
1345   //\r
1346   // Verify machine type is supported\r
1347   //\r
1348   if (*MachineType != EFI_IMAGE_MACHINE_IA32 && *MachineType != EFI_IMAGE_MACHINE_IA64 && *MachineType != EFI_IMAGE_MACHINE_X64 && *MachineType != EFI_IMAGE_MACHINE_EBC) {\r
1349     Error (NULL, 0, 0, NULL, "ERROR: Unrecognized machine type in the PE32 file.");\r
1350     return EFI_UNSUPPORTED;\r
1351   }\r
1352 \r
1353   return EFI_SUCCESS;\r
1354 }\r
1355 //\r
1356 // Exposed function implementations (prototypes are defined in GenFvImageLib.h)\r
1357 //\r
1358 EFI_STATUS\r
1359 GenerateFvImage (\r
1360   IN CHAR8                *InfFileImage,\r
1361   IN UINTN                InfFileSize,\r
1362   IN CHAR8                *FvFileName,\r
1363   IN EFI_PHYSICAL_ADDRESS XipBaseAddress\r
1364   )\r
1365 /*++\r
1366 \r
1367 Routine Description:\r
1368 \r
1369   This is the main function which will be called from application.\r
1370 \r
1371 Arguments:\r
1372 \r
1373   InfFileImage   Buffer containing the INF file contents.\r
1374   InfFileSize    Size of the contents of the InfFileImage buffer.\r
1375   FvFileName     Requested name for the FV file.\r
1376   XipBaseAddress BaseAddress is to be rebased.\r
1377 \r
1378 Returns:\r
1379 \r
1380   EFI_SUCCESS             Function completed successfully.\r
1381   EFI_OUT_OF_RESOURCES    Could not allocate required resources.\r
1382   EFI_ABORTED             Error encountered.\r
1383   EFI_INVALID_PARAMETER   A required parameter was NULL.\r
1384 \r
1385 --*/\r
1386 {\r
1387   EFI_STATUS                  Status;\r
1388   MEMORY_FILE                 InfMemoryFile;\r
1389   MEMORY_FILE                 FvImageMemoryFile;\r
1390   FV_INFO                     FvInfo;\r
1391   UINTN                       Index;\r
1392   EFI_FIRMWARE_VOLUME_HEADER  *FvHeader;\r
1393   EFI_FFS_FILE_HEADER         *VtfFileImage;\r
1394   UINT8                       *FvBufferHeader; // to make sure fvimage header 8 type alignment.\r
1395   UINT8                       *FvImage;\r
1396   UINTN                       FvImageSize;\r
1397   FILE                        *FvFile;\r
1398 \r
1399   FvBufferHeader = NULL;\r
1400   FvFile         = NULL;\r
1401   //\r
1402   // Check for invalid parameter\r
1403   //\r
1404   if (InfFileImage == NULL) {\r
1405     return EFI_INVALID_PARAMETER;\r
1406   }\r
1407 \r
1408   //\r
1409   // Initialize file structures\r
1410   //\r
1411   InfMemoryFile.FileImage           = InfFileImage;\r
1412   InfMemoryFile.CurrentFilePointer  = InfFileImage;\r
1413   InfMemoryFile.Eof                 = InfFileImage + InfFileSize;\r
1414 \r
1415   //\r
1416   // Parse the FV inf file for header information\r
1417   //\r
1418   Status = ParseFvInf (&InfMemoryFile, &FvInfo);\r
1419   if (EFI_ERROR (Status)) {\r
1420     Error (NULL, 0, 0, NULL, "ERROR: Could not parse the input INF file.");\r
1421     return Status;\r
1422   }\r
1423 \r
1424   //\r
1425   // Update the file name return values\r
1426   //\r
1427   if (FvFileName == NULL && FvInfo.FvName[0] != '\0') {\r
1428     FvFileName = FvInfo.FvName;\r
1429   }\r
1430   \r
1431   //\r
1432   // Update FvImage Base Address, XipBase not same to BtBase, RtBase address.\r
1433   //\r
1434   if (XipBaseAddress != -1) {\r
1435     FvInfo.BaseAddress = XipBaseAddress;\r
1436   }\r
1437 \r
1438   //\r
1439   // Calculate the FV size and Update Fv Size based on the actual FFS files.\r
1440   // And Update FvInfo data.\r
1441   //\r
1442   Status = CalculateFvSize (&FvInfo);\r
1443   if (EFI_ERROR (Status)) {\r
1444     return Status;    \r
1445   }\r
1446   \r
1447   //\r
1448   // support fv image and empty fv image\r
1449   //\r
1450   FvImageSize = FvInfo.Size;\r
1451 \r
1452   //\r
1453   // Allocate the FV, assure FvImage Header 8 byte alignment\r
1454   //\r
1455   FvBufferHeader = malloc (FvImageSize + 8);\r
1456   if (FvBufferHeader == NULL) {\r
1457     return EFI_OUT_OF_RESOURCES;\r
1458   }\r
1459   FvImage = (UINT8 *) (((UINTN) FvBufferHeader + 7) & ~7);\r
1460 \r
1461   //\r
1462   // Initialize the FV to the erase polarity\r
1463   //\r
1464   if (FvInfo.FvAttributes & EFI_FVB2_ERASE_POLARITY) {\r
1465     memset (FvImage, -1, FvImageSize);\r
1466   } else {\r
1467     memset (FvImage, 0, FvImageSize);\r
1468   }\r
1469 \r
1470   //\r
1471   // Initialize FV header\r
1472   //\r
1473   FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) FvImage;\r
1474 \r
1475   //\r
1476   // Initialize the zero vector to all zeros.\r
1477   //\r
1478   memset (FvHeader->ZeroVector, 0, 16);\r
1479 \r
1480   //\r
1481   // Copy the FFS GUID\r
1482   //\r
1483   memcpy (&FvHeader->FileSystemGuid, &FvInfo.FvGuid, sizeof (EFI_GUID));\r
1484 \r
1485   FvHeader->FvLength        = FvImageSize;\r
1486   FvHeader->Signature       = EFI_FVH_SIGNATURE;\r
1487   FvHeader->Attributes      = FvInfo.FvAttributes;\r
1488   FvHeader->Revision        = EFI_FVH_PI_REVISION;\r
1489   FvHeader->ExtHeaderOffset = 0;\r
1490   FvHeader->Reserved[0]     = 0;\r
1491   \r
1492   //\r
1493   // Copy firmware block map\r
1494   //\r
1495   for (Index = 0; FvInfo.FvBlocks[Index].Length != 0; Index++) {\r
1496     FvHeader->BlockMap[Index].NumBlocks   = FvInfo.FvBlocks[Index].NumBlocks;\r
1497     FvHeader->BlockMap[Index].Length      = FvInfo.FvBlocks[Index].Length;\r
1498   }\r
1499 \r
1500   //\r
1501   // Add block map terminator\r
1502   //\r
1503   FvHeader->BlockMap[Index].NumBlocks   = 0;\r
1504   FvHeader->BlockMap[Index].Length      = 0;\r
1505 \r
1506   //\r
1507   // Complete the header\r
1508   //\r
1509   FvHeader->HeaderLength  = (UINT16) (((UINTN) &(FvHeader->BlockMap[Index + 1])) - (UINTN) FvImage);\r
1510   FvHeader->Checksum      = 0;\r
1511   FvHeader->Checksum      = CalculateChecksum16 ((UINT16 *) FvHeader, FvHeader->HeaderLength / sizeof (UINT16));\r
1512 \r
1513   //\r
1514   // If there is no FFS file, generate one empty FV\r
1515   //\r
1516   if (FvInfo.FvFiles[0][0] == 0) {\r
1517     goto WriteFile;\r
1518   }\r
1519 \r
1520   //\r
1521   // Initialize our "file" view of the buffer\r
1522   //\r
1523   FvImageMemoryFile.FileImage           = FvImage;\r
1524   FvImageMemoryFile.CurrentFilePointer  = FvImage + FvHeader->HeaderLength;\r
1525   FvImageMemoryFile.Eof                 = FvImage + FvImageSize;\r
1526 \r
1527   //\r
1528   // Initialize the FV library.\r
1529   //\r
1530   InitializeFvLib (FvImageMemoryFile.FileImage, FvImageSize);\r
1531 \r
1532   //\r
1533   // Initialize the VTF file address.\r
1534   //\r
1535   VtfFileImage = (EFI_FFS_FILE_HEADER *) FvImageMemoryFile.Eof;\r
1536 \r
1537   //\r
1538   // Add files to FV\r
1539   //\r
1540   for (Index = 0; FvInfo.FvFiles[Index][0] != 0; Index++) {\r
1541     //\r
1542     // Add the file\r
1543     //\r
1544     Status = AddFile (&FvImageMemoryFile, &FvInfo, Index, &VtfFileImage);\r
1545 \r
1546     //\r
1547     // Exit if error detected while adding the file\r
1548     //\r
1549     if (EFI_ERROR (Status)) {\r
1550       Error (NULL, 0, 0, NULL, "ERROR: Could not add file %s.", FvInfo.FvFiles[Index]);\r
1551       goto Finish;\r
1552     }\r
1553   }\r
1554 \r
1555   //\r
1556   // If there is a VTF file, some special actions need to occur.\r
1557   //\r
1558   if ((UINTN) VtfFileImage != (UINTN) FvImageMemoryFile.Eof) {\r
1559     //\r
1560     // Pad from the end of the last file to the beginning of the VTF file.\r
1561     // If the left space is less than sizeof (EFI_FFS_FILE_HEADER)?\r
1562     //\r
1563     Status = PadFvImage (&FvImageMemoryFile, VtfFileImage);\r
1564     if (EFI_ERROR (Status)) {\r
1565       Error (NULL, 0, 0, NULL, "ERROR: Could not create the pad file between the last file and the VTF file.");\r
1566       goto Finish;\r
1567     }\r
1568     //\r
1569     // Update reset vector (SALE_ENTRY for IPF)\r
1570     // Now for IA32 and IA64 platform, the fv which has bsf file must have the \r
1571     // EndAddress of 0xFFFFFFFF. Thus, only this type fv needs to update the   \r
1572     // reset vector. If the PEI Core is found, the VTF file will probably get  \r
1573     // corrupted by updating the entry point.                                  \r
1574     //\r
1575     if ((FvInfo.BaseAddress + FvInfo.Size) == FV_IMAGES_TOP_ADDRESS) {       \r
1576       Status = UpdateResetVector (&FvImageMemoryFile, &FvInfo, VtfFileImage);\r
1577       if (EFI_ERROR(Status)) {                                               \r
1578         Error (NULL, 0, 0, NULL, "ERROR: Could not update the reset vector.");\r
1579         goto Finish;                                              \r
1580       }\r
1581     }\r
1582   } \r
1583   \r
1584   //\r
1585   // Update FV Alignment attribute to the largest alignment of all the FFS files in the FV\r
1586   //\r
1587   if ((((FvHeader->Attributes & EFI_FVB2_ALIGNMENT) >> 16)) < MaxFfsAlignment) {\r
1588     FvHeader->Attributes = ((MaxFfsAlignment << 16) | (FvHeader->Attributes & 0xFFFF));\r
1589     //\r
1590     // Update Checksum for FvHeader\r
1591     //\r
1592     FvHeader->Checksum      = 0;\r
1593     FvHeader->Checksum      = CalculateChecksum16 ((UINT16 *) FvHeader, FvHeader->HeaderLength / sizeof (UINT16));\r
1594   }\r
1595 \r
1596 WriteFile: \r
1597   //\r
1598   // Write fv file\r
1599   //\r
1600   if (FvFileName == NULL) {\r
1601     FvFile = stdout;\r
1602   } else {\r
1603     FvFile = fopen (FvFileName, "wb");\r
1604   }\r
1605 \r
1606   if (FvFile == NULL) {\r
1607     Error (NULL, 0, 0, FvFileName, "could not open output file");\r
1608     Status = EFI_ABORTED;\r
1609     goto Finish;\r
1610   }\r
1611 \r
1612   if (fwrite (FvImage, 1, FvImageSize, FvFile) != FvImageSize) {\r
1613     Error (NULL, 0, 0, FvFileName, "failed to write to output file");\r
1614     Status = EFI_ABORTED;\r
1615     goto Finish;\r
1616   }\r
1617 \r
1618 Finish:\r
1619   if (FvBufferHeader != NULL) {\r
1620     free (FvBufferHeader);\r
1621   }\r
1622   \r
1623   if (FvFile != NULL) {\r
1624     fclose (FvFile);\r
1625   }\r
1626 \r
1627   return Status;\r
1628 }\r
1629 \r
1630 EFI_STATUS\r
1631 UpdatePeiCoreEntryInFit (\r
1632   IN FIT_TABLE     *FitTablePtr,\r
1633   IN UINT64        PeiCorePhysicalAddress\r
1634   )\r
1635 /*++\r
1636 \r
1637 Routine Description:\r
1638 \r
1639   This function is used to update the Pei Core address in FIT, this can be used by Sec core to pass control from\r
1640   Sec to Pei Core\r
1641 \r
1642 Arguments:\r
1643 \r
1644   FitTablePtr             - The pointer of FIT_TABLE.\r
1645   PeiCorePhysicalAddress  - The address of Pei Core entry.\r
1646 \r
1647 Returns:\r
1648 \r
1649   EFI_SUCCESS             - The PEI_CORE FIT entry was updated successfully.\r
1650   EFI_NOT_FOUND           - Not found the PEI_CORE FIT entry.\r
1651 \r
1652 --*/\r
1653 {\r
1654   FIT_TABLE *TmpFitPtr;\r
1655   UINTN     Index;\r
1656   UINTN     NumFitComponents;\r
1657 \r
1658   TmpFitPtr         = FitTablePtr;\r
1659   NumFitComponents  = TmpFitPtr->CompSize;\r
1660 \r
1661   for (Index = 0; Index < NumFitComponents; Index++) {\r
1662     if ((TmpFitPtr->CvAndType & FIT_TYPE_MASK) == COMP_TYPE_FIT_PEICORE) {\r
1663       TmpFitPtr->CompAddress = PeiCorePhysicalAddress;\r
1664       return EFI_SUCCESS;\r
1665     }\r
1666 \r
1667     TmpFitPtr++;\r
1668   }\r
1669 \r
1670   return EFI_NOT_FOUND;\r
1671 }\r
1672 \r
1673 VOID\r
1674 UpdateFitCheckSum (\r
1675   IN FIT_TABLE   *FitTablePtr\r
1676   )\r
1677 /*++\r
1678 \r
1679 Routine Description:\r
1680 \r
1681   This function is used to update the checksum for FIT.\r
1682 \r
1683 \r
1684 Arguments:\r
1685 \r
1686   FitTablePtr             - The pointer of FIT_TABLE.\r
1687 \r
1688 Returns:\r
1689 \r
1690   None.\r
1691 \r
1692 --*/\r
1693 {\r
1694   if ((FitTablePtr->CvAndType & CHECKSUM_BIT_MASK) >> 7) {\r
1695     FitTablePtr->CheckSum = 0;\r
1696     FitTablePtr->CheckSum = CalculateChecksum8 ((UINT8 *) FitTablePtr, FitTablePtr->CompSize * 16);\r
1697   }\r
1698 }\r
1699 \r
1700 EFI_STATUS\r
1701 CalculateFvSize (\r
1702   FV_INFO *FvInfoPtr\r
1703   )\r
1704 /*++\r
1705 Routine Description:\r
1706   Calculate the FV size and Update Fv Size based on the actual FFS files.\r
1707   And Update FvInfo data.\r
1708 \r
1709 Arguments:\r
1710   FvInfoPtr     - The pointer to FV_INFO structure.\r
1711 \r
1712 Returns:\r
1713   EFI_ABORTED   - Ffs Image Error\r
1714   EFI_SUCCESS   - Successfully update FvSize\r
1715 --*/\r
1716 {\r
1717   UINTN               CurrentOffset;\r
1718   UINTN               Index;\r
1719   FILE                *fpin;\r
1720   UINTN               FfsFileSize;\r
1721   UINT32              FfsAlignment;\r
1722   EFI_FFS_FILE_HEADER FfsHeader;\r
1723   EFI_STATUS          Status;\r
1724   BOOLEAN             VtfFileFlag;\r
1725   \r
1726   VtfFileFlag = FALSE;\r
1727   fpin  = NULL;\r
1728   Index = 0;\r
1729   CurrentOffset = sizeof (EFI_FIRMWARE_VOLUME_HEADER);\r
1730   \r
1731   for (Index = 1;; Index ++) {\r
1732     CurrentOffset += sizeof (EFI_FV_BLOCK_MAP_ENTRY);\r
1733     if (FvInfoPtr->FvBlocks[Index].NumBlocks == 0 && FvInfoPtr->FvBlocks[Index].Length == 0) {\r
1734       break;\r
1735     }\r
1736   }\r
1737 \r
1738   //\r
1739   // Accumlate every FFS file size.\r
1740   //\r
1741   for (Index = 0; FvInfoPtr->FvFiles[Index][0] != 0; Index++) {\r
1742     //\r
1743     // Open FFS file\r
1744     //\r
1745     fpin = NULL;\r
1746     fpin = fopen (FvInfoPtr->FvFiles[Index], "rb");\r
1747     if (fpin == NULL) {\r
1748       Error (NULL, 0, 0, NULL, "%s could not open for reading", FvInfoPtr->FvFiles[Index]);\r
1749       return EFI_ABORTED;\r
1750     }\r
1751     //\r
1752     // Get the file size\r
1753     //\r
1754     FfsFileSize = _filelength (fileno (fpin));\r
1755     //\r
1756     // Read Ffs File header\r
1757     //\r
1758     fread (&FfsHeader, sizeof (UINT8), sizeof (EFI_FFS_FILE_HEADER), fpin);\r
1759     //\r
1760     // close file\r
1761     //\r
1762     fclose (fpin);\r
1763     //\r
1764     // Check whether this ffs file is vtf file\r
1765     //\r
1766     if (IsVtfFile (&FfsHeader)) {\r
1767       if (VtfFileFlag) {\r
1768         //\r
1769         // One Fv image can't have two vtf files.\r
1770         //\r
1771         return EFI_ABORTED;\r
1772       }\r
1773       VtfFileFlag = TRUE;\r
1774       //\r
1775       // The space between Vft File and the latest file must be able to contain \r
1776       // one ffs file header in order to add one pad file.\r
1777       //\r
1778       CurrentOffset += sizeof (EFI_FFS_FILE_HEADER);\r
1779     }\r
1780     //\r
1781     // Get the alignment of FFS file \r
1782     //\r
1783     ReadFfsAlignment (&FfsHeader, &FfsAlignment);\r
1784     FfsAlignment = 1 << FfsAlignment;\r
1785     //\r
1786     // Add Pad file\r
1787     //\r
1788     if (((CurrentOffset + sizeof (EFI_FFS_FILE_HEADER)) % FfsAlignment) != 0) {\r
1789       CurrentOffset = (CurrentOffset + sizeof (EFI_FFS_FILE_HEADER) * 2 + FfsAlignment - 1) & ~(FfsAlignment - 1);\r
1790       CurrentOffset -= sizeof (EFI_FFS_FILE_HEADER);\r
1791     }\r
1792     //\r
1793     // Add ffs file size\r
1794     //\r
1795     CurrentOffset += FfsFileSize;    \r
1796     //\r
1797     // Make next ffs file start at QWord Boundry\r
1798     //\r
1799     CurrentOffset = (CurrentOffset + EFI_FFS_FILE_HEADER_ALIGNMENT - 1) & ~(EFI_FFS_FILE_HEADER_ALIGNMENT - 1);\r
1800   }\r
1801   \r
1802   if (FvInfoPtr->Size < CurrentOffset) { \r
1803     //\r
1804     // Update FvInfo data\r
1805     //\r
1806     FvInfoPtr->FvBlocks[0].NumBlocks = CurrentOffset / FvInfoPtr->FvBlocks[0].Length + ((CurrentOffset % FvInfoPtr->FvBlocks[0].Length)?1:0);\r
1807     FvInfoPtr->Size = FvInfoPtr->FvBlocks[0].NumBlocks * FvInfoPtr->FvBlocks[0].Length;\r
1808     FvInfoPtr->FvBlocks[1].NumBlocks = 0;\r
1809     FvInfoPtr->FvBlocks[1].Length = 0;\r
1810   }\r
1811 \r
1812   return EFI_SUCCESS;\r
1813 }\r
1814 \r
1815 EFI_STATUS\r
1816 FfsRebaseImageRead (\r
1817   IN     VOID    *FileHandle,\r
1818   IN     UINTN   FileOffset,\r
1819   IN OUT UINT32  *ReadSize,\r
1820   OUT    VOID    *Buffer\r
1821   )\r
1822 /*++\r
1823 \r
1824 Routine Description:\r
1825 \r
1826   Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file\r
1827 \r
1828 Arguments:\r
1829 \r
1830   FileHandle - The handle to the PE/COFF file\r
1831 \r
1832   FileOffset - The offset, in bytes, into the file to read\r
1833 \r
1834   ReadSize   - The number of bytes to read from the file starting at FileOffset\r
1835 \r
1836   Buffer     - A pointer to the buffer to read the data into.\r
1837 \r
1838 Returns:\r
1839 \r
1840   EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset\r
1841 \r
1842 --*/\r
1843 {\r
1844   CHAR8   *Destination8;\r
1845   CHAR8   *Source8;\r
1846   UINT32  Length;\r
1847 \r
1848   Destination8  = Buffer;\r
1849   Source8       = (CHAR8 *) ((UINTN) FileHandle + FileOffset);\r
1850   Length        = *ReadSize;\r
1851   while (Length--) {\r
1852     *(Destination8++) = *(Source8++);\r
1853   }\r
1854 \r
1855   return EFI_SUCCESS;\r
1856 }\r
1857 \r
1858 EFI_STATUS\r
1859 FfsRebase ( \r
1860   IN OUT  FV_INFO               *FvInfo, \r
1861   IN      CHAR8                 *FileName,           \r
1862   IN OUT  EFI_FFS_FILE_HEADER   *FfsFile,\r
1863   IN      UINTN                 XipOffset\r
1864   )\r
1865 /*++\r
1866 \r
1867 Routine Description:\r
1868 \r
1869   This function determines if a file is XIP and should be rebased.  It will\r
1870   rebase any PE32 sections found in the file using the base address.\r
1871 \r
1872 Arguments:\r
1873   \r
1874   FvInfo            A pointer to FV_INFO struture.\r
1875   FfsFile           A pointer to Ffs file image.\r
1876   XipOffset         The offset address to use for rebasing the XIP file image.\r
1877 \r
1878 Returns:\r
1879 \r
1880   EFI_SUCCESS             The image was properly rebased.\r
1881   EFI_INVALID_PARAMETER   An input parameter is invalid.\r
1882   EFI_ABORTED             An error occurred while rebasing the input file image.\r
1883   EFI_OUT_OF_RESOURCES    Could not allocate a required resource.\r
1884   EFI_NOT_FOUND           No compressed sections could be found.\r
1885 \r
1886 --*/\r
1887 {\r
1888   EFI_STATUS                            Status;\r
1889   PE_COFF_LOADER_IMAGE_CONTEXT          ImageContext;\r
1890   EFI_PHYSICAL_ADDRESS                  XipBase;\r
1891   EFI_PHYSICAL_ADDRESS                  NewPe32BaseAddress;\r
1892   EFI_PHYSICAL_ADDRESS                  *BaseToUpdate;\r
1893   UINTN                                 Index;\r
1894   EFI_FILE_SECTION_POINTER              CurrentPe32Section;\r
1895   EFI_FFS_FILE_STATE                    SavedState;\r
1896   EFI_IMAGE_NT_HEADERS                  *PeHdr;\r
1897   EFI_IMAGE_OPTIONAL_HEADER32           *Optional32;\r
1898   EFI_IMAGE_OPTIONAL_HEADER64           *Optional64;\r
1899   EFI_TE_IMAGE_HEADER                   *TEImageHeader;\r
1900   UINT8                                 Flags;\r
1901   UINT8                                 *MemoryImagePointer;\r
1902   EFI_IMAGE_SECTION_HEADER              *SectionHeader;\r
1903 \r
1904   Index              = 0;  \r
1905   MemoryImagePointer = NULL;\r
1906   BaseToUpdate       = NULL;\r
1907   TEImageHeader      = NULL;\r
1908   PeHdr              = NULL;\r
1909   Optional32         = NULL;\r
1910   Optional64         = NULL;\r
1911   MemoryImagePointer = NULL;\r
1912   SectionHeader      = NULL;\r
1913   //\r
1914   // Check XipAddress, BootAddress and RuntimeAddress\r
1915   //\r
1916   Flags = 0;\r
1917 \r
1918   if (FvInfo->BaseAddress != -1) {\r
1919     Flags  |= REBASE_XIP_FILE;\r
1920     XipBase = FvInfo->BaseAddress + XipOffset;\r
1921   }\r
1922   if (FvInfo->BootBaseAddress != 0) {\r
1923     Flags  |= REBASE_BOOTTIME_FILE;\r
1924   }\r
1925   if (FvInfo->RuntimeBaseAddress != 0) {\r
1926     Flags  |= REBASE_RUNTIME_FILE;\r
1927   }\r
1928   //\r
1929   // Don't Rebase this FFS.\r
1930   //\r
1931   if (Flags == 0) {\r
1932     return EFI_SUCCESS;\r
1933   }\r
1934 \r
1935   //\r
1936   // We only process files potentially containing PE32 sections.\r
1937   //\r
1938   switch (FfsFile->Type) {\r
1939     case EFI_FV_FILETYPE_SECURITY_CORE:\r
1940     case EFI_FV_FILETYPE_PEI_CORE:\r
1941     case EFI_FV_FILETYPE_PEIM:\r
1942     case EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER:\r
1943     case EFI_FV_FILETYPE_DRIVER:\r
1944     case EFI_FV_FILETYPE_DXE_CORE:\r
1945       break;\r
1946     default:\r
1947       return EFI_SUCCESS;\r
1948   }\r
1949 \r
1950   //\r
1951   // Rebase each PE32 section\r
1952   //\r
1953   Status      = EFI_SUCCESS;\r
1954   for (Index = 1;; Index++) {\r
1955     Status = GetSectionByType (FfsFile, EFI_SECTION_PE32, Index, &CurrentPe32Section);\r
1956     if (EFI_ERROR (Status)) {\r
1957       break;\r
1958     }\r
1959 \r
1960     //\r
1961     // Initialize context\r
1962     //\r
1963     memset (&ImageContext, 0, sizeof (ImageContext));\r
1964     ImageContext.Handle     = (VOID *) ((UINTN) CurrentPe32Section.Pe32Section + sizeof (EFI_PE32_SECTION));\r
1965     ImageContext.ImageRead  = (PE_COFF_LOADER_READ_FILE) FfsRebaseImageRead;\r
1966     Status                  = PeCoffLoaderGetImageInfo (&ImageContext);\r
1967     if (EFI_ERROR (Status)) {\r
1968       Error (NULL, 0, 0, "GetImageInfo() call failed on rebase", FileName);\r
1969       return Status;\r
1970     }\r
1971 \r
1972     //\r
1973     // Don't Load PeImage, only to relocate current image.\r
1974     //\r
1975     ImageContext.ImageAddress = (UINTN) CurrentPe32Section.Pe32Section + sizeof (EFI_PE32_SECTION);\r
1976 \r
1977     //\r
1978     // Get PeHeader pointer\r
1979     //\r
1980     PeHdr = (EFI_IMAGE_NT_HEADERS *)((UINTN)ImageContext.ImageAddress + ImageContext.PeCoffHeaderOffset);\r
1981 \r
1982     //\r
1983     // Calculate the PE32 base address, based on file type\r
1984     //\r
1985     switch (FfsFile->Type) {\r
1986       case EFI_FV_FILETYPE_SECURITY_CORE:\r
1987       case EFI_FV_FILETYPE_PEI_CORE:\r
1988       case EFI_FV_FILETYPE_PEIM:\r
1989       case EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER:\r
1990         if ((Flags & REBASE_XIP_FILE) == 0) {\r
1991           //\r
1992           // We aren't relocating XIP code, so skip it.\r
1993           //\r
1994           return EFI_SUCCESS;\r
1995         }\r
1996         \r
1997         //\r
1998         // Check if section-alignment and file-alignment match or not\r
1999         //\r
2000         if ((PeHdr->OptionalHeader.SectionAlignment != PeHdr->OptionalHeader.FileAlignment)) {\r
2001           //\r
2002           // Xip module has the same section alignment and file alignment.\r
2003           //\r
2004           Warning (NULL, 0, 0, "Section-Alignment and File-Alignment does not match", FileName);\r
2005           return EFI_ABORTED;\r
2006         }\r
2007 \r
2008         NewPe32BaseAddress =\r
2009           XipBase + (UINTN)ImageContext.ImageAddress - (UINTN)FfsFile;\r
2010         BaseToUpdate = &XipBase;\r
2011         break;\r
2012 \r
2013       case EFI_FV_FILETYPE_DRIVER:\r
2014         switch (PeHdr->OptionalHeader.Subsystem) {\r
2015           case EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER:\r
2016             if ((Flags & REBASE_RUNTIME_FILE) == 0) {\r
2017               //\r
2018               // RT drivers aren't supposed to be relocated\r
2019               //\r
2020               continue;\r
2021             }\r
2022 \r
2023             NewPe32BaseAddress = FvInfo->RuntimeBaseAddress;\r
2024             BaseToUpdate = &(FvInfo->RuntimeBaseAddress);\r
2025             break;\r
2026 \r
2027           default:\r
2028             //\r
2029             // We treat all other subsystems the same as BS_DRIVER\r
2030             //\r
2031             if ((Flags & REBASE_BOOTTIME_FILE) == 0) {\r
2032               //\r
2033               // Skip all BS_DRIVER's\r
2034               //\r
2035               continue;\r
2036             }\r
2037 \r
2038             NewPe32BaseAddress = FvInfo->BootBaseAddress;\r
2039             BaseToUpdate = &(FvInfo->BootBaseAddress);\r
2040             break;\r
2041         }\r
2042         break;\r
2043 \r
2044       case EFI_FV_FILETYPE_DXE_CORE:\r
2045         if ((Flags & REBASE_BOOTTIME_FILE) == 0) {\r
2046           //\r
2047           // Skip DXE core, DxeCore only contain one PE image.\r
2048           //\r
2049           return EFI_SUCCESS;\r
2050         }\r
2051 \r
2052         NewPe32BaseAddress = FvInfo->BootBaseAddress;\r
2053         BaseToUpdate = &(FvInfo->BootBaseAddress);\r
2054         break;\r
2055 \r
2056       default:\r
2057         //\r
2058         // Not supported file type\r
2059         //\r
2060         return EFI_SUCCESS;\r
2061     }\r
2062 \r
2063     //\r
2064     // Load and Relocate Image Data\r
2065     //\r
2066     MemoryImagePointer = (UINT8 *) malloc ((UINTN) ImageContext.ImageSize + ImageContext.SectionAlignment);\r
2067     if (MemoryImagePointer == NULL) {\r
2068       Error (NULL, 0, 0, "Can't allocate enough memory on rebase", FileName);\r
2069       return EFI_OUT_OF_RESOURCES;\r
2070     }\r
2071     memset ((VOID *) MemoryImagePointer, 0, (UINTN) ImageContext.ImageSize + ImageContext.SectionAlignment);\r
2072     ImageContext.ImageAddress = ((UINTN) MemoryImagePointer + ImageContext.SectionAlignment - 1) & (~(ImageContext.SectionAlignment - 1));\r
2073     \r
2074     Status =  PeCoffLoaderLoadImage (&ImageContext);\r
2075     if (EFI_ERROR (Status)) {\r
2076       Error (NULL, 0, 0, "LocateImage() call failed on rebase", FileName);\r
2077       free ((VOID *) MemoryImagePointer);\r
2078       return Status;\r
2079     }\r
2080          \r
2081     ImageContext.DestinationAddress = NewPe32BaseAddress;\r
2082     Status                          = PeCoffLoaderRelocateImage (&ImageContext);\r
2083     if (EFI_ERROR (Status)) {\r
2084       Error (NULL, 0, 0, "RelocateImage() call failed on rebase", FileName);\r
2085       free ((VOID *) MemoryImagePointer);\r
2086       return Status;\r
2087     }\r
2088 \r
2089     //\r
2090     // Copy Relocated data to raw image file.\r
2091     //\r
2092     if (PeHdr->FileHeader.Machine == EFI_IMAGE_MACHINE_IA32) {\r
2093       Optional32 = (EFI_IMAGE_OPTIONAL_HEADER32 *) &(PeHdr->OptionalHeader);\r
2094       Optional32->ImageBase     = (UINT32) NewPe32BaseAddress;\r
2095     } else if (PeHdr->FileHeader.Machine == EFI_IMAGE_MACHINE_IA64 || \r
2096                PeHdr->FileHeader.Machine == EFI_IMAGE_MACHINE_X64) {\r
2097       Optional64 = (EFI_IMAGE_OPTIONAL_HEADER64 *) &(PeHdr->OptionalHeader);\r
2098       Optional64->ImageBase     = NewPe32BaseAddress;\r
2099     } else {\r
2100       Error (\r
2101         NULL,\r
2102         0,\r
2103         0,\r
2104         "unknown machine type in PE32 image",\r
2105         "machine type=0x%X, file=%s",\r
2106         (UINT32) PeHdr->FileHeader.Machine,\r
2107         FileName\r
2108         );\r
2109       free ((VOID *) MemoryImagePointer);\r
2110       return EFI_ABORTED;\r
2111     }\r
2112 \r
2113     SectionHeader = (EFI_IMAGE_SECTION_HEADER *) (\r
2114                        (UINTN) ImageContext.ImageAddress +\r
2115                        ImageContext.PeCoffHeaderOffset +\r
2116                        sizeof (UINT32) + \r
2117                        sizeof (EFI_IMAGE_FILE_HEADER) +  \r
2118                        PeHdr->FileHeader.SizeOfOptionalHeader\r
2119                        );\r
2120     \r
2121     for (Index = 0; Index < PeHdr->FileHeader.NumberOfSections; Index ++, SectionHeader ++) {\r
2122       CopyMem (\r
2123         (UINT8 *) ImageContext.Handle + SectionHeader->PointerToRawData, \r
2124         (VOID*) (UINTN) (ImageContext.ImageAddress + SectionHeader->VirtualAddress), \r
2125         SectionHeader->SizeOfRawData\r
2126         );\r
2127     }\r
2128 \r
2129     free ((VOID *) MemoryImagePointer);\r
2130 \r
2131     //\r
2132     // Update BASE address\r
2133     //\r
2134     *BaseToUpdate += EFI_SIZE_TO_PAGES (ImageContext.ImageSize) * EFI_PAGE_SIZE;\r
2135 \r
2136     //\r
2137     // Now update file checksum\r
2138     //\r
2139     if (FfsFile->Attributes & FFS_ATTRIB_CHECKSUM) {\r
2140       SavedState  = FfsFile->State;\r
2141       FfsFile->IntegrityCheck.Checksum.File = 0;\r
2142       FfsFile->State                        = 0;\r
2143       if (FfsFile->Attributes & FFS_ATTRIB_CHECKSUM) {\r
2144         FfsFile->IntegrityCheck.Checksum.File = CalculateChecksum8 (\r
2145                                                   (UINT8 *) FfsFile,\r
2146                                                   GetLength (FfsFile->Size)\r
2147                                                   );\r
2148       } else {\r
2149         FfsFile->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;\r
2150       }\r
2151 \r
2152       FfsFile->State = SavedState;\r
2153     }\r
2154   }\r
2155 \r
2156   if ((Flags & 1) == 0 || (\r
2157       FfsFile->Type != EFI_FV_FILETYPE_SECURITY_CORE &&\r
2158       FfsFile->Type != EFI_FV_FILETYPE_PEI_CORE &&\r
2159 \r
2160       FfsFile->Type != EFI_FV_FILETYPE_PEIM &&\r
2161       FfsFile->Type != EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER\r
2162       )) {\r
2163     //\r
2164     // Only XIP code may have a TE section\r
2165     //\r
2166     return EFI_SUCCESS;\r
2167   }\r
2168   \r
2169   //\r
2170   // Now process TE sections\r
2171   //\r
2172   for (Index = 1;; Index++) {\r
2173     Status = GetSectionByType (FfsFile, EFI_SECTION_TE, Index, &CurrentPe32Section);\r
2174     if (EFI_ERROR (Status)) {\r
2175       break;\r
2176     }\r
2177 \r
2178     //\r
2179     // Calculate the TE base address, the FFS file base plus the offset of the TE section less the size stripped off\r
2180     // by GenTEImage\r
2181     //\r
2182     TEImageHeader = (EFI_TE_IMAGE_HEADER *) ((UINT8 *) CurrentPe32Section.Pe32Section + sizeof (EFI_COMMON_SECTION_HEADER));\r
2183 \r
2184     //\r
2185     // Initialize context, load image info.\r
2186     //\r
2187     memset (&ImageContext, 0, sizeof (ImageContext));\r
2188     ImageContext.Handle     = (VOID *) TEImageHeader;\r
2189     ImageContext.ImageRead  = (PE_COFF_LOADER_READ_FILE) FfsRebaseImageRead;\r
2190 \r
2191     Status                  = PeCoffLoaderGetImageInfo (&ImageContext);\r
2192 \r
2193     if (EFI_ERROR (Status)) {\r
2194       Error (NULL, 0, 0, "GetImageInfo() call failed on rebase of TE image", FileName);\r
2195       return Status;\r
2196     }\r
2197     //\r
2198     // Don't reload TeImage\r
2199     //\r
2200     ImageContext.ImageAddress = (UINTN) TEImageHeader;\r
2201 \r
2202     //\r
2203     // Reloacate TeImage\r
2204     // \r
2205     ImageContext.DestinationAddress = XipBase + (UINTN) TEImageHeader + sizeof (EFI_TE_IMAGE_HEADER) \\r
2206                                       - TEImageHeader->StrippedSize - (UINTN) FfsFile;\r
2207     Status                          = PeCoffLoaderRelocateImage (&ImageContext);\r
2208     if (EFI_ERROR (Status)) {\r
2209       Error (NULL, 0, 0, "RelocateImage() call failed on rebase of TE image", FileName);\r
2210       return Status;\r
2211     }\r
2212 \r
2213     //\r
2214     // Now update file checksum\r
2215     //\r
2216     if (FfsFile->Attributes & FFS_ATTRIB_CHECKSUM) {\r
2217       SavedState  = FfsFile->State;\r
2218       FfsFile->IntegrityCheck.Checksum.File = 0;\r
2219       FfsFile->State                        = 0;\r
2220       if (FfsFile->Attributes & FFS_ATTRIB_CHECKSUM) {\r
2221         FfsFile->IntegrityCheck.Checksum.File = CalculateChecksum8 (\r
2222                                                   (UINT8 *) FfsFile,\r
2223                                                   GetLength (FfsFile->Size)\r
2224                                                   );\r
2225       } else {\r
2226         FfsFile->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;\r
2227       }\r
2228 \r
2229       FfsFile->State = SavedState;\r
2230     }\r
2231   }\r
2232  \r
2233   return EFI_SUCCESS;\r
2234 }