mirror of
				https://git.proxmox.com/git/mirror_edk2
				synced 2025-11-04 12:54:17 +00:00 
			
		
		
		
	git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@2313 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			1001 lines
		
	
	
		
			28 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1001 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
 | 
						|
EFIAPI
 | 
						|
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; Index < 3; 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;
 | 
						|
  UINTN               SizeofLanguage;
 | 
						|
  UINTN               SizeofString;
 | 
						|
 | 
						|
  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
 | 
						|
    //
 | 
						|
    SizeofLanguage = StrSize (Language);
 | 
						|
    SizeofString   = StrSize (String);
 | 
						|
    StringPackBuffer->Header.Length = (UINT32)
 | 
						|
      (
 | 
						|
        sizeof (EFI_HII_STRING_PACK) -
 | 
						|
        sizeof (EFI_STRING) +
 | 
						|
        sizeof (RELOFST) +
 | 
						|
        sizeof (RELOFST) +
 | 
						|
        SizeofLanguage +
 | 
						|
        SizeofString
 | 
						|
      );
 | 
						|
    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;
 | 
						|
}
 | 
						|
 | 
						|
STATIC
 | 
						|
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;
 | 
						|
}
 | 
						|
 |