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