Add Include directory, Common library and the first prototype GenSec, GenFv, GenFw...
[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", "AUTHENTIC", "BOTH" };\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 -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|AUTHENTIC|BOTH>\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     Crc32Checksum = 0;\r
627     CalculateCrc32 (FileBuffer, InputLength, &Crc32Checksum);\r
628 \r
629     TotalLength = InputLength + sizeof (CRC32_SECTION_HEADER);\r
630     if (TotalLength >= MAX_SECTION_SIZE) {\r
631       Error (__FILE__, __LINE__, 0, "input error", "The size of all files exceeds section size limit(%dM).", MAX_SECTION_SIZE>>20);\r
632       free (FileBuffer);\r
633       return STATUS_ERROR;\r
634     }\r
635 \r
636     Crc32GuidSect.GuidSectionHeader.CommonHeader.Type     = EFI_SECTION_GUID_DEFINED;\r
637     Crc32GuidSect.GuidSectionHeader.CommonHeader.Size[0]  = (UINT8) (TotalLength & 0xff);\r
638     Crc32GuidSect.GuidSectionHeader.CommonHeader.Size[1]  = (UINT8) ((TotalLength & 0xff00) >> 8);\r
639     Crc32GuidSect.GuidSectionHeader.CommonHeader.Size[2]  = (UINT8) ((TotalLength & 0xff0000) >> 16);\r
640     memcpy (&(Crc32GuidSect.GuidSectionHeader.SectionDefinitionGuid), &gEfiCrc32SectionGuid, sizeof (EFI_GUID));\r
641     Crc32GuidSect.GuidSectionHeader.Attributes  = EFI_GUIDED_SECTION_AUTH_STATUS_VALID;\r
642     Crc32GuidSect.GuidSectionHeader.DataOffset  = sizeof (CRC32_SECTION_HEADER);\r
643     Crc32GuidSect.CRC32Checksum                 = Crc32Checksum;\r
644     fwrite (&Crc32GuidSect, sizeof (Crc32GuidSect), 1, OutFile);  \r
645 \r
646   } else {\r
647     TotalLength = InputLength + sizeof (EFI_GUID_DEFINED_SECTION);\r
648     if (TotalLength >= MAX_SECTION_SIZE) {\r
649       Error (__FILE__, __LINE__, 0, "input error", "The size of all files exceeds section size limit(%dM).", MAX_SECTION_SIZE>>20);\r
650       free (FileBuffer);\r
651       return STATUS_ERROR;\r
652     }\r
653 \r
654     VendorGuidSect.CommonHeader.Type     = EFI_SECTION_GUID_DEFINED;\r
655     VendorGuidSect.CommonHeader.Size[0]  = (UINT8) (TotalLength & 0xff);\r
656     VendorGuidSect.CommonHeader.Size[1]  = (UINT8) ((TotalLength & 0xff00) >> 8);\r
657     VendorGuidSect.CommonHeader.Size[2]  = (UINT8) ((TotalLength & 0xff0000) >> 16);\r
658     memcpy (&(VendorGuidSect.SectionDefinitionGuid), VendorGuid, sizeof (EFI_GUID));\r
659     VendorGuidSect.Attributes  = DataAttribute;\r
660     VendorGuidSect.DataOffset  = sizeof (EFI_GUID_DEFINED_SECTION);\r
661     fwrite (&VendorGuidSect, sizeof (EFI_GUID_DEFINED_SECTION), 1, OutFile);  \r
662   }\r
663 \r
664   fwrite (FileBuffer, InputLength, 1, OutFile);\r
665   free (FileBuffer);\r
666 \r
667   return EFI_SUCCESS;\r
668 }\r
669 \r
670 int\r
671 main (\r
672   int  argc,\r
673   char *argv[]\r
674   )\r
675 /*++\r
676 \r
677 Routine Description:\r
678 \r
679   Main\r
680 \r
681 Arguments:\r
682 \r
683   command line parameters\r
684 \r
685 Returns:\r
686 \r
687   EFI_SUCCESS    Section header successfully generated and section concatenated.\r
688   EFI_ABORTED    Could not generate the section\r
689   EFI_OUT_OF_RESOURCES  No resource to complete the operation.\r
690 \r
691 --*/\r
692 {\r
693   UINT32                    Index;\r
694   UINT32                    InputFileNum;\r
695   FILE                      *InFile;\r
696   FILE                      *OutFile;\r
697   CHAR8                     **InputFileName;\r
698   CHAR8                     *OutputFileName;\r
699   CHAR8                     *SectionName;\r
700   CHAR8                     *CompressionName;\r
701   CHAR8                     *VendorGuidDataAttribute;\r
702   CHAR8                     *StringBuffer;\r
703   EFI_GUID                  VendorGuid = gZeroGuid;\r
704   INT32                     VersionNumber;\r
705   UINT8                     SectType;\r
706   UINT8                     SectCompSubType;\r
707   UINT16                    SectGuidAttribute; \r
708   EFI_COMMON_SECTION_HEADER CommonSect;\r
709   UINT32                    InputLength;\r
710   UINT8                     *FileBuffer;\r
711   BOOLEAN                   AllocatedFlag;\r
712   EFI_STATUS                Status;\r
713  \r
714   InputFileName         = NULL;\r
715   OutputFileName        = NULL;\r
716   SectionName           = NULL;\r
717   CompressionName       = NULL;\r
718   VendorGuidDataAttribute = NULL;\r
719   StringBuffer          = "";\r
720 \r
721   InFile                = NULL;\r
722   OutFile               = NULL;\r
723   VersionNumber         = 0;\r
724   InputFileNum          = 0;\r
725   SectType              = EFI_SECTION_ALL;\r
726   SectCompSubType       = 0;\r
727   SectGuidAttribute     = 0;\r
728   FileBuffer            = NULL;\r
729   InputLength           = 0;\r
730   AllocatedFlag         = FALSE;\r
731   Status                = STATUS_SUCCESS;\r
732   \r
733 \r
734   SetUtilityName (UTILITY_NAME);\r
735   \r
736   if (argc == 1) {\r
737     Usage ();\r
738     return STATUS_ERROR;\r
739   }\r
740 \r
741   //\r
742   // Parse command line\r
743   //\r
744   argc --;\r
745   argv ++;\r
746 \r
747   if ((stricmp (argv[0], "-h") == 0) || (stricmp (argv[0], "--help") == 0)) {\r
748     Usage();\r
749     return STATUS_ERROR;    \r
750   }\r
751 \r
752   if ((stricmp (argv[0], "-v") == 0) || (stricmp (argv[0], "--version") == 0)) {\r
753     Version();\r
754     return STATUS_ERROR;    \r
755   }\r
756 \r
757   while (argc > 0) {\r
758     if ((stricmp (argv[0], "-s") == 0) || (stricmp (argv[0], "--SectionType") == 0)) {\r
759       SectionName = argv[1];\r
760       argc -= 2;\r
761       argv += 2;\r
762       continue; \r
763     }\r
764 \r
765     if ((stricmp (argv[0], "-o") == 0) || (stricmp (argv[0], "--outputfile") == 0)) {\r
766       OutputFileName = argv[1];\r
767       argc -= 2;\r
768       argv += 2;\r
769       continue; \r
770     }\r
771 \r
772     if ((stricmp (argv[0], "-c") == 0) || (stricmp (argv[0], "--compress") == 0)) {\r
773       CompressionName = argv[1];\r
774       argc -= 2;\r
775       argv += 2;\r
776       continue;\r
777     }\r
778 \r
779     if ((stricmp (argv[0], "-g") == 0) || (stricmp (argv[0], "--vendorguid") == 0)) {\r
780       StringToGuid (argv[1], &VendorGuid);\r
781       argc -= 2;\r
782       argv += 2;\r
783       continue;\r
784     }\r
785 \r
786     if ((stricmp (argv[0], "-r") == 0) || (stricmp (argv[0], "--attribute") == 0)) {\r
787       VendorGuidDataAttribute = argv[1];\r
788       argc -= 2;\r
789       argv += 2;\r
790       continue;\r
791     }\r
792 \r
793     if ((stricmp (argv[0], "-n") == 0) || (stricmp (argv[0], "--name") == 0)) {\r
794       StringBuffer = argv[1];\r
795       argc -= 2;\r
796       argv += 2;\r
797       continue;\r
798     }\r
799 \r
800     if ((stricmp (argv[0], "-j") == 0) || (stricmp (argv[0], "--buildnumber") == 0)) {\r
801       //\r
802       // Verify string is a integrator number\r
803       //\r
804       for (Index = 0; Index < strlen (argv[1]); Index++) {\r
805         if ((argv[1][Index] != '-') && (isdigit (argv[1][Index]) == 0)) {\r
806           Error (NULL, 0, 0, NULL, "ERROR: %s is not a valid integer.", argv[1]);\r
807           Status = EFI_ABORTED;\r
808           goto Finish;\r
809         }\r
810       }\r
811 \r
812       sscanf (argv[1], "%d", &VersionNumber);\r
813       argc -= 2;\r
814       argv += 2;\r
815       continue;\r
816     }\r
817     \r
818     //\r
819     // Get Input file name\r
820     //\r
821     if ((InputFileNum == 0) && (InputFileName == NULL)) {\r
822       InputFileName = (CHAR8 **) malloc (MAXIMUM_INPUT_FILE_NUM * sizeof (CHAR8 *));\r
823       if (InputFileName == NULL) {\r
824         Error (__FILE__, __LINE__, 0, "application error", "failed to allocate memory");\r
825         return EFI_OUT_OF_RESOURCES;\r
826       }\r
827 \r
828       memset (InputFileName, 0, (MAXIMUM_INPUT_FILE_NUM * sizeof (CHAR8 *)));\r
829     } else if (InputFileNum % MAXIMUM_INPUT_FILE_NUM == 0) {\r
830       //\r
831       // InputFileName buffer too small, need to realloc\r
832       //\r
833       InputFileName = (CHAR8 **) realloc (\r
834                                   InputFileName,\r
835                                   (InputFileNum + MAXIMUM_INPUT_FILE_NUM) * sizeof (CHAR8 *)\r
836                                   );\r
837 \r
838       if (InputFileName == NULL) {\r
839         Error (__FILE__, __LINE__, 0, "application error", "failed to allocate memory");\r
840         return EFI_OUT_OF_RESOURCES;\r
841       }\r
842 \r
843       memset (&(InputFileName[InputFileNum]), 0, (MAXIMUM_INPUT_FILE_NUM * sizeof (CHAR8 *)));\r
844     }\r
845 \r
846     InputFileName[InputFileNum++] = argv[0];\r
847     argc --;\r
848     argv ++;\r
849   }\r
850 \r
851   //\r
852   // Parse all command line parameters to get the corresponding section type.\r
853   //\r
854   if (SectionName == NULL) {\r
855     //\r
856     // No specified Section type, default is SECTION_ALL.\r
857     //\r
858     SectType = EFI_SECTION_ALL;\r
859   } else if (stricmp (SectionName, SectionTypeName[EFI_SECTION_COMPRESSION]) == 0) {\r
860     SectType     = EFI_SECTION_COMPRESSION;\r
861     if (CompressionName == NULL) {\r
862       //\r
863       // Default is PI_STD compression algorithm.\r
864       //\r
865       SectCompSubType = EFI_STANDARD_COMPRESSION;\r
866     } else if (stricmp (CompressionName, CompressionTypeName[EFI_NOT_COMPRESSED]) == 0) {\r
867       SectCompSubType = EFI_NOT_COMPRESSED;\r
868     } else if (stricmp (CompressionName, CompressionTypeName[EFI_STANDARD_COMPRESSION]) == 0) {\r
869       SectCompSubType = EFI_STANDARD_COMPRESSION;\r
870     } else {\r
871       Error (NULL, 0, 0, CompressionName, "unknown compression type");\r
872       Usage ();\r
873       goto Finish;\r
874     }\r
875   } else if (stricmp (SectionName, SectionTypeName[EFI_SECTION_GUID_DEFINED]) == 0) {\r
876     SectType     = EFI_SECTION_GUID_DEFINED;\r
877 \r
878     if (CompareGuid (&VendorGuid, &gZeroGuid) == 0) {\r
879       memcpy (&VendorGuid, &gEfiCrc32SectionGuid, sizeof (EFI_GUID));\r
880     }\r
881 \r
882     if ((VendorGuidDataAttribute == NULL) || \\r
883         ((stricmp (VendorGuidDataAttribute, GUIDedSectionAttribue[EFI_GUIDED_SECTION_PROCESSING_REQUIRED]) == 0))) {\r
884       SectGuidAttribute = EFI_GUIDED_SECTION_PROCESSING_REQUIRED;\r
885     } else if (stricmp (VendorGuidDataAttribute, GUIDedSectionAttribue[EFI_GUIDED_SECTION_AUTH_STATUS_VALID]) == 0) {\r
886       SectGuidAttribute = EFI_GUIDED_SECTION_AUTH_STATUS_VALID;\r
887     } else if (stricmp (VendorGuidDataAttribute, GUIDedSectionAttribue[EFI_GUIDED_SECTION_PROCESSING_REQUIRED|EFI_GUIDED_SECTION_AUTH_STATUS_VALID]) == 0) {\r
888       SectGuidAttribute = EFI_GUIDED_SECTION_PROCESSING_REQUIRED | EFI_GUIDED_SECTION_AUTH_STATUS_VALID;\r
889     } else {\r
890       Error (NULL, 0, 0, VendorGuidDataAttribute, "unknown Guid Section Attribute");\r
891       Usage ();\r
892       goto Finish;\r
893     }\r
894 \r
895   } else if (stricmp (SectionName, SectionTypeName[EFI_SECTION_PE32]) == 0) {\r
896     SectType = EFI_SECTION_PE32;\r
897   } else if (stricmp (SectionName, SectionTypeName[EFI_SECTION_PIC]) == 0) {\r
898     SectType = EFI_SECTION_PIC;\r
899   } else if (stricmp (SectionName, SectionTypeName[EFI_SECTION_TE]) == 0) {\r
900     SectType = EFI_SECTION_TE;\r
901   } else if (stricmp (SectionName, SectionTypeName[EFI_SECTION_DXE_DEPEX]) == 0) {\r
902     SectType = EFI_SECTION_DXE_DEPEX;\r
903   } else if (stricmp (SectionName, SectionTypeName[EFI_SECTION_VERSION]) == 0) {\r
904     SectType = EFI_SECTION_VERSION;\r
905     if (VersionNumber < 0 || VersionNumber > 9999) {\r
906       Error (NULL, 0, 0, NULL, "%d is illegal version number\n", VersionNumber);\r
907       Usage ();\r
908       goto Finish;\r
909     }\r
910   } else if (stricmp (SectionName, SectionTypeName[EFI_SECTION_USER_INTERFACE]) == 0) {\r
911     SectType = EFI_SECTION_USER_INTERFACE;\r
912     if (StringBuffer[0] == '\0') {\r
913       Error (NULL, 0, 0, "user interface string not specified", NULL);\r
914       Usage ();\r
915       goto Finish;\r
916     }\r
917   } else if (stricmp (SectionName, SectionTypeName[EFI_SECTION_COMPATIBILITY16]) == 0) {\r
918     SectType = EFI_SECTION_COMPATIBILITY16;\r
919   } else if (stricmp (SectionName, SectionTypeName[EFI_SECTION_FIRMWARE_VOLUME_IMAGE]) == 0) {\r
920     SectType = EFI_SECTION_FIRMWARE_VOLUME_IMAGE;\r
921   } else if (stricmp (SectionName, SectionTypeName[EFI_SECTION_FREEFORM_SUBTYPE_GUID]) == 0) {\r
922     SectType = EFI_SECTION_FREEFORM_SUBTYPE_GUID;\r
923   } else if (stricmp (SectionName, SectionTypeName[EFI_SECTION_RAW]) == 0) {\r
924     SectType = EFI_SECTION_RAW;\r
925   } else if (stricmp (SectionName, SectionTypeName[EFI_SECTION_PEI_DEPEX]) == 0) {\r
926     SectType = EFI_SECTION_PEI_DEPEX;\r
927   } else {\r
928     Error (NULL, 0, 0, SectionName, "unknown section type");\r
929     Usage ();\r
930     goto Finish;\r
931   }\r
932   \r
933   if ((SectType != EFI_SECTION_VERSION) && (SectType != EFI_SECTION_USER_INTERFACE)) {\r
934     //\r
935     // The input file are required for those section type.\r
936     // The file are from stdin.\r
937     //\r
938     if (InputFileNum == 0) {\r
939 \r
940       AllocatedFlag = TRUE;\r
941 \r
942       //\r
943       // Init InputFileName pointer list\r
944       //\r
945       InputFileName = (CHAR8 **) malloc (MAXIMUM_INPUT_FILE_NUM * sizeof (CHAR8 *));\r
946       if (InputFileName == NULL) {\r
947         Error (__FILE__, __LINE__, 0, "application error", "failed to allocate memory");\r
948         return EFI_OUT_OF_RESOURCES;\r
949       }\r
950       memset (InputFileName, 0, (MAXIMUM_INPUT_FILE_NUM * sizeof (CHAR8 *)));\r
951 \r
952       do {\r
953         if ((InputFileNum != 0) && (InputFileNum % MAXIMUM_INPUT_FILE_NUM == 0)) {\r
954           //\r
955           // InputFileName buffer too small, need to realloc\r
956           //\r
957           InputFileName = (CHAR8 **) realloc (\r
958                                       InputFileName,\r
959                                       (InputFileNum + MAXIMUM_INPUT_FILE_NUM) * sizeof (CHAR8 *)\r
960                                       );\r
961     \r
962           if (InputFileName == NULL) {\r
963             for (Index = 0; Index < InputFileNum; Index ++) {\r
964               free (InputFileName [InputFileNum]);\r
965             }\r
966             Error (__FILE__, __LINE__, 0, "application error", "failed to allocate memory");\r
967             return EFI_OUT_OF_RESOURCES;\r
968           }\r
969           memset (&(InputFileName[InputFileNum]), 0, (MAXIMUM_INPUT_FILE_NUM * sizeof (CHAR8 *)));\r
970         }\r
971 \r
972         InputFileName [InputFileNum] = (CHAR8 *) malloc (_MAX_PATH); \r
973         if (InputFileName == NULL) {\r
974           Error (__FILE__, __LINE__, 0, "application error", "failed to allocate memory");\r
975           for (Index = 0; Index < InputFileNum; Index ++) {\r
976             free (InputFileName [InputFileNum]);\r
977           }\r
978           free (InputFileName);\r
979           return EFI_OUT_OF_RESOURCES;\r
980         }\r
981       } while (fscanf (stdin, "%s", InputFileName[InputFileNum++]) != EOF);\r
982       //\r
983       // Free the last memory space because it doesn't have data.\r
984       //\r
985       InputFileNum --;\r
986       free (InputFileName[InputFileNum]);\r
987     }\r
988   }\r
989   \r
990   //\r
991   // Open output file\r
992   //\r
993   if (OutputFileName == NULL) {\r
994     OutFile = stdout;\r
995   } else {\r
996     OutFile = fopen (OutputFileName, "wb");\r
997   }\r
998 \r
999   if (OutFile == NULL) {\r
1000     Error (NULL, 0, 0, OutputFileName, "failed to open output file for writing");\r
1001     goto Finish;\r
1002   }\r
1003   \r
1004   //\r
1005   // At this point, we've fully validated the command line, and opened appropriate\r
1006   // files, so let's go and do what we've been asked to do...\r
1007   //\r
1008   //\r
1009   // Within this switch, build and write out the section header including any\r
1010   // section type specific pieces.  If there's an input file, it's tacked on later\r
1011   //\r
1012   switch (SectType) {\r
1013   case EFI_SECTION_COMPRESSION:\r
1014     Status = GenSectionCompressionSection (\r
1015               InputFileName,\r
1016               InputFileNum,\r
1017               SectCompSubType,\r
1018               OutFile\r
1019               );\r
1020     break;\r
1021 \r
1022   case EFI_SECTION_GUID_DEFINED:\r
1023     Status = GenSectionGuidDefinedSection (\r
1024               InputFileName,\r
1025               InputFileNum,\r
1026               &VendorGuid,\r
1027               SectGuidAttribute,\r
1028               OutFile\r
1029               );\r
1030     break;\r
1031 \r
1032   case EFI_SECTION_VERSION:\r
1033     CommonSect.Type = (EFI_SECTION_TYPE) SectType;\r
1034 \r
1035     Index           = sizeof (CommonSect);\r
1036     //\r
1037     // 2 bytes for the build number UINT16\r
1038     //\r
1039     Index += 2;\r
1040     //\r
1041     // StringBuffer is ascii.. unicode is 2X + 2 bytes for terminating unicode null.\r
1042     //\r
1043     Index += (strlen (StringBuffer) * 2) + 2;\r
1044     memcpy (&CommonSect.Size, &Index, 3);\r
1045     fwrite (&CommonSect, sizeof (CommonSect), 1, OutFile);\r
1046     fwrite (&VersionNumber, sizeof (UINT16), 1, OutFile);\r
1047     Ascii2UnicodeWriteString (StringBuffer, OutFile);\r
1048     break;\r
1049 \r
1050   case EFI_SECTION_USER_INTERFACE:\r
1051     CommonSect.Type = (EFI_SECTION_TYPE) SectType;\r
1052     Index           = sizeof (CommonSect);\r
1053     //\r
1054     // StringBuffer is ascii.. unicode is 2X + 2 bytes for terminating unicode null.\r
1055     //\r
1056     Index += (strlen (StringBuffer) * 2) + 2;\r
1057     memcpy (&CommonSect.Size, &Index, 3);\r
1058     fwrite (&CommonSect, sizeof (CommonSect), 1, OutFile);\r
1059     Ascii2UnicodeWriteString (StringBuffer, OutFile);\r
1060     break;\r
1061 \r
1062   case EFI_SECTION_ALL:\r
1063     //\r
1064     // read all input file contents into a buffer\r
1065     // first get the size of all file contents\r
1066     //\r
1067     Status = GetSectionContents (\r
1068               InputFileName,\r
1069               InputFileNum,\r
1070               FileBuffer,\r
1071               &InputLength\r
1072               );\r
1073   \r
1074     if (Status == EFI_BUFFER_TOO_SMALL) {\r
1075       FileBuffer = (UINT8 *) malloc (InputLength);\r
1076       if (FileBuffer == NULL) {\r
1077         Error (__FILE__, __LINE__, 0, "application error", "failed to allocate memory");\r
1078         goto Finish;\r
1079       }\r
1080       //\r
1081       // read all input file contents into a buffer\r
1082       //\r
1083       Status = GetSectionContents (\r
1084                 InputFileName,\r
1085                 InputFileNum,\r
1086                 FileBuffer,\r
1087                 &InputLength\r
1088                 );\r
1089     }\r
1090   \r
1091     if (Status == EFI_SUCCESS) {\r
1092       fwrite (FileBuffer, InputLength, 1, OutFile);\r
1093     }\r
1094 \r
1095     if (FileBuffer != NULL) {\r
1096       free (FileBuffer);\r
1097     }\r
1098     \r
1099     break;\r
1100   default:\r
1101     //\r
1102     // All other section types are caught by default (they're all the same)\r
1103     //\r
1104     Status = GenSectionCommonLeafSection (\r
1105               InputFileName,\r
1106               InputFileNum,\r
1107               SectType,\r
1108               OutFile\r
1109               );\r
1110     break;\r
1111   }\r
1112 \r
1113 Finish:\r
1114   if (AllocatedFlag == TRUE) {\r
1115     for (Index = 0; Index < InputFileNum; Index ++) {\r
1116       free (InputFileName[Index]);\r
1117     }\r
1118   }\r
1119 \r
1120   if (InputFileName != NULL) {\r
1121     free (InputFileName);\r
1122   }\r
1123 \r
1124   if (OutFile != NULL) {\r
1125     fclose (OutFile);\r
1126     //\r
1127     // If we had errors, then delete the output file\r
1128     //\r
1129     if (GetUtilityStatus () == STATUS_ERROR) {\r
1130       remove (OutputFileName);\r
1131     }\r
1132   }\r
1133 \r
1134   return GetUtilityStatus ();\r
1135 }\r