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