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