3 Copyright (c) 2004 - 2010, Intel Corporation. All rights reserved.<BR>
4 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 "EfiUtilityMsgs.h"
28 #include "VfrServices.h"
30 #include EFI_PROTOCOL_DEFINITION (Hii)
32 static const char *mSourceFileHeader
[] = {
34 "// DO NOT EDIT -- auto-generated file",
36 "// This file is generated by the VFR compiler.",
47 // Create a table that can be used to do internal checking on the IFR
50 static const IFR_OPCODE_SIZES mOpcodeSizes
[] = {
52 { "EFI_IFR_FORM", sizeof (EFI_IFR_FORM
) },
53 { "EFI_IFR_SUBTITLE", sizeof (EFI_IFR_SUBTITLE
) },
54 { "EFI_IFR_TEXT", -6 }, //sizeof (EFI_IFR_TEXT) },
55 { "unused 0x04 opcode", 0 }, // EFI_IFR_GRAPHIC_OP
56 { "EFI_IFR_ONE_OF", sizeof (EFI_IFR_ONE_OF
) },
57 { "EFI_IFR_CHECK_BOX", sizeof (EFI_IFR_CHECK_BOX
) },
58 { "EFI_IFR_NUMERIC", sizeof (EFI_IFR_NUMERIC
) },
59 { "EFI_IFR_PASSWORD", sizeof (EFI_IFR_PASSWORD
) },
60 { "EFI_IFR_ONE_OF_OPTION", sizeof (EFI_IFR_ONE_OF_OPTION
) },
61 { "EFI_IFR_SUPPRESS", sizeof (EFI_IFR_SUPPRESS
) },
62 { "EFI_IFR_END_FORM", sizeof (EFI_IFR_END_FORM
) },
63 { "EFI_IFR_HIDDEN", sizeof (EFI_IFR_HIDDEN
) },
64 { "EFI_IFR_END_FORM_SET", sizeof (EFI_IFR_END_FORM_SET
) },
65 { "EFI_IFR_FORM_SET", sizeof (EFI_IFR_FORM_SET
) },
66 { "EFI_IFR_REF", sizeof (EFI_IFR_REF
) },
67 { "EFI_IFR_END_ONE_OF", sizeof (EFI_IFR_END_ONE_OF
) },
68 { "EFI_IFR_INCONSISTENT", sizeof (EFI_IFR_INCONSISTENT
) },
69 { "EFI_IFR_EQ_ID_VAL", sizeof (EFI_IFR_EQ_ID_VAL
) },
70 { "EFI_IFR_EQ_ID_ID", sizeof (EFI_IFR_EQ_ID_ID
) },
71 { "EFI_IFR_EQ_ID_LIST", -sizeof (EFI_IFR_EQ_ID_LIST
) },
72 { "EFI_IFR_AND", sizeof (EFI_IFR_AND
) },
73 { "EFI_IFR_OR", sizeof (EFI_IFR_OR
) },
74 { "EFI_IFR_NOT", sizeof (EFI_IFR_NOT
) },
75 { "EFI_IFR_END_IF", sizeof (EFI_IFR_END_IF
) },
76 { "EFI_IFR_GRAYOUT", sizeof (EFI_IFR_GRAYOUT
) },
77 { "EFI_IFR_DATE", sizeof (EFI_IFR_DATE
) / 3 },
78 { "EFI_IFR_TIME", sizeof (EFI_IFR_TIME
) / 3 },
79 { "EFI_IFR_STRING", sizeof (EFI_IFR_STRING
) },
80 { "EFI_IFR_LABEL", sizeof (EFI_IFR_LABEL
) },
81 { "EFI_IFR_SAVE_DEFAULTS", sizeof (EFI_IFR_SAVE_DEFAULTS
) },
82 { "EFI_IFR_RESTORE_DEFAULTS", sizeof (EFI_IFR_RESTORE_DEFAULTS
) },
83 { "EFI_IFR_BANNER", sizeof (EFI_IFR_BANNER
) },
84 { "EFI_IFR_INVENTORY", sizeof (EFI_IFR_INVENTORY
) },
85 { "EFI_IFR_EQ_VAR_VAL_OP", sizeof (EFI_IFR_EQ_VAR_VAL
) },
86 { "EFI_IFR_ORDERED_LIST_OP", sizeof (EFI_IFR_ORDERED_LIST
) },
87 { "EFI_IFR_VARSTORE_OP", -sizeof (EFI_IFR_VARSTORE
) },
88 { "EFI_IFR_VARSTORE_SELECT_OP", sizeof (EFI_IFR_VARSTORE_SELECT
) },
89 { "EFI_IFR_VARSTORE_SELECT_PAIR_OP", sizeof (EFI_IFR_VARSTORE_SELECT_PAIR
) },
90 { "EFI_IFR_TRUE", sizeof (EFI_IFR_TRUE
)},
91 { "EFI_IFR_FALSE", sizeof (EFI_IFR_FALSE
)},
92 { "EFI_IFR_GT", sizeof (EFI_IFR_GT
)},
93 { "EFI_IFR_GE", sizeof (EFI_IFR_GE
)},
94 { "EFI_IFR_OEM_DEFINED_OP", -2 },
98 VfrOpcodeHandler::VfrOpcodeHandler (
103 Constructor for the VFR opcode handling class.
116 mQueuedByteCount
= 0;
117 mQueuedOpcodeByteValid
= 0;
118 mPrimaryVarStoreId
= 0;
119 mSecondaryVarStoreId
= 0;
120 mSecondaryVarStoreIdSet
= 0;
121 mPrimaryVarStoreIdSet
= 0;
122 mDefaultVarStoreId
= 0;
126 VfrOpcodeHandler::SetVarStoreId (
132 This function is invoked by the parser when a variable is referenced in the
133 VFR. Save the variable store (and set a flag) so that we can later determine
134 if we need to emit a varstore-select or varstore-select-pair opcode.
137 VarStoreId - ID of the variable store referenced in the VFR
144 mPrimaryVarStoreId
= VarStoreId
;
145 mPrimaryVarStoreIdSet
= 1;
149 VfrOpcodeHandler::SetSecondaryVarStoreId (
155 This function is invoked by the parser when a secondary variable is
156 referenced in the VFR. Save the variable store (and set a flag) so
157 that we can later determine if we need to emit a varstore-select or
158 varstore-pair opcode.
161 VarStoreId - ID of the variable store referenced in the VFR
168 mSecondaryVarStoreId
= VarStoreId
;
169 mSecondaryVarStoreIdSet
= 1;
173 VfrOpcodeHandler::WriteIfrBytes (
178 This function is invoked at the end of parsing. Its purpose
179 is to write out all the IFR bytes that were queued up while
196 INT8 Line
[MAX_LINE_LEN
];
201 EFI_HII_IFR_PACK_HEADER IfrHeader
;
204 UINT32 BytesLeftThisOpcode
;
206 // If someone added a new opcode and didn't update our opcode sizes structure, error out.
208 if (sizeof(mOpcodeSizes
) / sizeof (mOpcodeSizes
[0]) != EFI_IFR_LAST_OPCODE
+ 1) {
209 Error (__FILE__
, __LINE__
, 0, "application error", "internal IFR binary table size is incorrect");
217 // If there have been any errors to this point, then skip dumping the IFR
218 // binary data. This way doing an nmake again will try to build it again, and
219 // the build will fail if they did not fix the problem.
221 if (GetUtilityStatus () != STATUS_ERROR
) {
222 if ((IfrBinFptr
= fopen (gOptions
.IfrOutputFileName
, "w")) == NULL
) {
223 Error (UTILITY_NAME
, 0, 0, gOptions
.IfrOutputFileName
, "could not open file for writing");
227 // Write the standard file header to the output file
229 WriteStandardFileHeader (IfrBinFptr
);
231 // Write the structure header
233 fprintf (IfrBinFptr
, "\nunsigned char %sBin[] = {", gOptions
.VfrBaseFileName
);
237 memset ((char *)&IfrHeader
, 0, sizeof (IfrHeader
));
238 IfrHeader
.Header
.Type
= EFI_HII_IFR
;
239 IfrHeader
.Header
.Length
= mBytesWritten
+ sizeof (IfrHeader
);
240 Ptr
= (UINT8
*)&IfrHeader
;
241 for (Count
= 0; Count
< sizeof (IfrHeader
); Count
++, Ptr
++) {
242 if ((Count
& 0x03) == 0) {
243 fprintf (IfrBinFptr
, "\n ");
245 fprintf (IfrBinFptr
, "0x%02X, ", *Ptr
);
249 // Write all the IFR bytes
251 fprintf (IfrBinFptr
, "\n // start of IFR data");
254 while (Curr
!= NULL
) {
255 if ((Count
& 0x0F) == 0) {
256 fprintf (IfrBinFptr
, "\n ");
258 if (Curr
->KeyByte
!= 0) {
259 fprintf (IfrBinFptr
, "/*%c*/ ", Curr
->KeyByte
);
261 fprintf (IfrBinFptr
, "0x%02X, ", Curr
->OpcodeByte
);
265 fprintf (IfrBinFptr
, "\n};\n\n");
274 // Write the bytes as binary data if the user specified to do so
276 if ((GetUtilityStatus () != STATUS_ERROR
) && (gOptions
.CreateIfrBinFile
!= 0)) {
278 // Use the Ifr output file name with a ".hpk" extension.
280 for (Cptr
= gOptions
.IfrOutputFileName
+ strlen (gOptions
.IfrOutputFileName
) - 1;
281 (*Cptr
!= '.') && (Cptr
> gOptions
.IfrOutputFileName
) && (*Cptr
!= '\\');
288 strcpy (Cptr
, ".hpk");
290 strcat (gOptions
.IfrOutputFileName
, ".hpk");
292 if ((IfrBinFptr
= fopen (gOptions
.IfrOutputFileName
, "wb")) == NULL
) {
293 Error (UTILITY_NAME
, 0, 0, gOptions
.IfrOutputFileName
, "could not open file for writing");
297 // Write the structure header
299 memset ((char *)&IfrHeader
, 0, sizeof (IfrHeader
));
300 IfrHeader
.Header
.Type
= EFI_HII_IFR
;
301 IfrHeader
.Header
.Length
= mBytesWritten
+ sizeof (IfrHeader
);
302 Ptr
= (UINT8
*)&IfrHeader
;
303 for (Count
= 0; Count
< sizeof (IfrHeader
); Count
++, Ptr
++) {
304 fwrite (Ptr
, 1, 1, IfrBinFptr
);
308 // Write all the IFR bytes
312 while (Curr
!= NULL
) {
313 fwrite (&Curr
->OpcodeByte
, 1, 1, IfrBinFptr
);
324 // If creating a listing file, then open the input and output files
327 if (gOptions
.CreateListFile
) {
329 // Open the input VFR file and the output list file
331 if ((InFptr
= fopen (gOptions
.PreprocessorOutputFileName
, "r")) == NULL
) {
332 Warning (UTILITY_NAME
, 0, 0, gOptions
.PreprocessorOutputFileName
, "could not open file for creating a list file");
334 if ((OutFptr
= fopen (gOptions
.VfrListFileName
, "w")) == NULL
) {
335 Warning (UTILITY_NAME
, 0, 0, gOptions
.VfrListFileName
, "could not open output list file for writing");
347 // Write the list file
351 // Write out the VFR compiler version
353 fprintf (OutFptr
, "//\n// VFR compiler version " UTILITY_VERSION
"\n//\n");
355 while (Curr
!= NULL
) {
357 // Print lines until we reach the line of the current opcode
359 while (LineCount
< PoundLines
+ Curr
->LineNum
) {
360 if (fgets (Line
, sizeof (Line
), InFptr
) != NULL
) {
362 // We should check for line length exceeded on the fgets(). Otherwise it
363 // throws the listing file output off. Future enhancement perhaps.
365 fprintf (OutFptr
, "%s", Line
);
366 if (strncmp (Line
, "#line", 5) == 0) {
373 // Print all opcodes with line numbers less than where we are now
375 BytesLeftThisOpcode
= 0;
376 while ((Curr
!= NULL
) && ((Curr
->LineNum
== 0) || (LineCount
>= PoundLines
+ Curr
->LineNum
))) {
377 if (BytesLeftThisOpcode
== 0) {
378 fprintf (OutFptr
, ">%08X: ", ByteCount
);
379 if (Curr
->Next
!= NULL
) {
380 BytesLeftThisOpcode
= (UINT32
)Curr
->Next
->OpcodeByte
;
383 fprintf (OutFptr
, "%02X ", (UINT32
)Curr
->OpcodeByte
);
385 BytesLeftThisOpcode
--;
386 if (BytesLeftThisOpcode
== 0) {
387 fprintf (OutFptr
, "\n");
393 // Dump any remaining lines from the input file
395 while (fgets (Line
, sizeof (Line
), InFptr
) != NULL
) {
396 fprintf (OutFptr
, "%s", Line
);
402 // Debug code to make sure that each opcode we write out has as many
403 // bytes as the IFR structure requires. If there were errors, then
404 // don't do this step.
406 if (GetUtilityStatus () != STATUS_ERROR
) {
409 while (Curr
!= NULL
) {
411 // First byte is the opcode, second byte is the length
413 if (Curr
->Next
== NULL
) {
414 Error (__FILE__
, __LINE__
, 0, "application error", "last opcode written does not contain a length byte");
417 Count
= (UINT32
)Curr
->Next
->OpcodeByte
;
424 "opcode with 0 length specified in output at offset 0x%X",
432 if ((Curr
->OpcodeByte
> EFI_IFR_LAST_OPCODE
) || (Curr
->OpcodeByte
== 0)) {
438 "invalid opcode 0x%X in output at offset 0x%X",
439 (UINT32
) Curr
->OpcodeByte
, ByteCount
441 } else if (mOpcodeSizes
[Curr
->OpcodeByte
].Size
< 0) {
443 // For those cases where the length is variable, the size is negative, and indicates
444 // the miniumum size.
446 if ((mOpcodeSizes
[Curr
->OpcodeByte
].Size
* -1) > Count
) {
452 "insufficient number of bytes written for %s at offset 0x%X",
453 mOpcodeSizes
[Curr
->OpcodeByte
].Name
,
461 if (mOpcodeSizes
[Curr
->OpcodeByte
].Size
== 0) {
467 "invalid opcode 0x%X in output at offset 0x%X",
468 (UINT32
)Curr
->OpcodeByte
,
475 if (mOpcodeSizes
[Curr
->OpcodeByte
].Size
!= Count
) {
481 "invalid number of bytes (%d written s/b %d) written for %s at offset 0x%X",
483 mOpcodeSizes
[Curr
->OpcodeByte
].Size
,
484 mOpcodeSizes
[Curr
->OpcodeByte
].Name
,
491 // Skip to next opcode
496 Error (__FILE__
, __LINE__
, 0, "application error", "last opcode written has invalid length");
506 VfrOpcodeHandler::~VfrOpcodeHandler(
511 Destructor for the VFR opcode handler. Free up memory allocated
512 while parsing the VFR script.
525 // Free up the IFR bytes
528 while (Curr
!= NULL
) {
536 VfrOpcodeHandler::AddOpcodeByte (
543 This function is invoked by the parser when a new IFR
544 opcode should be emitted.
547 OpcodeByte - the IFR opcode
548 LineNum - the line number from the source file that resulted
549 in the opcode being emitted.
560 // Now add this new byte
562 mQueuedOpcodeByte
= OpcodeByte
;
563 mQueuedLineNum
= LineNum
;
564 mQueuedOpcodeByteValid
= 1;
569 VfrOpcodeHandler::AddByte (
576 This function is invoked by the parser when it determines
577 that more raw IFR bytes should be emitted to the output stream.
578 Here we just queue them up into an output buffer.
581 ByteVal - the raw byte to emit to the output IFR stream
582 KeyByte - a value that can be used for debug.
590 // Check for buffer overflow
592 if (mQueuedByteCount
>= MAX_QUEUE_COUNT
) {
593 Error (UTILITY_NAME
, 0, 0, NULL
, "opcode queue overflow");
595 mQueuedBytes
[mQueuedByteCount
] = ByteVal
;
596 mQueuedKeyBytes
[mQueuedByteCount
] = KeyByte
;
602 VfrOpcodeHandler::FlushQueue (
607 This function is invoked to flush the internal IFR buffer.
618 UINT32 EmitNoneOnePair
;
622 // If the secondary varstore was specified, then we have to emit
623 // a varstore-select-pair opcode, which only applies to the following
626 if (mSecondaryVarStoreIdSet
) {
627 mSecondaryVarStoreIdSet
= 0;
629 // If primary and secondary are the same as the current default
630 // varstore, then we don't have to do anything.
631 // Note that the varstore-select-pair only applies to the following
634 if ((mPrimaryVarStoreId
!= mSecondaryVarStoreId
) || (mPrimaryVarStoreId
!= mDefaultVarStoreId
)) {
635 IAddByte (EFI_IFR_VARSTORE_SELECT_PAIR_OP
, 'O', mQueuedLineNum
);
636 IAddByte ((UINT8
)sizeof (EFI_IFR_VARSTORE_SELECT_PAIR
), 'L', 0);
637 IAddByte ((UINT8
)mPrimaryVarStoreId
, 0, 0);
638 IAddByte ((UINT8
)(mPrimaryVarStoreId
>> 8), 0, 0);
639 IAddByte ((UINT8
)mSecondaryVarStoreId
, 0, 0);
640 IAddByte ((UINT8
)(mSecondaryVarStoreId
>> 8), 0, 0);
642 } else if (mPrimaryVarStoreIdSet
!= 0) {
643 mPrimaryVarStoreIdSet
= 0;
644 if (mDefaultVarStoreId
!= mPrimaryVarStoreId
) {
646 // The VFR statement referenced a different variable store
647 // than the last one we reported. Insert a new varstore select
650 IAddByte (EFI_IFR_VARSTORE_SELECT_OP
, 'O', mQueuedLineNum
);
651 IAddByte ((UINT8
)sizeof (EFI_IFR_VARSTORE_SELECT
), 'L', 0);
652 IAddByte ((UINT8
)mPrimaryVarStoreId
, 0, 0);
653 IAddByte ((UINT8
)(mPrimaryVarStoreId
>> 8), 0, 0);
654 mDefaultVarStoreId
= mPrimaryVarStoreId
;
658 // Likely a new opcode is being added. Since each opcode item in the IFR has
659 // a header that specifies the size of the opcode item (which we don't
660 // know until we find the next opcode in the VFR), we queue up bytes
661 // until we know the size. Then we write them out. So flush the queue
664 if (mQueuedOpcodeByteValid
!= 0) {
666 // Add the previous opcode byte, the length byte, and the binary
669 IAddByte (mQueuedOpcodeByte
, 'O', mQueuedLineNum
);
670 IAddByte ((UINT8
)(mQueuedByteCount
+ 2), 'L', 0);
671 for (Count
= 0; Count
< mQueuedByteCount
; Count
++) {
672 IAddByte (mQueuedBytes
[Count
], mQueuedKeyBytes
[Count
], 0);
674 mQueuedByteCount
= 0;
675 mQueuedOpcodeByteValid
= 0;
681 VfrOpcodeHandler::IAddByte (
689 This internal function is used to add actual IFR bytes to
690 the output stream. Most other functions queue up the bytes
691 in an internal buffer. Once they come here, there's no
696 ByteVal - value to write to output
697 KeyByte - key value tied to the byte -- useful for debug
698 LineNum - line number from source file the byte resulted from
702 1 - failed due to memory allocation failure
707 NewByte
= (IFR_BYTE
*)malloc (sizeof (IFR_BYTE
));
708 if (NewByte
== NULL
) {
711 memset ((char *)NewByte
, 0, sizeof (IFR_BYTE
));
712 NewByte
->OpcodeByte
= ByteVal
;
713 NewByte
->KeyByte
= KeyByte
;
714 NewByte
->LineNum
= LineNum
;
718 if (mIfrBytes
== NULL
) {
721 mLastIfrByte
->Next
= NewByte
;
723 mLastIfrByte
= NewByte
;
729 WriteStandardFileHeader (
735 This function is invoked to emit a standard header to an
739 OutFptr - file to write the header to
747 for (TempIndex
= 0; mSourceFileHeader
[TempIndex
] != NULL
; TempIndex
++) {
748 fprintf (OutFptr
, "%s\n", mSourceFileHeader
[TempIndex
]);
751 // Write out the VFR compiler version
753 fprintf (OutFptr
, "// VFR compiler version " UTILITY_VERSION
"\n//\n");