Update GenFw and GenFv tool to support more features based on base tools spec.
[people/mcb30/basetools.git] / Source / C / GenFv / GenFv.c
1 /*++\r
2 \r
3 Copyright (c) 2007, 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   GenFv.c\r
15 \r
16 Abstract:\r
17 \r
18   This contains all code necessary to build the GenFvImage.exe utility.       \r
19   This utility relies heavily on the GenFvImage Lib.  Definitions for both\r
20   can be found in the Tiano Firmware Volume Generation Utility \r
21   Specification, review draft.\r
22 \r
23 --*/\r
24 \r
25 //\r
26 // File included in build\r
27 //\r
28 #include <stdio.h>\r
29 #include <string.h>\r
30 #include <stdlib.h>\r
31 #include "CommonLib.h"\r
32 #include "GenFvInternalLib.h"\r
33 #include "EfiUtilityMsgs.h"\r
34 \r
35 //\r
36 // Utility Name\r
37 //\r
38 #define UTILITY_NAME  "GenFv"\r
39 \r
40 //\r
41 // Utility version information\r
42 //\r
43 #define UTILITY_MAJOR_VERSION 0\r
44 #define UTILITY_MINOR_VERSION 1\r
45 \r
46 EFI_STATUS\r
47 ParseCapInf (\r
48   IN  MEMORY_FILE  *InfFile,\r
49   OUT CAP_INFO     *CapInfo\r
50   );\r
51 \r
52 static\r
53 void \r
54 Version(\r
55   void\r
56 )\r
57 /*++\r
58 \r
59 Routine Description:\r
60 \r
61   Displays the standard utility information to SDTOUT\r
62 \r
63 Arguments:\r
64 \r
65   None\r
66 \r
67 Returns:\r
68 \r
69   None\r
70 \r
71 --*/\r
72 {\r
73   printf ("%s v%d.%d - EDKII Firmware Volume Generation Utility.\n", UTILITY_NAME, UTILITY_MAJOR_VERSION, UTILITY_MINOR_VERSION);\r
74   printf ("Copyright (c) 2007 Intel Corporation. All rights reserved.\n");\r
75 }\r
76  \r
77 \r
78 static\r
79 void \r
80 Usage(\r
81   void\r
82   )\r
83 /*++\r
84 \r
85 Routine Description:\r
86 \r
87   Displays the utility usage syntax to STDOUT\r
88 \r
89 Arguments:\r
90 \r
91   None\r
92 \r
93 Returns:\r
94 \r
95   None\r
96 \r
97 --*/\r
98 {\r
99   Version();\r
100 \r
101   printf ("\nUsage: " UTILITY_NAME "\n\\r
102         -i, --inputfile [FileName (FV.inf or Cap.inf)]\n\\r
103         -o, --outputfile [FileName (FileName.fv)]\n\\r
104         -r, --baseaddress (0x##### or #####)\n\\r
105         -c, --capsule\n\\r
106         -h, --help\n\\r
107         -V, --version\n");\r
108 }\r
109 \r
110 int\r
111 main (\r
112   IN INTN   argc,\r
113   IN CHAR8  **argv\r
114   )\r
115 /*++\r
116 \r
117 Routine Description:\r
118 \r
119   This utility uses GenFvImage.Lib to build a firmware volume image.\r
120 \r
121 Arguments:\r
122 \r
123   FvInfFileName      The name of an FV image description file.\r
124 \r
125   Arguments come in pair in any order.\r
126     -I FvInfFileName \r
127 \r
128 Returns:\r
129 \r
130   EFI_SUCCESS            No error conditions detected.\r
131   EFI_INVALID_PARAMETER  One or more of the input parameters is invalid.\r
132   EFI_OUT_OF_RESOURCES   A resource required by the utility was unavailable.  \r
133                          Most commonly this will be memory allocation \r
134                          or file creation.\r
135   EFI_LOAD_ERROR         GenFvImage.lib could not be loaded.\r
136   EFI_ABORTED            Error executing the GenFvImage lib.\r
137 \r
138 --*/\r
139 {\r
140   EFI_STATUS            Status;\r
141   CHAR8                 *InfFileName;\r
142   CHAR8                 *InfFileImage;\r
143   UINTN                 InfFileSize;\r
144   CHAR8                 *OutFileName;\r
145   EFI_PHYSICAL_ADDRESS  XipBase;\r
146   UINT8                 CapsuleFlag;\r
147   CAP_INFO              CapInfo;\r
148   MEMORY_FILE           InfMemoryFile;\r
149   FILE                  *fpin, *fpout;\r
150   UINT32                FileSize;\r
151   UINT32                CapSize;\r
152   UINT8                 *CapBuffer;\r
153   EFI_CAPSULE_HEADER    *CapsuleHeader;\r
154   UINT32                Index;\r
155 \r
156   InfFileName   = NULL;\r
157   InfFileImage  = NULL;\r
158   OutFileName   = NULL;\r
159   XipBase       = -1;\r
160   InfFileSize   = 0;\r
161   CapsuleFlag   = 0;\r
162   fpin          = NULL;\r
163   fpout         = NULL;\r
164   FileSize      = 0;\r
165   CapSize       = 0;\r
166   Index         = 0;\r
167   CapBuffer     = NULL;\r
168   CapsuleHeader = NULL;\r
169 \r
170   SetUtilityName (UTILITY_NAME);\r
171 \r
172   if (argc == 1) {\r
173     Usage ();\r
174     return STATUS_ERROR;\r
175   }\r
176 \r
177   //\r
178   // Parse command line\r
179   //\r
180   argc --;\r
181   argv ++;\r
182 \r
183   if ((stricmp (argv[0], "-h") == 0) || (stricmp (argv[0], "--help") == 0)) {\r
184     Usage();\r
185     return STATUS_SUCCESS;    \r
186   }\r
187 \r
188   if ((stricmp (argv[0], "-v") == 0) || (stricmp (argv[0], "--version") == 0)) {\r
189     Version();\r
190     return STATUS_SUCCESS;    \r
191   }\r
192 \r
193   while (argc > 0) {\r
194     if ((stricmp (argv[0], "-i") == 0) || (stricmp (argv[0], "--inputfile") == 0)) {\r
195       InfFileName = argv[1];\r
196       if (InfFileName == NULL) {\r
197         Warning (NULL, 0, 0, NULL, "No input file specified.");\r
198       }\r
199       argc -= 2;\r
200       argv += 2;\r
201       continue; \r
202     }\r
203 \r
204     if ((stricmp (argv[0], "-o") == 0) || (stricmp (argv[0], "--outputfile") == 0)) {\r
205       OutFileName = argv[1];\r
206       if (OutFileName == NULL) {\r
207         Warning (NULL, 0, 0, NULL, "No output file specified.");\r
208       }\r
209       argc -= 2;\r
210       argv += 2;\r
211       continue; \r
212     }\r
213 \r
214     if ((stricmp (argv[0], "-r") == 0) || (stricmp (argv[0], "--baseaddr") == 0)) {\r
215       Status = AsciiStringToUint64 (argv[1], FALSE, &XipBase);\r
216       if (EFI_ERROR (Status)) {\r
217         Error (NULL, 0, 0, "Input paramter is not one valid integrator.", NULL);\r
218         return STATUS_ERROR;        \r
219       }\r
220       argc -= 2;\r
221       argv += 2;\r
222       continue; \r
223     }\r
224 \r
225     if ((stricmp (argv[0], "-c") == 0) || (stricmp (argv[0], "--capsule") == 0)) {\r
226       CapsuleFlag = 1;\r
227       argc --;\r
228       argv ++;\r
229       continue; \r
230     }\r
231     //\r
232     // Don't recognize the paramter.\r
233     //\r
234     Error (NULL, 0, 0, NULL, "%s is invaild paramter!", argv[0]);\r
235     return STATUS_ERROR;\r
236   }\r
237 \r
238   //\r
239   // Read the INF file image\r
240   //\r
241   Status = GetFileImage (InfFileName, &InfFileImage, &InfFileSize);\r
242   if (EFI_ERROR (Status)) {\r
243     return STATUS_ERROR;\r
244   }\r
245 \r
246   //\r
247   // Create Capsule Header\r
248   //\r
249   if (CapsuleFlag) {\r
250     //\r
251     // Initialize file structures\r
252     //\r
253     InfMemoryFile.FileImage           = InfFileImage;\r
254     InfMemoryFile.CurrentFilePointer  = InfFileImage;\r
255     InfMemoryFile.Eof                 = InfFileImage + InfFileSize;\r
256 \r
257     //\r
258     // Parse the Cap inf file for header information\r
259     //\r
260     Status = ParseCapInf (&InfMemoryFile, &CapInfo);\r
261     if (Status != EFI_SUCCESS) {\r
262       goto Finish;\r
263     }\r
264     \r
265     if (CapInfo.HeaderSize == 0) {\r
266       CapInfo.HeaderSize = sizeof (EFI_CAPSULE_HEADER);\r
267     }\r
268 \r
269     if (CapInfo.HeaderSize < sizeof (EFI_CAPSULE_HEADER)) {\r
270       Error (NULL, 0, 0, NULL, "The specified HeaderSize can't be less than the size of EFI_CAPSULE_HEADER.");\r
271       goto Finish;\r
272     }\r
273     \r
274     //\r
275     // Calculate the size of capsule image.\r
276     //\r
277     Index    = 0;\r
278     FileSize = 0;\r
279     CapSize  = sizeof (EFI_CAPSULE_HEADER);\r
280     while (CapInfo.CapFiles [Index][0] != '\0') {\r
281       fpin = fopen (CapInfo.CapFiles[Index], "rb");\r
282       if (fpin == NULL) {\r
283         Error (NULL, 0, 0, NULL, "%s could not open for reading", CapInfo.CapFiles[Index]);\r
284         goto Finish;\r
285       }\r
286       FileSize  = _filelength (fileno (fpin));\r
287       CapSize  += FileSize;\r
288       fclose (fpin);\r
289       Index ++;\r
290     }\r
291 \r
292     //\r
293     // Allocate buffer for capsule image.\r
294     //\r
295     CapBuffer = (UINT8 *) malloc (CapSize);\r
296     if (CapBuffer == NULL) {\r
297       Error (NULL, 0, 0, NULL, "could not allocate enough memory space for capsule");\r
298       goto Finish;\r
299     }\r
300 \r
301     //\r
302     // Initialize the capsule header to zero\r
303     //\r
304     memset (CapBuffer, 0, sizeof (EFI_CAPSULE_HEADER));\r
305     \r
306     //\r
307     // create capsule header and get capsule body\r
308     //\r
309     CapsuleHeader = (EFI_CAPSULE_HEADER *) CapBuffer;\r
310     memcpy (&CapsuleHeader->CapsuleGuid, &CapInfo.CapGuid, sizeof (EFI_GUID));\r
311     CapsuleHeader->HeaderSize       = CapInfo.HeaderSize;\r
312     CapsuleHeader->Flags            = CapInfo.Flags;\r
313     CapsuleHeader->CapsuleImageSize = CapSize;\r
314 \r
315     Index    = 0;\r
316     FileSize = 0;\r
317     CapSize  = CapsuleHeader->HeaderSize;\r
318     while (CapInfo.CapFiles [Index][0] != '\0') {\r
319       fpin = fopen (CapInfo.CapFiles[Index], "rb");\r
320       if (fpin == NULL) {\r
321         Error (NULL, 0, 0, NULL, "%s could not open for reading", CapInfo.CapFiles[Index]);\r
322         goto Finish;\r
323       }\r
324       FileSize = _filelength (fileno (fpin));\r
325       fread (CapBuffer + CapSize, 1, FileSize, fpin);\r
326       fclose (fpin);\r
327       Index ++;\r
328       CapSize += FileSize;\r
329     }\r
330     \r
331     //\r
332     // write capsule data into the output file\r
333     //\r
334     if (OutFileName == NULL) {\r
335       fpout = stdout;\r
336     } else {\r
337       fpout = fopen (OutFileName, "wb");\r
338       if (fpout == NULL) {\r
339         Error (NULL, 0, 0, NULL, "could not open %s file for writing", OutFileName);\r
340         free (CapBuffer);\r
341         goto Finish;\r
342       }\r
343     }\r
344     fwrite (CapBuffer, 1, CapSize, fpout);\r
345     fclose (fpout);\r
346 \r
347   } else {\r
348     //\r
349     // Call the GenFvImageFunction to generate Fv Image\r
350     //\r
351     GenerateFvImage (\r
352       InfFileImage,\r
353       InfFileSize,\r
354       OutFileName,\r
355       XipBase\r
356       );\r
357   }\r
358 \r
359 Finish:\r
360   //\r
361   // free InfFileImage memory\r
362   //\r
363   free (InfFileImage);\r
364 \r
365   return GetUtilityStatus ();\r
366 }\r
367 \r
368 EFI_STATUS\r
369 ParseCapInf (\r
370   IN  MEMORY_FILE  *InfFile,\r
371   OUT CAP_INFO     *CapInfo\r
372   )\r
373 /*++\r
374 \r
375 Routine Description:\r
376 \r
377   This function parses a Cap.INF file and copies info into a CAP_INFO structure.\r
378 \r
379 Arguments:\r
380 \r
381   InfFile        Memory file image.\r
382   CapInfo        Information read from INF file.\r
383 \r
384 Returns:\r
385 \r
386   EFI_SUCCESS       INF file information successfully retrieved.\r
387   EFI_ABORTED       INF file has an invalid format.\r
388   EFI_NOT_FOUND     A required string was not found in the INF file.\r
389 --*/\r
390 {\r
391   CHAR8       Value[_MAX_PATH];\r
392   UINT64      Value64;\r
393   UINTN       Index;\r
394   EFI_STATUS  Status;\r
395 \r
396   //\r
397   // Initialize Cap info\r
398   //\r
399   memset (CapInfo, 0, sizeof (CAP_INFO));\r
400 \r
401   //\r
402   // Read the Capsule Guid\r
403   //\r
404   Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_CAPSULE_GUID_STRING, 0, Value);\r
405   if (Status == EFI_SUCCESS) {\r
406     //\r
407     // Get the Capsule Guid\r
408     //\r
409     Status = StringToGuid (Value, &CapInfo->CapGuid);\r
410     if (EFI_ERROR (Status)) {\r
411       Error (NULL, 0, 0, EFI_CAPSULE_GUID_STRING, "not valid guid value");\r
412       return EFI_ABORTED;\r
413     }\r
414   } else {\r
415     Error (NULL, 0, 0, EFI_CAPSULE_GUID_STRING, "is not specified.");\r
416     return EFI_ABORTED;\r
417   }\r
418 \r
419   //\r
420   // Read the Capsule Header Size\r
421   //\r
422   Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_CAPSULE_HEADER_SIZE_STRING, 0, Value);\r
423   if (Status == EFI_SUCCESS) {\r
424     Status = AsciiStringToUint64 (Value, FALSE, &Value64);\r
425     if (EFI_ERROR (Status)) {\r
426       Error (NULL, 0, 0, Value, "invalid value for %s", EFI_CAPSULE_HEADER_SIZE_STRING);\r
427       return EFI_ABORTED;\r
428     }\r
429     CapInfo->HeaderSize = (UINT32) Value64;\r
430   }\r
431 \r
432   //\r
433   // Read the Capsule Flag\r
434   //\r
435   Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_CAPSULE_FLAGS_STRING, 0, Value);\r
436   if (Status == EFI_SUCCESS) {\r
437     if (stricmp (Value, "PersistAcrossReset") == 0) {\r
438       CapInfo->Flags = CAPSULE_FLAGS_PERSIST_ACROSS_RESET; \r
439     } else if (stricmp (Value, "PopulateSystemTable") == 0) {\r
440       CapInfo->Flags = CAPSULE_FLAGS_PERSIST_ACROSS_RESET | CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE;\r
441     } else {\r
442       Error (NULL, 0, 0, Value, "invalid Flag setting for %s", EFI_CAPSULE_FLAGS_STRING);\r
443       return EFI_ABORTED;\r
444     }\r
445   }\r
446   \r
447   //\r
448   // Read the Capsule Version\r
449   //\r
450   Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_CAPSULE_VERSION_STRING, 0, Value);\r
451   if (Status == EFI_SUCCESS) {\r
452     if (stricmp (Value, "UEFI") == 0) {\r
453       CapInfo->Version = 0x20000;  \r
454     } else if (stricmp (Value, "FRAMEWORK") == 0) {\r
455       CapInfo->Version = 0x10010;\r
456       Error (NULL, 0, 0, Value, "is not supported Version for %s", EFI_CAPSULE_VERSION_STRING);\r
457       return EFI_ABORTED;\r
458     } else {\r
459       Error (NULL, 0, 0, Value, "invalid Version setting for %s", EFI_CAPSULE_VERSION_STRING);\r
460       return EFI_ABORTED;\r
461     }\r
462   }\r
463 \r
464   //\r
465   // Read the Capsule FileImage\r
466   //\r
467   for (Index = 0; Index < MAX_NUMBER_OF_FILES_IN_CAP; Index++) {\r
468     //\r
469     // Read the capsule file name\r
470     //\r
471     Status = FindToken (InfFile, FILES_SECTION_STRING, EFI_FILE_NAME_STRING, Index, Value);\r
472 \r
473     if (Status == EFI_SUCCESS) {\r
474       //\r
475       // Add the file\r
476       //\r
477       strcpy (CapInfo->CapFiles[Index], Value);\r
478     } else {\r
479       break;\r
480     }\r
481   }\r
482   \r
483   if (Index == 0) {\r
484     printf("Cap Files are not specified.\n");\r
485   }\r
486 \r
487   return EFI_SUCCESS;\r
488 }