3 Copyright (c) 2004 - 2005, 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.
18 Support routines for the VFR compiler
22 #include <stdio.h> // for FILE routines
23 #include <stdlib.h> // for malloc() and free()
26 #include <UefiBaseTypes.h>
27 #include <MultiPhase.h>
28 #include "EfiUtilityMsgs.h"
30 #include "VfrServices.h"
35 static const char *mSourceFileHeader
[] = {
37 "// DO NOT EDIT -- auto-generated file",
39 "// This file is generated by the VFR compiler.",
50 // Create a table that can be used to do internal checking on the IFR
53 static const IFR_OPCODE_SIZES mOpcodeSizes
[] = {
55 { "EFI_IFR_FORM", sizeof (EFI_IFR_FORM
) },
56 { "EFI_IFR_SUBTITLE", sizeof (EFI_IFR_SUBTITLE
) },
57 { "EFI_IFR_TEXT", -6 }, //sizeof (EFI_IFR_TEXT) },
58 { "unused 0x04 opcode", 0 }, // EFI_IFR_GRAPHIC_OP
59 { "EFI_IFR_ONE_OF", sizeof (EFI_IFR_ONE_OF
) },
60 { "EFI_IFR_CHECKBOX", sizeof (EFI_IFR_CHECKBOX
) },
61 { "EFI_IFR_NUMERIC", sizeof (EFI_IFR_NUMERIC
) },
62 { "EFI_IFR_PASSWORD", sizeof (EFI_IFR_PASSWORD
) },
63 { "EFI_IFR_ONE_OF_OPTION", sizeof (EFI_IFR_ONE_OF_OPTION
) },
64 { "EFI_IFR_SUPPRESS", sizeof (EFI_IFR_SUPPRESS
) },
65 { "EFI_IFR_END_FORM", sizeof (EFI_IFR_END_FORM
) },
66 { "EFI_IFR_HIDDEN", sizeof (EFI_IFR_HIDDEN
) },
67 { "EFI_IFR_END_FORM_SET", sizeof (EFI_IFR_END_FORM_SET
) },
68 { "EFI_IFR_FORM_SET", sizeof (EFI_IFR_FORM_SET
) },
69 { "EFI_IFR_REF", sizeof (EFI_IFR_REF
) },
70 { "EFI_IFR_END_ONE_OF", sizeof (EFI_IFR_END_ONE_OF
) },
71 { "EFI_IFR_INCONSISTENT", sizeof (EFI_IFR_INCONSISTENT
) },
72 { "EFI_IFR_EQ_ID_VAL", sizeof (EFI_IFR_EQ_ID_VAL
) },
73 { "EFI_IFR_EQ_ID_ID", sizeof (EFI_IFR_EQ_ID_ID
) },
74 { "EFI_IFR_EQ_ID_LIST", -sizeof (EFI_IFR_EQ_ID_LIST
) },
75 { "EFI_IFR_AND", sizeof (EFI_IFR_AND
) },
76 { "EFI_IFR_OR", sizeof (EFI_IFR_OR
) },
77 { "EFI_IFR_NOT", sizeof (EFI_IFR_NOT
) },
78 { "EFI_IFR_END_EXPR", sizeof (EFI_IFR_END_EXPR
) },
79 { "EFI_IFR_GRAY_OUT", sizeof (EFI_IFR_GRAY_OUT
) },
80 { "EFI_IFR_DATE", sizeof (EFI_IFR_DATE
) / 3 },
81 { "EFI_IFR_TIME", sizeof (EFI_IFR_TIME
) / 3 },
82 { "EFI_IFR_STRING", sizeof (EFI_IFR_STRING
) },
83 { "EFI_IFR_LABEL", sizeof (EFI_IFR_LABEL
) },
84 { "EFI_IFR_SAVE_DEFAULTS", sizeof (EFI_IFR_SAVE_DEFAULTS
) },
85 { "EFI_IFR_RESTORE_DEFAULTS", sizeof (EFI_IFR_RESTORE_DEFAULTS
) },
86 { "EFI_IFR_BANNER", sizeof (EFI_IFR_BANNER
) },
87 { "EFI_IFR_INVENTORY", sizeof (EFI_IFR_INVENTORY
) },
88 { "EFI_IFR_EQ_VAR_VAL_OP", sizeof (EFI_IFR_EQ_VAR_VAL
) },
89 { "EFI_IFR_ORDERED_LIST_OP", sizeof (EFI_IFR_ORDERED_LIST
) },
90 { "EFI_IFR_VARSTORE_OP", -sizeof (EFI_IFR_VARSTORE
) },
91 { "EFI_IFR_VARSTORE_SELECT_OP", sizeof (EFI_IFR_VARSTORE_SELECT
) },
92 { "EFI_IFR_VARSTORE_SELECT_PAIR_OP", sizeof (EFI_IFR_VARSTORE_SELECT_PAIR
) },
93 { "EFI_IFR_TRUE", sizeof (EFI_IFR_TRUE
)},
94 { "EFI_IFR_FALSE", sizeof (EFI_IFR_FALSE
)},
95 { "EFI_IFR_GT", sizeof (EFI_IFR_GT
)},
96 { "EFI_IFR_GE", sizeof (EFI_IFR_GE
)},
97 { "EFI_IFR_OEM_DEFINED_OP", -2 },
101 VfrOpcodeHandler::VfrOpcodeHandler (
106 Constructor for the VFR opcode handling class.
119 mQueuedByteCount
= 0;
120 mQueuedOpcodeByteValid
= 0;
121 mPrimaryVarStoreId
= 0;
122 mSecondaryVarStoreId
= 0;
123 mSecondaryVarStoreIdSet
= 0;
124 mPrimaryVarStoreIdSet
= 0;
125 mDefaultVarStoreId
= 0;
129 VfrOpcodeHandler::SetVarStoreId (
135 This function is invoked by the parser when a variable is referenced in the
136 VFR. Save the variable store (and set a flag) so that we can later determine
137 if we need to emit a varstore-select or varstore-select-pair opcode.
140 VarStoreId - ID of the variable store referenced in the VFR
147 mPrimaryVarStoreId
= VarStoreId
;
148 mPrimaryVarStoreIdSet
= 1;
152 VfrOpcodeHandler::SetSecondaryVarStoreId (
158 This function is invoked by the parser when a secondary variable is
159 referenced in the VFR. Save the variable store (and set a flag) so
160 that we can later determine if we need to emit a varstore-select or
161 varstore-pair opcode.
164 VarStoreId - ID of the variable store referenced in the VFR
171 mSecondaryVarStoreId
= VarStoreId
;
172 mSecondaryVarStoreIdSet
= 1;
176 VfrOpcodeHandler::WriteIfrBytes (
181 This function is invoked at the end of parsing. Its purpose
182 is to write out all the IFR bytes that were queued up while
199 CHAR8 Line
[MAX_LINE_LEN
];
204 EFI_HII_IFR_PACK_HEADER IfrHeader
;
207 UINT32 BytesLeftThisOpcode
;
209 // If someone added a new opcode and didn't update our opcode sizes structure, error out.
211 if (sizeof(mOpcodeSizes
) / sizeof (mOpcodeSizes
[0]) != EFI_IFR_LAST_OPCODE
+ 1) {
212 Error (__FILE__
, __LINE__
, 0, "application error", "internal IFR binary table size is incorrect");
220 // If there have been any errors to this point, then skip dumping the IFR
221 // binary data. This way doing an nmake again will try to build it again, and
222 // the build will fail if they did not fix the problem.
224 if (GetUtilityStatus () != STATUS_ERROR
) {
225 if ((IfrBinFptr
= fopen (gOptions
.IfrOutputFileName
, "w")) == NULL
) {
226 Error (PROGRAM_NAME
, 0, 0, gOptions
.IfrOutputFileName
, "could not open file for writing");
230 // Write the standard file header to the output file
232 WriteStandardFileHeader (IfrBinFptr
);
234 // Write the structure header
236 fprintf (IfrBinFptr
, "\nunsigned char %sBin[] = {", gOptions
.VfrBaseFileName
);
240 memset ((char *)&IfrHeader
, 0, sizeof (IfrHeader
));
241 IfrHeader
.Header
.Type
= EFI_HII_IFR
;
242 IfrHeader
.Header
.Length
= mBytesWritten
+ sizeof (IfrHeader
);
243 Ptr
= (UINT8
*)&IfrHeader
;
244 for (Count
= 0; Count
< sizeof (IfrHeader
); Count
++, Ptr
++) {
245 if ((Count
& 0x03) == 0) {
246 fprintf (IfrBinFptr
, "\n ");
248 fprintf (IfrBinFptr
, "0x%02X, ", *Ptr
);
252 // Write all the IFR bytes
254 fprintf (IfrBinFptr
, "\n // start of IFR data");
257 while (Curr
!= NULL
) {
258 if ((Count
& 0x0F) == 0) {
259 fprintf (IfrBinFptr
, "\n ");
261 if (Curr
->KeyByte
!= 0) {
262 fprintf (IfrBinFptr
, "/*%c*/ ", Curr
->KeyByte
);
264 fprintf (IfrBinFptr
, "0x%02X, ", Curr
->OpcodeByte
);
268 fprintf (IfrBinFptr
, "\n};\n\n");
277 // Write the bytes as binary data if the user specified to do so
279 if ((GetUtilityStatus () != STATUS_ERROR
) && (gOptions
.CreateIfrBinFile
!= 0)) {
281 // Use the Ifr output file name with a ".hpk" extension.
283 for (Cptr
= gOptions
.IfrOutputFileName
+ strlen (gOptions
.IfrOutputFileName
) - 1;
284 (*Cptr
!= '.') && (Cptr
> gOptions
.IfrOutputFileName
) && (*Cptr
!= '\\');
291 strcpy (Cptr
, ".hpk");
293 strcat (gOptions
.IfrOutputFileName
, ".hpk");
295 if ((IfrBinFptr
= fopen (gOptions
.IfrOutputFileName
, "wb")) == NULL
) {
296 Error (PROGRAM_NAME
, 0, 0, gOptions
.IfrOutputFileName
, "could not open file for writing");
300 // Write the structure header
302 memset ((char *)&IfrHeader
, 0, sizeof (IfrHeader
));
303 IfrHeader
.Header
.Type
= EFI_HII_IFR
;
304 IfrHeader
.Header
.Length
= mBytesWritten
+ sizeof (IfrHeader
);
305 Ptr
= (UINT8
*)&IfrHeader
;
306 for (Count
= 0; Count
< sizeof (IfrHeader
); Count
++, Ptr
++) {
307 fwrite (Ptr
, 1, 1, IfrBinFptr
);
311 // Write all the IFR bytes
315 while (Curr
!= NULL
) {
316 fwrite (&Curr
->OpcodeByte
, 1, 1, IfrBinFptr
);
327 // If creating a listing file, then open the input and output files
330 if (gOptions
.CreateListFile
) {
332 // Open the input VFR file and the output list file
334 if ((InFptr
= fopen (gOptions
.PreprocessorOutputFileName
, "r")) == NULL
) {
335 Warning (PROGRAM_NAME
, 0, 0, gOptions
.PreprocessorOutputFileName
, "could not open file for creating a list file");
337 if ((OutFptr
= fopen (gOptions
.VfrListFileName
, "w")) == NULL
) {
338 Warning (PROGRAM_NAME
, 0, 0, gOptions
.VfrListFileName
, "could not open output list file for writing");
350 // Write the list file
354 // Write out the VFR compiler version
356 fprintf (OutFptr
, "//\n// VFR compiler version " VFR_COMPILER_VERSION
"\n//\n");
358 while (Curr
!= NULL
) {
360 // Print lines until we reach the line of the current opcode
362 while (LineCount
< PoundLines
+ Curr
->LineNum
) {
363 if (fgets (Line
, sizeof (Line
), InFptr
) != NULL
) {
365 // We should check for line length exceeded on the fgets(). Otherwise it
366 // throws the listing file output off. Future enhancement perhaps.
368 fprintf (OutFptr
, "%s", Line
);
369 if (strncmp (Line
, "#line", 5) == 0) {
376 // Print all opcodes with line numbers less than where we are now
378 BytesLeftThisOpcode
= 0;
379 while ((Curr
!= NULL
) && ((Curr
->LineNum
== 0) || (LineCount
>= PoundLines
+ Curr
->LineNum
))) {
380 if (BytesLeftThisOpcode
== 0) {
381 fprintf (OutFptr
, ">%08X: ", ByteCount
);
382 if (Curr
->Next
!= NULL
) {
383 BytesLeftThisOpcode
= (UINT32
)Curr
->Next
->OpcodeByte
;
386 fprintf (OutFptr
, "%02X ", (UINT32
)Curr
->OpcodeByte
);
388 BytesLeftThisOpcode
--;
389 if (BytesLeftThisOpcode
== 0) {
390 fprintf (OutFptr
, "\n");
396 // Dump any remaining lines from the input file
398 while (fgets (Line
, sizeof (Line
), InFptr
) != NULL
) {
399 fprintf (OutFptr
, "%s", Line
);
405 // Debug code to make sure that each opcode we write out has as many
406 // bytes as the IFR structure requires. If there were errors, then
407 // don't do this step.
409 if (GetUtilityStatus () != STATUS_ERROR
) {
412 while (Curr
!= NULL
) {
414 // First byte is the opcode, second byte is the length
416 if (Curr
->Next
== NULL
) {
417 Error (__FILE__
, __LINE__
, 0, "application error", "last opcode written does not contain a length byte");
420 Count
= (UINT32
)Curr
->Next
->OpcodeByte
;
427 "opcode with 0 length specified in output at offset 0x%X",
435 if ((Curr
->OpcodeByte
> EFI_IFR_LAST_OPCODE
) || (Curr
->OpcodeByte
== 0)) {
441 "invalid opcode 0x%X in output at offset 0x%X",
442 (UINT32
) Curr
->OpcodeByte
, ByteCount
444 } else if (mOpcodeSizes
[Curr
->OpcodeByte
].Size
< 0) {
446 // For those cases where the length is variable, the size is negative, and indicates
447 // the miniumum size.
449 if ((mOpcodeSizes
[Curr
->OpcodeByte
].Size
* -1) > Count
) {
455 "insufficient number of bytes written for %s at offset 0x%X",
456 mOpcodeSizes
[Curr
->OpcodeByte
].Name
,
464 if (mOpcodeSizes
[Curr
->OpcodeByte
].Size
== 0) {
470 "invalid opcode 0x%X in output at offset 0x%X",
471 (UINT32
)Curr
->OpcodeByte
,
478 if (mOpcodeSizes
[Curr
->OpcodeByte
].Size
!= Count
) {
484 "invalid number of bytes (%d written s/b %d) written for %s at offset 0x%X",
486 mOpcodeSizes
[Curr
->OpcodeByte
].Size
,
487 mOpcodeSizes
[Curr
->OpcodeByte
].Name
,
494 // Skip to next opcode
499 Error (__FILE__
, __LINE__
, 0, "application error", "last opcode written has invalid length");
509 VfrOpcodeHandler::~VfrOpcodeHandler(
514 Destructor for the VFR opcode handler. Free up memory allocated
515 while parsing the VFR script.
528 // Free up the IFR bytes
531 while (Curr
!= NULL
) {
539 VfrOpcodeHandler::AddOpcodeByte (
546 This function is invoked by the parser when a new IFR
547 opcode should be emitted.
550 OpcodeByte - the IFR opcode
551 LineNum - the line number from the source file that resulted
552 in the opcode being emitted.
563 // Now add this new byte
565 mQueuedOpcodeByte
= OpcodeByte
;
566 mQueuedLineNum
= LineNum
;
567 mQueuedOpcodeByteValid
= 1;
572 VfrOpcodeHandler::AddByte (
579 This function is invoked by the parser when it determines
580 that more raw IFR bytes should be emitted to the output stream.
581 Here we just queue them up into an output buffer.
584 ByteVal - the raw byte to emit to the output IFR stream
585 KeyByte - a value that can be used for debug.
593 // Check for buffer overflow
595 if (mQueuedByteCount
> MAX_QUEUE_COUNT
) {
596 Error (PROGRAM_NAME
, 0, 0, NULL
, "opcode queue overflow");
598 mQueuedBytes
[mQueuedByteCount
] = ByteVal
;
599 mQueuedKeyBytes
[mQueuedByteCount
] = KeyByte
;
605 VfrOpcodeHandler::FlushQueue (
610 This function is invoked to flush the internal IFR buffer.
621 UINT32 EmitNoneOnePair
;
625 // If the secondary varstore was specified, then we have to emit
626 // a varstore-select-pair opcode, which only applies to the following
629 if (mSecondaryVarStoreIdSet
) {
630 mSecondaryVarStoreIdSet
= 0;
632 // If primary and secondary are the same as the current default
633 // varstore, then we don't have to do anything.
634 // Note that the varstore-select-pair only applies to the following
637 if ((mPrimaryVarStoreId
!= mSecondaryVarStoreId
) || (mPrimaryVarStoreId
!= mDefaultVarStoreId
)) {
638 IAddByte (EFI_IFR_VARSTORE_SELECT_PAIR_OP
, 'O', mQueuedLineNum
);
639 IAddByte ((UINT8
)sizeof (EFI_IFR_VARSTORE_SELECT_PAIR
), 'L', 0);
640 IAddByte ((UINT8
)mPrimaryVarStoreId
, 0, 0);
641 IAddByte ((UINT8
)(mPrimaryVarStoreId
>> 8), 0, 0);
642 IAddByte ((UINT8
)mSecondaryVarStoreId
, 0, 0);
643 IAddByte ((UINT8
)(mSecondaryVarStoreId
>> 8), 0, 0);
645 } else if (mPrimaryVarStoreIdSet
!= 0) {
646 mPrimaryVarStoreIdSet
= 0;
647 if (mDefaultVarStoreId
!= mPrimaryVarStoreId
) {
649 // The VFR statement referenced a different variable store
650 // than the last one we reported. Insert a new varstore select
653 IAddByte (EFI_IFR_VARSTORE_SELECT_OP
, 'O', mQueuedLineNum
);
654 IAddByte ((UINT8
)sizeof (EFI_IFR_VARSTORE_SELECT
), 'L', 0);
655 IAddByte ((UINT8
)mPrimaryVarStoreId
, 0, 0);
656 IAddByte ((UINT8
)(mPrimaryVarStoreId
>> 8), 0, 0);
657 mDefaultVarStoreId
= mPrimaryVarStoreId
;
661 // Likely a new opcode is being added. Since each opcode item in the IFR has
662 // a header that specifies the size of the opcode item (which we don't
663 // know until we find the next opcode in the VFR), we queue up bytes
664 // until we know the size. Then we write them out. So flush the queue
667 if (mQueuedOpcodeByteValid
!= 0) {
669 // Add the previous opcode byte, the length byte, and the binary
672 IAddByte (mQueuedOpcodeByte
, 'O', mQueuedLineNum
);
673 IAddByte ((UINT8
)(mQueuedByteCount
+ 2), 'L', 0);
674 for (Count
= 0; Count
< mQueuedByteCount
; Count
++) {
675 IAddByte (mQueuedBytes
[Count
], mQueuedKeyBytes
[Count
], 0);
677 mQueuedByteCount
= 0;
678 mQueuedOpcodeByteValid
= 0;
684 VfrOpcodeHandler::IAddByte (
692 This internal function is used to add actual IFR bytes to
693 the output stream. Most other functions queue up the bytes
694 in an internal buffer. Once they come here, there's no
699 ByteVal - value to write to output
700 KeyByte - key value tied to the byte -- useful for debug
701 LineNum - line number from source file the byte resulted from
705 1 - failed due to memory allocation failure
710 NewByte
= (IFR_BYTE
*)malloc (sizeof (IFR_BYTE
));
711 if (NewByte
== NULL
) {
714 memset ((char *)NewByte
, 0, sizeof (IFR_BYTE
));
715 NewByte
->OpcodeByte
= ByteVal
;
716 NewByte
->KeyByte
= KeyByte
;
717 NewByte
->LineNum
= LineNum
;
721 if (mIfrBytes
== NULL
) {
724 mLastIfrByte
->Next
= NewByte
;
726 mLastIfrByte
= NewByte
;
732 WriteStandardFileHeader (
738 This function is invoked to emit a standard header to an
742 OutFptr - file to write the header to
750 for (TempIndex
= 0; mSourceFileHeader
[TempIndex
] != NULL
; TempIndex
++) {
751 fprintf (OutFptr
, "%s\n", mSourceFileHeader
[TempIndex
]);
754 // Write out the VFR compiler version
756 fprintf (OutFptr
, "// VFR compiler version " VFR_COMPILER_VERSION
"\n//\n");