| /*++ | |
| Copyright (c) 2004 - 2005, Intel Corporation | |
| All rights reserved. This program and the accompanying materials | |
| are licensed and made available under the terms and conditions of the BSD License | |
| which accompanies this distribution. The full text of the license may be found at | |
| http://opensource.org/licenses/bsd-license.php | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
| Module Name: | |
| VfrServices.cpp | |
| Abstract: | |
| Support routines for the VFR compiler | |
| --*/ | |
| #include <stdio.h> // for FILE routines | |
| #include <stdlib.h> // for malloc() and free() | |
| #include <Common/UefiBaseTypes.h> | |
| #include <Common/MultiPhase.h> | |
| #include <Common/InternalFormRepresentation.h> | |
| #include <Protocol/UgaDraw.h> // for EFI_UGA_PIXEL definition | |
| #include <Protocol/Hii.h> | |
| #include "EfiUtilityMsgs.h" | |
| #include "EfiVfr.h" | |
| #include "VfrServices.h" | |
| static const char *mSourceFileHeader[] = { | |
| "//", | |
| "// DO NOT EDIT -- auto-generated file", | |
| "//", | |
| "// This file is generated by the VFR compiler.", | |
| "//", | |
| NULL | |
| }; | |
| typedef struct { | |
| CHAR8 *Name; | |
| INT32 Size; | |
| } IFR_OPCODE_SIZES; | |
| // | |
| // Create a table that can be used to do internal checking on the IFR | |
| // bytes we emit. | |
| // | |
| static const IFR_OPCODE_SIZES mOpcodeSizes[] = { | |
| { 0, 0 }, // invalid | |
| { "EFI_IFR_FORM", sizeof (EFI_IFR_FORM) }, | |
| { "EFI_IFR_SUBTITLE", sizeof (EFI_IFR_SUBTITLE) }, | |
| { "EFI_IFR_TEXT", -6 }, //sizeof (EFI_IFR_TEXT) }, | |
| { "unused 0x04 opcode", 0 }, // EFI_IFR_GRAPHIC_OP | |
| { "EFI_IFR_ONE_OF", sizeof (EFI_IFR_ONE_OF) }, | |
| { "EFI_IFR_CHECKBOX", sizeof (EFI_IFR_CHECKBOX) }, | |
| { "EFI_IFR_NUMERIC", sizeof (EFI_IFR_NUMERIC) }, | |
| { "EFI_IFR_PASSWORD", sizeof (EFI_IFR_PASSWORD) }, | |
| { "EFI_IFR_ONE_OF_OPTION", sizeof (EFI_IFR_ONE_OF_OPTION) }, | |
| { "EFI_IFR_SUPPRESS", sizeof (EFI_IFR_SUPPRESS) }, | |
| { "EFI_IFR_END_FORM", sizeof (EFI_IFR_END_FORM) }, | |
| { "EFI_IFR_HIDDEN", sizeof (EFI_IFR_HIDDEN) }, | |
| { "EFI_IFR_END_FORM_SET", sizeof (EFI_IFR_END_FORM_SET) }, | |
| { "EFI_IFR_FORM_SET", sizeof (EFI_IFR_FORM_SET) }, | |
| { "EFI_IFR_REF", sizeof (EFI_IFR_REF) }, | |
| { "EFI_IFR_END_ONE_OF", sizeof (EFI_IFR_END_ONE_OF) }, | |
| { "EFI_IFR_INCONSISTENT", sizeof (EFI_IFR_INCONSISTENT) }, | |
| { "EFI_IFR_EQ_ID_VAL", sizeof (EFI_IFR_EQ_ID_VAL) }, | |
| { "EFI_IFR_EQ_ID_ID", sizeof (EFI_IFR_EQ_ID_ID) }, | |
| { "EFI_IFR_EQ_ID_LIST", -sizeof (EFI_IFR_EQ_ID_LIST) }, | |
| { "EFI_IFR_AND", sizeof (EFI_IFR_AND) }, | |
| { "EFI_IFR_OR", sizeof (EFI_IFR_OR) }, | |
| { "EFI_IFR_NOT", sizeof (EFI_IFR_NOT) }, | |
| { "EFI_IFR_END_EXPR", sizeof (EFI_IFR_END_EXPR) }, | |
| { "EFI_IFR_GRAY_OUT", sizeof (EFI_IFR_GRAY_OUT) }, | |
| { "EFI_IFR_DATE", sizeof (EFI_IFR_DATE) / 3 }, | |
| { "EFI_IFR_TIME", sizeof (EFI_IFR_TIME) / 3 }, | |
| { "EFI_IFR_STRING", sizeof (EFI_IFR_STRING) }, | |
| { "EFI_IFR_LABEL", sizeof (EFI_IFR_LABEL) }, | |
| { "EFI_IFR_SAVE_DEFAULTS", sizeof (EFI_IFR_SAVE_DEFAULTS) }, | |
| { "EFI_IFR_RESTORE_DEFAULTS", sizeof (EFI_IFR_RESTORE_DEFAULTS) }, | |
| { "EFI_IFR_BANNER", sizeof (EFI_IFR_BANNER) }, | |
| { "EFI_IFR_INVENTORY", sizeof (EFI_IFR_INVENTORY) }, | |
| { "EFI_IFR_EQ_VAR_VAL_OP", sizeof (EFI_IFR_EQ_VAR_VAL) }, | |
| { "EFI_IFR_ORDERED_LIST_OP", sizeof (EFI_IFR_ORDERED_LIST) }, | |
| { "EFI_IFR_VARSTORE_OP", -sizeof (EFI_IFR_VARSTORE) }, | |
| { "EFI_IFR_VARSTORE_SELECT_OP", sizeof (EFI_IFR_VARSTORE_SELECT) }, | |
| { "EFI_IFR_VARSTORE_SELECT_PAIR_OP", sizeof (EFI_IFR_VARSTORE_SELECT_PAIR) }, | |
| { "EFI_IFR_TRUE", sizeof (EFI_IFR_TRUE)}, | |
| { "EFI_IFR_FALSE", sizeof (EFI_IFR_FALSE)}, | |
| { "EFI_IFR_GT", sizeof (EFI_IFR_GT)}, | |
| { "EFI_IFR_GE", sizeof (EFI_IFR_GE)}, | |
| { "EFI_IFR_OEM_DEFINED_OP", -2 }, | |
| }; | |
| VfrOpcodeHandler::VfrOpcodeHandler ( | |
| ) | |
| /*++ | |
| Routine Description: | |
| Constructor for the VFR opcode handling class. | |
| Arguments: | |
| None | |
| Returns: | |
| None | |
| --*/ | |
| { | |
| mIfrBytes = NULL; | |
| mLastIfrByte = NULL; | |
| mBytesWritten = 0; | |
| mQueuedByteCount = 0; | |
| mQueuedOpcodeByteValid = 0; | |
| mPrimaryVarStoreId = 0; | |
| mSecondaryVarStoreId = 0; | |
| mSecondaryVarStoreIdSet = 0; | |
| mPrimaryVarStoreIdSet = 0; | |
| mDefaultVarStoreId = 0; | |
| } | |
| VOID | |
| VfrOpcodeHandler::SetVarStoreId ( | |
| UINT16 VarStoreId | |
| ) | |
| /*++ | |
| Routine Description: | |
| This function is invoked by the parser when a variable is referenced in the | |
| VFR. Save the variable store (and set a flag) so that we can later determine | |
| if we need to emit a varstore-select or varstore-select-pair opcode. | |
| Arguments: | |
| VarStoreId - ID of the variable store referenced in the VFR | |
| Returns: | |
| None | |
| --*/ | |
| { | |
| mPrimaryVarStoreId = VarStoreId; | |
| mPrimaryVarStoreIdSet = 1; | |
| } | |
| VOID | |
| VfrOpcodeHandler::SetSecondaryVarStoreId ( | |
| UINT16 VarStoreId | |
| ) | |
| /*++ | |
| Routine Description: | |
| This function is invoked by the parser when a secondary variable is | |
| referenced in the VFR. Save the variable store (and set a flag) so | |
| that we can later determine if we need to emit a varstore-select or | |
| varstore-pair opcode. | |
| Arguments: | |
| VarStoreId - ID of the variable store referenced in the VFR | |
| Returns: | |
| None | |
| --*/ | |
| { | |
| mSecondaryVarStoreId = VarStoreId; | |
| mSecondaryVarStoreIdSet = 1; | |
| } | |
| VOID | |
| VfrOpcodeHandler::WriteIfrBytes ( | |
| ) | |
| /*++ | |
| Routine Description: | |
| This function is invoked at the end of parsing. Its purpose | |
| is to write out all the IFR bytes that were queued up while | |
| parsing. | |
| Arguments: | |
| None | |
| Returns: | |
| None | |
| --*/ | |
| { | |
| IFR_BYTE *Curr; | |
| IFR_BYTE *Next; | |
| UINT32 Count; | |
| UINT32 LineCount; | |
| UINT32 PoundLines; | |
| UINT32 ByteCount; | |
| CHAR8 Line[MAX_LINE_LEN]; | |
| CHAR8 *Cptr; | |
| FILE *InFptr; | |
| FILE *OutFptr; | |
| UINT32 ListFile; | |
| EFI_HII_IFR_PACK_HEADER IfrHeader; | |
| UINT8 *Ptr; | |
| FILE *IfrBinFptr; | |
| UINT32 BytesLeftThisOpcode; | |
| // | |
| // If someone added a new opcode and didn't update our opcode sizes structure, error out. | |
| // | |
| if (sizeof(mOpcodeSizes) / sizeof (mOpcodeSizes[0]) != EFI_IFR_LAST_OPCODE + 1) { | |
| Error (__FILE__, __LINE__, 0, "application error", "internal IFR binary table size is incorrect"); | |
| return; | |
| } | |
| // | |
| // Flush the queue | |
| // | |
| FlushQueue (); | |
| // | |
| // If there have been any errors to this point, then skip dumping the IFR | |
| // binary data. This way doing an nmake again will try to build it again, and | |
| // the build will fail if they did not fix the problem. | |
| // | |
| if (GetUtilityStatus () != STATUS_ERROR) { | |
| if ((IfrBinFptr = fopen (gOptions.IfrOutputFileName, "w")) == NULL) { | |
| Error (PROGRAM_NAME, 0, 0, gOptions.IfrOutputFileName, "could not open file for writing"); | |
| return; | |
| } | |
| // | |
| // Write the standard file header to the output file | |
| // | |
| WriteStandardFileHeader (IfrBinFptr); | |
| // | |
| // Write the structure header | |
| // | |
| fprintf (IfrBinFptr, "\nunsigned char %sBin[] = {", gOptions.VfrBaseFileName); | |
| // | |
| // Write the header | |
| // | |
| memset ((char *)&IfrHeader, 0, sizeof (IfrHeader)); | |
| IfrHeader.Header.Type = EFI_HII_IFR; | |
| IfrHeader.Header.Length = mBytesWritten + sizeof (IfrHeader); | |
| Ptr = (UINT8 *)&IfrHeader; | |
| for (Count = 0; Count < sizeof (IfrHeader); Count++, Ptr++) { | |
| if ((Count & 0x03) == 0) { | |
| fprintf (IfrBinFptr, "\n "); | |
| } | |
| fprintf (IfrBinFptr, "0x%02X, ", *Ptr); | |
| } | |
| // | |
| // | |
| // Write all the IFR bytes | |
| // | |
| fprintf (IfrBinFptr, "\n // start of IFR data"); | |
| Curr = mIfrBytes; | |
| Count = 0; | |
| while (Curr != NULL) { | |
| if ((Count & 0x0F) == 0) { | |
| fprintf (IfrBinFptr, "\n "); | |
| } | |
| if (Curr->KeyByte != 0) { | |
| fprintf (IfrBinFptr, "/*%c*/ ", Curr->KeyByte); | |
| } | |
| fprintf (IfrBinFptr, "0x%02X, ", Curr->OpcodeByte); | |
| Count++; | |
| Curr = Curr->Next; | |
| } | |
| fprintf (IfrBinFptr, "\n};\n\n"); | |
| // | |
| // | |
| // Close the file | |
| // | |
| fclose (IfrBinFptr); | |
| IfrBinFptr = NULL; | |
| } | |
| // | |
| // Write the bytes as binary data if the user specified to do so | |
| // | |
| if ((GetUtilityStatus () != STATUS_ERROR) && (gOptions.CreateIfrBinFile != 0)) { | |
| // | |
| // Use the Ifr output file name with a ".hpk" extension. | |
| // | |
| for (Cptr = gOptions.IfrOutputFileName + strlen (gOptions.IfrOutputFileName) - 1; | |
| (*Cptr != '.') && (Cptr > gOptions.IfrOutputFileName) && (*Cptr != '\\'); | |
| Cptr--) { | |
| // | |
| // do nothing | |
| // | |
| } | |
| if (*Cptr == '.') { | |
| strcpy (Cptr, ".hpk"); | |
| } else { | |
| strcat (gOptions.IfrOutputFileName, ".hpk"); | |
| } | |
| if ((IfrBinFptr = fopen (gOptions.IfrOutputFileName, "wb")) == NULL) { | |
| Error (PROGRAM_NAME, 0, 0, gOptions.IfrOutputFileName, "could not open file for writing"); | |
| return; | |
| } | |
| // | |
| // Write the structure header | |
| // | |
| memset ((char *)&IfrHeader, 0, sizeof (IfrHeader)); | |
| IfrHeader.Header.Type = EFI_HII_IFR; | |
| IfrHeader.Header.Length = mBytesWritten + sizeof (IfrHeader); | |
| Ptr = (UINT8 *)&IfrHeader; | |
| for (Count = 0; Count < sizeof (IfrHeader); Count++, Ptr++) { | |
| fwrite (Ptr, 1, 1, IfrBinFptr); | |
| } | |
| // | |
| // | |
| // Write all the IFR bytes | |
| // | |
| Curr = mIfrBytes; | |
| Count = 0; | |
| while (Curr != NULL) { | |
| fwrite (&Curr->OpcodeByte, 1, 1, IfrBinFptr); | |
| Curr = Curr->Next; | |
| } | |
| // | |
| // | |
| // Close the file | |
| // | |
| fclose (IfrBinFptr); | |
| IfrBinFptr = NULL; | |
| } | |
| // | |
| // If creating a listing file, then open the input and output files | |
| // | |
| ListFile = 0; | |
| if (gOptions.CreateListFile) { | |
| // | |
| // Open the input VFR file and the output list file | |
| // | |
| if ((InFptr = fopen (gOptions.PreprocessorOutputFileName, "r")) == NULL) { | |
| Warning (PROGRAM_NAME, 0, 0, gOptions.PreprocessorOutputFileName, "could not open file for creating a list file"); | |
| } else { | |
| if ((OutFptr = fopen (gOptions.VfrListFileName, "w")) == NULL) { | |
| Warning (PROGRAM_NAME, 0, 0, gOptions.VfrListFileName, "could not open output list file for writing"); | |
| fclose (InFptr); | |
| InFptr = NULL; | |
| } else { | |
| LineCount = 0; | |
| ListFile = 1; | |
| PoundLines = 0; | |
| ByteCount = 0; | |
| } | |
| } | |
| } | |
| // | |
| // Write the list file | |
| // | |
| if (ListFile) { | |
| // | |
| // Write out the VFR compiler version | |
| // | |
| fprintf (OutFptr, "//\n// VFR compiler version " VFR_COMPILER_VERSION "\n//\n"); | |
| Curr = mIfrBytes; | |
| while (Curr != NULL) { | |
| // | |
| // Print lines until we reach the line of the current opcode | |
| // | |
| while (LineCount < PoundLines + Curr->LineNum) { | |
| if (fgets (Line, sizeof (Line), InFptr) != NULL) { | |
| // | |
| // We should check for line length exceeded on the fgets(). Otherwise it | |
| // throws the listing file output off. Future enhancement perhaps. | |
| // | |
| fprintf (OutFptr, "%s", Line); | |
| if (strncmp (Line, "#line", 5) == 0) { | |
| PoundLines++; | |
| } | |
| } | |
| LineCount++; | |
| } | |
| // | |
| // Print all opcodes with line numbers less than where we are now | |
| // | |
| BytesLeftThisOpcode = 0; | |
| while ((Curr != NULL) && ((Curr->LineNum == 0) || (LineCount >= PoundLines + Curr->LineNum))) { | |
| if (BytesLeftThisOpcode == 0) { | |
| fprintf (OutFptr, ">%08X: ", ByteCount); | |
| if (Curr->Next != NULL) { | |
| BytesLeftThisOpcode = (UINT32)Curr->Next->OpcodeByte; | |
| } | |
| } | |
| fprintf (OutFptr, "%02X ", (UINT32)Curr->OpcodeByte); | |
| ByteCount++; | |
| BytesLeftThisOpcode--; | |
| if (BytesLeftThisOpcode == 0) { | |
| fprintf (OutFptr, "\n"); | |
| } | |
| Curr = Curr->Next; | |
| } | |
| } | |
| // | |
| // Dump any remaining lines from the input file | |
| // | |
| while (fgets (Line, sizeof (Line), InFptr) != NULL) { | |
| fprintf (OutFptr, "%s", Line); | |
| } | |
| fclose (InFptr); | |
| fclose (OutFptr); | |
| } | |
| // | |
| // Debug code to make sure that each opcode we write out has as many | |
| // bytes as the IFR structure requires. If there were errors, then | |
| // don't do this step. | |
| // | |
| if (GetUtilityStatus () != STATUS_ERROR) { | |
| Curr = mIfrBytes; | |
| ByteCount = 0; | |
| while (Curr != NULL) { | |
| // | |
| // First byte is the opcode, second byte is the length | |
| // | |
| if (Curr->Next == NULL) { | |
| Error (__FILE__, __LINE__, 0, "application error", "last opcode written does not contain a length byte"); | |
| break; | |
| } | |
| Count = (UINT32)Curr->Next->OpcodeByte; | |
| if (Count == 0) { | |
| Error ( | |
| __FILE__, | |
| __LINE__, | |
| 0, | |
| "application error", | |
| "opcode with 0 length specified in output at offset 0x%X", | |
| ByteCount | |
| ); | |
| break; | |
| } | |
| // | |
| // Check the length | |
| // | |
| if ((Curr->OpcodeByte > EFI_IFR_LAST_OPCODE) || (Curr->OpcodeByte == 0)) { | |
| Error ( | |
| __FILE__, | |
| __LINE__, | |
| 0, | |
| "application error", | |
| "invalid opcode 0x%X in output at offset 0x%X", | |
| (UINT32) Curr->OpcodeByte, ByteCount | |
| ); | |
| } else if (mOpcodeSizes[Curr->OpcodeByte].Size < 0) { | |
| // | |
| // For those cases where the length is variable, the size is negative, and indicates | |
| // the miniumum size. | |
| // | |
| if ((mOpcodeSizes[Curr->OpcodeByte].Size * -1) > Count) { | |
| Error ( | |
| __FILE__, | |
| __LINE__, | |
| 0, | |
| "application error", | |
| "insufficient number of bytes written for %s at offset 0x%X", | |
| mOpcodeSizes[Curr->OpcodeByte].Name, | |
| ByteCount | |
| ); | |
| } | |
| } else { | |
| // | |
| // Check for gaps | |
| // | |
| if (mOpcodeSizes[Curr->OpcodeByte].Size == 0) { | |
| Error ( | |
| __FILE__, | |
| __LINE__, | |
| 0, | |
| "application error", | |
| "invalid opcode 0x%X in output at offset 0x%X", | |
| (UINT32)Curr->OpcodeByte, | |
| ByteCount | |
| ); | |
| } else { | |
| // | |
| // Check size | |
| // | |
| if (mOpcodeSizes[Curr->OpcodeByte].Size != Count) { | |
| Error ( | |
| __FILE__, | |
| __LINE__, | |
| 0, | |
| "application error", | |
| "invalid number of bytes (%d written s/b %d) written for %s at offset 0x%X", | |
| Count, | |
| mOpcodeSizes[Curr->OpcodeByte].Size, | |
| mOpcodeSizes[Curr->OpcodeByte].Name, | |
| ByteCount | |
| ); | |
| } | |
| } | |
| } | |
| // | |
| // Skip to next opcode | |
| // | |
| while (Count > 0) { | |
| ByteCount++; | |
| if (Curr == NULL) { | |
| Error (__FILE__, __LINE__, 0, "application error", "last opcode written has invalid length"); | |
| break; | |
| } | |
| Curr = Curr->Next; | |
| Count--; | |
| } | |
| } | |
| } | |
| } | |
| VfrOpcodeHandler::~VfrOpcodeHandler( | |
| ) | |
| /*++ | |
| Routine Description: | |
| Destructor for the VFR opcode handler. Free up memory allocated | |
| while parsing the VFR script. | |
| Arguments: | |
| None | |
| Returns: | |
| None | |
| --*/ | |
| { | |
| IFR_BYTE *Curr; | |
| IFR_BYTE *Next; | |
| // | |
| // Free up the IFR bytes | |
| // | |
| Curr = mIfrBytes; | |
| while (Curr != NULL) { | |
| Next = Curr->Next; | |
| free (Curr); | |
| Curr = Next; | |
| } | |
| } | |
| int | |
| VfrOpcodeHandler::AddOpcodeByte ( | |
| UINT8 OpcodeByte, | |
| UINT32 LineNum | |
| ) | |
| /*++ | |
| Routine Description: | |
| This function is invoked by the parser when a new IFR | |
| opcode should be emitted. | |
| Arguments: | |
| OpcodeByte - the IFR opcode | |
| LineNum - the line number from the source file that resulted | |
| in the opcode being emitted. | |
| Returns: | |
| 0 always | |
| --*/ | |
| { | |
| UINT32 Count; | |
| FlushQueue(); | |
| // | |
| // Now add this new byte | |
| // | |
| mQueuedOpcodeByte = OpcodeByte; | |
| mQueuedLineNum = LineNum; | |
| mQueuedOpcodeByteValid = 1; | |
| return 0; | |
| } | |
| VOID | |
| VfrOpcodeHandler::AddByte ( | |
| UINT8 ByteVal, | |
| UINT8 KeyByte | |
| ) | |
| /*++ | |
| Routine Description: | |
| This function is invoked by the parser when it determines | |
| that more raw IFR bytes should be emitted to the output stream. | |
| Here we just queue them up into an output buffer. | |
| Arguments: | |
| ByteVal - the raw byte to emit to the output IFR stream | |
| KeyByte - a value that can be used for debug. | |
| Returns: | |
| None | |
| --*/ | |
| { | |
| // | |
| // Check for buffer overflow | |
| // | |
| if (mQueuedByteCount > MAX_QUEUE_COUNT) { | |
| Error (PROGRAM_NAME, 0, 0, NULL, "opcode queue overflow"); | |
| } else { | |
| mQueuedBytes[mQueuedByteCount] = ByteVal; | |
| mQueuedKeyBytes[mQueuedByteCount] = KeyByte; | |
| mQueuedByteCount++; | |
| } | |
| } | |
| int | |
| VfrOpcodeHandler::FlushQueue ( | |
| ) | |
| /*++ | |
| Routine Description: | |
| This function is invoked to flush the internal IFR buffer. | |
| Arguments: | |
| None | |
| Returns: | |
| 0 always | |
| --*/ | |
| { | |
| UINT32 Count; | |
| UINT32 EmitNoneOnePair; | |
| EmitNoneOnePair = 0; | |
| // | |
| // If the secondary varstore was specified, then we have to emit | |
| // a varstore-select-pair opcode, which only applies to the following | |
| // statement. | |
| // | |
| if (mSecondaryVarStoreIdSet) { | |
| mSecondaryVarStoreIdSet = 0; | |
| // | |
| // If primary and secondary are the same as the current default | |
| // varstore, then we don't have to do anything. | |
| // Note that the varstore-select-pair only applies to the following | |
| // opcode. | |
| // | |
| if ((mPrimaryVarStoreId != mSecondaryVarStoreId) || (mPrimaryVarStoreId != mDefaultVarStoreId)) { | |
| IAddByte (EFI_IFR_VARSTORE_SELECT_PAIR_OP, 'O', mQueuedLineNum); | |
| IAddByte ((UINT8)sizeof (EFI_IFR_VARSTORE_SELECT_PAIR), 'L', 0); | |
| IAddByte ((UINT8)mPrimaryVarStoreId, 0, 0); | |
| IAddByte ((UINT8)(mPrimaryVarStoreId >> 8), 0, 0); | |
| IAddByte ((UINT8)mSecondaryVarStoreId, 0, 0); | |
| IAddByte ((UINT8)(mSecondaryVarStoreId >> 8), 0, 0); | |
| } | |
| } else if (mPrimaryVarStoreIdSet != 0) { | |
| mPrimaryVarStoreIdSet = 0; | |
| if (mDefaultVarStoreId != mPrimaryVarStoreId) { | |
| // | |
| // The VFR statement referenced a different variable store | |
| // than the last one we reported. Insert a new varstore select | |
| // statement. | |
| // | |
| IAddByte (EFI_IFR_VARSTORE_SELECT_OP, 'O', mQueuedLineNum); | |
| IAddByte ((UINT8)sizeof (EFI_IFR_VARSTORE_SELECT), 'L', 0); | |
| IAddByte ((UINT8)mPrimaryVarStoreId, 0, 0); | |
| IAddByte ((UINT8)(mPrimaryVarStoreId >> 8), 0, 0); | |
| mDefaultVarStoreId = mPrimaryVarStoreId; | |
| } | |
| } | |
| // | |
| // Likely a new opcode is being added. Since each opcode item in the IFR has | |
| // a header that specifies the size of the opcode item (which we don't | |
| // know until we find the next opcode in the VFR), we queue up bytes | |
| // until we know the size. Then we write them out. So flush the queue | |
| // now. | |
| // | |
| if (mQueuedOpcodeByteValid != 0) { | |
| // | |
| // Add the previous opcode byte, the length byte, and the binary | |
| // data. | |
| // | |
| IAddByte (mQueuedOpcodeByte, 'O', mQueuedLineNum); | |
| IAddByte ((UINT8)(mQueuedByteCount + 2), 'L', 0); | |
| for (Count = 0; Count < mQueuedByteCount; Count++) { | |
| IAddByte (mQueuedBytes[Count], mQueuedKeyBytes[Count], 0); | |
| } | |
| mQueuedByteCount = 0; | |
| mQueuedOpcodeByteValid = 0; | |
| } | |
| return 0; | |
| } | |
| int | |
| VfrOpcodeHandler::IAddByte ( | |
| UINT8 ByteVal, | |
| UINT8 KeyByte, | |
| UINT32 LineNum | |
| ) | |
| /*++ | |
| Routine Description: | |
| This internal function is used to add actual IFR bytes to | |
| the output stream. Most other functions queue up the bytes | |
| in an internal buffer. Once they come here, there's no | |
| going back. | |
| Arguments: | |
| ByteVal - value to write to output | |
| KeyByte - key value tied to the byte -- useful for debug | |
| LineNum - line number from source file the byte resulted from | |
| Returns: | |
| 0 - if successful | |
| 1 - failed due to memory allocation failure | |
| --*/ | |
| { | |
| IFR_BYTE *NewByte; | |
| NewByte = (IFR_BYTE *)malloc (sizeof (IFR_BYTE)); | |
| if (NewByte == NULL) { | |
| return 1; | |
| } | |
| memset ((char *)NewByte, 0, sizeof (IFR_BYTE)); | |
| NewByte->OpcodeByte = ByteVal; | |
| NewByte->KeyByte = KeyByte; | |
| NewByte->LineNum = LineNum; | |
| // | |
| // Add to the list | |
| // | |
| if (mIfrBytes == NULL) { | |
| mIfrBytes = NewByte; | |
| } else { | |
| mLastIfrByte->Next = NewByte; | |
| } | |
| mLastIfrByte = NewByte; | |
| mBytesWritten++; | |
| return 0; | |
| } | |
| VOID | |
| WriteStandardFileHeader ( | |
| FILE *OutFptr | |
| ) | |
| /*++ | |
| Routine Description: | |
| This function is invoked to emit a standard header to an | |
| output text file. | |
| Arguments: | |
| OutFptr - file to write the header to | |
| Returns: | |
| None | |
| --*/ | |
| { | |
| UINT32 TempIndex; | |
| for (TempIndex = 0; mSourceFileHeader[TempIndex] != NULL; TempIndex++) { | |
| fprintf (OutFptr, "%s\n", mSourceFileHeader[TempIndex]); | |
| } | |
| // | |
| // Write out the VFR compiler version | |
| // | |
| fprintf (OutFptr, "// VFR compiler version " VFR_COMPILER_VERSION "\n//\n"); | |
| } |