Initial import.
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@3 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
995
EdkModulePkg/Library/EdkIfrSupportLib/IfrCommon.c
Normal file
995
EdkModulePkg/Library/EdkIfrSupportLib/IfrCommon.c
Normal file
@@ -0,0 +1,995 @@
|
||||
/*++
|
||||
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;
|
||||
}
|
||||
|
Reference in New Issue
Block a user