RedfishPkg: introduce HII utility helper library

HiiUtilityLib is a helper library that provides the
functions to manipulate HII options.

Signed-off-by: Nickle Wang <nicklew@nvidia.com>
Cc: Abner Chang <abner.chang@amd.com>
Cc: Igor Kulchytskyy <igork@ami.com>
Cc: Nick Ramirez <nramirez@nvidia.com>
Reviewed-by: Abner Chang <abner.chang@amd.com>
Reviewed-by: Igor Kulchytskyy <igork @ami.com>
This commit is contained in:
Nickle Wang 2023-04-10 21:12:03 +08:00 committed by mergify[bot]
parent 78f088b5a7
commit 02990e2558
9 changed files with 12571 additions and 0 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,191 @@
/** @file
Definitions of Hii Expression.
Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
(C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>
Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#ifndef HII_EXPRESSION_H_
#define HII_EXPRESSION_H_
#include <Library/HiiUtilityLib.h>
/**
Get the expression list count.
@param[in] Level Which type this expression belong to. Form,
statement or option?
@retval >=0 The expression count
@retval -1 Input parameter error.
**/
INTN
GetConditionalExpressionCount (
IN EXPRESS_LEVEL Level
);
/**
Get the expression Buffer pointer.
@param[in] Level Which type this expression belong to. Form,
statement or option?
@retval The start pointer of the expression buffer or NULL.
**/
HII_EXPRESSION **
GetConditionalExpressionList (
IN EXPRESS_LEVEL Level
);
/**
Push the expression options onto the Stack.
@param[in] Pointer Pointer to the current expression.
@param[in] Level Which type this expression belong to. Form,
statement or option?
@retval EFI_SUCCESS The value was pushed onto the stack.
@retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack.
**/
EFI_STATUS
PushConditionalExpression (
IN HII_EXPRESSION *Pointer,
IN EXPRESS_LEVEL Level
);
/**
Pop the expression options from the Stack
@param[in] Level Which type this expression belong to. Form,
statement or option?
@retval EFI_SUCCESS The value was pushed onto the stack.
@retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack.
**/
EFI_STATUS
PopConditionalExpression (
IN EXPRESS_LEVEL Level
);
/**
Reset stack pointer to begin of the stack.
**/
VOID
ResetCurrentExpressionStack (
VOID
);
/**
Push current expression onto the Stack
@param[in] Pointer Pointer to current expression.
@retval EFI_SUCCESS The value was pushed onto the stack.
@retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack.
**/
EFI_STATUS
PushCurrentExpression (
IN VOID *Pointer
);
/**
Pop current expression from the Stack
@param[in] Pointer Pointer to current expression to be pop.
@retval EFI_SUCCESS The value was pushed onto the stack.
@retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack.
**/
EFI_STATUS
PopCurrentExpression (
OUT VOID **Pointer
);
/**
Reset stack pointer to begin of the stack.
**/
VOID
ResetMapExpressionListStack (
VOID
);
/**
Push the list of map expression onto the Stack
@param[in] Pointer Pointer to the list of map expression to be pushed.
@retval EFI_SUCCESS The value was pushed onto the stack.
@retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack.
**/
EFI_STATUS
PushMapExpressionList (
IN VOID *Pointer
);
/**
Pop the list of map expression from the Stack
@param[in] Pointer Pointer to the list of map expression to be pop.
@retval EFI_SUCCESS The value was pushed onto the stack.
@retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack.
**/
EFI_STATUS
PopMapExpressionList (
OUT VOID **Pointer
);
/**
Reset stack pointer to begin of the stack.
**/
VOID
ResetScopeStack (
VOID
);
/**
Push an Operand onto the Stack
@param[in] Operand Operand to push.
@retval EFI_SUCCESS The value was pushed onto the stack.
@retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the
stack.
**/
EFI_STATUS
PushScope (
IN UINT8 Operand
);
/**
Pop an Operand from the Stack
@param[out] Operand Operand to pop.
@retval EFI_SUCCESS The value was pushed onto the stack.
@retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the
stack.
**/
EFI_STATUS
PopScope (
OUT UINT8 *Operand
);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,376 @@
/** @file
HII internal header file.
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
**/
#ifndef HII_INTERNAL_H_
#define HII_INTERNAL_H_
#include <Uefi.h>
#include <Protocol/UnicodeCollation.h>
#include <Protocol/HiiConfigRouting.h>
#include <Protocol/HiiDatabase.h>
#include <Protocol/UserManager.h>
#include <Protocol/DevicePathFromText.h>
#include <Protocol/RegularExpressionProtocol.h>
#include <Guid/MdeModuleHii.h>
#include <Guid/ZeroGuid.h>
#include <Guid/HiiPlatformSetupFormset.h>
#include <Guid/HiiFormMapMethodGuid.h>
#include <Library/PrintLib.h>
#include <Library/DebugLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/UefiRuntimeServicesTableLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/HiiLib.h>
#include <Library/DevicePathLib.h>
#include <Library/UefiLib.h>
#include "HiiExpression.h"
#include <Library/HiiUtilityLib.h>
#define EXPRESSION_STACK_SIZE_INCREMENT 0x100
#define EFI_IFR_SPECIFICATION_VERSION (UINT16) (((EFI_SYSTEM_TABLE_REVISION >> 16) << 8) | (((EFI_SYSTEM_TABLE_REVISION & 0xFFFF) / 10) << 4) | ((EFI_SYSTEM_TABLE_REVISION & 0xFFFF) % 10))
///
/// Definition of HII_FORM_CONFIG_REQUEST
//
typedef struct {
UINTN Signature;
LIST_ENTRY Link;
CHAR16 *ConfigRequest; ///< <ConfigRequest> = <ConfigHdr> + <RequestElement>
CHAR16 *ConfigAltResp; ///< Alt config response string for this ConfigRequest.
UINTN ElementCount; ///< Number of <RequestElement> in the <ConfigRequest>
UINTN SpareStrLen;
CHAR16 *RestoreConfigRequest; ///< When submit form fail, the element need to be restored
CHAR16 *SyncConfigRequest; ///< When submit form fail, the element need to be synced
HII_FORMSET_STORAGE *Storage;
} HII_FORM_CONFIG_REQUEST;
#define HII_FORM_CONFIG_REQUEST_SIGNATURE SIGNATURE_32 ('F', 'C', 'R', 'S')
#define HII_FORM_CONFIG_REQUEST_FROM_LINK(a) CR (a, HII_FORM_CONFIG_REQUEST, Link, HII_FORM_CONFIG_REQUEST_SIGNATURE)
///
/// Incremental string length of ConfigRequest
///
#define CONFIG_REQUEST_STRING_INCREMENTAL 1024
/**
Allocate new memory and then copy the Unicode string Source to Destination.
@param[in,out] Dest Location to copy string
@param[in] Src String to copy
**/
VOID
NewStringCopy (
IN OUT CHAR16 **Dest,
IN CHAR16 *Src
);
/**
Set Value of given Name in a NameValue Storage.
@param[in] Storage The NameValue Storage.
@param[in] Name The Name.
@param[in] Value The Value to set.
@param[out] ReturnNode The node use the input name.
@retval EFI_SUCCESS Value found for given Name.
@retval EFI_NOT_FOUND No such Name found in NameValue storage.
**/
EFI_STATUS
SetValueByName (
IN HII_FORMSET_STORAGE *Storage,
IN CHAR16 *Name,
IN CHAR16 *Value,
OUT HII_NAME_VALUE_NODE **ReturnNode
);
/**
Get bit field value from the buffer and then set the value for the question.
Note: Data type UINT32 can cover all the bit field value.
@param[in] Question The question refer to bit field.
@param[in] Buffer Point to the buffer which the question value get from.
@param[out] QuestionValue The Question Value retrieved from Bits.
**/
VOID
GetBitsQuestionValue (
IN HII_STATEMENT *Question,
IN UINT8 *Buffer,
OUT HII_STATEMENT_VALUE *QuestionValue
);
/**
Set bit field value to the buffer.
Note: Data type UINT32 can cover all the bit field value.
@param[in] Question The question refer to bit field.
@param[in,out] Buffer Point to the buffer which the question value set to.
@param[in] Value The bit field value need to set.
**/
VOID
SetBitsQuestionValue (
IN HII_STATEMENT *Question,
IN OUT UINT8 *Buffer,
IN UINT32 Value
);
/**
Convert the buffer value to HiiValue.
@param[in] Question The question.
@param[in] Value Unicode buffer save the question value.
@param[out] QuestionValue The Question Value retrieved from Buffer.
@retval Status whether convert the value success.
**/
EFI_STATUS
BufferToQuestionValue (
IN HII_STATEMENT *Question,
IN CHAR16 *Value,
OUT HII_STATEMENT_VALUE *QuestionValue
);
/**
Get the string based on the StringId and HII Package List Handle.
@param[in] Token The String's ID.
@param[in] HiiHandle The package list in the HII database to search for
the specified string.
@return The output string.
**/
CHAR16 *
GetTokenString (
IN EFI_STRING_ID Token,
IN EFI_HII_HANDLE HiiHandle
);
/**
Converts the unicode character of the string from uppercase to lowercase.
This is a internal function.
@param[in] ConfigString String to be converted
**/
VOID
EFIAPI
HiiStringToLowercase (
IN EFI_STRING ConfigString
);
/**
Evaluate if the result is a non-zero value.
@param[in] Result The result to be evaluated.
@retval TRUE It is a non-zero value.
@retval FALSE It is a zero value.
**/
BOOLEAN
IsHiiValueTrue (
IN EFI_HII_VALUE *Result
);
/**
Set a new string to string package.
@param[in] String A pointer to the Null-terminated Unicode string
to add or update in the String Package associated
with HiiHandle.
@param[in] HiiHandle A handle that was previously registered in the
HII Database.
@return the Id for this new string.
**/
EFI_STRING_ID
NewHiiString (
IN CHAR16 *String,
IN EFI_HII_HANDLE HiiHandle
);
/**
Perform nosubmitif check for a Form.
@param[in] FormSet FormSet data structure.
@param[in] Form Form data structure.
@param[in] Question The Question to be validated.
@retval EFI_SUCCESS Form validation pass.
@retval other Form validation failed.
**/
EFI_STATUS
ValidateNoSubmit (
IN HII_FORMSET *FormSet,
IN HII_FORM *Form,
IN HII_STATEMENT *Question
);
/**
Perform NoSubmit check for each Form in FormSet.
@param[in] FormSet FormSet data structure.
@param[in,out] CurrentForm Current input form data structure.
@param[out] Statement The statement for this check.
@retval EFI_SUCCESS Form validation pass.
@retval other Form validation failed.
**/
EFI_STATUS
NoSubmitCheck (
IN HII_FORMSET *FormSet,
IN OUT HII_FORM **CurrentForm,
OUT HII_STATEMENT **Statement
);
/**
Convert setting of Buffer Storage or NameValue Storage to <ConfigResp>.
@param[in] Storage The Storage to be converted.
@param[in] ConfigResp The returned <ConfigResp>.
@param[in] ConfigRequest The ConfigRequest string.
@retval EFI_SUCCESS Convert success.
@retval EFI_INVALID_PARAMETER Incorrect storage type.
**/
EFI_STATUS
StorageToConfigResp (
IN HII_FORMSET_STORAGE *Storage,
IN CHAR16 **ConfigResp,
IN CHAR16 *ConfigRequest
);
/**
Convert <ConfigResp> to settings in Buffer Storage or NameValue Storage.
@param[in] Storage The Storage to receive the settings.
@param[in] ConfigResp The <ConfigResp> to be converted.
@retval EFI_SUCCESS Convert success.
@retval EFI_INVALID_PARAMETER Incorrect storage type.
**/
EFI_STATUS
ConfigRespToStorage (
IN HII_FORMSET_STORAGE *Storage,
IN CHAR16 *ConfigResp
);
/**
Fetch the Ifr binary data of a FormSet.
@param[in] Handle PackageList Handle
@param[in,out] 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[out] BinaryLength The length of the FormSet IFR binary.
@param[out] BinaryData The buffer designed to receive the FormSet.
@retval EFI_SUCCESS Buffer filled with the requested FormSet.
BufferLength was updated.
@retval EFI_INVALID_PARAMETER The handle is unknown.
@retval EFI_NOT_FOUND A form or FormSet on the requested handle cannot
be found with the requested FormId.
**/
EFI_STATUS
GetIfrBinaryData (
IN EFI_HII_HANDLE Handle,
IN OUT EFI_GUID *FormSetGuid,
OUT UINTN *BinaryLength,
OUT UINT8 **BinaryData
);
/**
Fill storage with settings requested from Configuration Driver.
@param[in] FormSet FormSet data structure.
@param[in] Storage Buffer Storage.
**/
VOID
LoadFormSetStorage (
IN HII_FORMSET *FormSet,
IN HII_FORMSET_STORAGE *Storage
);
/**
Free resources of a Form.
@param[in] FormSet Pointer of the FormSet
@param[in,out] Form Pointer of the Form.
**/
VOID
DestroyForm (
IN HII_FORMSET *FormSet,
IN OUT HII_FORM *Form
);
/**
Get formset storage based on the input varstoreid info.
@param[in] FormSet Pointer of the current FormSet.
@param[in] VarStoreId Varstore ID info.
@return Pointer to a HII_FORMSET_STORAGE data structure.
**/
HII_FORMSET_STORAGE *
GetFstStgFromVarId (
IN HII_FORMSET *FormSet,
IN EFI_VARSTORE_ID VarStoreId
);
/**
Zero extend integer/boolean/date/time to UINT64 for comparing.
@param[in] Value HII Value to be converted.
**/
VOID
ExtendValueToU64 (
IN HII_STATEMENT_VALUE *Value
);
/**
Parse opcodes in the formset IFR binary.
@param[in] FormSet Pointer of the FormSet data structure.
@retval EFI_SUCCESS Opcode parse success.
@retval Other Opcode parse fail.
**/
EFI_STATUS
ParseOpCodes (
IN HII_FORMSET *FormSet
);
#endif // HII_INTERNAL_H_

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,810 @@
/** @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) {
return EFI_OUT_OF_RESOURCES;
}
CopyMem (Question->Value.Buffer, TemString, StrSize (TemString));
Src = Question->Value.Buffer;
} 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;
}

View File

@ -0,0 +1,62 @@
## @file
# Library to handle HII IFR data.
#
# 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
#
##
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = HiiUtilityLib
FILE_GUID = D00DA028-F19A-47AF-B22A-6EE9E8BD7335
MODULE_TYPE = UEFI_DRIVER
VERSION_STRING = 1.0
LIBRARY_CLASS = HiiUtilityLib|DXE_DRIVER UEFI_DRIVER UEFI_APPLICATION
#
# VALID_ARCHITECTURES = IA32 X64 EBC
#
[Sources]
HiiUtilityLib.c
HiiExpression.c
HiiUtilityInternal.c
HiiIfrParse.c
HiiInternal.h
HiiExpression.h
[Packages]
MdePkg/MdePkg.dec
MdeModulePkg/MdeModulePkg.dec
RedfishPkg/RedfishPkg.dec
[LibraryClasses]
PrintLib
DebugLib
BaseMemoryLib
UefiRuntimeServicesTableLib
UefiBootServicesTableLib
MemoryAllocationLib
HiiLib
[Guids]
gZeroGuid
gEdkiiIfrBitVarstoreGuid
gEfiHiiPlatformSetupFormsetGuid
gEfiHiiStandardFormGuid
[Protocols]
gEfiHiiDatabaseProtocolGuid
gEfiHiiConfigRoutingProtocolGuid
gEfiHiiConfigAccessProtocolGuid
gEfiDevicePathFromTextProtocolGuid
gEfiUnicodeCollation2ProtocolGuid
gEfiRegularExpressionProtocolGuid
gEfiUserManagerProtocolGuid
[Depex]
TRUE

View File

@ -60,6 +60,10 @@
# Library provides Redfish debug functions.
RedfishDebugLib|Include/Library/RedfishDebugLib.h
## @libraryclass Provides the library functions to parse IFR binary data.
#
HiiUtilityLib|Include/Library/HiiUtilityLib.h
[LibraryClasses.Common.Private]
## @libraryclass Provides the private C runtime library functions.
# CRT library is currently used by edk2 JsonLib (open source