/** @file | |
Implementation of HII utility library. | |
Copyright (c) 2019, Intel Corporation. All rights reserved.<BR> | |
(C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR> | |
Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. | |
SPDX-License-Identifier: BSD-2-Clause-Patent | |
**/ | |
#include "HiiInternal.h" | |
/** | |
Initialize the internal data structure of a FormSet. | |
@param Handle PackageList Handle | |
@param FormSetGuid On input, GUID or class GUID of a formset. If not | |
specified (NULL or zero GUID), take the first | |
FormSet with class GUID EFI_HII_PLATFORM_SETUP_FORMSET_GUID | |
found in package list. | |
On output, GUID of the formset found(if not NULL). | |
@param FormSet FormSet data structure. | |
@retval EFI_SUCCESS The function completed successfully. | |
@retval EFI_NOT_FOUND The specified FormSet could not be found. | |
**/ | |
EFI_STATUS | |
CreateFormSetFromHiiHandle ( | |
IN EFI_HII_HANDLE Handle, | |
IN OUT EFI_GUID *FormSetGuid, | |
OUT HII_FORMSET *FormSet | |
) | |
{ | |
EFI_STATUS Status; | |
EFI_HANDLE DriverHandle; | |
EFI_HII_DATABASE_PROTOCOL *HiiDatabase; | |
if ((FormSetGuid == NULL) || (FormSet == NULL)) { | |
return EFI_INVALID_PARAMETER; | |
} | |
// | |
// Locate required Hii Database protocol | |
// | |
Status = gBS->LocateProtocol ( | |
&gEfiHiiDatabaseProtocolGuid, | |
NULL, | |
(VOID **)&HiiDatabase | |
); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
Status = GetIfrBinaryData (Handle, FormSetGuid, &FormSet->IfrBinaryLength, &FormSet->IfrBinaryData); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
FormSet->Signature = HII_FORMSET_SIGNATURE; | |
FormSet->HiiHandle = Handle; | |
CopyMem (&FormSet->Guid, FormSetGuid, sizeof (EFI_GUID)); | |
// | |
// Retrieve ConfigAccess Protocol associated with this HiiPackageList | |
// | |
Status = HiiDatabase->GetPackageListHandle (HiiDatabase, Handle, &DriverHandle); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
FormSet->DriverHandle = DriverHandle; | |
Status = gBS->HandleProtocol ( | |
DriverHandle, | |
&gEfiHiiConfigAccessProtocolGuid, | |
(VOID **)&FormSet->ConfigAccess | |
); | |
if (EFI_ERROR (Status)) { | |
// | |
// Configuration Driver don't attach ConfigAccess protocol to its HII package | |
// list, then there will be no configuration action required | |
// | |
FormSet->ConfigAccess = NULL; | |
} | |
Status = gBS->HandleProtocol ( | |
DriverHandle, | |
&gEfiDevicePathProtocolGuid, | |
(VOID **)&FormSet->DevicePath | |
); | |
if (EFI_ERROR (Status)) { | |
// | |
// Configuration Driver don't attach ConfigAccess protocol to its HII package | |
// list, then there will be no configuration action required | |
// | |
FormSet->DevicePath = NULL; | |
} | |
// | |
// Parse the IFR binary OpCodes | |
// | |
Status = ParseOpCodes (FormSet); | |
return Status; | |
} | |
/** | |
Initialize a Formset and get current setting for Questions. | |
@param FormSet FormSet data structure. | |
**/ | |
VOID | |
InitializeFormSet ( | |
IN OUT HII_FORMSET *FormSet | |
) | |
{ | |
LIST_ENTRY *Link; | |
HII_FORMSET_STORAGE *Storage; | |
LIST_ENTRY *FormLink; | |
HII_STATEMENT *Question; | |
HII_FORM *Form; | |
if (FormSet == NULL) { | |
return; | |
} | |
// | |
// Load Storage for all questions with storage | |
// | |
Link = GetFirstNode (&FormSet->StorageListHead); | |
while (!IsNull (&FormSet->StorageListHead, Link)) { | |
Storage = HII_STORAGE_FROM_LINK (Link); | |
LoadFormSetStorage (FormSet, Storage); | |
Link = GetNextNode (&FormSet->StorageListHead, Link); | |
} | |
// | |
// Get Current Value for all no storage questions | |
// | |
FormLink = GetFirstNode (&FormSet->FormListHead); | |
while (!IsNull (&FormSet->FormListHead, FormLink)) { | |
Form = HII_FORM_FROM_LINK (FormLink); | |
Link = GetFirstNode (&Form->StatementListHead); | |
while (!IsNull (&Form->StatementListHead, Link)) { | |
Question = HII_STATEMENT_FROM_LINK (Link); | |
if (Question->Storage == NULL) { | |
RetrieveQuestion (FormSet, Form, Question); | |
} | |
Link = GetNextNode (&Form->StatementListHead, Link); | |
} | |
FormLink = GetNextNode (&FormSet->FormListHead, FormLink); | |
} | |
} | |
/** | |
Free resources allocated for a FormSet. | |
@param[in,out] FormSet Pointer of the FormSet | |
**/ | |
VOID | |
DestroyFormSet ( | |
IN OUT HII_FORMSET *FormSet | |
) | |
{ | |
LIST_ENTRY *Link; | |
HII_FORMSET_STORAGE *Storage; | |
HII_FORMSET_DEFAULTSTORE *DefaultStore; | |
HII_FORM *Form; | |
if (FormSet->IfrBinaryData == NULL) { | |
// | |
// Uninitialized FormSet | |
// | |
FreePool (FormSet); | |
return; | |
} | |
// | |
// Free IFR binary buffer | |
// | |
FreePool (FormSet->IfrBinaryData); | |
// | |
// Free FormSet Storage | |
// | |
if (FormSet->StorageListHead.ForwardLink != NULL) { | |
while (!IsListEmpty (&FormSet->StorageListHead)) { | |
Link = GetFirstNode (&FormSet->StorageListHead); | |
Storage = HII_STORAGE_FROM_LINK (Link); | |
RemoveEntryList (&Storage->Link); | |
if (Storage != NULL) { | |
FreePool (Storage); | |
} | |
} | |
} | |
// | |
// Free FormSet Default Store | |
// | |
if (FormSet->DefaultStoreListHead.ForwardLink != NULL) { | |
while (!IsListEmpty (&FormSet->DefaultStoreListHead)) { | |
Link = GetFirstNode (&FormSet->DefaultStoreListHead); | |
DefaultStore = HII_FORMSET_DEFAULTSTORE_FROM_LINK (Link); | |
RemoveEntryList (&DefaultStore->Link); | |
FreePool (DefaultStore); | |
} | |
} | |
// | |
// Free Forms | |
// | |
if (FormSet->FormListHead.ForwardLink != NULL) { | |
while (!IsListEmpty (&FormSet->FormListHead)) { | |
Link = GetFirstNode (&FormSet->FormListHead); | |
Form = HII_FORM_FROM_LINK (Link); | |
RemoveEntryList (&Form->Link); | |
DestroyForm (FormSet, Form); | |
} | |
} | |
FreePool (FormSet); | |
} | |
/** | |
Submit data for a form. | |
@param[in] FormSet FormSet which contains the Form. | |
@param[in] Form Form to submit. | |
@retval EFI_SUCCESS The function completed successfully. | |
@retval Others Other errors occur. | |
**/ | |
EFI_STATUS | |
SubmitForm ( | |
IN HII_FORMSET *FormSet, | |
IN HII_FORM *Form | |
) | |
{ | |
EFI_STATUS Status; | |
EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting; | |
LIST_ENTRY *Link; | |
EFI_STRING ConfigResp; | |
EFI_STRING Progress; | |
HII_FORMSET_STORAGE *Storage; | |
HII_FORM_CONFIG_REQUEST *ConfigInfo; | |
if ((FormSet == NULL) || (Form == NULL)) { | |
return EFI_INVALID_PARAMETER; | |
} | |
Status = NoSubmitCheck (FormSet, &Form, NULL); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
Link = GetFirstNode (&Form->ConfigRequestHead); | |
while (!IsNull (&Form->ConfigRequestHead, Link)) { | |
ConfigInfo = HII_FORM_CONFIG_REQUEST_FROM_LINK (Link); | |
Link = GetNextNode (&Form->ConfigRequestHead, Link); | |
Storage = ConfigInfo->Storage; | |
if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) { | |
continue; | |
} | |
// | |
// Skip if there is no RequestElement | |
// | |
if (ConfigInfo->ElementCount == 0) { | |
continue; | |
} | |
Status = StorageToConfigResp (ConfigInfo->Storage, &ConfigResp, ConfigInfo->ConfigRequest); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
Status = gBS->LocateProtocol ( | |
&gEfiHiiConfigRoutingProtocolGuid, | |
NULL, | |
(VOID **)&HiiConfigRouting | |
); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
Status = HiiConfigRouting->RouteConfig ( | |
HiiConfigRouting, | |
ConfigResp, | |
&Progress | |
); | |
if (EFI_ERROR (Status)) { | |
FreePool (ConfigResp); | |
continue; | |
} | |
FreePool (ConfigResp); | |
} | |
return Status; | |
} | |
/** | |
Save Question Value to the memory, but not to storage. | |
@param[in] FormSet FormSet data structure. | |
@param[in] Form Form data structure. | |
@param[in,out] Question Pointer to the Question. | |
@param[in] QuestionValue New Question Value to be set. | |
@retval EFI_SUCCESS The question value has been set successfully. | |
@retval EFI_INVALID_PARAMETER One or more parameters are invalid. | |
**/ | |
EFI_STATUS | |
SetQuestionValue ( | |
IN HII_FORMSET *FormSet, | |
IN HII_FORM *Form, | |
IN OUT HII_STATEMENT *Question, | |
IN HII_STATEMENT_VALUE *QuestionValue | |
) | |
{ | |
UINT8 *Src; | |
UINTN BufferLen; | |
UINTN StorageWidth; | |
HII_FORMSET_STORAGE *Storage; | |
CHAR16 *ValueStr; | |
BOOLEAN IsBufferStorage; | |
UINT8 *TemBuffer; | |
CHAR16 *TemName; | |
CHAR16 *TemString; | |
UINTN Index; | |
HII_NAME_VALUE_NODE *Node; | |
EFI_STATUS Status; | |
if ((FormSet == NULL) || (Form == NULL) || (Question == NULL) || (QuestionValue == NULL)) { | |
return EFI_INVALID_PARAMETER; | |
} | |
Status = EFI_SUCCESS; | |
Node = NULL; | |
// | |
// If Question value is provided by an Expression, then it is read only | |
// | |
if ((Question->ValueExpression != NULL) || (Question->Value.Type != QuestionValue->Type)) { | |
return EFI_INVALID_PARAMETER; | |
} | |
// | |
// Before set question value, evaluate its write expression. | |
// | |
if ((Question->WriteExpression != NULL) && (Form->FormType == STANDARD_MAP_FORM_TYPE)) { | |
Status = EvaluateHiiExpression (FormSet, Form, Question->WriteExpression); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
} | |
Storage = Question->Storage; | |
if (Storage != NULL) { | |
StorageWidth = Question->StorageWidth; | |
if (Question->Value.Type == EFI_IFR_TYPE_BUFFER) { | |
Question->Value.BufferLen = QuestionValue->BufferLen; | |
Question->Value.Buffer = AllocateCopyPool (QuestionValue->BufferLen, QuestionValue->Buffer); | |
if (Question->Value.Buffer == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
Question->Value.BufferValueType = QuestionValue->BufferValueType; | |
Src = Question->Value.Buffer; | |
} else if (Question->Value.Type == EFI_IFR_TYPE_STRING) { | |
Question->Value.Value.string = QuestionValue->Value.string; | |
TemString = HiiGetString (FormSet->HiiHandle, QuestionValue->Value.string, NULL); | |
if (TemString == NULL) { | |
return EFI_ABORTED; | |
} | |
Question->Value.BufferLen = Question->StorageWidth; | |
Question->Value.Buffer = AllocateZeroPool (Question->StorageWidth); | |
if (Question->Value.Buffer == NULL) { | |
FreePool (TemString); | |
return EFI_OUT_OF_RESOURCES; | |
} | |
CopyMem (Question->Value.Buffer, TemString, StrSize (TemString)); | |
Src = Question->Value.Buffer; | |
FreePool (TemString); | |
} else { | |
CopyMem (&Question->Value.Value, &QuestionValue->Value, sizeof (EFI_IFR_TYPE_VALUE)); | |
Src = (UINT8 *)&Question->Value.Value; | |
} | |
if ((Storage->Type == EFI_HII_VARSTORE_BUFFER) || (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) { | |
IsBufferStorage = TRUE; | |
} else { | |
IsBufferStorage = FALSE; | |
} | |
if (IsBufferStorage) { | |
// | |
// If the Question refer to bit filed, copy the value in related bit filed to storage edit buffer. | |
// | |
if (Question->QuestionReferToBitField) { | |
SetBitsQuestionValue (Question, Storage->Buffer + Question->VarStoreInfo.VarOffset, (UINT32)(*Src)); | |
} else { | |
CopyMem (Storage->Buffer + Question->VarStoreInfo.VarOffset, Src, StorageWidth); | |
} | |
} else { | |
if (Question->Value.Type == EFI_IFR_TYPE_STRING) { | |
// | |
// Allocate enough string buffer. | |
// | |
ValueStr = NULL; | |
BufferLen = ((StrLen ((CHAR16 *)Src) * 4) + 1) * sizeof (CHAR16); | |
ValueStr = AllocatePool (BufferLen); | |
if (ValueStr == NULL) { | |
if (Question->Value.Buffer != NULL) { | |
FreePool (Question->Value.Buffer); | |
} | |
return EFI_OUT_OF_RESOURCES; | |
} | |
// | |
// Convert Unicode String to Config String, e.g. "ABCD" => "0041004200430044" | |
// | |
TemName = (CHAR16 *)Src; | |
TemString = ValueStr; | |
for ( ; *TemName != L'\0'; TemName++) { | |
UnicodeValueToStringS ( | |
TemString, | |
BufferLen - ((UINTN)TemString - (UINTN)ValueStr), | |
PREFIX_ZERO | RADIX_HEX, | |
*TemName, | |
4 | |
); | |
TemString += StrnLenS (TemString, (BufferLen - ((UINTN)TemString - (UINTN)ValueStr)) / sizeof (CHAR16)); | |
} | |
} else { | |
BufferLen = StorageWidth * 2 + 1; | |
ValueStr = AllocateZeroPool (BufferLen * sizeof (CHAR16)); | |
if (ValueStr == NULL) { | |
if (Question->Value.Buffer != NULL) { | |
FreePool (Question->Value.Buffer); | |
} | |
return EFI_OUT_OF_RESOURCES; | |
} | |
// | |
// Convert Buffer to Hex String | |
// | |
TemBuffer = Src + StorageWidth - 1; | |
TemString = ValueStr; | |
for (Index = 0; Index < StorageWidth; Index++, TemBuffer--) { | |
UnicodeValueToStringS ( | |
TemString, | |
BufferLen * sizeof (CHAR16) - ((UINTN)TemString - (UINTN)ValueStr), | |
PREFIX_ZERO | RADIX_HEX, | |
*TemBuffer, | |
2 | |
); | |
TemString += StrnLenS (TemString, BufferLen - ((UINTN)TemString - (UINTN)ValueStr) / sizeof (CHAR16)); | |
} | |
} | |
Status = SetValueByName (Storage, Question->VariableName, ValueStr, &Node); | |
FreePool (ValueStr); | |
if (EFI_ERROR (Status)) { | |
if (Question->Value.Buffer != NULL) { | |
FreePool (Question->Value.Buffer); | |
} | |
return Status; | |
} | |
} | |
} else { | |
if (Question->Value.Type == EFI_IFR_TYPE_BUFFER) { | |
Question->Value.BufferLen = QuestionValue->BufferLen; | |
Question->Value.Buffer = AllocateCopyPool (QuestionValue->BufferLen, QuestionValue->Buffer); | |
if (Question->Value.Buffer == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
Question->Value.BufferValueType = QuestionValue->BufferValueType; | |
} else if (Question->Value.Type == EFI_IFR_TYPE_STRING) { | |
Question->Value.Value.string = QuestionValue->Value.string; | |
TemString = HiiGetString (FormSet->HiiHandle, QuestionValue->Value.string, NULL); | |
if (TemString == NULL) { | |
return EFI_ABORTED; | |
} | |
Question->Value.BufferLen = (UINT16)StrSize (TemString); | |
Question->Value.Buffer = AllocateZeroPool (QuestionValue->BufferLen); | |
if (Question->Value.Buffer == NULL) { | |
FreePool (TemString); | |
return EFI_OUT_OF_RESOURCES; | |
} | |
CopyMem (Question->Value.Buffer, TemString, StrSize (TemString)); | |
FreePool (TemString); | |
} else { | |
CopyMem (&Question->Value.Value, &QuestionValue->Value, sizeof (EFI_IFR_TYPE_VALUE)); | |
} | |
} | |
return Status; | |
} | |
/** | |
Get Question's current Value from storage. | |
@param[in] FormSet FormSet data structure. | |
@param[in] Form Form data structure. | |
@param[in,out] Question Question to be initialized. | |
@return the current Question Value in storage if success. | |
@return NULL if Question is not found or any error occurs. | |
**/ | |
HII_STATEMENT_VALUE * | |
RetrieveQuestion ( | |
IN HII_FORMSET *FormSet, | |
IN HII_FORM *Form, | |
IN OUT HII_STATEMENT *Question | |
) | |
{ | |
EFI_STATUS Status; | |
EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting; | |
EFI_BROWSER_ACTION_REQUEST ActionRequest; | |
HII_FORMSET_STORAGE *Storage; | |
HII_STATEMENT_VALUE *QuestionValue; | |
EFI_IFR_TYPE_VALUE *TypeValue; | |
EFI_TIME EfiTime; | |
BOOLEAN Enabled; | |
BOOLEAN Pending; | |
UINT8 *Dst; | |
UINTN StorageWidth; | |
CHAR16 *ConfigRequest; | |
CHAR16 *Progress; | |
CHAR16 *Result; | |
CHAR16 *ValueStr; | |
UINTN Length; | |
BOOLEAN IsBufferStorage; | |
CHAR16 *NewHiiString; | |
if ((FormSet == NULL) || (Form == NULL) || (Question == NULL)) { | |
return NULL; | |
} | |
Status = EFI_SUCCESS; | |
ValueStr = NULL; | |
Result = NULL; | |
QuestionValue = AllocateZeroPool (sizeof (HII_STATEMENT_VALUE)); | |
if (QuestionValue == NULL) { | |
return NULL; | |
} | |
QuestionValue->Type = Question->Value.Type; | |
QuestionValue->BufferLen = Question->Value.BufferLen; | |
if (QuestionValue->BufferLen != 0) { | |
QuestionValue->Buffer = AllocateZeroPool (QuestionValue->BufferLen); | |
if (QuestionValue->Buffer == NULL) { | |
FreePool (QuestionValue); | |
return NULL; | |
} | |
} | |
// | |
// Question value is provided by RTC | |
// | |
Storage = Question->Storage; | |
StorageWidth = Question->StorageWidth; | |
if (Storage == NULL) { | |
// | |
// It's a Question without storage, or RTC date/time | |
// | |
if ((Question->Operand == EFI_IFR_DATE_OP) || (Question->Operand == EFI_IFR_TIME_OP)) { | |
// | |
// Date and time define the same Flags bit | |
// | |
switch (Question->ExtraData.Flags & EFI_QF_DATE_STORAGE) { | |
case QF_DATE_STORAGE_TIME: | |
Status = gRT->GetTime (&EfiTime, NULL); | |
break; | |
case QF_DATE_STORAGE_WAKEUP: | |
Status = gRT->GetWakeupTime (&Enabled, &Pending, &EfiTime); | |
break; | |
case QF_DATE_STORAGE_NORMAL: | |
default: | |
goto ON_ERROR; | |
} | |
if (EFI_ERROR (Status)) { | |
if (Question->Operand == EFI_IFR_DATE_OP) { | |
QuestionValue->Value.date.Year = 0xff; | |
QuestionValue->Value.date.Month = 0xff; | |
QuestionValue->Value.date.Day = 0xff; | |
} else { | |
QuestionValue->Value.time.Hour = 0xff; | |
QuestionValue->Value.time.Minute = 0xff; | |
QuestionValue->Value.time.Second = 0xff; | |
} | |
return QuestionValue; | |
} | |
if (Question->Operand == EFI_IFR_DATE_OP) { | |
QuestionValue->Value.date.Year = EfiTime.Year; | |
QuestionValue->Value.date.Month = EfiTime.Month; | |
QuestionValue->Value.date.Day = EfiTime.Day; | |
} else { | |
QuestionValue->Value.time.Hour = EfiTime.Hour; | |
QuestionValue->Value.time.Minute = EfiTime.Minute; | |
QuestionValue->Value.time.Second = EfiTime.Second; | |
} | |
} else { | |
if (((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != EFI_IFR_FLAG_CALLBACK) || | |
(FormSet->ConfigAccess == NULL)) | |
{ | |
goto ON_ERROR; | |
} | |
if (QuestionValue->Type == EFI_IFR_TYPE_BUFFER) { | |
// | |
// For OrderedList, passing in the value buffer to Callback() | |
// | |
TypeValue = (EFI_IFR_TYPE_VALUE *)QuestionValue->Buffer; | |
} else { | |
TypeValue = &QuestionValue->Value; | |
} | |
ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE; | |
Status = FormSet->ConfigAccess->Callback ( | |
FormSet->ConfigAccess, | |
EFI_BROWSER_ACTION_RETRIEVE, | |
Question->QuestionId, | |
QuestionValue->Type, | |
TypeValue, | |
&ActionRequest | |
); | |
if (!EFI_ERROR (Status) && (QuestionValue->Type == EFI_IFR_TYPE_STRING)) { | |
if (TypeValue->string == 0) { | |
goto ON_ERROR; | |
} | |
NewHiiString = GetTokenString (TypeValue->string, FormSet->HiiHandle); | |
if (NewHiiString == NULL) { | |
goto ON_ERROR; | |
} | |
QuestionValue->Buffer = AllocatePool (StrSize (NewHiiString)); | |
if (QuestionValue->Buffer == NULL) { | |
FreePool (NewHiiString); | |
goto ON_ERROR; | |
} | |
CopyMem (QuestionValue->Buffer, NewHiiString, StrSize (NewHiiString)); | |
QuestionValue->BufferLen = (UINT16)StrSize (NewHiiString); | |
FreePool (NewHiiString); | |
} | |
} | |
return QuestionValue; | |
} | |
// | |
// Question value is provided by EFI variable | |
// | |
if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) { | |
if ((QuestionValue->Type != EFI_IFR_TYPE_BUFFER) && (QuestionValue->Type != EFI_IFR_TYPE_STRING)) { | |
Dst = QuestionValue->Buffer; | |
StorageWidth = QuestionValue->BufferLen; | |
} else { | |
Dst = (UINT8 *)&QuestionValue->Value; | |
StorageWidth = sizeof (EFI_IFR_TYPE_VALUE); | |
} | |
Status = gRT->GetVariable ( | |
Question->VariableName, | |
&Storage->Guid, | |
NULL, | |
&StorageWidth, | |
Dst | |
); | |
return QuestionValue; | |
} | |
Status = gBS->LocateProtocol ( | |
&gEfiHiiConfigRoutingProtocolGuid, | |
NULL, | |
(VOID **)&HiiConfigRouting | |
); | |
if (EFI_ERROR (Status)) { | |
goto ON_ERROR; | |
} | |
if (QuestionValue->BufferLen != 0) { | |
Dst = QuestionValue->Buffer; | |
} else { | |
Dst = (UINT8 *)&QuestionValue->Value; | |
} | |
if ((Storage->Type == EFI_HII_VARSTORE_BUFFER) || (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) { | |
IsBufferStorage = TRUE; | |
} else { | |
IsBufferStorage = FALSE; | |
} | |
Storage = GetFstStgFromVarId (FormSet, Question->VarStoreId); | |
if (Storage == NULL) { | |
goto ON_ERROR; | |
} | |
// | |
// <ConfigRequest> ::= <ConfigHdr> + <BlockName> || <ConfigHdr> + "&" + <VariableName> | |
// | |
if (IsBufferStorage) { | |
Length = StrLen (Storage->ConfigHdr); | |
Length += StrLen (Question->BlockName); | |
} else { | |
Length = StrLen (Storage->ConfigHdr); | |
Length += StrLen (Question->VariableName) + 1; | |
} | |
ConfigRequest = AllocatePool ((Length + 1) * sizeof (CHAR16)); | |
if (ConfigRequest == NULL) { | |
goto ON_ERROR; | |
} | |
StrCpyS (ConfigRequest, Length + 1, Storage->ConfigHdr); | |
if (IsBufferStorage) { | |
StrCatS (ConfigRequest, Length + 1, Question->BlockName); | |
} else { | |
StrCatS (ConfigRequest, Length + 1, L"&"); | |
StrCatS (ConfigRequest, Length + 1, Question->VariableName); | |
} | |
// | |
// Request current settings from Configuration Driver | |
// | |
Status = HiiConfigRouting->ExtractConfig ( | |
HiiConfigRouting, | |
ConfigRequest, | |
&Progress, | |
&Result | |
); | |
FreePool (ConfigRequest); | |
if (EFI_ERROR (Status)) { | |
goto ON_ERROR; | |
} | |
if (IsBufferStorage) { | |
ValueStr = StrStr (Result, L"&VALUE"); | |
if (ValueStr == NULL) { | |
FreePool (Result); | |
goto ON_ERROR; | |
} | |
ValueStr = ValueStr + 6; | |
} else { | |
ValueStr = Result + Length; | |
} | |
if (*ValueStr != '=') { | |
FreePool (Result); | |
goto ON_ERROR; | |
} | |
ValueStr++; | |
Status = BufferToQuestionValue (Question, ValueStr, QuestionValue); | |
if (EFI_ERROR (Status)) { | |
FreePool (Result); | |
goto ON_ERROR; | |
} | |
if (Result != NULL) { | |
FreePool (Result); | |
} | |
return QuestionValue; | |
ON_ERROR: | |
if (QuestionValue->Buffer != NULL) { | |
FreePool (QuestionValue->Buffer); | |
} | |
FreePool (QuestionValue); | |
return NULL; | |
} |