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()
25 #include <Common/UefiBaseTypes.h>
26 #include <Common/MultiPhase.h>
27 #include <Common/InternalFormRepresentation.h>
28 #include <Protocol/UgaDraw.h> // for EFI_UGA_PIXEL definition
29 #include <Protocol/Hii.h>
31 #include "EfiUtilityMsgs.h"
33 #include "VfrServices.h"
36 static const char *mSourceFileHeader
[] = {
38 "// DO NOT EDIT -- auto-generated file",
40 "// This file is generated by the VFR compiler.",
51 // Create a table that can be used to do internal checking on the IFR
54 static const IFR_OPCODE_SIZES mOpcodeSizes
[] = {
56 { "EFI_IFR_FORM", sizeof (EFI_IFR_FORM
) },
57 { "EFI_IFR_SUBTITLE", sizeof (EFI_IFR_SUBTITLE
) },
58 { "EFI_IFR_TEXT", -6 }, //sizeof (EFI_IFR_TEXT) },
59 { "unused 0x04 opcode", 0 }, // EFI_IFR_GRAPHIC_OP
60 { "EFI_IFR_ONE_OF", sizeof (EFI_IFR_ONE_OF
) },
61 { "EFI_IFR_CHECKBOX", sizeof (EFI_IFR_CHECKBOX
) },
62 { "EFI_IFR_NUMERIC", sizeof (EFI_IFR_NUMERIC
) },
63 { "EFI_IFR_PASSWORD", sizeof (EFI_IFR_PASSWORD
) },
64 { "EFI_IFR_ONE_OF_OPTION", sizeof (EFI_IFR_ONE_OF_OPTION
) },
65 { "EFI_IFR_SUPPRESS", sizeof (EFI_IFR_SUPPRESS
) },
66 { "EFI_IFR_END_FORM", sizeof (EFI_IFR_END_FORM
) },
67 { "EFI_IFR_HIDDEN", sizeof (EFI_IFR_HIDDEN
) },
68 { "EFI_IFR_END_FORM_SET", sizeof (EFI_IFR_END_FORM_SET
) },
69 { "EFI_IFR_FORM_SET", sizeof (EFI_IFR_FORM_SET
) },
70 { "EFI_IFR_REF", sizeof (EFI_IFR_REF
) },
71 { "EFI_IFR_END_ONE_OF", sizeof (EFI_IFR_END_ONE_OF
) },
72 { "EFI_IFR_INCONSISTENT", sizeof (EFI_IFR_INCONSISTENT
) },
73 { "EFI_IFR_EQ_ID_VAL", sizeof (EFI_IFR_EQ_ID_VAL
) },
74 { "EFI_IFR_EQ_ID_ID", sizeof (EFI_IFR_EQ_ID_ID
) },
75 { "EFI_IFR_EQ_ID_LIST", -sizeof (EFI_IFR_EQ_ID_LIST
) },
76 { "EFI_IFR_AND", sizeof (EFI_IFR_AND
) },
77 { "EFI_IFR_OR", sizeof (EFI_IFR_OR
) },
78 { "EFI_IFR_NOT", sizeof (EFI_IFR_NOT
) },
79 { "EFI_IFR_END_EXPR", sizeof (EFI_IFR_END_EXPR
) },
80 { "EFI_IFR_GRAY_OUT", sizeof (EFI_IFR_GRAY_OUT
) },
81 { "EFI_IFR_DATE", sizeof (EFI_IFR_DATE
) / 3 },
82 { "EFI_IFR_TIME", sizeof (EFI_IFR_TIME
) / 3 },
83 { "EFI_IFR_STRING", sizeof (EFI_IFR_STRING
) },
84 { "EFI_IFR_LABEL", sizeof (EFI_IFR_LABEL
) },
85 { "EFI_IFR_SAVE_DEFAULTS", sizeof (EFI_IFR_SAVE_DEFAULTS
) },
86 { "EFI_IFR_RESTORE_DEFAULTS", sizeof (EFI_IFR_RESTORE_DEFAULTS
) },
87 { "EFI_IFR_BANNER", sizeof (EFI_IFR_BANNER
) },
88 { "EFI_IFR_INVENTORY", sizeof (EFI_IFR_INVENTORY
) },
89 { "EFI_IFR_EQ_VAR_VAL_OP", sizeof (EFI_IFR_EQ_VAR_VAL
) },
90 { "EFI_IFR_ORDERED_LIST_OP", sizeof (EFI_IFR_ORDERED_LIST
) },
91 { "EFI_IFR_VARSTORE_OP", -sizeof (EFI_IFR_VARSTORE
) },
92 { "EFI_IFR_VARSTORE_SELECT_OP", sizeof (EFI_IFR_VARSTORE_SELECT
) },
93 { "EFI_IFR_VARSTORE_SELECT_PAIR_OP", sizeof (EFI_IFR_VARSTORE_SELECT_PAIR
) },
94 { "EFI_IFR_TRUE", sizeof (EFI_IFR_TRUE
)},
95 { "EFI_IFR_FALSE", sizeof (EFI_IFR_FALSE
)},
96 { "EFI_IFR_GT", sizeof (EFI_IFR_GT
)},
97 { "EFI_IFR_GE", sizeof (EFI_IFR_GE
)},
98 { "EFI_IFR_OEM_DEFINED_OP", -2 },
102 VfrOpcodeHandler::VfrOpcodeHandler (
107 Constructor for the VFR opcode handling class.
120 mQueuedByteCount
= 0;
121 mQueuedOpcodeByteValid
= 0;
122 mPrimaryVarStoreId
= 0;
123 mSecondaryVarStoreId
= 0;
124 mSecondaryVarStoreIdSet
= 0;
125 mPrimaryVarStoreIdSet
= 0;
126 mDefaultVarStoreId
= 0;
130 VfrOpcodeHandler::SetVarStoreId (
136 This function is invoked by the parser when a variable is referenced in the
137 VFR. Save the variable store (and set a flag) so that we can later determine
138 if we need to emit a varstore-select or varstore-select-pair opcode.
141 VarStoreId - ID of the variable store referenced in the VFR
148 mPrimaryVarStoreId
= VarStoreId
;
149 mPrimaryVarStoreIdSet
= 1;
153 VfrOpcodeHandler::SetSecondaryVarStoreId (
159 This function is invoked by the parser when a secondary variable is
160 referenced in the VFR. Save the variable store (and set a flag) so
161 that we can later determine if we need to emit a varstore-select or
162 varstore-pair opcode.
165 VarStoreId - ID of the variable store referenced in the VFR
172 mSecondaryVarStoreId
= VarStoreId
;
173 mSecondaryVarStoreIdSet
= 1;
177 VfrOpcodeHandler::WriteIfrBytes (
182 This function is invoked at the end of parsing. Its purpose
183 is to write out all the IFR bytes that were queued up while
200 CHAR8 Line
[MAX_LINE_LEN
];
205 EFI_HII_IFR_PACK_HEADER IfrHeader
;
208 UINT32 BytesLeftThisOpcode
;
210 // If someone added a new opcode and didn't update our opcode sizes structure, error out.
212 if (sizeof(mOpcodeSizes
) / sizeof (mOpcodeSizes
[0]) != EFI_IFR_LAST_OPCODE
+ 1) {
213 Error (__FILE__
, __LINE__
, 0, "application error", "internal IFR binary table size is incorrect");
221 // If there have been any errors to this point, then skip dumping the IFR
222 // binary data. This way doing an nmake again will try to build it again, and
223 // the build will fail if they did not fix the problem.
225 if (GetUtilityStatus () != STATUS_ERROR
) {
226 if ((IfrBinFptr
= fopen (gOptions
.IfrOutputFileName
, "w")) == NULL
) {
227 Error (PROGRAM_NAME
, 0, 0, gOptions
.IfrOutputFileName
, "could not open file for writing");
231 // Write the standard file header to the output file
233 WriteStandardFileHeader (IfrBinFptr
);
235 // Write the structure header
237 fprintf (IfrBinFptr
, "\nunsigned char %sBin[] = {", gOptions
.VfrBaseFileName
);
241 memset ((char *)&IfrHeader
, 0, sizeof (IfrHeader
));
242 IfrHeader
.Header
.Type
= EFI_HII_IFR
;
243 IfrHeader
.Header
.Length
= mBytesWritten
+ sizeof (IfrHeader
);
244 Ptr
= (UINT8
*)&IfrHeader
;
245 for (Count
= 0; Count
< sizeof (IfrHeader
); Count
++, Ptr
++) {
246 if ((Count
& 0x03) == 0) {
247 fprintf (IfrBinFptr
, "\n ");
249 fprintf (IfrBinFptr
, "0x%02X, ", *Ptr
);
253 // Write all the IFR bytes
255 fprintf (IfrBinFptr
, "\n // start of IFR data");
258 while (Curr
!= NULL
) {
259 if ((Count
& 0x0F) == 0) {
260 fprintf (IfrBinFptr
, "\n ");
262 if (Curr
->KeyByte
!= 0) {
263 fprintf (IfrBinFptr
, "/*%c*/ ", Curr
->KeyByte
);
265 fprintf (IfrBinFptr
, "0x%02X, ", Curr
->OpcodeByte
);
269 fprintf (IfrBinFptr
, "\n};\n\n");
278 // Write the bytes as binary data if the user specified to do so
280 if ((GetUtilityStatus () != STATUS_ERROR
) && (gOptions
.CreateIfrBinFile
!= 0)) {
282 // Use the Ifr output file name with a ".hpk" extension.
284 for (Cptr
= gOptions
.IfrOutputFileName
+ strlen (gOptions
.IfrOutputFileName
) - 1;
285 (*Cptr
!= '.') && (Cptr
> gOptions
.IfrOutputFileName
) && (*Cptr
!= '\\');
292 strcpy (Cptr
, ".hpk");
294 strcat (gOptions
.IfrOutputFileName
, ".hpk");
296 if ((IfrBinFptr
= fopen (gOptions
.IfrOutputFileName
, "wb")) == NULL
) {
297 Error (PROGRAM_NAME
, 0, 0, gOptions
.IfrOutputFileName
, "could not open file for writing");
301 // Write the structure header
303 memset ((char *)&IfrHeader
, 0, sizeof (IfrHeader
));
304 IfrHeader
.Header
.Type
= EFI_HII_IFR
;
305 IfrHeader
.Header
.Length
= mBytesWritten
+ sizeof (IfrHeader
);
306 Ptr
= (UINT8
*)&IfrHeader
;
307 for (Count
= 0; Count
< sizeof (IfrHeader
); Count
++, Ptr
++) {
308 fwrite (Ptr
, 1, 1, IfrBinFptr
);
312 // Write all the IFR bytes
316 while (Curr
!= NULL
) {
317 fwrite (&Curr
->OpcodeByte
, 1, 1, IfrBinFptr
);
328 // If creating a listing file, then open the input and output files
331 if (gOptions
.CreateListFile
) {
333 // Open the input VFR file and the output list file
335 if ((InFptr
= fopen (gOptions
.VfrFileName
, "r")) == NULL
) {
336 Warning (PROGRAM_NAME
, 0, 0, gOptions
.VfrFileName
, "could not open file for creating a list file");
338 if ((OutFptr
= fopen (gOptions
.VfrListFileName
, "w")) == NULL
) {
339 Warning (PROGRAM_NAME
, 0, 0, gOptions
.VfrListFileName
, "could not open output list file for writing");
351 // Write the list file
355 // Write out the VFR compiler version
357 fprintf (OutFptr
, "//\n// VFR compiler version " VFR_COMPILER_VERSION
"\n//\n");
359 while (Curr
!= NULL
) {
361 // Print lines until we reach the line of the current opcode
363 while (LineCount
< PoundLines
+ Curr
->LineNum
) {
364 if (fgets (Line
, sizeof (Line
), InFptr
) != NULL
) {
366 // We should check for line length exceeded on the fgets(). Otherwise it
367 // throws the listing file output off. Future enhancement perhaps.
369 fprintf (OutFptr
, "%s", Line
);
370 if (strncmp (Line
, "#line", 5) == 0) {
377 // Print all opcodes with line numbers less than where we are now
379 BytesLeftThisOpcode
= 0;
380 while ((Curr
!= NULL
) && ((Curr
->LineNum
== 0) || (LineCount
>= PoundLines
+ Curr
->LineNum
))) {
381 if (BytesLeftThisOpcode
== 0) {
382 fprintf (OutFptr
, ">%08X: ", ByteCount
);
383 if (Curr
->Next
!= NULL
) {
384 BytesLeftThisOpcode
= (UINT32
)Curr
->Next
->OpcodeByte
;
387 fprintf (OutFptr
, "%02X ", (UINT32
)Curr
->OpcodeByte
);
389 BytesLeftThisOpcode
--;
390 if (BytesLeftThisOpcode
== 0) {
391 fprintf (OutFptr
, "\n");
397 // Dump any remaining lines from the input file
399 while (fgets (Line
, sizeof (Line
), InFptr
) != NULL
) {
400 fprintf (OutFptr
, "%s", Line
);
406 // Debug code to make sure that each opcode we write out has as many
407 // bytes as the IFR structure requires. If there were errors, then
408 // don't do this step.
410 if (GetUtilityStatus () != STATUS_ERROR
) {
413 while (Curr
!= NULL
) {
415 // First byte is the opcode, second byte is the length
417 if (Curr
->Next
== NULL
) {
418 Error (__FILE__
, __LINE__
, 0, "application error", "last opcode written does not contain a length byte");
421 Count
= (UINT32
)Curr
->Next
->OpcodeByte
;
428 "opcode with 0 length specified in output at offset 0x%X",
436 if ((Curr
->OpcodeByte
> EFI_IFR_LAST_OPCODE
) || (Curr
->OpcodeByte
== 0)) {
442 "invalid opcode 0x%X in output at offset 0x%X",
443 (UINT32
) Curr
->OpcodeByte
, ByteCount
445 } else if (mOpcodeSizes
[Curr
->OpcodeByte
].Size
< 0) {
447 // For those cases where the length is variable, the size is negative, and indicates
448 // the miniumum size.
450 if ((mOpcodeSizes
[Curr
->OpcodeByte
].Size
* -1) > Count
) {
456 "insufficient number of bytes written for %s at offset 0x%X",
457 mOpcodeSizes
[Curr
->OpcodeByte
].Name
,
465 if (mOpcodeSizes
[Curr
->OpcodeByte
].Size
== 0) {
471 "invalid opcode 0x%X in output at offset 0x%X",
472 (UINT32
)Curr
->OpcodeByte
,
479 if (mOpcodeSizes
[Curr
->OpcodeByte
].Size
!= Count
) {
485 "invalid number of bytes (%d written s/b %d) written for %s at offset 0x%X",
487 mOpcodeSizes
[Curr
->OpcodeByte
].Size
,
488 mOpcodeSizes
[Curr
->OpcodeByte
].Name
,
495 // Skip to next opcode
500 Error (__FILE__
, __LINE__
, 0, "application error", "last opcode written has invalid length");
510 VfrOpcodeHandler::~VfrOpcodeHandler(
515 Destructor for the VFR opcode handler. Free up memory allocated
516 while parsing the VFR script.
529 // Free up the IFR bytes
532 while (Curr
!= NULL
) {
540 VfrOpcodeHandler::AddOpcodeByte (
547 This function is invoked by the parser when a new IFR
548 opcode should be emitted.
551 OpcodeByte - the IFR opcode
552 LineNum - the line number from the source file that resulted
553 in the opcode being emitted.
564 // Now add this new byte
566 mQueuedOpcodeByte
= OpcodeByte
;
567 mQueuedLineNum
= LineNum
;
568 mQueuedOpcodeByteValid
= 1;
573 VfrOpcodeHandler::AddByte (
580 This function is invoked by the parser when it determines
581 that more raw IFR bytes should be emitted to the output stream.
582 Here we just queue them up into an output buffer.
585 ByteVal - the raw byte to emit to the output IFR stream
586 KeyByte - a value that can be used for debug.
594 // Check for buffer overflow
596 if (mQueuedByteCount
> MAX_QUEUE_COUNT
) {
597 Error (PROGRAM_NAME
, 0, 0, NULL
, "opcode queue overflow");
599 mQueuedBytes
[mQueuedByteCount
] = ByteVal
;
600 mQueuedKeyBytes
[mQueuedByteCount
] = KeyByte
;
606 VfrOpcodeHandler::FlushQueue (
611 This function is invoked to flush the internal IFR buffer.
622 UINT32 EmitNoneOnePair
;
626 // If the secondary varstore was specified, then we have to emit
627 // a varstore-select-pair opcode, which only applies to the following
630 if (mSecondaryVarStoreIdSet
) {
631 mSecondaryVarStoreIdSet
= 0;
633 // If primary and secondary are the same as the current default
634 // varstore, then we don't have to do anything.
635 // Note that the varstore-select-pair only applies to the following
638 if ((mPrimaryVarStoreId
!= mSecondaryVarStoreId
) || (mPrimaryVarStoreId
!= mDefaultVarStoreId
)) {
639 IAddByte (EFI_IFR_VARSTORE_SELECT_PAIR_OP
, 'O', mQueuedLineNum
);
640 IAddByte ((UINT8
)sizeof (EFI_IFR_VARSTORE_SELECT_PAIR
), 'L', 0);
641 IAddByte ((UINT8
)mPrimaryVarStoreId
, 0, 0);
642 IAddByte ((UINT8
)(mPrimaryVarStoreId
>> 8), 0, 0);
643 IAddByte ((UINT8
)mSecondaryVarStoreId
, 0, 0);
644 IAddByte ((UINT8
)(mSecondaryVarStoreId
>> 8), 0, 0);
646 } else if (mPrimaryVarStoreIdSet
!= 0) {
647 mPrimaryVarStoreIdSet
= 0;
648 if (mDefaultVarStoreId
!= mPrimaryVarStoreId
) {
650 // The VFR statement referenced a different variable store
651 // than the last one we reported. Insert a new varstore select
654 IAddByte (EFI_IFR_VARSTORE_SELECT_OP
, 'O', mQueuedLineNum
);
655 IAddByte ((UINT8
)sizeof (EFI_IFR_VARSTORE_SELECT
), 'L', 0);
656 IAddByte ((UINT8
)mPrimaryVarStoreId
, 0, 0);
657 IAddByte ((UINT8
)(mPrimaryVarStoreId
>> 8), 0, 0);
658 mDefaultVarStoreId
= mPrimaryVarStoreId
;
662 // Likely a new opcode is being added. Since each opcode item in the IFR has
663 // a header that specifies the size of the opcode item (which we don't
664 // know until we find the next opcode in the VFR), we queue up bytes
665 // until we know the size. Then we write them out. So flush the queue
668 if (mQueuedOpcodeByteValid
!= 0) {
670 // Add the previous opcode byte, the length byte, and the binary
673 IAddByte (mQueuedOpcodeByte
, 'O', mQueuedLineNum
);
674 IAddByte ((UINT8
)(mQueuedByteCount
+ 2), 'L', 0);
675 for (Count
= 0; Count
< mQueuedByteCount
; Count
++) {
676 IAddByte (mQueuedBytes
[Count
], mQueuedKeyBytes
[Count
], 0);
678 mQueuedByteCount
= 0;
679 mQueuedOpcodeByteValid
= 0;
685 VfrOpcodeHandler::IAddByte (
693 This internal function is used to add actual IFR bytes to
694 the output stream. Most other functions queue up the bytes
695 in an internal buffer. Once they come here, there's no
700 ByteVal - value to write to output
701 KeyByte - key value tied to the byte -- useful for debug
702 LineNum - line number from source file the byte resulted from
706 1 - failed due to memory allocation failure
711 NewByte
= (IFR_BYTE
*)malloc (sizeof (IFR_BYTE
));
712 if (NewByte
== NULL
) {
715 memset ((char *)NewByte
, 0, sizeof (IFR_BYTE
));
716 NewByte
->OpcodeByte
= ByteVal
;
717 NewByte
->KeyByte
= KeyByte
;
718 NewByte
->LineNum
= LineNum
;
722 if (mIfrBytes
== NULL
) {
725 mLastIfrByte
->Next
= NewByte
;
727 mLastIfrByte
= NewByte
;
733 WriteStandardFileHeader (
739 This function is invoked to emit a standard header to an
743 OutFptr - file to write the header to
751 for (TempIndex
= 0; mSourceFileHeader
[TempIndex
] != NULL
; TempIndex
++) {
752 fprintf (OutFptr
, "%s\n", mSourceFileHeader
[TempIndex
]);
755 // Write out the VFR compiler version
757 fprintf (OutFptr
, "// VFR compiler version " VFR_COMPILER_VERSION
"\n//\n");