git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@3 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			758 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			758 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*++
 | |
| 
 | |
| 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 <Base.h>
 | |
| #include <UefiBaseTypes.h>
 | |
| #include <MultiPhase.h>
 | |
| #include "EfiUtilityMsgs.h"
 | |
| #include "EfiVfr.h"
 | |
| #include "VfrServices.h"
 | |
| 
 | |
| #include <UgaDraw.h>
 | |
| #include <Hii.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");
 | |
| }
 |