git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@3 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			996 lines
		
	
	
		
			28 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			996 lines
		
	
	
		
			28 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*++
 | |
| Copyright (c) 2006, 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:
 | |
|   IfrCommon.c
 | |
| 
 | |
| Abstract:
 | |
| 
 | |
|   Common Library Routines to assist in IFR creation on-the-fly
 | |
| 
 | |
| Revision History:
 | |
| 
 | |
| --*/
 | |
| 
 | |
| EFI_STATUS
 | |
| IfrLibConstruct (
 | |
|   IN EFI_HANDLE        ImageHandle,
 | |
|   IN EFI_SYSTEM_TABLE  *SystemTable
 | |
|   )
 | |
| {
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| EFI_STATUS
 | |
| GetCurrentLanguage (
 | |
|   OUT     CHAR16              *Lang
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Determine what is the current language setting
 | |
|   
 | |
| Arguments:
 | |
|   
 | |
|   Lang      - Pointer of system language
 | |
|   
 | |
| Returns: 
 | |
| 
 | |
|   Status code
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
|   UINTN       Size;
 | |
|   UINTN       Index;
 | |
|   CHAR8       Language[4];
 | |
| 
 | |
|   //
 | |
|   // Getting the system language and placing it into our Global Data
 | |
|   //
 | |
|   Size = sizeof (Language);
 | |
| 
 | |
|   Status = gRT->GetVariable (
 | |
|                   (CHAR16 *) L"Lang",
 | |
|                   &gEfiGlobalVariableGuid,
 | |
|                   NULL,
 | |
|                   &Size,
 | |
|                   Language
 | |
|                   );
 | |
| 
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     AsciiStrCpy (Language, "eng");
 | |
|   }
 | |
| 
 | |
|   for (Index = 0; Language[Index] != 0; Index++) {
 | |
|     //
 | |
|     // Bitwise AND ascii value with 0xDF yields an uppercase value.
 | |
|     // Sign extend into a unicode value
 | |
|     //
 | |
|     Lang[Index] = (CHAR16) (Language[Index] & 0xDF);
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Null-terminate the value
 | |
|   //
 | |
|   Lang[3] = (CHAR16) 0;
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| 
 | |
| EFI_STATUS
 | |
| AddString (
 | |
|   IN      VOID                *StringBuffer,
 | |
|   IN      CHAR16              *Language,
 | |
|   IN      CHAR16              *String,
 | |
|   IN OUT  STRING_REF          *StringToken
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Add a string to the incoming buffer and return the token and offset data
 | |
|   
 | |
| Arguments:
 | |
|   
 | |
|   StringBuffer      - The incoming buffer
 | |
|   
 | |
|   Language          - Currrent language
 | |
|   
 | |
|   String            - The string to be added
 | |
|   
 | |
|   StringToken       - The index where the string placed
 | |
|   
 | |
| Returns: 
 | |
| 
 | |
|   EFI_OUT_OF_RESOURCES    - No enough buffer to allocate
 | |
|   
 | |
|   EFI_SUCCESS             - String successfully added to the incoming buffer
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   EFI_HII_STRING_PACK *StringPack;
 | |
|   EFI_HII_STRING_PACK *StringPackBuffer;
 | |
|   VOID                *NewBuffer;
 | |
|   RELOFST             *PackSource;
 | |
|   RELOFST             *PackDestination;
 | |
|   UINT8               *Source;
 | |
|   UINT8               *Destination;
 | |
|   UINTN               Index;
 | |
|   BOOLEAN             Finished;
 | |
| 
 | |
|   StringPack  = (EFI_HII_STRING_PACK *) StringBuffer;
 | |
|   Finished    = FALSE;
 | |
| 
 | |
|   //
 | |
|   // Pre-allocate a buffer sufficient for us to work on.
 | |
|   // We will use it as a destination scratch pad to build data on
 | |
|   // and when complete shift the data back to the original buffer
 | |
|   //
 | |
|   NewBuffer = AllocateZeroPool (DEFAULT_STRING_BUFFER_SIZE);
 | |
|   if (NewBuffer == NULL) {
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
| 
 | |
|   StringPackBuffer = (EFI_HII_STRING_PACK *) NewBuffer;
 | |
| 
 | |
|   //
 | |
|   // StringPack is terminated with a length 0 entry
 | |
|   //
 | |
|   for (; StringPack->Header.Length != 0;) {
 | |
|     //
 | |
|     // If this stringpack's language is same as CurrentLanguage, use it
 | |
|     //
 | |
|     if (CompareMem ((VOID *) ((CHAR8 *) (StringPack) + StringPack->LanguageNameString), Language, 3) == 0) {
 | |
|       //
 | |
|       // We have some data in this string pack, copy the string package up to the string data
 | |
|       //
 | |
|       CopyMem (&StringPackBuffer->Header, &StringPack->Header, sizeof (StringPack));
 | |
| 
 | |
|       //
 | |
|       // These are references in the structure to tokens, need to increase them by the space occupied by an additional StringPointer
 | |
|       //
 | |
|       StringPackBuffer->LanguageNameString = (UINT16) (StringPackBuffer->LanguageNameString + (UINT16) sizeof (RELOFST));
 | |
|       StringPackBuffer->PrintableLanguageName = (UINT16) (StringPackBuffer->PrintableLanguageName + (UINT16) sizeof (RELOFST));
 | |
| 
 | |
|       PackSource      = (RELOFST *) (StringPack + 1);
 | |
|       PackDestination = (RELOFST *) (StringPackBuffer + 1);
 | |
|       for (Index = 0; PackSource[Index] != 0x0000; Index++) {
 | |
|         //
 | |
|         // Copy the stringpointers from old to new buffer
 | |
|         // remember that we are adding a string, so the string offsets will all go up by sizeof (RELOFST)
 | |
|         //
 | |
|         PackDestination[Index] = (UINT16) (PackDestination[Index] + sizeof (RELOFST));
 | |
|       }
 | |
|       
 | |
|       //
 | |
|       // Add a new stringpointer in the new buffer since we are adding a string.  Null terminate it
 | |
|       //
 | |
|       PackDestination[Index] = (UINT16)(PackDestination[Index-1] + 
 | |
|                                         StrSize((CHAR16 *)((CHAR8 *)(StringPack) + PackSource[Index-1])));
 | |
|       PackDestination[Index + 1] = (UINT16) 0;
 | |
| 
 | |
|       //
 | |
|       // Index is the token value for the new string
 | |
|       //
 | |
|       *StringToken = (UINT16) Index;
 | |
| 
 | |
|       //
 | |
|       // Source now points to the beginning of the old buffer strings
 | |
|       // Destination now points to the beginning of the new buffer strings
 | |
|       //
 | |
|       Source      = (UINT8 *) &PackSource[Index + 1];
 | |
|       Destination = (UINT8 *) &PackDestination[Index + 2];
 | |
| 
 | |
|       //
 | |
|       // This should copy all the strings from the old buffer to the new buffer
 | |
|       //
 | |
|       for (; Index != 0; Index--) {
 | |
|         //
 | |
|         // Copy Source string to destination buffer
 | |
|         //
 | |
|         StrCpy ((CHAR16 *) Destination, (CHAR16 *) Source);
 | |
| 
 | |
|         //
 | |
|         // Adjust the source/destination to the next string location
 | |
|         //
 | |
|         Destination = Destination + StrSize ((CHAR16 *) Source);
 | |
|         Source      = Source + StrSize ((CHAR16 *) Source);
 | |
|       }
 | |
|       
 | |
|       //
 | |
|       // This copies the new string to the destination buffer
 | |
|       //
 | |
|       StrCpy ((CHAR16 *) Destination, (CHAR16 *) String);
 | |
| 
 | |
|       //
 | |
|       // Adjust the size of the changed string pack by adding the size of the new string
 | |
|       // along with the size of the additional offset entry for the new string
 | |
|       //
 | |
|       StringPackBuffer->Header.Length = (UINT32) ((UINTN) StringPackBuffer->Header.Length + StrSize (String) + sizeof (RELOFST));
 | |
| 
 | |
|       //
 | |
|       // Advance the buffers to point to the next spots.
 | |
|       //
 | |
|       StringPackBuffer  = (EFI_HII_STRING_PACK *) ((CHAR8 *) (StringPackBuffer) + StringPackBuffer->Header.Length);
 | |
|       StringPack        = (EFI_HII_STRING_PACK *) ((CHAR8 *) (StringPack) + StringPack->Header.Length);
 | |
|       Finished          = TRUE;
 | |
|       continue;
 | |
|     }
 | |
|     //
 | |
|     // This isn't the language of the stringpack we were asked to add a string to
 | |
|     // so we need to copy it to the new buffer.
 | |
|     //
 | |
|     CopyMem (&StringPackBuffer->Header, &StringPack->Header, StringPack->Header.Length);
 | |
| 
 | |
|     //
 | |
|     // Advance the buffers to point to the next spots.
 | |
|     //
 | |
|     StringPackBuffer  = (EFI_HII_STRING_PACK *) ((CHAR8 *) (StringPackBuffer) + StringPack->Header.Length);
 | |
|     StringPack        = (EFI_HII_STRING_PACK *) ((CHAR8 *) (StringPack) + StringPack->Header.Length);
 | |
|   }
 | |
|   
 | |
|   //
 | |
|   // If we didn't copy the new data to a stringpack yet
 | |
|   //
 | |
|   if (!Finished) {
 | |
|     PackDestination = (RELOFST *) (StringPackBuffer + 1);
 | |
|     //
 | |
|     // Pointing to a new string pack location
 | |
|     //
 | |
|     StringPackBuffer->Header.Length = (UINT32)
 | |
|       (
 | |
|         sizeof (EFI_HII_STRING_PACK) -
 | |
|         sizeof (EFI_STRING) +
 | |
|         sizeof (RELOFST) +
 | |
|         sizeof (RELOFST) +
 | |
|         StrSize (Language) +
 | |
|         StrSize (String)
 | |
|       );
 | |
|     StringPackBuffer->Header.Type           = EFI_HII_STRING;
 | |
|     StringPackBuffer->LanguageNameString    = (UINT16) ((UINTN) &PackDestination[3] - (UINTN) StringPackBuffer);
 | |
|     StringPackBuffer->PrintableLanguageName = (UINT16) ((UINTN) &PackDestination[3] - (UINTN) StringPackBuffer);
 | |
|     StringPackBuffer->Attributes            = 0;
 | |
|     PackDestination[0]                      = (UINT16) ((UINTN) &PackDestination[3] - (UINTN) StringPackBuffer);
 | |
|     PackDestination[1]                      = (UINT16) (PackDestination[0] + StrSize (Language));
 | |
|     PackDestination[2]                      = (UINT16) 0;
 | |
| 
 | |
|     //
 | |
|     // The first string location will be set to destination.  The minimum number of strings
 | |
|     // associated with a stringpack will always be token 0 stored as the languagename (e.g. ENG, SPA, etc)
 | |
|     // and token 1 as the new string being added and and null entry for the stringpointers
 | |
|     //
 | |
|     Destination = (UINT8 *) &PackDestination[3];
 | |
| 
 | |
|     //
 | |
|     // Copy the language name string to the new buffer
 | |
|     //
 | |
|     StrCpy ((CHAR16 *) Destination, Language);
 | |
| 
 | |
|     //
 | |
|     // Advance the destination to the new empty spot
 | |
|     //
 | |
|     Destination = Destination + StrSize (Language);
 | |
| 
 | |
|     //
 | |
|     // Copy the string to the new buffer
 | |
|     //
 | |
|     StrCpy ((CHAR16 *) Destination, String);
 | |
| 
 | |
|     //
 | |
|     // Since we are starting with a new string pack - we know the new string is token 1
 | |
|     //
 | |
|     *StringToken = (UINT16) 1;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Zero out the original buffer and copy the updated data in the new buffer to the old buffer
 | |
|   //
 | |
|   ZeroMem (StringBuffer, DEFAULT_STRING_BUFFER_SIZE);
 | |
|   CopyMem (StringBuffer, NewBuffer, DEFAULT_STRING_BUFFER_SIZE);
 | |
| 
 | |
|   //
 | |
|   // Free the newly created buffer since we don't need it anymore
 | |
|   //
 | |
|   gBS->FreePool (NewBuffer);
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| 
 | |
| EFI_STATUS
 | |
| AddOpCode (
 | |
|   IN      VOID                *FormBuffer,
 | |
|   IN OUT  VOID                *OpCodeData
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Add op-code data to the FormBuffer
 | |
|   
 | |
| Arguments:
 | |
|   
 | |
|   FormBuffer      - Form buffer to be inserted to
 | |
|   
 | |
|   OpCodeData      - Op-code data to be inserted
 | |
|   
 | |
| Returns: 
 | |
| 
 | |
|   EFI_OUT_OF_RESOURCES    - No enough buffer to allocate
 | |
|   
 | |
|   EFI_SUCCESS             - Op-code data successfully inserted
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   EFI_HII_PACK_HEADER *NewBuffer;
 | |
|   UINT8               *Source;
 | |
|   UINT8               *Destination;
 | |
| 
 | |
|   //
 | |
|   // Pre-allocate a buffer sufficient for us to work on.
 | |
|   // We will use it as a destination scratch pad to build data on
 | |
|   // and when complete shift the data back to the original buffer
 | |
|   //
 | |
|   NewBuffer = AllocateZeroPool (DEFAULT_FORM_BUFFER_SIZE);
 | |
|   if (NewBuffer == NULL) {
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
| 
 | |
|   Source      = (UINT8 *) FormBuffer;
 | |
|   Destination = (UINT8 *) NewBuffer;
 | |
| 
 | |
|   //
 | |
|   // Copy the IFR Package header to the new buffer
 | |
|   //
 | |
|   CopyMem (Destination, Source, sizeof (EFI_HII_PACK_HEADER));
 | |
| 
 | |
|   //
 | |
|   // Advance Source and Destination to next op-code
 | |
|   //
 | |
|   Source      = Source + sizeof (EFI_HII_PACK_HEADER);
 | |
|   Destination = Destination + sizeof (EFI_HII_PACK_HEADER);
 | |
| 
 | |
|   //
 | |
|   // Copy data to the new buffer until we run into the end_form
 | |
|   //
 | |
|   for (; ((EFI_IFR_OP_HEADER *) Source)->OpCode != EFI_IFR_END_FORM_OP;) {
 | |
|     //
 | |
|     // If the this opcode is an end_form_set we better be creating and endform
 | |
|     // Nonetheless, we will add data before the end_form_set.  This also provides
 | |
|     // for interesting behavior in the code we will run, but has no bad side-effects
 | |
|     // since we will possibly do a 0 byte copy in this particular end-case.
 | |
|     //
 | |
|     if (((EFI_IFR_OP_HEADER *) Source)->OpCode == EFI_IFR_END_FORM_SET_OP) {
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Copy data to new buffer
 | |
|     //
 | |
|     CopyMem (Destination, Source, ((EFI_IFR_OP_HEADER *) Source)->Length);
 | |
| 
 | |
|     //
 | |
|     // Adjust Source/Destination to next op-code location
 | |
|     //
 | |
|     Destination = Destination + (UINTN) ((EFI_IFR_OP_HEADER *) Source)->Length;
 | |
|     Source      = Source + (UINTN) ((EFI_IFR_OP_HEADER *) Source)->Length;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Prior to the end_form is where we insert the new op-code data
 | |
|   //
 | |
|   CopyMem (Destination, OpCodeData, ((EFI_IFR_OP_HEADER *) OpCodeData)->Length);
 | |
|   Destination       = Destination + (UINTN) ((EFI_IFR_OP_HEADER *) OpCodeData)->Length;
 | |
| 
 | |
|   NewBuffer->Length = (UINT32) (NewBuffer->Length + (UINT32) (((EFI_IFR_OP_HEADER *) OpCodeData)->Length));
 | |
| 
 | |
|   //
 | |
|   // Copy end-form data to new buffer
 | |
|   //
 | |
|   CopyMem (Destination, Source, ((EFI_IFR_OP_HEADER *) Source)->Length);
 | |
| 
 | |
|   //
 | |
|   // Adjust Source/Destination to next op-code location
 | |
|   //
 | |
|   Destination = Destination + (UINTN) ((EFI_IFR_OP_HEADER *) Source)->Length;
 | |
|   Source      = Source + (UINTN) ((EFI_IFR_OP_HEADER *) Source)->Length;
 | |
| 
 | |
|   //
 | |
|   // Copy end-formset data to new buffer
 | |
|   //
 | |
|   CopyMem (Destination, Source, ((EFI_IFR_OP_HEADER *) Source)->Length);
 | |
| 
 | |
|   //
 | |
|   // Zero out the original buffer and copy the updated data in the new buffer to the old buffer
 | |
|   //
 | |
|   ZeroMem (FormBuffer, DEFAULT_FORM_BUFFER_SIZE);
 | |
|   CopyMem (FormBuffer, NewBuffer, DEFAULT_FORM_BUFFER_SIZE);
 | |
| 
 | |
|   //
 | |
|   // Free the newly created buffer since we don't need it anymore
 | |
|   //
 | |
|   gBS->FreePool (NewBuffer);
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| 
 | |
| EFI_STATUS
 | |
| GetHiiInterface (
 | |
|   OUT     EFI_HII_PROTOCOL    **Hii
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Get the HII protocol interface
 | |
|   
 | |
| Arguments:
 | |
|   
 | |
|   Hii     - HII protocol interface
 | |
|   
 | |
| Returns: 
 | |
| 
 | |
|   Status code
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
| 
 | |
|   //
 | |
|   // There should only be one HII protocol
 | |
|   //
 | |
|   Status = gBS->LocateProtocol (
 | |
|                   &gEfiHiiProtocolGuid,
 | |
|                   NULL,
 | |
|                   (VOID **) Hii
 | |
|                   );
 | |
| 
 | |
|   return Status;;
 | |
| }
 | |
| 
 | |
| 
 | |
| EFI_STATUS
 | |
| ExtractDataFromHiiHandle (
 | |
|   IN      EFI_HII_HANDLE      HiiHandle,
 | |
|   IN OUT  UINT16              *ImageLength,
 | |
|   OUT     UINT8               *DefaultImage,
 | |
|   OUT     EFI_GUID            *Guid
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Extract information pertaining to the HiiHandle
 | |
|   
 | |
| Arguments:
 | |
|   
 | |
|   HiiHandle       - Hii handle
 | |
|   
 | |
|   ImageLength     - For input, length of DefaultImage;
 | |
|                     For output, length of actually required
 | |
|                     
 | |
|   DefaultImage    - Image buffer prepared by caller
 | |
|   
 | |
|   Guid            - Guid information about the form
 | |
|   
 | |
| Returns: 
 | |
| 
 | |
|   EFI_OUT_OF_RESOURCES    - No enough buffer to allocate
 | |
|   
 | |
|   EFI_BUFFER_TOO_SMALL    - DefualtImage has no enough ImageLength
 | |
|   
 | |
|   EFI_SUCCESS             - Successfully extract data from Hii database.
 | |
|   
 | |
|   
 | |
| --*/
 | |
| {
 | |
|   EFI_STATUS        Status;
 | |
|   EFI_HII_PROTOCOL  *Hii;
 | |
|   UINTN             DataLength;
 | |
|   UINT8             *RawData;
 | |
|   UINT8             *OldData;
 | |
|   UINTN             Index;
 | |
|   UINTN             Temp;
 | |
|   UINTN             SizeOfNvStore;
 | |
|   UINTN             CachedStart;
 | |
| 
 | |
|   DataLength    = DEFAULT_FORM_BUFFER_SIZE;
 | |
|   SizeOfNvStore = 0;
 | |
|   CachedStart   = 0;
 | |
| 
 | |
|   Status        = GetHiiInterface (&Hii);
 | |
| 
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Allocate space for retrieval of IFR data
 | |
|   //
 | |
|   RawData = AllocateZeroPool (DataLength);
 | |
|   if (RawData == NULL) {
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Get all the forms associated with this HiiHandle
 | |
|   //
 | |
|   Status = Hii->GetForms (Hii, HiiHandle, 0, &DataLength, RawData);
 | |
| 
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     gBS->FreePool (RawData);
 | |
| 
 | |
|     //
 | |
|     // Allocate space for retrieval of IFR data
 | |
|     //
 | |
|     RawData = AllocateZeroPool (DataLength);
 | |
|     if (RawData == NULL) {
 | |
|       return EFI_OUT_OF_RESOURCES;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Get all the forms associated with this HiiHandle
 | |
|     //
 | |
|     Status = Hii->GetForms (Hii, HiiHandle, 0, &DataLength, RawData);
 | |
|   }
 | |
| 
 | |
|   OldData = RawData;
 | |
| 
 | |
|   //
 | |
|   // Point RawData to the beginning of the form data
 | |
|   //
 | |
|   RawData = (UINT8 *) ((UINTN) RawData + sizeof (EFI_HII_PACK_HEADER));
 | |
| 
 | |
|   for (Index = 0; RawData[Index] != EFI_IFR_END_FORM_SET_OP;) {
 | |
|     switch (RawData[Index]) {
 | |
|     case EFI_IFR_FORM_SET_OP:
 | |
|       //
 | |
|       // Copy the GUID information from this handle
 | |
|       //
 | |
|       CopyMem (Guid, &((EFI_IFR_FORM_SET *) &RawData[Index])->Guid, sizeof (EFI_GUID));
 | |
|       break;
 | |
| 
 | |
|     case EFI_IFR_ONE_OF_OP:
 | |
|     case EFI_IFR_CHECKBOX_OP:
 | |
|     case EFI_IFR_NUMERIC_OP:
 | |
|     case EFI_IFR_DATE_OP:
 | |
|     case EFI_IFR_TIME_OP:
 | |
|     case EFI_IFR_PASSWORD_OP:
 | |
|     case EFI_IFR_STRING_OP:
 | |
|       //
 | |
|       // Remember, multiple op-codes may reference the same item, so let's keep a running
 | |
|       // marker of what the highest QuestionId that wasn't zero length.  This will accurately
 | |
|       // maintain the Size of the NvStore
 | |
|       //
 | |
|       if (((EFI_IFR_ONE_OF *) &RawData[Index])->Width != 0) {
 | |
|         Temp = ((EFI_IFR_ONE_OF *) &RawData[Index])->QuestionId + ((EFI_IFR_ONE_OF *) &RawData[Index])->Width;
 | |
|         if (SizeOfNvStore < Temp) {
 | |
|           SizeOfNvStore = ((EFI_IFR_ONE_OF *) &RawData[Index])->QuestionId + ((EFI_IFR_ONE_OF *) &RawData[Index])->Width;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     Index = RawData[Index + 1] + Index;
 | |
|   }
 | |
|     
 | |
|   //
 | |
|   // Return an error if buffer is too small
 | |
|   //
 | |
|   if (SizeOfNvStore > *ImageLength) {
 | |
|     gBS->FreePool (OldData);
 | |
|     *ImageLength = (UINT16) SizeOfNvStore;
 | |
|     return EFI_BUFFER_TOO_SMALL;
 | |
|   }
 | |
| 
 | |
|   if (DefaultImage != NULL) {
 | |
|     ZeroMem (DefaultImage, SizeOfNvStore);
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Copy the default image information to the user's buffer
 | |
|   //
 | |
|   for (Index = 0; RawData[Index] != EFI_IFR_END_FORM_SET_OP;) {
 | |
|     switch (RawData[Index]) {
 | |
|     case EFI_IFR_ONE_OF_OP:
 | |
|       CachedStart = ((EFI_IFR_ONE_OF *) &RawData[Index])->QuestionId;
 | |
|       break;
 | |
| 
 | |
|     case EFI_IFR_ONE_OF_OPTION_OP:
 | |
|       if (((EFI_IFR_ONE_OF_OPTION *) &RawData[Index])->Flags & EFI_IFR_FLAG_DEFAULT) {
 | |
|         CopyMem (&DefaultImage[CachedStart], &((EFI_IFR_ONE_OF_OPTION *) &RawData[Index])->Value, 2);
 | |
|       }
 | |
|       break;
 | |
| 
 | |
|     case EFI_IFR_CHECKBOX_OP:
 | |
|       DefaultImage[((EFI_IFR_ONE_OF *) &RawData[Index])->QuestionId] = ((EFI_IFR_CHECKBOX *) &RawData[Index])->Flags;
 | |
|       break;
 | |
| 
 | |
|     case EFI_IFR_NUMERIC_OP:
 | |
|       CopyMem (
 | |
|         &DefaultImage[((EFI_IFR_ONE_OF *) &RawData[Index])->QuestionId],
 | |
|         &((EFI_IFR_NUMERIC *) &RawData[Index])->Default,
 | |
|         2
 | |
|         );
 | |
|       break;
 | |
| 
 | |
|     }
 | |
| 
 | |
|     Index = RawData[Index + 1] + Index;
 | |
|   }
 | |
| 
 | |
|   *ImageLength = (UINT16) SizeOfNvStore;
 | |
| 
 | |
|   //
 | |
|   // Free our temporary repository of form data
 | |
|   //
 | |
|   gBS->FreePool (OldData);
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| 
 | |
| EFI_HII_HANDLE
 | |
| FindHiiHandle (
 | |
|   IN OUT EFI_HII_PROTOCOL    **HiiProtocol, OPTIONAL
 | |
|   IN     EFI_GUID            *Guid
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
|   Finds HII handle for given pack GUID previously registered with the HII.
 | |
| 
 | |
| Arguments:
 | |
|   HiiProtocol - pointer to pointer to HII protocol interface. 
 | |
|                 If NULL, the interface will be found but not returned.
 | |
|                 If it points to NULL, the interface will be found and 
 | |
|                 written back to the pointer that is pointed to.
 | |
|   Guid        - The GUID of the pack that registered with the HII.
 | |
| 
 | |
| Returns:
 | |
|   Handle to the HII pack previously registered by the memory driver.
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   EFI_STATUS        Status;
 | |
| 
 | |
|   EFI_HII_HANDLE    *HiiHandleBuffer;
 | |
|   EFI_HII_HANDLE    HiiHandle;
 | |
|   UINT16            HiiHandleBufferLength;
 | |
|   UINT32            NumberOfHiiHandles;
 | |
|   EFI_GUID          HiiGuid;
 | |
|   EFI_HII_PROTOCOL  *HiiProt;
 | |
|   UINT32            Index;
 | |
|   UINT16            Length;
 | |
| 
 | |
|   HiiHandle = 0;
 | |
|   if ((HiiProtocol != NULL) && (*HiiProtocol != NULL)) {
 | |
|     //
 | |
|     // The protocol has been passed in
 | |
|     //
 | |
|     HiiProt = *HiiProtocol;
 | |
|   } else {
 | |
|     gBS->LocateProtocol (
 | |
|           &gEfiHiiProtocolGuid,
 | |
|           NULL,
 | |
|           (VOID **) &HiiProt
 | |
|           );
 | |
|     if (HiiProt == NULL) {
 | |
|       return HiiHandle;
 | |
|     }
 | |
| 
 | |
|     if (HiiProtocol != NULL) {
 | |
|       //
 | |
|       // Return back the HII protocol for the caller as promissed
 | |
|       //
 | |
|       *HiiProtocol = HiiProt;
 | |
|     }
 | |
|   }
 | |
|   //
 | |
|   // Allocate buffer
 | |
|   //
 | |
|   HiiHandleBufferLength = 10;
 | |
|   HiiHandleBuffer       = AllocatePool (HiiHandleBufferLength);
 | |
|   ASSERT (HiiHandleBuffer != NULL);
 | |
| 
 | |
|   //
 | |
|   // Get the Handles of the packages that were registered with Hii
 | |
|   //
 | |
|   Status = HiiProt->FindHandles (
 | |
|                       HiiProt,
 | |
|                       &HiiHandleBufferLength,
 | |
|                       HiiHandleBuffer
 | |
|                       );
 | |
| 
 | |
|   //
 | |
|   // Get a bigger bugffer if this one is to small, and try again
 | |
|   //
 | |
|   if (Status == EFI_BUFFER_TOO_SMALL) {
 | |
| 
 | |
|     gBS->FreePool (HiiHandleBuffer);
 | |
| 
 | |
|     HiiHandleBuffer = AllocatePool (HiiHandleBufferLength);
 | |
|     ASSERT (HiiHandleBuffer != NULL);
 | |
| 
 | |
|     Status = HiiProt->FindHandles (
 | |
|                         HiiProt,
 | |
|                         &HiiHandleBufferLength,
 | |
|                         HiiHandleBuffer
 | |
|                         );
 | |
|   }
 | |
| 
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     goto lbl_exit;
 | |
|   }
 | |
| 
 | |
|   NumberOfHiiHandles = HiiHandleBufferLength / sizeof (EFI_HII_HANDLE);
 | |
| 
 | |
|   //
 | |
|   // Iterate Hii handles and look for the one that matches our Guid
 | |
|   //
 | |
|   for (Index = 0; Index < NumberOfHiiHandles; Index++) {
 | |
| 
 | |
|     Length = 0;
 | |
|     ExtractDataFromHiiHandle (HiiHandleBuffer[Index], &Length, NULL, &HiiGuid);
 | |
| 
 | |
|     if (CompareGuid (&HiiGuid, Guid)) {
 | |
| 
 | |
|       HiiHandle = HiiHandleBuffer[Index];
 | |
|       break;
 | |
|     }
 | |
|   }
 | |
| 
 | |
| lbl_exit:
 | |
|   gBS->FreePool (HiiHandleBuffer);
 | |
|   return HiiHandle;
 | |
| }
 | |
| 
 | |
| 
 | |
| EFI_STATUS
 | |
| ValidateDataFromHiiHandle (
 | |
|   IN      EFI_HII_HANDLE      HiiHandle,
 | |
|   OUT     BOOLEAN             *Results
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Validate that the data associated with the HiiHandle in NVRAM is within
 | |
|   the reasonable parameters for that FormSet.  Values for strings and passwords
 | |
|   are not verified due to their not having the equivalent of valid range settings.
 | |
|   
 | |
| Arguments:
 | |
| 
 | |
|   HiiHandle -   Handle of the HII database entry to query
 | |
| 
 | |
|   Results -     If return Status is EFI_SUCCESS, Results provides valid data
 | |
|                 TRUE  = NVRAM Data is within parameters
 | |
|                 FALSE = NVRAM Data is NOT within parameters
 | |
|   
 | |
| Returns: 
 | |
| 
 | |
|   EFI_OUT_OF_RESOURCES      - No enough buffer to allocate
 | |
|   
 | |
|   EFI_SUCCESS               - Data successfully validated
 | |
| --*/
 | |
| {
 | |
|   EFI_STATUS        Status;
 | |
|   EFI_HII_PROTOCOL  *Hii;
 | |
|   EFI_GUID          Guid;
 | |
|   UINT8             *RawData;
 | |
|   UINT8             *OldData;
 | |
|   UINTN             RawDataLength;
 | |
|   UINT8             *VariableData;
 | |
|   UINTN             Index;
 | |
|   UINTN             Temp;
 | |
|   UINTN             SizeOfNvStore;
 | |
|   UINTN             CachedStart;
 | |
|   BOOLEAN           GotMatch;
 | |
| 
 | |
|   RawDataLength = DEFAULT_FORM_BUFFER_SIZE;
 | |
|   SizeOfNvStore = 0;
 | |
|   CachedStart   = 0;
 | |
|   GotMatch      = FALSE;
 | |
|   *Results      = TRUE;
 | |
| 
 | |
|   Status        = GetHiiInterface (&Hii);
 | |
| 
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Allocate space for retrieval of IFR data
 | |
|   //
 | |
|   RawData = AllocateZeroPool (RawDataLength);
 | |
|   if (RawData == NULL) {
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Get all the forms associated with this HiiHandle
 | |
|   //
 | |
|   Status = Hii->GetForms (Hii, HiiHandle, 0, &RawDataLength, RawData);
 | |
| 
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     gBS->FreePool (RawData);
 | |
| 
 | |
|     //
 | |
|     // Allocate space for retrieval of IFR data
 | |
|     //
 | |
|     RawData = AllocateZeroPool (RawDataLength);
 | |
|     if (RawData == NULL) {
 | |
|       return EFI_OUT_OF_RESOURCES;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Get all the forms associated with this HiiHandle
 | |
|     //
 | |
|     Status = Hii->GetForms (Hii, HiiHandle, 0, &RawDataLength, RawData);
 | |
|   }
 | |
| 
 | |
|   OldData = RawData;
 | |
| 
 | |
|   //
 | |
|   // Point RawData to the beginning of the form data
 | |
|   //
 | |
|   RawData = (UINT8 *) ((UINTN) RawData + sizeof (EFI_HII_PACK_HEADER));
 | |
| 
 | |
|   for (Index = 0; RawData[Index] != EFI_IFR_END_FORM_SET_OP;) {
 | |
|     if (RawData[Index] == EFI_IFR_FORM_SET_OP) {
 | |
|       CopyMem (&Guid, &((EFI_IFR_FORM_SET *) &RawData[Index])->Guid, sizeof (EFI_GUID));
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|     Index = RawData[Index + 1] + Index;
 | |
|   }
 | |
| 
 | |
|   for (Index = 0; RawData[Index] != EFI_IFR_END_FORM_SET_OP;) {
 | |
|     switch (RawData[Index]) {
 | |
|     case EFI_IFR_FORM_SET_OP:
 | |
|       break;
 | |
| 
 | |
|     case EFI_IFR_ONE_OF_OP:
 | |
|     case EFI_IFR_CHECKBOX_OP:
 | |
|     case EFI_IFR_NUMERIC_OP:
 | |
|     case EFI_IFR_DATE_OP:
 | |
|     case EFI_IFR_TIME_OP:
 | |
|     case EFI_IFR_PASSWORD_OP:
 | |
|     case EFI_IFR_STRING_OP:
 | |
|       //
 | |
|       // Remember, multiple op-codes may reference the same item, so let's keep a running
 | |
|       // marker of what the highest QuestionId that wasn't zero length.  This will accurately
 | |
|       // maintain the Size of the NvStore
 | |
|       //
 | |
|       if (((EFI_IFR_ONE_OF *) &RawData[Index])->Width != 0) {
 | |
|         Temp = ((EFI_IFR_ONE_OF *) &RawData[Index])->QuestionId + ((EFI_IFR_ONE_OF *) &RawData[Index])->Width;
 | |
|         if (SizeOfNvStore < Temp) {
 | |
|           SizeOfNvStore = ((EFI_IFR_ONE_OF *) &RawData[Index])->QuestionId + ((EFI_IFR_ONE_OF *) &RawData[Index])->Width;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     Index = RawData[Index + 1] + Index;
 | |
|   }
 | |
|     
 | |
|   //
 | |
|   // Allocate memory for our File Form Tags
 | |
|   //
 | |
|   VariableData = AllocateZeroPool (SizeOfNvStore);
 | |
|   if (VariableData == NULL) {
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
| 
 | |
|   Status = gRT->GetVariable (
 | |
|                   (CHAR16 *) L"Setup",
 | |
|                   &Guid,
 | |
|                   NULL,
 | |
|                   &SizeOfNvStore,
 | |
|                   (VOID *) VariableData
 | |
|                   );
 | |
| 
 | |
|   if (EFI_ERROR (Status)) {
 | |
| 
 | |
|     //
 | |
|     // If there is a variable that exists already and it is larger than what we calculated the
 | |
|     // storage needs to be, we must assume the variable size from GetVariable is correct and not
 | |
|     // allow the truncation of the variable.  It is very possible that the user who created the IFR
 | |
|     // we are cracking is not referring to a variable that was in a previous map, however we cannot
 | |
|     // allow it's truncation.
 | |
|     //
 | |
|     if (Status == EFI_BUFFER_TOO_SMALL) {
 | |
|       //
 | |
|       // Free the buffer that was allocated that was too small
 | |
|       //
 | |
|       gBS->FreePool (VariableData);
 | |
| 
 | |
|       VariableData = AllocatePool (SizeOfNvStore);
 | |
|       if (VariableData == NULL) {
 | |
|         return EFI_OUT_OF_RESOURCES;
 | |
|       }
 | |
| 
 | |
|       Status = gRT->GetVariable (
 | |
|                       (CHAR16 *) L"Setup",
 | |
|                       &Guid,
 | |
|                       NULL,
 | |
|                       &SizeOfNvStore,
 | |
|                       (VOID *) VariableData
 | |
|                       );
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Walk through the form and see that the variable data it refers to is ok.
 | |
|   // This allows for the possibility of stale (obsoleted) data in the variable
 | |
|   // can be overlooked without causing an error
 | |
|   //
 | |
|   for (Index = 0; RawData[Index] != EFI_IFR_END_FORM_SET_OP;) {
 | |
|     switch (RawData[Index]) {
 | |
|     case EFI_IFR_ONE_OF_OP:
 | |
|       //
 | |
|       // A one_of has no data, its the option that does - cache the storage Id
 | |
|       //
 | |
|       CachedStart = ((EFI_IFR_ONE_OF *) &RawData[Index])->QuestionId;
 | |
|       break;
 | |
| 
 | |
|     case EFI_IFR_ONE_OF_OPTION_OP:
 | |
|       //
 | |
|       // A one_of_option can be any value
 | |
|       //
 | |
|       if (VariableData[CachedStart] == ((EFI_IFR_ONE_OF_OPTION *) &RawData[Index])->Value) {
 | |
|         GotMatch = TRUE;
 | |
|       }
 | |
|       break;
 | |
| 
 | |
|     case EFI_IFR_END_ONE_OF_OP:
 | |
|       //
 | |
|       // At this point lets make sure that the data value in the NVRAM matches one of the options
 | |
|       //
 | |
|       if (!GotMatch) {
 | |
|         *Results = FALSE;
 | |
|         return EFI_SUCCESS;
 | |
|       }
 | |
|       break;
 | |
| 
 | |
|     case EFI_IFR_CHECKBOX_OP:
 | |
|       //
 | |
|       // A checkbox is a boolean, so 0 and 1 are valid
 | |
|       // Remember, QuestionId corresponds to the offset location of the data in the variable
 | |
|       //
 | |
|       if (VariableData[((EFI_IFR_CHECKBOX *) &RawData[Index])->QuestionId] > 1) {
 | |
|         *Results = FALSE;
 | |
|         return EFI_SUCCESS;
 | |
|       }
 | |
|       break;
 | |
| 
 | |
|     case EFI_IFR_NUMERIC_OP:
 | |
|         if ((VariableData[((EFI_IFR_NUMERIC *)&RawData[Index])->QuestionId] < ((EFI_IFR_NUMERIC *)&RawData[Index])->Minimum) ||
 | |
|             (VariableData[((EFI_IFR_NUMERIC *)&RawData[Index])->QuestionId] > ((EFI_IFR_NUMERIC *)&RawData[Index])->Maximum)) {
 | |
|         *Results = FALSE;
 | |
|         return EFI_SUCCESS;
 | |
|       }
 | |
|       break;
 | |
| 
 | |
|     }
 | |
| 
 | |
|     Index = RawData[Index + 1] + Index;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Free our temporary repository of form data
 | |
|   //
 | |
|   gBS->FreePool (OldData);
 | |
|   gBS->FreePool (VariableData);
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 |