Sync basetools' source and binary files with r1707 of the basetools project.
[edk2.git] / BaseTools / Source / C / GenSec / GenSec.c
blob32b8cfd5a0c5ad40cba785abf648a8828180025b
1 /** @file
3 Copyright (c) 2004 - 2008, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12 Module Name:
14 GenSection.c
16 Abstract:
18 Creates output file that is a properly formed section per the PI spec.
20 **/
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <ctype.h>
27 #include <Common/UefiBaseTypes.h>
28 #include <Common/PiFirmwareFile.h>
29 #include <Protocol/GuidedSectionExtraction.h>
31 #include "CommonLib.h"
32 #include "Compress.h"
33 #include "Crc32.h"
34 #include "EfiUtilityMsgs.h"
35 #include "ParseInf.h"
38 // GenSec Tool Information
40 #define UTILITY_NAME "GenSec"
41 #define UTILITY_MAJOR_VERSION 0
42 #define UTILITY_MINOR_VERSION 1
44 #define MAX_SECTION_SIZE 0x1000000
46 STATIC CHAR8 *mSectionTypeName[] = {
47 NULL, // 0x00 - reserved
48 "EFI_SECTION_COMPRESSION", // 0x01
49 "EFI_SECTION_GUID_DEFINED", // 0x02
50 NULL, // 0x03 - reserved
51 NULL, // 0x04 - reserved
52 NULL, // 0x05 - reserved
53 NULL, // 0x06 - reserved
54 NULL, // 0x07 - reserved
55 NULL, // 0x08 - reserved
56 NULL, // 0x09 - reserved
57 NULL, // 0x0A - reserved
58 NULL, // 0x0B - reserved
59 NULL, // 0x0C - reserved
60 NULL, // 0x0D - reserved
61 NULL, // 0x0E - reserved
62 NULL, // 0x0F - reserved
63 "EFI_SECTION_PE32", // 0x10
64 "EFI_SECTION_PIC", // 0x11
65 "EFI_SECTION_TE", // 0x12
66 "EFI_SECTION_DXE_DEPEX", // 0x13
67 "EFI_SECTION_VERSION", // 0x14
68 "EFI_SECTION_USER_INTERFACE", // 0x15
69 "EFI_SECTION_COMPATIBILITY16", // 0x16
70 "EFI_SECTION_FIRMWARE_VOLUME_IMAGE", // 0x17
71 "EFI_SECTION_FREEFORM_SUBTYPE_GUID", // 0x18
72 "EFI_SECTION_RAW", // 0x19
73 NULL, // 0x1A
74 "EFI_SECTION_PEI_DEPEX", // 0x1B
75 "EFI_SECTION_SMM_DEPEX" // 0x1C
78 STATIC CHAR8 *mCompressionTypeName[] = { "PI_NONE", "PI_STD" };
80 #define EFI_GUIDED_SECTION_NONE 0x80
81 STATIC CHAR8 *mGUIDedSectionAttribue[] = { "NONE", "PROCESSING_REQUIRED", "AUTH_STATUS_VALID"};
84 // Crc32 GUID section related definitions.
86 typedef struct {
87 EFI_GUID_DEFINED_SECTION GuidSectionHeader;
88 UINT32 CRC32Checksum;
89 } CRC32_SECTION_HEADER;
91 STATIC EFI_GUID mZeroGuid = {0x0, 0x0, 0x0, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}};
92 STATIC EFI_GUID mEfiCrc32SectionGuid = EFI_CRC32_GUIDED_SECTION_EXTRACTION_PROTOCOL_GUID;
94 STATIC
95 VOID
96 Version (
97 VOID
99 /*++
101 Routine Description:
103 Print out version information for this utility.
105 Arguments:
107 None
109 Returns:
111 None
113 --*/
115 fprintf (stdout, "%s Version %d.%d\n", UTILITY_NAME, UTILITY_MAJOR_VERSION, UTILITY_MINOR_VERSION);
118 STATIC
119 VOID
120 Usage (
121 VOID
123 /*++
125 Routine Description:
127 Print Help message.
129 Arguments:
131 VOID
133 Returns:
135 None
137 --*/
140 // Summary usage
142 fprintf (stdout, "\nUsage: %s [options] [input_file]\n\n", UTILITY_NAME);
145 // Copyright declaration
147 fprintf (stdout, "Copyright (c) 2007, Intel Corporation. All rights reserved.\n\n");
150 // Details Option
152 fprintf (stdout, "Options:\n");
153 fprintf (stdout, " -o FileName, --outputfile FileName\n\
154 File is the SectionFile to be created.\n");
155 fprintf (stdout, " -s [SectionType], --sectiontype [SectionType]\n\
156 SectionType defined in PI spec is one type of\n\
157 EFI_SECTION_COMPRESSION, EFI_SECTION_GUID_DEFINED,\n\
158 EFI_SECTION_PE32, EFI_SECTION_PIC, EFI_SECTION_TE,\n\
159 EFI_SECTION_DXE_DEPEX, EFI_SECTION_COMPATIBILITY16,\n\
160 EFI_SECTION_USER_INTERFACE, EFI_SECTION_VERSION,\n\
161 EFI_SECTION_FIRMWARE_VOLUME_IMAGE, EFI_SECTION_RAW,\n\
162 EFI_SECTION_FREEFORM_SUBTYPE_GUID,\n\
163 EFI_SECTION_PEI_DEPEX, EFI_SECTION_SMM_DEPEX.\n\
164 if -s option is not given, \n\
165 EFI_SECTION_ALL is default section type.\n");
166 fprintf (stdout, " -c [Type], --compress [Type]\n\
167 Compress method type can be PI_NONE or PI_STD.\n\
168 if -c option is not given, PI_STD is default type.\n");
169 fprintf (stdout, " -g GuidValue, --vendor GuidValue\n\
170 GuidValue is one specific vendor guid value.\n\
171 Its format is xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\n");
172 fprintf (stdout, " -l GuidHeaderLength, --HeaderLength GuidHeaderLength\n\
173 GuidHeaderLength is the size of header of guided data\n");
174 fprintf (stdout, " -r GuidAttr, --attributes GuidAttr\n\
175 GuidAttr is guid section atttributes, which may be\n\
176 PROCESSING_REQUIRED, AUTH_STATUS_VALID and NONE. \n\
177 if -r option is not given, default PROCESSING_REQUIRED\n");
178 fprintf (stdout, " -n String, --name String\n\
179 String is a NULL terminated string used in Ui section.\n");
180 fprintf (stdout, " -j Number, --buildnumber Number\n\
181 Number is an integer value between 0000 and 9999\n\
182 used in Ver section.\n");
183 fprintf (stdout, " -v, --verbose Turn on verbose output with informational messages.\n");
184 fprintf (stdout, " -q, --quiet Disable all messages except key message and fatal error\n");
185 fprintf (stdout, " -d, --debug level Enable debug messages, at input debug level.\n");
186 fprintf (stdout, " --version Show program's version number and exit.\n");
187 fprintf (stdout, " -h, --help Show this help message and exit.\n");
190 VOID
191 Ascii2UnicodeString (
192 CHAR8 *String,
193 CHAR16 *UniString
195 /*++
197 Routine Description:
199 Write ascii string as unicode string format to FILE
201 Arguments:
203 String - Pointer to string that is written to FILE.
204 UniString - Pointer to unicode string
206 Returns:
208 NULL
210 --*/
212 while (*String != '\0') {
213 *(UniString++) = (CHAR16) *(String++);
216 // End the UniString with a NULL.
218 *UniString = '\0';
221 STATUS
222 GenSectionCommonLeafSection (
223 CHAR8 **InputFileName,
224 UINT32 InputFileNum,
225 UINT8 SectionType,
226 UINT8 **OutFileBuffer
228 /*++
230 Routine Description:
232 Generate a leaf section of type other than EFI_SECTION_VERSION
233 and EFI_SECTION_USER_INTERFACE. Input file must be well formed.
234 The function won't validate the input file's contents. For
235 common leaf sections, the input file may be a binary file.
236 The utility will add section header to the file.
238 Arguments:
240 InputFileName - Name of the input file.
242 InputFileNum - Number of input files. Should be 1 for leaf section.
244 SectionType - A valid section type string
246 OutFileBuffer - Buffer pointer to Output file contents
248 Returns:
250 STATUS_ERROR - can't continue
251 STATUS_SUCCESS - successful return
253 --*/
255 UINT32 InputFileLength;
256 FILE *InFile;
257 UINT8 *Buffer;
258 UINT32 TotalLength;
259 EFI_COMMON_SECTION_HEADER *CommonSect;
260 STATUS Status;
262 if (InputFileNum > 1) {
263 Error (NULL, 0, 2000, "Invalid paramter", "more than one input file specified");
264 return STATUS_ERROR;
265 } else if (InputFileNum < 1) {
266 Error (NULL, 0, 2000, "Invalid paramter", "no input file specified");
267 return STATUS_ERROR;
270 // Open the input file
272 InFile = fopen (InputFileName[0], "rb");
273 if (InFile == NULL) {
274 Error (NULL, 0, 0001, "Error opening file", InputFileName[0]);
275 return STATUS_ERROR;
278 Status = STATUS_ERROR;
279 Buffer = NULL;
281 // Seek to the end of the input file so we can determine its size
283 fseek (InFile, 0, SEEK_END);
284 InputFileLength = ftell (InFile);
285 fseek (InFile, 0, SEEK_SET);
286 DebugMsg (NULL, 0, 9, "Input file", "File name is %s and File size is %u bytes", InputFileName[0], (unsigned) InputFileLength);
287 TotalLength = sizeof (EFI_COMMON_SECTION_HEADER) + InputFileLength;
289 // Size must fit in 3 bytes
291 if (TotalLength >= MAX_SECTION_SIZE) {
292 Error (NULL, 0, 2000, "Invalid paramter", "%s file size (0x%X) exceeds section size limit(%uM).", InputFileName[0], (unsigned) TotalLength, MAX_SECTION_SIZE>>20);
293 goto Done;
295 VerboseMsg ("the size of the created section file is %u bytes", (unsigned) TotalLength);
297 // Fill in the fields in the local section header structure
299 Buffer = (UINT8 *) malloc ((size_t) TotalLength);
300 if (Buffer == NULL) {
301 Error (NULL, 0, 4001, "Resource", "memory cannot be allcoated");
302 goto Done;
304 CommonSect = (EFI_COMMON_SECTION_HEADER *) Buffer;
305 CommonSect->Type = SectionType;
306 CommonSect->Size[0] = (UINT8) (TotalLength & 0xff);
307 CommonSect->Size[1] = (UINT8) ((TotalLength & 0xff00) >> 8);
308 CommonSect->Size[2] = (UINT8) ((TotalLength & 0xff0000) >> 16);
311 // read data from the input file.
313 if (InputFileLength != 0) {
314 if (fread (Buffer + sizeof (EFI_COMMON_SECTION_HEADER), (size_t) InputFileLength, 1, InFile) != 1) {
315 Error (NULL, 0, 0004, "Error reading file", InputFileName[0]);
316 goto Done;
321 // Set OutFileBuffer
323 *OutFileBuffer = Buffer;
324 Status = STATUS_SUCCESS;
326 Done:
327 fclose (InFile);
329 return Status;
332 EFI_STATUS
333 GetSectionContents (
334 CHAR8 **InputFileName,
335 UINT32 InputFileNum,
336 UINT8 *FileBuffer,
337 UINT32 *BufferLength
339 /*++
341 Routine Description:
343 Get the contents of all section files specified in InputFileName
344 into FileBuffer.
346 Arguments:
348 InputFileName - Name of the input file.
350 InputFileNum - Number of input files. Should be at least 1.
352 FileBuffer - Output buffer to contain data
354 BufferLength - On input, this is size of the FileBuffer.
355 On output, this is the actual length of the data.
357 Returns:
359 EFI_SUCCESS on successful return
360 EFI_INVALID_PARAMETER if InputFileNum is less than 1 or BufferLength point is NULL.
361 EFI_ABORTED if unable to open input file.
362 EFI_BUFFER_TOO_SMALL FileBuffer is not enough to contain all file data.
363 --*/
365 UINT32 Size;
366 UINT32 FileSize;
367 UINT32 Index;
368 FILE *InFile;
370 if (InputFileNum < 1) {
371 Error (NULL, 0, 2000, "Invalid paramter", "must specify at least one input file");
372 return EFI_INVALID_PARAMETER;
375 if (BufferLength == NULL) {
376 Error (NULL, 0, 2000, "Invalid paramter", "BufferLength can't be NULL");
377 return EFI_INVALID_PARAMETER;
380 Size = 0;
382 // Go through our array of file names and copy their contents
383 // to the output buffer.
385 for (Index = 0; Index < InputFileNum; Index++) {
387 // make sure section ends on a DWORD boundary
389 while ((Size & 0x03) != 0) {
390 if (FileBuffer != NULL && Size < *BufferLength) {
391 FileBuffer[Size] = 0;
393 Size++;
397 // Open file and read contents
399 InFile = fopen (InputFileName[Index], "rb");
400 if (InFile == NULL) {
401 Error (NULL, 0, 0001, "Error opening file", InputFileName[Index]);
402 return EFI_ABORTED;
405 fseek (InFile, 0, SEEK_END);
406 FileSize = ftell (InFile);
407 fseek (InFile, 0, SEEK_SET);
408 DebugMsg (NULL, 0, 9, "Input files", "the input file name is %s and the size is %u bytes", InputFileName[Index], (unsigned) FileSize);
410 // Now read the contents of the file into the buffer
411 // Buffer must be enough to contain the file content.
413 if (FileSize > 0 && FileBuffer != NULL && (Size + FileSize) <= *BufferLength) {
414 if (fread (FileBuffer + Size, (size_t) FileSize, 1, InFile) != 1) {
415 Error (NULL, 0, 0004, "Error reading file", InputFileName[Index]);
416 fclose (InFile);
417 return EFI_ABORTED;
421 fclose (InFile);
422 Size += FileSize;
426 // Set the real required buffer size.
428 if (Size > *BufferLength) {
429 *BufferLength = Size;
430 return EFI_BUFFER_TOO_SMALL;
431 } else {
432 *BufferLength = Size;
433 return EFI_SUCCESS;
437 EFI_STATUS
438 GenSectionCompressionSection (
439 CHAR8 **InputFileName,
440 UINT32 InputFileNum,
441 UINT8 SectCompSubType,
442 UINT8 **OutFileBuffer
444 /*++
446 Routine Description:
448 Generate an encapsulating section of type EFI_SECTION_COMPRESSION
449 Input file must be already sectioned. The function won't validate
450 the input files' contents. Caller should hand in files already
451 with section header.
453 Arguments:
455 InputFileName - Name of the input file.
457 InputFileNum - Number of input files. Should be at least 1.
459 SectCompSubType - Specify the compression algorithm requested.
461 OutFileBuffer - Buffer pointer to Output file contents
463 Returns:
465 EFI_SUCCESS on successful return
466 EFI_INVALID_PARAMETER if InputFileNum is less than 1
467 EFI_ABORTED if unable to open input file.
468 EFI_OUT_OF_RESOURCES No resource to complete the operation.
469 --*/
471 UINT32 TotalLength;
472 UINT32 InputLength;
473 UINT32 CompressedLength;
474 UINT8 *FileBuffer;
475 UINT8 *OutputBuffer;
476 EFI_STATUS Status;
477 EFI_COMPRESSION_SECTION *CompressionSect;
478 COMPRESS_FUNCTION CompressFunction;
480 InputLength = 0;
481 FileBuffer = NULL;
482 OutputBuffer = NULL;
483 CompressedLength = 0;
485 // read all input file contents into a buffer
486 // first get the size of all file contents
488 Status = GetSectionContents (
489 InputFileName,
490 InputFileNum,
491 FileBuffer,
492 &InputLength
495 if (Status == EFI_BUFFER_TOO_SMALL) {
496 FileBuffer = (UINT8 *) malloc (InputLength);
497 if (FileBuffer == NULL) {
498 Error (NULL, 0, 4001, "Resource", "memory cannot be allcoated");
499 return EFI_OUT_OF_RESOURCES;
502 // read all input file contents into a buffer
504 Status = GetSectionContents (
505 InputFileName,
506 InputFileNum,
507 FileBuffer,
508 &InputLength
512 if (EFI_ERROR (Status)) {
513 if (FileBuffer != NULL) {
514 free (FileBuffer);
516 return Status;
519 CompressFunction = NULL;
522 // Now data is in FileBuffer, compress the data
524 switch (SectCompSubType) {
525 case EFI_NOT_COMPRESSED:
526 CompressedLength = InputLength;
527 break;
529 case EFI_STANDARD_COMPRESSION:
530 CompressFunction = (COMPRESS_FUNCTION) EfiCompress;
531 break;
533 default:
534 Error (NULL, 0, 2000, "Invalid paramter", "unknown compression type");
535 free (FileBuffer);
536 return EFI_ABORTED;
539 if (CompressFunction != NULL) {
541 Status = CompressFunction (FileBuffer, InputLength, OutputBuffer, &CompressedLength);
542 if (Status == EFI_BUFFER_TOO_SMALL) {
543 OutputBuffer = malloc (CompressedLength + sizeof (EFI_COMPRESSION_SECTION));
544 if (!OutputBuffer) {
545 free (FileBuffer);
546 return EFI_OUT_OF_RESOURCES;
549 Status = CompressFunction (FileBuffer, InputLength, OutputBuffer + sizeof (EFI_COMPRESSION_SECTION), &CompressedLength);
552 free (FileBuffer);
553 FileBuffer = OutputBuffer;
555 if (EFI_ERROR (Status)) {
556 if (FileBuffer != NULL) {
557 free (FileBuffer);
560 return Status;
564 DebugMsg (NULL, 0, 9, "comprss file size",
565 "the original section size is %d bytes and the compressed section size is %u bytes", (unsigned) InputLength, (unsigned) CompressedLength);
566 TotalLength = CompressedLength + sizeof (EFI_COMPRESSION_SECTION);
567 if (TotalLength >= MAX_SECTION_SIZE) {
568 Error (NULL, 0, 2000, "Invalid paramter", "The size of all files exceeds section size limit(%uM).", MAX_SECTION_SIZE>>20);
569 if (FileBuffer != NULL) {
570 free (FileBuffer);
572 if (OutputBuffer != NULL) {
573 free (OutputBuffer);
575 return STATUS_ERROR;
577 VerboseMsg ("the size of the created section file is %u bytes", (unsigned) TotalLength);
580 // Add the section header for the compressed data
582 CompressionSect = (EFI_COMPRESSION_SECTION *) FileBuffer;
584 CompressionSect->CommonHeader.Type = EFI_SECTION_COMPRESSION;
585 CompressionSect->CommonHeader.Size[0] = (UINT8) (TotalLength & 0xff);
586 CompressionSect->CommonHeader.Size[1] = (UINT8) ((TotalLength & 0xff00) >> 8);
587 CompressionSect->CommonHeader.Size[2] = (UINT8) ((TotalLength & 0xff0000) >> 16);
588 CompressionSect->CompressionType = SectCompSubType;
589 CompressionSect->UncompressedLength = InputLength;
592 // Set OutFileBuffer
594 *OutFileBuffer = FileBuffer;
596 return EFI_SUCCESS;
599 EFI_STATUS
600 GenSectionGuidDefinedSection (
601 CHAR8 **InputFileName,
602 UINT32 InputFileNum,
603 EFI_GUID *VendorGuid,
604 UINT16 DataAttribute,
605 UINT32 DataHeaderSize,
606 UINT8 **OutFileBuffer
608 /*++
610 Routine Description:
612 Generate an encapsulating section of type EFI_SECTION_GUID_DEFINED
613 Input file must be already sectioned. The function won't validate
614 the input files' contents. Caller should hand in files already
615 with section header.
617 Arguments:
619 InputFileName - Name of the input file.
621 InputFileNum - Number of input files. Should be at least 1.
623 VendorGuid - Specify vendor guid value.
625 DataAttribute - Specify attribute for the vendor guid data.
627 DataHeaderSize- Guided Data Header Size
629 OutFileBuffer - Buffer pointer to Output file contents
631 Returns:
633 EFI_SUCCESS on successful return
634 EFI_INVALID_PARAMETER if InputFileNum is less than 1
635 EFI_ABORTED if unable to open input file.
636 EFI_OUT_OF_RESOURCES No resource to complete the operation.
638 --*/
640 UINT32 TotalLength;
641 UINT32 InputLength;
642 UINT32 Offset;
643 UINT8 *FileBuffer;
644 UINT32 Crc32Checksum;
645 EFI_STATUS Status;
646 CRC32_SECTION_HEADER *Crc32GuidSect;
647 EFI_GUID_DEFINED_SECTION *VendorGuidSect;
649 InputLength = 0;
650 Offset = 0;
651 FileBuffer = NULL;
653 if (CompareGuid (VendorGuid, &mEfiCrc32SectionGuid) == 0) {
654 Offset = sizeof (CRC32_SECTION_HEADER);
655 } else {
656 Offset = sizeof (EFI_GUID_DEFINED_SECTION);
660 // read all input file contents into a buffer
661 // first get the size of all file contents
663 Status = GetSectionContents (
664 InputFileName,
665 InputFileNum,
666 FileBuffer,
667 &InputLength
670 if (Status == EFI_BUFFER_TOO_SMALL) {
671 FileBuffer = (UINT8 *) malloc (InputLength + Offset);
672 if (FileBuffer == NULL) {
673 Error (NULL, 0, 4001, "Resource", "memory cannot be allcoated");
674 return EFI_OUT_OF_RESOURCES;
677 // read all input file contents into a buffer
679 Status = GetSectionContents (
680 InputFileName,
681 InputFileNum,
682 FileBuffer + Offset,
683 &InputLength
687 if (EFI_ERROR (Status)) {
688 if (FileBuffer != NULL) {
689 free (FileBuffer);
691 Error (NULL, 0, 0001, "Error opening file for reading", InputFileName[0]);
692 return Status;
695 if (InputLength == 0) {
696 Error (NULL, 0, 2000, "Invalid parameter", "the size of input file %s can't be zero", InputFileName);
697 return EFI_NOT_FOUND;
701 // Now data is in FileBuffer + Offset
703 if (CompareGuid (VendorGuid, &mEfiCrc32SectionGuid) == 0) {
705 // Default Guid section is CRC32.
707 Crc32Checksum = 0;
708 CalculateCrc32 (FileBuffer + Offset, InputLength, &Crc32Checksum);
710 TotalLength = InputLength + sizeof (CRC32_SECTION_HEADER);
711 if (TotalLength >= MAX_SECTION_SIZE) {
712 Error (NULL, 0, 2000, "Invalid paramter", "The size of all files exceeds section size limit(%uM).", MAX_SECTION_SIZE>>20);
713 free (FileBuffer);
714 return STATUS_ERROR;
717 Crc32GuidSect = (CRC32_SECTION_HEADER *) FileBuffer;
718 Crc32GuidSect->GuidSectionHeader.CommonHeader.Type = EFI_SECTION_GUID_DEFINED;
719 Crc32GuidSect->GuidSectionHeader.CommonHeader.Size[0] = (UINT8) (TotalLength & 0xff);
720 Crc32GuidSect->GuidSectionHeader.CommonHeader.Size[1] = (UINT8) ((TotalLength & 0xff00) >> 8);
721 Crc32GuidSect->GuidSectionHeader.CommonHeader.Size[2] = (UINT8) ((TotalLength & 0xff0000) >> 16);
722 memcpy (&(Crc32GuidSect->GuidSectionHeader.SectionDefinitionGuid), &mEfiCrc32SectionGuid, sizeof (EFI_GUID));
723 Crc32GuidSect->GuidSectionHeader.Attributes = EFI_GUIDED_SECTION_AUTH_STATUS_VALID;
724 Crc32GuidSect->GuidSectionHeader.DataOffset = sizeof (CRC32_SECTION_HEADER);
725 Crc32GuidSect->CRC32Checksum = Crc32Checksum;
726 DebugMsg (NULL, 0, 9, "Guided section", "Data offset is %u", Crc32GuidSect->GuidSectionHeader.DataOffset);
728 } else {
729 TotalLength = InputLength + sizeof (EFI_GUID_DEFINED_SECTION);
730 if (TotalLength >= MAX_SECTION_SIZE) {
731 Error (NULL, 0, 2000, "Invalid paramter", "The size of all files exceeds section size limit(%uM).", MAX_SECTION_SIZE>>20);
732 free (FileBuffer);
733 return STATUS_ERROR;
736 VendorGuidSect = (EFI_GUID_DEFINED_SECTION *) FileBuffer;
737 VendorGuidSect->CommonHeader.Type = EFI_SECTION_GUID_DEFINED;
738 VendorGuidSect->CommonHeader.Size[0] = (UINT8) (TotalLength & 0xff);
739 VendorGuidSect->CommonHeader.Size[1] = (UINT8) ((TotalLength & 0xff00) >> 8);
740 VendorGuidSect->CommonHeader.Size[2] = (UINT8) ((TotalLength & 0xff0000) >> 16);
741 memcpy (&(VendorGuidSect->SectionDefinitionGuid), VendorGuid, sizeof (EFI_GUID));
742 VendorGuidSect->Attributes = DataAttribute;
743 VendorGuidSect->DataOffset = (UINT16) (sizeof (EFI_GUID_DEFINED_SECTION) + DataHeaderSize);
744 DebugMsg (NULL, 0, 9, "Guided section", "Data offset is %u", VendorGuidSect->DataOffset);
746 VerboseMsg ("the size of the created section file is %u bytes", (unsigned) TotalLength);
749 // Set OutFileBuffer
751 *OutFileBuffer = FileBuffer;
753 return EFI_SUCCESS;
757 main (
758 int argc,
759 char *argv[]
761 /*++
763 Routine Description:
765 Main
767 Arguments:
769 command line parameters
771 Returns:
773 EFI_SUCCESS Section header successfully generated and section concatenated.
774 EFI_ABORTED Could not generate the section
775 EFI_OUT_OF_RESOURCES No resource to complete the operation.
777 --*/
779 UINT32 Index;
780 UINT32 InputFileNum;
781 FILE *InFile;
782 FILE *OutFile;
783 CHAR8 **InputFileName;
784 CHAR8 *OutputFileName;
785 CHAR8 *SectionName;
786 CHAR8 *CompressionName;
787 CHAR8 *StringBuffer;
788 EFI_GUID VendorGuid = mZeroGuid;
789 int VersionNumber;
790 UINT8 SectType;
791 UINT8 SectCompSubType;
792 UINT16 SectGuidAttribute;
793 UINT64 SectGuidHeaderLength;
794 EFI_VERSION_SECTION *VersionSect;
795 EFI_USER_INTERFACE_SECTION *UiSect;
796 UINT32 InputLength;
797 UINT8 *OutFileBuffer;
798 EFI_STATUS Status;
799 UINT64 LogLevel;
801 InputFileName = NULL;
802 OutputFileName = NULL;
803 SectionName = NULL;
804 CompressionName = NULL;
805 StringBuffer = "";
806 InFile = NULL;
807 OutFile = NULL;
808 VersionNumber = 0;
809 InputFileNum = 0;
810 SectType = EFI_SECTION_ALL;
811 SectCompSubType = 0;
812 SectGuidAttribute = 0;
813 OutFileBuffer = NULL;
814 InputLength = 0;
815 Status = STATUS_SUCCESS;
816 LogLevel = 0;
817 SectGuidHeaderLength = 0;
818 VersionSect = NULL;
819 UiSect = NULL;
821 SetUtilityName (UTILITY_NAME);
823 if (argc == 1) {
824 Error (NULL, 0, 1001, "Missing options", "No options input");
825 Usage ();
826 return STATUS_ERROR;
830 // Parse command line
832 argc --;
833 argv ++;
835 if ((stricmp (argv[0], "-h") == 0) || (stricmp (argv[0], "--help") == 0)) {
836 Version ();
837 Usage ();
838 return STATUS_SUCCESS;
841 if (stricmp (argv[0], "--version") == 0) {
842 Version ();
843 return STATUS_SUCCESS;
846 while (argc > 0) {
847 if ((stricmp (argv[0], "-s") == 0) || (stricmp (argv[0], "--SectionType") == 0)) {
848 SectionName = argv[1];
849 if (SectionName == NULL) {
850 Error (NULL, 0, 1003, "Invalid option value", "Section Type can't be NULL");
851 goto Finish;
853 argc -= 2;
854 argv += 2;
855 continue;
858 if ((stricmp (argv[0], "-o") == 0) || (stricmp (argv[0], "--outputfile") == 0)) {
859 OutputFileName = argv[1];
860 if (OutputFileName == NULL) {
861 Error (NULL, 0, 1003, "Invalid option value", "Output file can't be NULL");
862 goto Finish;
864 argc -= 2;
865 argv += 2;
866 continue;
869 if ((stricmp (argv[0], "-c") == 0) || (stricmp (argv[0], "--compress") == 0)) {
870 CompressionName = argv[1];
871 if (CompressionName == NULL) {
872 Error (NULL, 0, 1003, "Invalid option value", "Compression Type can't be NULL");
873 goto Finish;
875 argc -= 2;
876 argv += 2;
877 continue;
880 if ((stricmp (argv[0], "-g") == 0) || (stricmp (argv[0], "--vendor") == 0)) {
881 Status = StringToGuid (argv[1], &VendorGuid);
882 if (EFI_ERROR (Status)) {
883 Error (NULL, 0, 1003, "Invalid option value", "%s = %s", argv[0], argv[1]);
884 goto Finish;
886 argc -= 2;
887 argv += 2;
888 continue;
891 if ((stricmp (argv[0], "-r") == 0) || (stricmp (argv[0], "--attributes") == 0)) {
892 if (stricmp (argv[1], mGUIDedSectionAttribue[EFI_GUIDED_SECTION_PROCESSING_REQUIRED]) == 0) {
893 SectGuidAttribute |= EFI_GUIDED_SECTION_PROCESSING_REQUIRED;
894 } else if (stricmp (argv[1], mGUIDedSectionAttribue[EFI_GUIDED_SECTION_AUTH_STATUS_VALID]) == 0) {
895 SectGuidAttribute |= EFI_GUIDED_SECTION_AUTH_STATUS_VALID;
896 } else if (stricmp (argv[1], mGUIDedSectionAttribue[0]) == 0) {
898 // NONE attribute
900 SectGuidAttribute |= EFI_GUIDED_SECTION_NONE;
901 } else {
902 Error (NULL, 0, 1003, "Invalid option value", "%s = %s", argv[0], argv[1]);
903 goto Finish;
905 argc -= 2;
906 argv += 2;
907 continue;
910 if ((stricmp (argv[0], "-l") == 0) || (stricmp (argv[0], "--HeaderLength") == 0)) {
911 Status = AsciiStringToUint64 (argv[1], FALSE, &SectGuidHeaderLength);
912 if (EFI_ERROR (Status)) {
913 Error (NULL, 0, 1003, "Invalid option value for GuidHeaderLength", "%s = %s", argv[0], argv[1]);
914 goto Finish;
916 argc -= 2;
917 argv += 2;
918 continue;
921 if ((stricmp (argv[0], "-n") == 0) || (stricmp (argv[0], "--name") == 0)) {
922 StringBuffer = argv[1];
923 if (StringBuffer == NULL) {
924 Error (NULL, 0, 1003, "Invalid option value", "Name can't be NULL");
925 goto Finish;
927 argc -= 2;
928 argv += 2;
929 continue;
932 if ((stricmp (argv[0], "-j") == 0) || (stricmp (argv[0], "--buildnumber") == 0)) {
933 if (argv[1] == NULL) {
934 Error (NULL, 0, 1003, "Invalid option value", "build number can't be NULL");
935 goto Finish;
938 // Verify string is a integrator number
940 for (Index = 0; Index < strlen (argv[1]); Index++) {
941 if ((argv[1][Index] != '-') && (isdigit (argv[1][Index]) == 0)) {
942 Error (NULL, 0, 1003, "Invalid option value", "%s = %s", argv[0], argv[1]);
943 goto Finish;
947 sscanf (argv[1], "%d", &VersionNumber);
948 argc -= 2;
949 argv += 2;
950 continue;
953 if ((stricmp (argv[0], "-v") == 0) || (stricmp (argv[0], "--verbose") == 0)) {
954 SetPrintLevel (VERBOSE_LOG_LEVEL);
955 VerboseMsg ("Verbose output Mode Set!");
956 argc --;
957 argv ++;
958 continue;
961 if ((stricmp (argv[0], "-q") == 0) || (stricmp (argv[0], "--quiet") == 0)) {
962 SetPrintLevel (KEY_LOG_LEVEL);
963 KeyMsg ("Quiet output Mode Set!");
964 argc --;
965 argv ++;
966 continue;
969 if ((stricmp (argv[0], "-d") == 0) || (stricmp (argv[0], "--debug") == 0)) {
970 Status = AsciiStringToUint64 (argv[1], FALSE, &LogLevel);
971 if (EFI_ERROR (Status)) {
972 Error (NULL, 0, 1003, "Invalid option value", "%s = %s", argv[0], argv[1]);
973 goto Finish;
975 if (LogLevel > 9) {
976 Error (NULL, 0, 1003, "Invalid option value", "Debug Level range is 0~9, currnt input level is %d", (int) LogLevel);
977 goto Finish;
979 SetPrintLevel (LogLevel);
980 DebugMsg (NULL, 0, 9, "Debug Mode Set", "Debug Output Mode Level %s is set!", argv[1]);
981 argc -= 2;
982 argv += 2;
983 continue;
987 // Get Input file name
989 if ((InputFileNum == 0) && (InputFileName == NULL)) {
990 InputFileName = (CHAR8 **) malloc (MAXIMUM_INPUT_FILE_NUM * sizeof (CHAR8 *));
991 if (InputFileName == NULL) {
992 Error (NULL, 0, 4001, "Resource", "memory cannot be allcoated");
993 return 1;
996 memset (InputFileName, 0, (MAXIMUM_INPUT_FILE_NUM * sizeof (CHAR8 *)));
997 } else if (InputFileNum % MAXIMUM_INPUT_FILE_NUM == 0) {
999 // InputFileName buffer too small, need to realloc
1001 InputFileName = (CHAR8 **) realloc (
1002 InputFileName,
1003 (InputFileNum + MAXIMUM_INPUT_FILE_NUM) * sizeof (CHAR8 *)
1006 if (InputFileName == NULL) {
1007 Error (NULL, 0, 4001, "Resource", "memory cannot be allcoated");
1008 return 1;
1011 memset (&(InputFileName[InputFileNum]), 0, (MAXIMUM_INPUT_FILE_NUM * sizeof (CHAR8 *)));
1014 InputFileName[InputFileNum++] = argv[0];
1015 argc --;
1016 argv ++;
1019 VerboseMsg ("%s tool start.", UTILITY_NAME);
1022 // Parse all command line parameters to get the corresponding section type.
1024 VerboseMsg ("Section type is %s", SectionName);
1025 if (SectionName == NULL) {
1027 // No specified Section type, default is SECTION_ALL.
1029 SectType = EFI_SECTION_ALL;
1030 } else if (stricmp (SectionName, mSectionTypeName[EFI_SECTION_COMPRESSION]) == 0) {
1031 SectType = EFI_SECTION_COMPRESSION;
1032 if (CompressionName == NULL) {
1034 // Default is PI_STD compression algorithm.
1036 SectCompSubType = EFI_STANDARD_COMPRESSION;
1037 } else if (stricmp (CompressionName, mCompressionTypeName[EFI_NOT_COMPRESSED]) == 0) {
1038 SectCompSubType = EFI_NOT_COMPRESSED;
1039 } else if (stricmp (CompressionName, mCompressionTypeName[EFI_STANDARD_COMPRESSION]) == 0) {
1040 SectCompSubType = EFI_STANDARD_COMPRESSION;
1041 } else {
1042 Error (NULL, 0, 1003, "Invalid option value", "--compress = %s", CompressionName);
1043 goto Finish;
1045 VerboseMsg ("Compress method is %s", mCompressionTypeName [SectCompSubType]);
1046 } else if (stricmp (SectionName, mSectionTypeName[EFI_SECTION_GUID_DEFINED]) == 0) {
1047 SectType = EFI_SECTION_GUID_DEFINED;
1049 if (CompareGuid (&VendorGuid, &mZeroGuid) == 0) {
1050 memcpy (&VendorGuid, &mEfiCrc32SectionGuid, sizeof (EFI_GUID));
1053 if (SectGuidAttribute == 0) {
1054 SectGuidAttribute = EFI_GUIDED_SECTION_PROCESSING_REQUIRED;
1056 if ((SectGuidAttribute & EFI_GUIDED_SECTION_NONE) != 0) {
1058 // NONE attribute, clear attribute value.
1060 SectGuidAttribute = 0;
1062 VerboseMsg ("Vendor Guid is %08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
1063 (unsigned) VendorGuid.Data1,
1064 VendorGuid.Data2,
1065 VendorGuid.Data3,
1066 VendorGuid.Data4[0],
1067 VendorGuid.Data4[1],
1068 VendorGuid.Data4[2],
1069 VendorGuid.Data4[3],
1070 VendorGuid.Data4[4],
1071 VendorGuid.Data4[5],
1072 VendorGuid.Data4[6],
1073 VendorGuid.Data4[7]);
1074 if ((SectGuidAttribute & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) != 0) {
1075 VerboseMsg ("Guid Attribute is %s", mGUIDedSectionAttribue[EFI_GUIDED_SECTION_PROCESSING_REQUIRED]);
1077 if ((SectGuidAttribute & EFI_GUIDED_SECTION_AUTH_STATUS_VALID) != 0) {
1078 VerboseMsg ("Guid Attribute is %s", mGUIDedSectionAttribue[EFI_GUIDED_SECTION_AUTH_STATUS_VALID]);
1080 if (SectGuidHeaderLength != 0) {
1081 VerboseMsg ("Guid Data Header size is 0x%llx", (unsigned long long) SectGuidHeaderLength);
1083 } else if (stricmp (SectionName, mSectionTypeName[EFI_SECTION_PE32]) == 0) {
1084 SectType = EFI_SECTION_PE32;
1085 } else if (stricmp (SectionName, mSectionTypeName[EFI_SECTION_PIC]) == 0) {
1086 SectType = EFI_SECTION_PIC;
1087 } else if (stricmp (SectionName, mSectionTypeName[EFI_SECTION_TE]) == 0) {
1088 SectType = EFI_SECTION_TE;
1089 } else if (stricmp (SectionName, mSectionTypeName[EFI_SECTION_DXE_DEPEX]) == 0) {
1090 SectType = EFI_SECTION_DXE_DEPEX;
1091 } else if (stricmp (SectionName, mSectionTypeName[EFI_SECTION_SMM_DEPEX]) == 0) {
1092 SectType = EFI_SECTION_SMM_DEPEX;
1093 } else if (stricmp (SectionName, mSectionTypeName[EFI_SECTION_VERSION]) == 0) {
1094 SectType = EFI_SECTION_VERSION;
1095 if (VersionNumber < 0 || VersionNumber > 9999) {
1096 Error (NULL, 0, 1003, "Invalid option value", "%d is not in 0~9999", VersionNumber);
1097 goto Finish;
1099 VerboseMsg ("Version section number is %d", VersionNumber);
1100 } else if (stricmp (SectionName, mSectionTypeName[EFI_SECTION_USER_INTERFACE]) == 0) {
1101 SectType = EFI_SECTION_USER_INTERFACE;
1102 if (StringBuffer[0] == '\0') {
1103 Error (NULL, 0, 1001, "Missing option", "user interface string");
1104 goto Finish;
1106 VerboseMsg ("UI section string name is %s", StringBuffer);
1107 } else if (stricmp (SectionName, mSectionTypeName[EFI_SECTION_COMPATIBILITY16]) == 0) {
1108 SectType = EFI_SECTION_COMPATIBILITY16;
1109 } else if (stricmp (SectionName, mSectionTypeName[EFI_SECTION_FIRMWARE_VOLUME_IMAGE]) == 0) {
1110 SectType = EFI_SECTION_FIRMWARE_VOLUME_IMAGE;
1111 } else if (stricmp (SectionName, mSectionTypeName[EFI_SECTION_FREEFORM_SUBTYPE_GUID]) == 0) {
1112 SectType = EFI_SECTION_FREEFORM_SUBTYPE_GUID;
1113 } else if (stricmp (SectionName, mSectionTypeName[EFI_SECTION_RAW]) == 0) {
1114 SectType = EFI_SECTION_RAW;
1115 } else if (stricmp (SectionName, mSectionTypeName[EFI_SECTION_PEI_DEPEX]) == 0) {
1116 SectType = EFI_SECTION_PEI_DEPEX;
1117 } else {
1118 Error (NULL, 0, 1003, "Invalid option value", "SectionType = %s", SectionName);
1119 goto Finish;
1123 // GuidValue is only required by Guided section.
1125 if ((SectType != EFI_SECTION_GUID_DEFINED) && (CompareGuid (&VendorGuid, &mZeroGuid) != 0)) {
1126 fprintf (stdout, "Warning: the input guid value is not required for this section type %s\n", SectionName);
1130 // Check whether there is input file
1132 if ((SectType != EFI_SECTION_VERSION) && (SectType != EFI_SECTION_USER_INTERFACE)) {
1134 // The input file are required for other section type.
1136 if (InputFileNum == 0) {
1137 Error (NULL, 0, 1001, "Missing options", "Input files");
1138 goto Finish;
1142 // Check whether there is output file
1144 for (Index = 0; Index < InputFileNum; Index ++) {
1145 VerboseMsg ("the %uth input file name is %s", (unsigned) Index, InputFileName[Index]);
1147 if (OutputFileName == NULL) {
1148 Error (NULL, 0, 1001, "Missing options", "Output file");
1149 goto Finish;
1150 // OutFile = stdout;
1152 VerboseMsg ("Output file name is %s", OutputFileName);
1155 // At this point, we've fully validated the command line, and opened appropriate
1156 // files, so let's go and do what we've been asked to do...
1159 // Within this switch, build and write out the section header including any
1160 // section type specific pieces. If there's an input file, it's tacked on later
1162 switch (SectType) {
1163 case EFI_SECTION_COMPRESSION:
1164 Status = GenSectionCompressionSection (
1165 InputFileName,
1166 InputFileNum,
1167 SectCompSubType,
1168 &OutFileBuffer
1170 break;
1172 case EFI_SECTION_GUID_DEFINED:
1173 Status = GenSectionGuidDefinedSection (
1174 InputFileName,
1175 InputFileNum,
1176 &VendorGuid,
1177 SectGuidAttribute,
1178 (UINT32) SectGuidHeaderLength,
1179 &OutFileBuffer
1181 break;
1183 case EFI_SECTION_VERSION:
1184 Index = sizeof (EFI_COMMON_SECTION_HEADER);
1186 // 2 bytes for the build number UINT16
1188 Index += 2;
1190 // StringBuffer is ascii.. unicode is 2X + 2 bytes for terminating unicode null.
1192 Index += (strlen (StringBuffer) * 2) + 2;
1193 OutFileBuffer = (UINT8 *) malloc (Index);
1194 if (OutFileBuffer == NULL) {
1195 Error (NULL, 0, 4001, "Resource", "memory cannot be allcoated");
1196 goto Finish;
1198 VersionSect = (EFI_VERSION_SECTION *) OutFileBuffer;
1199 VersionSect->CommonHeader.Type = SectType;
1200 VersionSect->CommonHeader.Size[0] = (UINT8) (Index & 0xff);
1201 VersionSect->CommonHeader.Size[1] = (UINT8) ((Index & 0xff00) >> 8);
1202 VersionSect->CommonHeader.Size[2] = (UINT8) ((Index & 0xff0000) >> 16);
1203 VersionSect->BuildNumber = (UINT16) VersionNumber;
1204 Ascii2UnicodeString (StringBuffer, VersionSect->VersionString);
1205 VerboseMsg ("the size of the created section file is %u bytes", (unsigned) Index);
1206 break;
1208 case EFI_SECTION_USER_INTERFACE:
1209 Index = sizeof (EFI_COMMON_SECTION_HEADER);
1211 // StringBuffer is ascii.. unicode is 2X + 2 bytes for terminating unicode null.
1213 Index += (strlen (StringBuffer) * 2) + 2;
1214 OutFileBuffer = (UINT8 *) malloc (Index);
1215 if (OutFileBuffer == NULL) {
1216 Error (NULL, 0, 4001, "Resource", "memory cannot be allcoated");
1217 goto Finish;
1219 UiSect = (EFI_USER_INTERFACE_SECTION *) OutFileBuffer;
1220 UiSect->CommonHeader.Type = SectType;
1221 UiSect->CommonHeader.Size[0] = (UINT8) (Index & 0xff);
1222 UiSect->CommonHeader.Size[1] = (UINT8) ((Index & 0xff00) >> 8);
1223 UiSect->CommonHeader.Size[2] = (UINT8) ((Index & 0xff0000) >> 16);
1224 Ascii2UnicodeString (StringBuffer, UiSect->FileNameString);
1225 VerboseMsg ("the size of the created section file is %u bytes", (unsigned) Index);
1226 break;
1228 case EFI_SECTION_ALL:
1230 // read all input file contents into a buffer
1231 // first get the size of all file contents
1233 Status = GetSectionContents (
1234 InputFileName,
1235 InputFileNum,
1236 OutFileBuffer,
1237 &InputLength
1240 if (Status == EFI_BUFFER_TOO_SMALL) {
1241 OutFileBuffer = (UINT8 *) malloc (InputLength);
1242 if (OutFileBuffer == NULL) {
1243 Error (NULL, 0, 4001, "Resource", "memory cannot be allcoated");
1244 goto Finish;
1247 // read all input file contents into a buffer
1249 Status = GetSectionContents (
1250 InputFileName,
1251 InputFileNum,
1252 OutFileBuffer,
1253 &InputLength
1256 VerboseMsg ("the size of the created section file is %u bytes", (unsigned) InputLength);
1257 break;
1258 default:
1260 // All other section types are caught by default (they're all the same)
1262 Status = GenSectionCommonLeafSection (
1263 InputFileName,
1264 InputFileNum,
1265 SectType,
1266 &OutFileBuffer
1268 break;
1271 if (Status != EFI_SUCCESS || OutFileBuffer == NULL) {
1272 Error (NULL, 0, 2000, "Status is not successful", "Status value is 0x%X", (int) Status);
1273 goto Finish;
1277 // Get output file length
1279 if (SectType != EFI_SECTION_ALL) {
1280 InputLength = SECTION_SIZE (OutFileBuffer);
1284 // Write the output file
1286 OutFile = fopen (OutputFileName, "wb");
1287 if (OutFile == NULL) {
1288 Error (NULL, 0, 0001, "Error opening file for writing", OutputFileName);
1289 goto Finish;
1292 fwrite (OutFileBuffer, InputLength, 1, OutFile);
1294 Finish:
1295 if (InputFileName != NULL) {
1296 free (InputFileName);
1299 if (OutFileBuffer != NULL) {
1300 free (OutFileBuffer);
1303 if (OutFile != NULL) {
1304 fclose (OutFile);
1307 VerboseMsg ("%s tool done with return code is 0x%x.", UTILITY_NAME, GetUtilityStatus ());
1309 return GetUtilityStatus ();