Correct usage help information and error information format for Genfw, GenSec, GenFfs...
[efi/basetools/.git] / Source / C / GenSec / GenSec.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   GenSection.c\r
15 \r
16 Abstract:\r
17 \r
18   Creates output file that is a properly formed section per the FV spec.\r
19 \r
20 --*/\r
21 \r
22 #include <stdio.h>\r
23 #include <stdlib.h>\r
24 #include <string.h>\r
25 \r
26 #include <Common/UefiBaseTypes.h>\r
27 #include <Common/PiFirmwareFile.h>\r
28 #include <Protocol/GuidedSectionExtraction.h>\r
29 \r
30 #include "CommonLib.h"\r
31 #include "Compress.h"\r
32 #include "Crc32.h"\r
33 #include "EfiUtilityMsgs.h"\r
34 \r
35 //\r
36 // GenSec Tool Information\r
37 //\r
38 #define UTILITY_NAME            "GenSec"\r
39 #define UTILITY_MAJOR_VERSION   0\r
40 #define UTILITY_MINOR_VERSION   1\r
41 \r
42 #define MAX_SECTION_SIZE        0x1000000\r
43 \r
44 static CHAR8      *SectionTypeName[] = {\r
45   NULL,                                 // 0x00 - reserved\r
46   "EFI_SECTION_COMPRESSION",            // 0x01\r
47   "EFI_SECTION_GUID_DEFINED",           // 0x02\r
48   NULL,                                 // 0x03 - reserved\r
49   NULL,                                 // 0x04 - reserved\r
50   NULL,                                 // 0x05 - reserved\r
51   NULL,                                 // 0x06 - reserved\r
52   NULL,                                 // 0x07 - reserved\r
53   NULL,                                 // 0x08 - reserved\r
54   NULL,                                 // 0x09 - reserved\r
55   NULL,                                 // 0x0A - reserved\r
56   NULL,                                 // 0x0B - reserved\r
57   NULL,                                 // 0x0C - reserved\r
58   NULL,                                 // 0x0D - reserved\r
59   NULL,                                 // 0x0E - reserved\r
60   NULL,                                 // 0x0F - reserved\r
61   "EFI_SECTION_PE32",                   // 0x10\r
62   "EFI_SECTION_PIC",                    // 0x11\r
63   "EFI_SECTION_TE",                     // 0x12\r
64   "EFI_SECTION_DXE_DEPEX",              // 0x13\r
65   "EFI_SECTION_VERSION",                // 0x14\r
66   "EFI_SECTION_USER_INTERFACE",         // 0x15\r
67   "EFI_SECTION_COMPATIBILITY16",        // 0x16\r
68   "EFI_SECTION_FIRMWARE_VOLUME_IMAGE",  // 0x17\r
69   "EFI_SECTION_FREEFORM_SUBTYPE_GUID",  // 0x18\r
70   "EFI_SECTION_RAW",                    // 0x19\r
71   NULL,                                 // 0x1A\r
72   "EFI_SECTION_PEI_DEPEX"               // 0x1B\r
73 };\r
74 \r
75 static CHAR8      *CompressionTypeName[]    = { "PI_NONE", "PI_STD" };\r
76 static CHAR8      *GUIDedSectionAttribue[]  = { NULL, "PROCESSING_REQUIRED", "AUTH_STATUS_VALID"};\r
77 \r
78 //\r
79 // Crc32 GUID section related definitions.\r
80 //\r
81 typedef struct {\r
82   EFI_GUID_DEFINED_SECTION  GuidSectionHeader;\r
83   UINT32                    CRC32Checksum;\r
84 } CRC32_SECTION_HEADER;\r
85 \r
86 static EFI_GUID  gZeroGuid                 = {0x0, 0x0, 0x0, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}};\r
87 static EFI_GUID  gEfiCrc32SectionGuid      = EFI_CRC32_GUIDED_SECTION_EXTRACTION_PROTOCOL_GUID;\r
88 \r
89 //\r
90 // VerboseMode setting\r
91 //\r
92 static BOOLEAN VerboseMode = FALSE;\r
93 \r
94 STATIC\r
95 VOID \r
96 Version (\r
97   VOID\r
98   )\r
99 /*++\r
100 \r
101 Routine Description:\r
102 \r
103   Print out version information for this utility.\r
104 \r
105 Arguments:\r
106 \r
107   None\r
108   \r
109 Returns:\r
110 \r
111   None\r
112   \r
113 --*/ \r
114 {\r
115   fprintf (stdout, "%s Version %d.%d\n", UTILITY_NAME, UTILITY_MAJOR_VERSION, UTILITY_MINOR_VERSION);\r
116 }\r
117 \r
118 STATIC\r
119 VOID\r
120 Usage (\r
121   VOID\r
122   )\r
123 {\r
124   //\r
125   // Summary usage\r
126   //\r
127   fprintf (stdout, "Usage: %s [options] <input_file>\n\n", UTILITY_NAME);\r
128   \r
129   //\r
130   // Copyright declaration\r
131   // \r
132   fprintf (stdout, "Copyright (c) 2007, Intel Corporation. All rights reserved.\n\n");\r
133 \r
134   //\r
135   // Details Option\r
136   //\r
137   fprintf (stdout, "Options:\n");\r
138   fprintf (stdout, "  -o FileName, --outputfile FileName\n\\r
139                         File is the SectionFile to be created.\n");\r
140   fprintf (stdout, "  -s [SectionType], --sectiontype [SectionType]\n\\r
141                         SectionType defined in PI spec is one type of\n\\r
142                         EFI_SECTION_COMPRESSION, EFI_SECTION_GUID_DEFINED,\n\\r
143                         EFI_SECTION_PE32, EFI_SECTION_PIC, EFI_SECTION_TE,\n\\r
144                         EFI_SECTION_DXE_DEPEX, EFI_SECTION_COMPATIBILITY16,\n\\r
145                         EFI_SECTION_USER_INTERFACE, EFI_SECTION_VERSION,\n\\r
146                         EFI_SECTION_FIRMWARE_VOLUME_IMAGE, EFI_SECTION_RAW,\n\\r
147                         EFI_SECTION_FREEFORM_SUBTYPE_GUID,\n\\r
148                         EFI_SECTION_PEI_DEPEX. if sectiontype is not given, \n\\r
149                         EFI_SECTION_ALL is default type.\n");\r
150   fprintf (stdout, "  -c [Type], --compress [Type]\n\\r
151                         Compress method type can be PI_NONE or PI_STD.\n\\r
152                         if Type is not given, PI_STD is default type.\n"); \r
153   fprintf (stdout, "  -g GuidValue, --vendorguid GuidValue\n\\r
154                         GuidValue is one specific vendor guid value.\n\\r
155                         Its format is 00000000-0000-0000-0000-000000000000\n");\r
156   fprintf (stdout, "  -r GuidAttr, --attributes GuidAttr\n\\r
157                         GuidAttr is guid section atttributes, which may be\n\\r
158                         PROCESSING_REQUIRED or AUTH_STATUS_VALID\n");\r
159   fprintf (stdout, "  -n String, --name String\n\\r
160                         String is a NULL terminated string used in Ui section.\n");\r
161   fprintf (stdout, "  -j Number, --buildnumber Number\n\\r
162                         Number is an integer value between 0000 and 9999\n\\r
163                         used in Ver section.\n");\r
164   fprintf (stdout, "  -v, --verbose         Turn on verbose output with informational messages.\n");\r
165   fprintf (stdout, "  --version             Show program's version number and exit.\n");\r
166   fprintf (stdout, "  -h, --help            Show this help message and exit.\n");\r
167 }\r
168 \r
169 VOID\r
170 Ascii2UnicodeWriteString (\r
171   CHAR8    *String,\r
172   FILE     *OutFile\r
173   )\r
174 {\r
175   UINT32 Index;\r
176   UINT8  AsciiNull;\r
177 \r
178   AsciiNull = 0;\r
179 \r
180   //\r
181   // Next, write out the string... Convert ASCII to Unicode in the process.\r
182   //\r
183   Index = 0;\r
184   do {\r
185     fwrite (&String[Index], 1, 1, OutFile);\r
186     fwrite (&AsciiNull, 1, 1, OutFile);\r
187   } while (String[Index++] != 0);\r
188 }\r
189 \r
190 STATUS\r
191 GenSectionCommonLeafSection (\r
192   CHAR8   **InputFileName,\r
193   UINT32  InputFileNum,\r
194   UINT8   SectionType,\r
195   FILE    *OutFile\r
196   )\r
197 /*++\r
198         \r
199 Routine Description:\r
200            \r
201   Generate a leaf section of type other than EFI_SECTION_VERSION\r
202   and EFI_SECTION_USER_INTERFACE. Input file must be well formed.\r
203   The function won't validate the input file's contents. For\r
204   common leaf sections, the input file may be a binary file.\r
205   The utility will add section header to the file.\r
206             \r
207 Arguments:\r
208                \r
209   InputFileName  - Name of the input file.\r
210                 \r
211   InputFileNum   - Number of input files. Should be 1 for leaf section.\r
212 \r
213   SectionType    - A valid section type string\r
214 \r
215   OutFile        - Output file handle\r
216 \r
217 Returns:\r
218                        \r
219   STATUS_ERROR            - can't continue\r
220   STATUS_SUCCESS          - successful return\r
221 \r
222 --*/\r
223 {\r
224   UINT32                    InputFileLength;\r
225   FILE                      *InFile;\r
226   UINT8                     *Buffer;\r
227   UINT32                    TotalLength;\r
228   EFI_COMMON_SECTION_HEADER CommonSect;\r
229   STATUS                    Status;\r
230 \r
231   if (InputFileNum > 1) {\r
232     Error (NULL, 0, 2000, "Invalid paramter", "more than one input file specified");\r
233     return STATUS_ERROR;\r
234   } else if (InputFileNum < 1) {\r
235     Error (NULL, 0, 2000, "Invalid paramter", "no input file specified");\r
236     return STATUS_ERROR;\r
237   }\r
238   //\r
239   // Open the input file\r
240   //\r
241   InFile = fopen (InputFileName[0], "rb");\r
242   if (InFile == NULL) {\r
243     Error (NULL, 0, 0001, "Error opening file", InputFileName[0]);\r
244     return STATUS_ERROR;\r
245   }\r
246 \r
247   Status  = STATUS_ERROR;\r
248   Buffer  = NULL;\r
249   //\r
250   // Seek to the end of the input file so we can determine its size\r
251   //\r
252   fseek (InFile, 0, SEEK_END);\r
253   InputFileLength = ftell (InFile);\r
254   fseek (InFile, 0, SEEK_SET);\r
255   //\r
256   // Fill in the fields in the local section header structure\r
257   //\r
258   CommonSect.Type = (EFI_SECTION_TYPE) SectionType;\r
259   TotalLength     = sizeof (CommonSect) + InputFileLength;\r
260   //\r
261   // Size must fit in 3 bytes\r
262   //\r
263   if (TotalLength >= MAX_SECTION_SIZE) {\r
264     Error (NULL, 0, 2000, "Invalid paramter", "%s file size (0x%X) exceeds section size limit(%dM).", InputFileName[0], TotalLength, MAX_SECTION_SIZE>>20);\r
265     goto Done;\r
266   }\r
267   //\r
268   // Now copy the size into the section header and write out the section header\r
269   //\r
270   memcpy (&CommonSect.Size, &TotalLength, 3);\r
271   fwrite (&CommonSect, sizeof (CommonSect), 1, OutFile);\r
272   //\r
273   // Allocate a buffer to read in the contents of the input file. Then\r
274   // read it in as one block and write it to the output file.\r
275   //\r
276   if (InputFileLength != 0) {\r
277     Buffer = (UINT8 *) malloc ((size_t) InputFileLength);\r
278     if (Buffer == NULL) {\r
279       Error (NULL, 0, 4001, "Resource", "memory cannot be allcoated"); \r
280       goto Done;\r
281     }\r
282 \r
283     if (fread (Buffer, (size_t) InputFileLength, 1, InFile) != 1) {\r
284       Error (NULL, 0, 0004, "Error reading file", InputFileName[0]);\r
285       goto Done;\r
286     }\r
287 \r
288     if (fwrite (Buffer, (size_t) InputFileLength, 1, OutFile) != 1) {\r
289       Error (NULL, 0, 0002, "Error writing file", NULL);\r
290       goto Done;\r
291     }\r
292   }\r
293 \r
294   Status = STATUS_SUCCESS;\r
295 \r
296 Done:\r
297   fclose (InFile);\r
298   if (Buffer != NULL) {\r
299     free (Buffer);\r
300   }\r
301 \r
302   return Status;\r
303 }\r
304 \r
305 EFI_STATUS\r
306 GetSectionContents (\r
307   CHAR8   **InputFileName,\r
308   UINT32  InputFileNum,\r
309   UINT8   *FileBuffer,\r
310   UINT32  *BufferLength\r
311   )\r
312 /*++\r
313         \r
314 Routine Description:\r
315            \r
316   Get the contents of all section files specified in InputFileName\r
317   into FileBuffer.\r
318             \r
319 Arguments:\r
320                \r
321   InputFileName  - Name of the input file.\r
322                 \r
323   InputFileNum   - Number of input files. Should be at least 1.\r
324 \r
325   FileBuffer     - Output buffer to contain data\r
326 \r
327   BufferLength   - On input, this is size of the FileBuffer. \r
328                    On output, this is the actual length of the data.\r
329 \r
330 Returns:\r
331                        \r
332   EFI_SUCCESS on successful return\r
333   EFI_INVALID_PARAMETER if InputFileNum is less than 1 or BufferLength point is NULL.\r
334   EFI_ABORTED if unable to open input file.\r
335   EFI_BUFFER_TOO_SMALL FileBuffer is not enough to contain all file data.\r
336 --*/\r
337 {\r
338   UINT32   Size;\r
339   UINT32   FileSize;\r
340   UINT32   Index;\r
341   FILE    *InFile;\r
342 \r
343   if (InputFileNum < 1) {\r
344     Error (NULL, 0, 2000, "Invalid paramter", "must specify at least one input file");\r
345     return EFI_INVALID_PARAMETER;\r
346   }\r
347 \r
348   if (BufferLength == NULL) {\r
349     Error (NULL, 0, 2000, "Invalid paramter", "BufferLength can't be NULL");\r
350     return EFI_INVALID_PARAMETER;\r
351   }\r
352 \r
353   Size = 0;\r
354   //\r
355   // Go through our array of file names and copy their contents\r
356   // to the output buffer.\r
357   //\r
358   for (Index = 0; Index < InputFileNum; Index++) {\r
359     //\r
360     // make sure section ends on a DWORD boundary\r
361     //\r
362     while ((Size & 0x03) != 0) {\r
363       if (FileBuffer != NULL && Size < *BufferLength) {\r
364         FileBuffer[Size] = 0;\r
365       }\r
366       Size++;\r
367     }\r
368     \r
369     // \r
370     // Open file and read contents\r
371     //\r
372     InFile = fopen (InputFileName[Index], "rb");\r
373     if (InFile == NULL) {\r
374       Error (NULL, 0, 0001, "Error opening file", InputFileName[Index]);\r
375       return EFI_ABORTED;\r
376     }\r
377 \r
378     fseek (InFile, 0, SEEK_END);\r
379     FileSize = ftell (InFile);\r
380     fseek (InFile, 0, SEEK_SET);\r
381     //\r
382     // Now read the contents of the file into the buffer\r
383     // Buffer must be enough to contain the file content.\r
384     //\r
385     if (FileSize > 0 && FileBuffer != NULL && (Size + FileSize) <= *BufferLength) {\r
386       if (fread (FileBuffer + Size, (size_t) FileSize, 1, InFile) != 1) {\r
387         Error (NULL, 0, 0004, "Error reading file", InputFileName[Index]);\r
388         fclose (InFile);\r
389         return EFI_ABORTED;\r
390       }\r
391     }\r
392 \r
393     fclose (InFile);\r
394     Size += FileSize;\r
395   }\r
396   \r
397   if (Size > *BufferLength) {\r
398     *BufferLength = Size;\r
399     return EFI_BUFFER_TOO_SMALL;\r
400   } else {\r
401     *BufferLength = Size;\r
402     return EFI_SUCCESS;\r
403   }\r
404 }\r
405 \r
406 EFI_STATUS\r
407 GenSectionCompressionSection (\r
408   CHAR8    **InputFileName,\r
409   UINT32  InputFileNum,\r
410   UINT8   SectCompSubType,\r
411   FILE    *OutFile\r
412   )\r
413 /*++\r
414         \r
415 Routine Description:\r
416            \r
417   Generate an encapsulating section of type EFI_SECTION_COMPRESSION\r
418   Input file must be already sectioned. The function won't validate\r
419   the input files' contents. Caller should hand in files already \r
420   with section header.\r
421             \r
422 Arguments:\r
423                \r
424   InputFileName  - Name of the input file.\r
425                 \r
426   InputFileNum   - Number of input files. Should be at least 1.\r
427 \r
428   SectCompSubType - Specify the compression algorithm requested. \r
429   \r
430   OutFile        - Output file handle\r
431 \r
432 Returns:\r
433                        \r
434   EFI_SUCCESS           on successful return\r
435   EFI_INVALID_PARAMETER if InputFileNum is less than 1\r
436   EFI_ABORTED           if unable to open input file.\r
437   EFI_OUT_OF_RESOURCES  No resource to complete the operation.\r
438 --*/\r
439 {\r
440   UINT32                  TotalLength;\r
441   UINT32                  InputLength;\r
442   UINT32                  CompressedLength;\r
443   UINT8                   *FileBuffer;\r
444   UINT8                   *OutputBuffer;\r
445   EFI_STATUS              Status;\r
446   EFI_COMPRESSION_SECTION CompressionSect;\r
447   COMPRESS_FUNCTION       CompressFunction;\r
448 \r
449   InputLength       = 0;\r
450   FileBuffer        = NULL;\r
451   OutputBuffer      = NULL;\r
452   CompressedLength  = 0;\r
453   //\r
454   // read all input file contents into a buffer\r
455   // first get the size of all file contents\r
456   //\r
457   Status = GetSectionContents (\r
458             InputFileName,\r
459             InputFileNum,\r
460             FileBuffer,\r
461             &InputLength\r
462             );\r
463 \r
464   if (Status == EFI_BUFFER_TOO_SMALL) {\r
465     FileBuffer = (UINT8 *) malloc (InputLength);\r
466     if (FileBuffer == NULL) {\r
467       Error (NULL, 0, 4001, "Resource", "memory cannot be allcoated");\r
468       return EFI_OUT_OF_RESOURCES;\r
469     }\r
470     //\r
471     // read all input file contents into a buffer\r
472     //\r
473     Status = GetSectionContents (\r
474               InputFileName,\r
475               InputFileNum,\r
476               FileBuffer,\r
477               &InputLength\r
478               );\r
479   }\r
480 \r
481   if (EFI_ERROR (Status)) {\r
482     if (FileBuffer != NULL) {\r
483       free (FileBuffer);\r
484     }\r
485     return Status;\r
486   }\r
487 \r
488   CompressFunction = NULL;\r
489 \r
490   //\r
491   // Now data is in FileBuffer, compress the data\r
492   //\r
493   switch (SectCompSubType) {\r
494   case EFI_NOT_COMPRESSED:\r
495     CompressedLength = InputLength;\r
496     break;\r
497 \r
498   case EFI_STANDARD_COMPRESSION:\r
499     CompressFunction = (COMPRESS_FUNCTION) EfiCompress;\r
500     break;\r
501 \r
502   default:\r
503     Error (NULL, 0, 2000, "Invalid paramter", "unknown compression type");\r
504     free (FileBuffer);\r
505     return EFI_ABORTED;\r
506   }\r
507 \r
508   if (CompressFunction != NULL) {\r
509 \r
510     Status = CompressFunction (FileBuffer, InputLength, OutputBuffer, &CompressedLength);\r
511     if (Status == EFI_BUFFER_TOO_SMALL) {\r
512       OutputBuffer = malloc (CompressedLength);\r
513       if (!OutputBuffer) {\r
514         free (FileBuffer);\r
515         return EFI_OUT_OF_RESOURCES;\r
516       }\r
517 \r
518       Status = CompressFunction (FileBuffer, InputLength, OutputBuffer, &CompressedLength);\r
519     }\r
520 \r
521     free (FileBuffer);\r
522     FileBuffer = OutputBuffer;\r
523 \r
524     if (EFI_ERROR (Status)) {\r
525       if (FileBuffer != NULL) {\r
526         free (FileBuffer);\r
527       }\r
528 \r
529       return Status;\r
530     }\r
531   }\r
532 \r
533   TotalLength = CompressedLength + sizeof (EFI_COMPRESSION_SECTION);\r
534   if (TotalLength >= MAX_SECTION_SIZE) {\r
535     Error (NULL, 0, 2000, "Invalid paramter", "The size of all files exceeds section size limit(%dM).", MAX_SECTION_SIZE>>20);\r
536     if (FileBuffer != NULL) {\r
537       free (FileBuffer);\r
538     }\r
539     if (OutputBuffer != NULL) {\r
540       free (OutputBuffer);\r
541     }\r
542     return STATUS_ERROR;\r
543   }\r
544 \r
545   //\r
546   // Add the section header for the compressed data\r
547   //\r
548   CompressionSect.CommonHeader.Type     = EFI_SECTION_COMPRESSION;\r
549   CompressionSect.CommonHeader.Size[0]  = (UINT8) (TotalLength & 0xff);\r
550   CompressionSect.CommonHeader.Size[1]  = (UINT8) ((TotalLength & 0xff00) >> 8);\r
551   CompressionSect.CommonHeader.Size[2]  = (UINT8) ((TotalLength & 0xff0000) >> 16);\r
552   CompressionSect.CompressionType       = SectCompSubType;\r
553   CompressionSect.UncompressedLength    = InputLength;\r
554 \r
555   fwrite (&CompressionSect, sizeof (CompressionSect), 1, OutFile);\r
556   fwrite (FileBuffer, CompressedLength, 1, OutFile);\r
557   free (FileBuffer);\r
558   return EFI_SUCCESS;\r
559 }\r
560 \r
561 EFI_STATUS\r
562 GenSectionGuidDefinedSection (\r
563   CHAR8    **InputFileName,\r
564   UINT32   InputFileNum,\r
565   EFI_GUID *VendorGuid,\r
566   UINT16   DataAttribute,\r
567   FILE     *OutFile\r
568   )\r
569 /*++\r
570         \r
571 Routine Description:\r
572            \r
573   Generate an encapsulating section of type EFI_SECTION_GUID_DEFINED\r
574   Input file must be already sectioned. The function won't validate\r
575   the input files' contents. Caller should hand in files already \r
576   with section header.\r
577             \r
578 Arguments:\r
579                \r
580   InputFileName - Name of the input file.\r
581                 \r
582   InputFileNum  - Number of input files. Should be at least 1.\r
583 \r
584   VendorGuid    - Specify vendor guid value.\r
585 \r
586   DataAttribute - Specify attribute for the vendor guid data. \r
587   \r
588   OutFile       - Output file handle\r
589 \r
590 Returns:\r
591                        \r
592   EFI_SUCCESS on successful return\r
593   EFI_INVALID_PARAMETER if InputFileNum is less than 1\r
594   EFI_ABORTED if unable to open input file.\r
595   EFI_OUT_OF_RESOURCES  No resource to complete the operation.\r
596 \r
597 --*/\r
598 {\r
599   UINT32                TotalLength;\r
600   UINT32                InputLength;\r
601   UINT8                 *FileBuffer;\r
602   UINT32                Crc32Checksum;\r
603   EFI_STATUS            Status;\r
604   CRC32_SECTION_HEADER  Crc32GuidSect;\r
605   EFI_GUID_DEFINED_SECTION  VendorGuidSect;\r
606 \r
607   InputLength = 0;\r
608   FileBuffer  = NULL;\r
609   //\r
610   // read all input file contents into a buffer\r
611   // first get the size of all file contents\r
612   //\r
613   Status = GetSectionContents (\r
614             InputFileName,\r
615             InputFileNum,\r
616             FileBuffer,\r
617             &InputLength\r
618             );\r
619 \r
620   if (Status == EFI_BUFFER_TOO_SMALL) {\r
621     FileBuffer = (UINT8 *) malloc (InputLength);\r
622     if (FileBuffer == NULL) {\r
623       Error (NULL, 0, 4001, "Resource", "memory cannot be allcoated");\r
624       return EFI_OUT_OF_RESOURCES;\r
625     }\r
626     //\r
627     // read all input file contents into a buffer\r
628     //\r
629     Status = GetSectionContents (\r
630               InputFileName,\r
631               InputFileNum,\r
632               FileBuffer,\r
633               &InputLength\r
634               );\r
635   }\r
636 \r
637   if (EFI_ERROR (Status)) {\r
638     if (FileBuffer != NULL) {\r
639       free (FileBuffer);\r
640     }\r
641     return Status;\r
642   }\r
643 \r
644   //\r
645   // Now data is in FileBuffer\r
646   //\r
647   if (CompareGuid (VendorGuid, &gEfiCrc32SectionGuid) == 0) {\r
648     //\r
649     // Default Guid section is CRC32.\r
650     //\r
651     Crc32Checksum = 0;\r
652     CalculateCrc32 (FileBuffer, InputLength, &Crc32Checksum);\r
653 \r
654     TotalLength = InputLength + sizeof (CRC32_SECTION_HEADER);\r
655     if (TotalLength >= MAX_SECTION_SIZE) {\r
656       Error (NULL, 0, 2000, "Invalid paramter", "The size of all files exceeds section size limit(%dM).", MAX_SECTION_SIZE>>20);\r
657       free (FileBuffer);\r
658       return STATUS_ERROR;\r
659     }\r
660 \r
661     Crc32GuidSect.GuidSectionHeader.CommonHeader.Type     = EFI_SECTION_GUID_DEFINED;\r
662     Crc32GuidSect.GuidSectionHeader.CommonHeader.Size[0]  = (UINT8) (TotalLength & 0xff);\r
663     Crc32GuidSect.GuidSectionHeader.CommonHeader.Size[1]  = (UINT8) ((TotalLength & 0xff00) >> 8);\r
664     Crc32GuidSect.GuidSectionHeader.CommonHeader.Size[2]  = (UINT8) ((TotalLength & 0xff0000) >> 16);\r
665     memcpy (&(Crc32GuidSect.GuidSectionHeader.SectionDefinitionGuid), &gEfiCrc32SectionGuid, sizeof (EFI_GUID));\r
666     Crc32GuidSect.GuidSectionHeader.Attributes  = EFI_GUIDED_SECTION_AUTH_STATUS_VALID;\r
667     Crc32GuidSect.GuidSectionHeader.DataOffset  = sizeof (CRC32_SECTION_HEADER);\r
668     Crc32GuidSect.CRC32Checksum                 = Crc32Checksum;\r
669     fwrite (&Crc32GuidSect, sizeof (Crc32GuidSect), 1, OutFile);  \r
670 \r
671   } else {\r
672     TotalLength = InputLength + sizeof (EFI_GUID_DEFINED_SECTION);\r
673     if (TotalLength >= MAX_SECTION_SIZE) {\r
674       Error (NULL, 0, 2000, "Invalid paramter", "The size of all files exceeds section size limit(%dM).", MAX_SECTION_SIZE>>20);\r
675       free (FileBuffer);\r
676       return STATUS_ERROR;\r
677     }\r
678 \r
679     VendorGuidSect.CommonHeader.Type     = EFI_SECTION_GUID_DEFINED;\r
680     VendorGuidSect.CommonHeader.Size[0]  = (UINT8) (TotalLength & 0xff);\r
681     VendorGuidSect.CommonHeader.Size[1]  = (UINT8) ((TotalLength & 0xff00) >> 8);\r
682     VendorGuidSect.CommonHeader.Size[2]  = (UINT8) ((TotalLength & 0xff0000) >> 16);\r
683     memcpy (&(VendorGuidSect.SectionDefinitionGuid), VendorGuid, sizeof (EFI_GUID));\r
684     VendorGuidSect.Attributes  = DataAttribute;\r
685     VendorGuidSect.DataOffset  = sizeof (EFI_GUID_DEFINED_SECTION);\r
686     fwrite (&VendorGuidSect, sizeof (EFI_GUID_DEFINED_SECTION), 1, OutFile);  \r
687   }\r
688 \r
689   fwrite (FileBuffer, InputLength, 1, OutFile);\r
690   free (FileBuffer);\r
691 \r
692   return EFI_SUCCESS;\r
693 }\r
694 \r
695 int\r
696 main (\r
697   int  argc,\r
698   char *argv[]\r
699   )\r
700 /*++\r
701 \r
702 Routine Description:\r
703 \r
704   Main\r
705 \r
706 Arguments:\r
707 \r
708   command line parameters\r
709 \r
710 Returns:\r
711 \r
712   EFI_SUCCESS    Section header successfully generated and section concatenated.\r
713   EFI_ABORTED    Could not generate the section\r
714   EFI_OUT_OF_RESOURCES  No resource to complete the operation.\r
715 \r
716 --*/\r
717 {\r
718   UINT32                    Index;\r
719   UINT32                    InputFileNum;\r
720   FILE                      *InFile;\r
721   FILE                      *OutFile;\r
722   CHAR8                     **InputFileName;\r
723   CHAR8                     *OutputFileName;\r
724   CHAR8                     *SectionName;\r
725   CHAR8                     *CompressionName;\r
726   CHAR8                     *StringBuffer;\r
727   EFI_GUID                  VendorGuid = gZeroGuid;\r
728   INT32                     VersionNumber;\r
729   UINT8                     SectType;\r
730   UINT8                     SectCompSubType;\r
731   UINT16                    SectGuidAttribute; \r
732   EFI_COMMON_SECTION_HEADER CommonSect;\r
733   UINT32                    InputLength;\r
734   UINT8                     *FileBuffer;\r
735   EFI_STATUS                Status;\r
736   \r
737   InputFileName         = NULL;\r
738   OutputFileName        = NULL;\r
739   SectionName           = NULL;\r
740   CompressionName       = NULL;\r
741   StringBuffer          = "";\r
742   InFile                = NULL;\r
743   OutFile               = NULL;\r
744   VersionNumber         = 0;\r
745   InputFileNum          = 0;\r
746   SectType              = EFI_SECTION_ALL;\r
747   SectCompSubType       = 0;\r
748   SectGuidAttribute     = 0;\r
749   FileBuffer            = NULL;\r
750   InputLength           = 0;\r
751   Status                = STATUS_SUCCESS;\r
752   \r
753   SetUtilityName (UTILITY_NAME);\r
754   \r
755   if (argc == 1) {\r
756     Error (NULL, 0, 1001, "Missing options", "Input file");\r
757     Usage ();\r
758     return STATUS_ERROR;\r
759   }\r
760 \r
761   //\r
762   // Parse command line\r
763   //\r
764   argc --;\r
765   argv ++;\r
766 \r
767   if ((stricmp (argv[0], "-h") == 0) || (stricmp (argv[0], "--help") == 0)) {\r
768     Usage();\r
769     return STATUS_SUCCESS;    \r
770   }\r
771 \r
772   if (stricmp (argv[0], "--version") == 0) {\r
773     Version ();\r
774     return STATUS_SUCCESS;    \r
775   }\r
776 \r
777   while (argc > 0) {\r
778     if ((stricmp (argv[0], "-s") == 0) || (stricmp (argv[0], "--SectionType") == 0)) {\r
779       SectionName = argv[1];\r
780       argc -= 2;\r
781       argv += 2;\r
782       continue; \r
783     }\r
784 \r
785     if ((stricmp (argv[0], "-o") == 0) || (stricmp (argv[0], "--outputfile") == 0)) {\r
786       OutputFileName = argv[1];\r
787       argc -= 2;\r
788       argv += 2;\r
789       continue; \r
790     }\r
791 \r
792     if ((stricmp (argv[0], "-c") == 0) || (stricmp (argv[0], "--compress") == 0)) {\r
793       CompressionName = argv[1];\r
794       argc -= 2;\r
795       argv += 2;\r
796       continue;\r
797     }\r
798 \r
799     if ((stricmp (argv[0], "-g") == 0) || (stricmp (argv[0], "--vendorguid") == 0)) {\r
800       Status = StringToGuid (argv[1], &VendorGuid);\r
801       if (EFI_ERROR (Status)) {\r
802         Error (NULL, 0, 1003, "Invalid option value", "%s = %s", argv[0], argv[1]);\r
803         goto Finish;\r
804       }\r
805       argc -= 2;\r
806       argv += 2;\r
807       continue;\r
808     }\r
809 \r
810     if ((stricmp (argv[0], "-r") == 0) || (stricmp (argv[0], "--attributes") == 0)) {\r
811       if (stricmp (argv[1], GUIDedSectionAttribue[EFI_GUIDED_SECTION_PROCESSING_REQUIRED]) == 0) {\r
812         SectGuidAttribute |= EFI_GUIDED_SECTION_PROCESSING_REQUIRED;\r
813       } else if (stricmp (argv[1], GUIDedSectionAttribue[EFI_GUIDED_SECTION_AUTH_STATUS_VALID]) == 0) {\r
814         SectGuidAttribute |= EFI_GUIDED_SECTION_AUTH_STATUS_VALID;\r
815       } else {\r
816         Error (NULL, 0, 1003, "Invalid option value", "%s = %s", argv[0], argv[1]);\r
817         goto Finish;\r
818       }\r
819       argc -= 2;\r
820       argv += 2;\r
821       continue;\r
822     }\r
823 \r
824     if ((stricmp (argv[0], "-n") == 0) || (stricmp (argv[0], "--name") == 0)) {\r
825       StringBuffer = argv[1];\r
826       argc -= 2;\r
827       argv += 2;\r
828       continue;\r
829     }\r
830 \r
831     if ((stricmp (argv[0], "-j") == 0) || (stricmp (argv[0], "--buildnumber") == 0)) {\r
832       //\r
833       // Verify string is a integrator number\r
834       //\r
835       for (Index = 0; Index < strlen (argv[1]); Index++) {\r
836         if ((argv[1][Index] != '-') && (isdigit (argv[1][Index]) == 0)) {\r
837           Error (NULL, 0, 1003, "Invalid option value", "%s = %s", argv[0], argv[1]);\r
838           goto Finish;\r
839         }\r
840       }\r
841 \r
842       sscanf (argv[1], "%d", &VersionNumber);\r
843       argc -= 2;\r
844       argv += 2;\r
845       continue;\r
846     }\r
847 \r
848     if ((stricmp (argv[0], "-v") == 0) || (stricmp (argv[0], "--verbose") == 0)) {\r
849       VerboseMode = TRUE;\r
850       argc --;\r
851       argv ++;\r
852       continue;\r
853     }\r
854     //\r
855     // Get Input file name\r
856     //\r
857     if ((InputFileNum == 0) && (InputFileName == NULL)) {\r
858       InputFileName = (CHAR8 **) malloc (MAXIMUM_INPUT_FILE_NUM * sizeof (CHAR8 *));\r
859       if (InputFileName == NULL) {\r
860         Error (NULL, 0, 4001, "Resource", "memory cannot be allcoated");\r
861         return EFI_OUT_OF_RESOURCES;\r
862       }\r
863 \r
864       memset (InputFileName, 0, (MAXIMUM_INPUT_FILE_NUM * sizeof (CHAR8 *)));\r
865     } else if (InputFileNum % MAXIMUM_INPUT_FILE_NUM == 0) {\r
866       //\r
867       // InputFileName buffer too small, need to realloc\r
868       //\r
869       InputFileName = (CHAR8 **) realloc (\r
870                                   InputFileName,\r
871                                   (InputFileNum + MAXIMUM_INPUT_FILE_NUM) * sizeof (CHAR8 *)\r
872                                   );\r
873 \r
874       if (InputFileName == NULL) {\r
875         Error (NULL, 0, 4001, "Resource", "memory cannot be allcoated");\r
876         return EFI_OUT_OF_RESOURCES;\r
877       }\r
878 \r
879       memset (&(InputFileName[InputFileNum]), 0, (MAXIMUM_INPUT_FILE_NUM * sizeof (CHAR8 *)));\r
880     }\r
881 \r
882     InputFileName[InputFileNum++] = argv[0];\r
883     argc --;\r
884     argv ++;\r
885   }\r
886 \r
887   if (VerboseMode) {\r
888     fprintf (stdout, "%s tool start.\n", UTILITY_NAME);\r
889   }\r
890   //\r
891   // Parse all command line parameters to get the corresponding section type.\r
892   //\r
893   if (SectionName == NULL) {\r
894     //\r
895     // No specified Section type, default is SECTION_ALL.\r
896     //\r
897     SectType = EFI_SECTION_ALL;\r
898   } else if (stricmp (SectionName, SectionTypeName[EFI_SECTION_COMPRESSION]) == 0) {\r
899     SectType     = EFI_SECTION_COMPRESSION;\r
900     if (CompressionName == NULL) {\r
901       //\r
902       // Default is PI_STD compression algorithm.\r
903       //\r
904       SectCompSubType = EFI_STANDARD_COMPRESSION;\r
905     } else if (stricmp (CompressionName, CompressionTypeName[EFI_NOT_COMPRESSED]) == 0) {\r
906       SectCompSubType = EFI_NOT_COMPRESSED;\r
907     } else if (stricmp (CompressionName, CompressionTypeName[EFI_STANDARD_COMPRESSION]) == 0) {\r
908       SectCompSubType = EFI_STANDARD_COMPRESSION;\r
909     } else {\r
910       Error (NULL, 0, 1003, "Invalid option value", "--compress = %s", CompressionName);\r
911       goto Finish;\r
912     }\r
913   } else if (stricmp (SectionName, SectionTypeName[EFI_SECTION_GUID_DEFINED]) == 0) {\r
914     SectType     = EFI_SECTION_GUID_DEFINED;\r
915 \r
916     if (CompareGuid (&VendorGuid, &gZeroGuid) == 0) {\r
917       memcpy (&VendorGuid, &gEfiCrc32SectionGuid, sizeof (EFI_GUID));\r
918     }\r
919     \r
920     if (SectGuidAttribute == 0) {\r
921       SectGuidAttribute = EFI_GUIDED_SECTION_PROCESSING_REQUIRED;\r
922     }\r
923   } else if (stricmp (SectionName, SectionTypeName[EFI_SECTION_PE32]) == 0) {\r
924     SectType = EFI_SECTION_PE32;\r
925   } else if (stricmp (SectionName, SectionTypeName[EFI_SECTION_PIC]) == 0) {\r
926     SectType = EFI_SECTION_PIC;\r
927   } else if (stricmp (SectionName, SectionTypeName[EFI_SECTION_TE]) == 0) {\r
928     SectType = EFI_SECTION_TE;\r
929   } else if (stricmp (SectionName, SectionTypeName[EFI_SECTION_DXE_DEPEX]) == 0) {\r
930     SectType = EFI_SECTION_DXE_DEPEX;\r
931   } else if (stricmp (SectionName, SectionTypeName[EFI_SECTION_VERSION]) == 0) {\r
932     SectType = EFI_SECTION_VERSION;\r
933     if (VersionNumber < 0 || VersionNumber > 9999) {\r
934       Error (NULL, 0, 1003, "Invalid option value", "%d is not in 0~9999", VersionNumber);\r
935       goto Finish;\r
936     }\r
937   } else if (stricmp (SectionName, SectionTypeName[EFI_SECTION_USER_INTERFACE]) == 0) {\r
938     SectType = EFI_SECTION_USER_INTERFACE;\r
939     if (StringBuffer[0] == '\0') {\r
940       Error (NULL, 0, 1001, "Missing option", "user interface string");\r
941       goto Finish;\r
942     }\r
943   } else if (stricmp (SectionName, SectionTypeName[EFI_SECTION_COMPATIBILITY16]) == 0) {\r
944     SectType = EFI_SECTION_COMPATIBILITY16;\r
945   } else if (stricmp (SectionName, SectionTypeName[EFI_SECTION_FIRMWARE_VOLUME_IMAGE]) == 0) {\r
946     SectType = EFI_SECTION_FIRMWARE_VOLUME_IMAGE;\r
947   } else if (stricmp (SectionName, SectionTypeName[EFI_SECTION_FREEFORM_SUBTYPE_GUID]) == 0) {\r
948     SectType = EFI_SECTION_FREEFORM_SUBTYPE_GUID;\r
949   } else if (stricmp (SectionName, SectionTypeName[EFI_SECTION_RAW]) == 0) {\r
950     SectType = EFI_SECTION_RAW;\r
951   } else if (stricmp (SectionName, SectionTypeName[EFI_SECTION_PEI_DEPEX]) == 0) {\r
952     SectType = EFI_SECTION_PEI_DEPEX;\r
953   } else {\r
954     Error (NULL, 0, 1003, "Invalid option value", "SectionType = %s", SectionName);\r
955     goto Finish;\r
956   }\r
957   \r
958   if ((SectType != EFI_SECTION_VERSION) && (SectType != EFI_SECTION_USER_INTERFACE)) {\r
959     //\r
960     // The input file are required for those section type.\r
961     //\r
962     if (InputFileNum == 0) {\r
963       Error (NULL, 0, 1001, "Missing options", "Input files");\r
964       goto Finish;\r
965     }\r
966   }\r
967   \r
968   //\r
969   // Open output file\r
970   //\r
971   if (OutputFileName == NULL) {\r
972     Error (NULL, 0, 1001, "Missing options", "Output file");\r
973     goto Finish;\r
974     // OutFile = stdout;\r
975   } else {\r
976     OutFile = fopen (OutputFileName, "wb");\r
977   }\r
978 \r
979   if (OutFile == NULL) {\r
980     Error (NULL, 0, 0001, "Error opening file", OutputFileName);\r
981     goto Finish;\r
982   }\r
983   \r
984   //\r
985   // At this point, we've fully validated the command line, and opened appropriate\r
986   // files, so let's go and do what we've been asked to do...\r
987   //\r
988   //\r
989   // Within this switch, build and write out the section header including any\r
990   // section type specific pieces.  If there's an input file, it's tacked on later\r
991   //\r
992   switch (SectType) {\r
993   case EFI_SECTION_COMPRESSION:\r
994     Status = GenSectionCompressionSection (\r
995               InputFileName,\r
996               InputFileNum,\r
997               SectCompSubType,\r
998               OutFile\r
999               );\r
1000     break;\r
1001 \r
1002   case EFI_SECTION_GUID_DEFINED:\r
1003     Status = GenSectionGuidDefinedSection (\r
1004               InputFileName,\r
1005               InputFileNum,\r
1006               &VendorGuid,\r
1007               SectGuidAttribute,\r
1008               OutFile\r
1009               );\r
1010     break;\r
1011 \r
1012   case EFI_SECTION_VERSION:\r
1013     CommonSect.Type = (EFI_SECTION_TYPE) SectType;\r
1014 \r
1015     Index           = sizeof (CommonSect);\r
1016     //\r
1017     // 2 bytes for the build number UINT16\r
1018     //\r
1019     Index += 2;\r
1020     //\r
1021     // StringBuffer is ascii.. unicode is 2X + 2 bytes for terminating unicode null.\r
1022     //\r
1023     Index += (strlen (StringBuffer) * 2) + 2;\r
1024     memcpy (&CommonSect.Size, &Index, 3);\r
1025     fwrite (&CommonSect, sizeof (CommonSect), 1, OutFile);\r
1026     fwrite (&VersionNumber, sizeof (UINT16), 1, OutFile);\r
1027     Ascii2UnicodeWriteString (StringBuffer, OutFile);\r
1028     break;\r
1029 \r
1030   case EFI_SECTION_USER_INTERFACE:\r
1031     CommonSect.Type = (EFI_SECTION_TYPE) SectType;\r
1032     Index           = sizeof (CommonSect);\r
1033     //\r
1034     // StringBuffer is ascii.. unicode is 2X + 2 bytes for terminating unicode null.\r
1035     //\r
1036     Index += (strlen (StringBuffer) * 2) + 2;\r
1037     memcpy (&CommonSect.Size, &Index, 3);\r
1038     fwrite (&CommonSect, sizeof (CommonSect), 1, OutFile);\r
1039     Ascii2UnicodeWriteString (StringBuffer, OutFile);\r
1040     break;\r
1041 \r
1042   case EFI_SECTION_ALL:\r
1043     //\r
1044     // read all input file contents into a buffer\r
1045     // first get the size of all file contents\r
1046     //\r
1047     Status = GetSectionContents (\r
1048               InputFileName,\r
1049               InputFileNum,\r
1050               FileBuffer,\r
1051               &InputLength\r
1052               );\r
1053   \r
1054     if (Status == EFI_BUFFER_TOO_SMALL) {\r
1055       FileBuffer = (UINT8 *) malloc (InputLength);\r
1056       if (FileBuffer == NULL) {\r
1057         Error (NULL, 0, 4001, "Resource", "memory cannot be allcoated");\r
1058         goto Finish;\r
1059       }\r
1060       //\r
1061       // read all input file contents into a buffer\r
1062       //\r
1063       Status = GetSectionContents (\r
1064                 InputFileName,\r
1065                 InputFileNum,\r
1066                 FileBuffer,\r
1067                 &InputLength\r
1068                 );\r
1069     }\r
1070   \r
1071     if (Status == EFI_SUCCESS) {\r
1072       fwrite (FileBuffer, InputLength, 1, OutFile);\r
1073     }\r
1074 \r
1075     if (FileBuffer != NULL) {\r
1076       free (FileBuffer);\r
1077     }\r
1078     \r
1079     break;\r
1080   default:\r
1081     //\r
1082     // All other section types are caught by default (they're all the same)\r
1083     //\r
1084     Status = GenSectionCommonLeafSection (\r
1085               InputFileName,\r
1086               InputFileNum,\r
1087               SectType,\r
1088               OutFile\r
1089               );\r
1090     break;\r
1091   }\r
1092 \r
1093 Finish:\r
1094   if (InputFileName != NULL) {\r
1095     free (InputFileName);\r
1096   }\r
1097 \r
1098   if (OutFile != NULL) {\r
1099     fclose (OutFile);\r
1100   }\r
1101   \r
1102   if (VerboseMode) {\r
1103     fprintf (stdout, "%s tool done with return code is 0x%x.\n", UTILITY_NAME, GetUtilityStatus ());  \r
1104   }\r
1105 \r
1106   return GetUtilityStatus ();\r
1107 }\r