public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
* [edk2-staging][PATCH 1/3] edk2-staging/RedfishPkg: Add interface to get question default value
@ 2022-12-07 14:09 Nickle Wang
  2022-12-12  1:58 ` Chang, Abner
  0 siblings, 1 reply; 2+ messages in thread
From: Nickle Wang @ 2022-12-07 14:09 UTC (permalink / raw)
  To: devel; +Cc: Abner Chang, Igor Kulchytskyy, Nick Ramirez

Implement GetQuestionDefault() in HiiUtilityLib. Caller can get question
default value from this interface. GetQuestionDefault() is created and
modifed from SetupBrowserDxe\Setup.c under MdeModulePkg.

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>
---
 RedfishPkg/Include/Library/HiiUtilityLib.h    |  31 +-
 .../Library/HiiUtilityLib/HiiExpression.c     |  77 +++
 .../Library/HiiUtilityLib/HiiExpression.h     |  23 +
 .../HiiUtilityLib/HiiUtilityInternal.c        | 614 ++++++++++++++++++
 4 files changed, 728 insertions(+), 17 deletions(-)

diff --git a/RedfishPkg/Include/Library/HiiUtilityLib.h b/RedfishPkg/Include/Library/HiiUtilityLib.h
index 1f164ba49c..f4be485423 100644
--- a/RedfishPkg/Include/Library/HiiUtilityLib.h
+++ b/RedfishPkg/Include/Library/HiiUtilityLib.h
@@ -3,6 +3,7 @@
 
   Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
   (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>
+  Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
 
   SPDX-License-Identifier: BSD-2-Clause-Patent
 
@@ -1168,28 +1169,24 @@ GetHiiExpressionDependency (
   );
 
 /**
-  Evaluate the result of a HII expression.
-
-  If Expression is NULL, then ASSERT.
+  Get default value of question.
 
-  @param  FormSet                FormSet associated with this expression.
-  @param  Form                   Form associated with this expression.
-  @param  Expression             Expression to be evaluated.
+  @param  FormSet                The form set.
+  @param  Form                   The form.
+  @param  Question               The question.
+  @param  DefaultId              The Class of the default.
+  @param  DefaultValue           The default value of given question.
 
-  @retval EFI_SUCCESS            The expression evaluated successfuly
-  @retval EFI_NOT_FOUND          The Question which referenced by a QuestionId
-                                 could not be found.
-  @retval EFI_OUT_OF_RESOURCES   There is not enough system memory to grow the
-                                 stack.
-  @retval EFI_ACCESS_DENIED      The pop operation underflowed the stack
-  @retval EFI_INVALID_PARAMETER  Syntax error with the Expression
+  @retval EFI_SUCCESS            Question is reset to default value.
 
 **/
 EFI_STATUS
-HpEvaluateHiiExpression (
-  IN     HII_FORMSET       *FormSet,
-  IN     HII_FORM          *Form,
-  IN OUT HII_EXPRESSION    *Expression
+GetQuestionDefault (
+  IN HII_FORMSET           *FormSet,
+  IN HII_FORM              *Form,
+  IN HII_STATEMENT         *Question,
+  IN UINT16                DefaultId,
+  OUT HII_STATEMENT_VALUE  *DefaultValue
   );
 
 #endif // _HII_UTILITY_LIB_
diff --git a/RedfishPkg/Library/HiiUtilityLib/HiiExpression.c b/RedfishPkg/Library/HiiUtilityLib/HiiExpression.c
index 7111b40acf..c6954587f5 100644
--- a/RedfishPkg/Library/HiiUtilityLib/HiiExpression.c
+++ b/RedfishPkg/Library/HiiUtilityLib/HiiExpression.c
@@ -3,6 +3,7 @@
 
   Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
   (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>
+  Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
 
   SPDX-License-Identifier: BSD-2-Clause-Patent
 
@@ -1365,3 +1366,79 @@ GetHiiExpressionDependency (
 Done:
   return Status;
 }
+
+/**
+  Return the result of the expression list. Check the expression list and
+  return the highest priority express result.
+  Priority: DisableIf > SuppressIf > GrayOutIf > FALSE
+
+  @param  ExpList             The input expression list.
+  @param  Evaluate            Whether need to evaluate the expression first.
+  @param  FormSet             FormSet associated with this expression.
+  @param  Form                Form associated with this expression.
+
+  @retval EXPRESS_RESULT      Return the higher priority express result.
+                              DisableIf > SuppressIf > GrayOutIf > FALSE
+
+**/
+EXPRESS_RESULT
+EvaluateExpressionList (
+  IN HII_EXPRESSION_LIST *ExpList,
+  IN BOOLEAN Evaluate,
+  IN HII_FORMSET *FormSet, OPTIONAL
+  IN HII_FORM    *Form OPTIONAL
+  )
+{
+  UINTN           Index;
+  EXPRESS_RESULT  ReturnVal;
+  EXPRESS_RESULT  CompareOne;
+  EFI_STATUS      Status;
+
+  if (ExpList == NULL) {
+    return ExpressFalse;
+  }
+
+  ASSERT (ExpList->Signature == HII_EXPRESSION_LIST_SIGNATURE);
+  Index = 0;
+
+  //
+  // Check whether need to evaluate the expression first.
+  //
+  if (Evaluate) {
+    while (ExpList->Count > Index) {
+      Status = EvaluateHiiExpression (FormSet, Form, ExpList->Expression[Index++]);
+      if (EFI_ERROR (Status)) {
+        return ExpressFalse;
+      }
+    }
+  }
+
+  //
+  // Run the list of expressions.
+  //
+  ReturnVal = ExpressFalse;
+  for (Index = 0; Index < ExpList->Count; Index++) {
+    if (IsTrue (&ExpList->Expression[Index]->Result)) {
+      switch (ExpList->Expression[Index]->Type) {
+        case EFI_HII_EXPRESSION_SUPPRESS_IF:
+          CompareOne = ExpressSuppress;
+          break;
+
+        case EFI_HII_EXPRESSION_GRAY_OUT_IF:
+          CompareOne = ExpressGrayOut;
+          break;
+
+        case EFI_HII_EXPRESSION_DISABLE_IF:
+          CompareOne = ExpressDisable;
+          break;
+
+        default:
+          return ExpressFalse;
+      }
+
+      ReturnVal = ReturnVal < CompareOne ? CompareOne : ReturnVal;
+    }
+  }
+
+  return ReturnVal;
+}
diff --git a/RedfishPkg/Library/HiiUtilityLib/HiiExpression.h b/RedfishPkg/Library/HiiUtilityLib/HiiExpression.h
index e96c07b4de..25a3a44b48 100644
--- a/RedfishPkg/Library/HiiUtilityLib/HiiExpression.h
+++ b/RedfishPkg/Library/HiiUtilityLib/HiiExpression.h
@@ -3,6 +3,7 @@
 
   Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
   (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>
+  Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
 
   SPDX-License-Identifier: BSD-2-Clause-Patent
 
@@ -187,4 +188,26 @@ PopScope (
   OUT UINT8    *Operand
   );
 
+/**
+  Return the result of the expression list. Check the expression list and
+  return the highest priority express result.
+  Priority: DisableIf > SuppressIf > GrayOutIf > FALSE
+
+  @param  ExpList             The input expression list.
+  @param  Evaluate            Whether need to evaluate the expression first.
+  @param  FormSet             FormSet associated with this expression.
+  @param  Form                Form associated with this expression.
+
+  @retval EXPRESS_RESULT      Return the higher priority express result.
+                              DisableIf > SuppressIf > GrayOutIf > FALSE
+
+**/
+EXPRESS_RESULT
+EvaluateExpressionList (
+  IN HII_EXPRESSION_LIST *ExpList,
+  IN BOOLEAN Evaluate,
+  IN HII_FORMSET *FormSet, OPTIONAL
+  IN HII_FORM    *Form OPTIONAL
+  );
+
 #endif
diff --git a/RedfishPkg/Library/HiiUtilityLib/HiiUtilityInternal.c b/RedfishPkg/Library/HiiUtilityLib/HiiUtilityInternal.c
index 55b78315d1..b4dd61f360 100644
--- a/RedfishPkg/Library/HiiUtilityLib/HiiUtilityInternal.c
+++ b/RedfishPkg/Library/HiiUtilityLib/HiiUtilityInternal.c
@@ -3,6 +3,7 @@
 
   Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
   (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>
+  Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
 
   SPDX-License-Identifier: BSD-2-Clause-Patent
 
@@ -5043,3 +5044,616 @@ Done:
 
   return Status;
 }
+
+/**
+  Set value of a data element in an Array by its Index.
+
+  @param  Array                  The data array.
+  @param  Type                   Type of the data in this array.
+  @param  Index                  Zero based index for data in this array.
+  @param  Value                  The value to be set.
+
+**/
+VOID
+SetArrayData (
+  IN VOID    *Array,
+  IN UINT8   Type,
+  IN UINTN   Index,
+  IN UINT64  Value
+  )
+{
+  ASSERT (Array != NULL);
+
+  switch (Type) {
+    case EFI_IFR_TYPE_NUM_SIZE_8:
+      *(((UINT8 *)Array) + Index) = (UINT8)Value;
+      break;
+
+    case EFI_IFR_TYPE_NUM_SIZE_16:
+      *(((UINT16 *)Array) + Index) = (UINT16)Value;
+      break;
+
+    case EFI_IFR_TYPE_NUM_SIZE_32:
+      *(((UINT32 *)Array) + Index) = (UINT32)Value;
+      break;
+
+    case EFI_IFR_TYPE_NUM_SIZE_64:
+      *(((UINT64 *)Array) + Index) = (UINT64)Value;
+      break;
+
+    default:
+      break;
+  }
+}
+
+/**
+  Search an Option of a Question by its value.
+
+  @param  Question               The Question
+  @param  OptionValue            Value for Option to be searched.
+
+  @retval Pointer                Pointer to the found Option.
+  @retval NULL                   Option not found.
+
+**/
+HII_QUESTION_OPTION *
+ValueToOption (
+  IN HII_STATEMENT        *Question,
+  IN HII_STATEMENT_VALUE  *OptionValue
+  )
+{
+  LIST_ENTRY           *Link;
+  HII_QUESTION_OPTION  *Option;
+  EFI_HII_VALUE        Data1;
+  EFI_HII_VALUE        Data2;
+  INTN                 Result;
+  EFI_STATUS           Status;
+
+  Status = HiiStatementValueToHiiValue (OptionValue, &Data1);
+  ASSERT_EFI_ERROR (Status);
+
+  Link = GetFirstNode (&Question->OptionListHead);
+  while (!IsNull (&Question->OptionListHead, Link)) {
+    Option = HII_QUESTION_OPTION_FROM_LINK (Link);
+
+    Status = HiiStatementValueToHiiValue (&Option->Value, &Data2);
+    ASSERT_EFI_ERROR (Status);
+
+    if ((CompareHiiValue (&Data1, &Data2, &Result, NULL) == EFI_SUCCESS) && (Result == 0)) {
+      //
+      // Check the suppressif condition, only a valid option can be return.
+      //
+      if ((Option->SuppressExpression == NULL) ||
+          ((EvaluateExpressionList (Option->SuppressExpression, FALSE, NULL, NULL) == ExpressFalse)))
+      {
+        return Option;
+      }
+    }
+
+    Link = GetNextNode (&Question->OptionListHead, Link);
+  }
+
+  return NULL;
+}
+
+/**
+  Find the point in the ConfigResp string for this question.
+
+  @param  Question               The question.
+  @param  ConfigResp             Get ConfigResp string.
+
+  @retval  point to the offset where is for this question.
+
+**/
+CHAR16 *
+GetOffsetFromConfigResp (
+  IN HII_STATEMENT  *Question,
+  IN CHAR16         *ConfigResp
+  )
+{
+  CHAR16  *RequestElement;
+  CHAR16  *BlockData;
+
+  //
+  // Type is EFI_HII_VARSTORE_NAME_VALUE.
+  //
+  if (Question->Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
+    RequestElement = StrStr (ConfigResp, Question->VariableName);
+    if (RequestElement != NULL) {
+      //
+      // Skip the "VariableName=" field.
+      //
+      RequestElement += StrLen (Question->VariableName) + 1;
+    }
+
+    return RequestElement;
+  }
+
+  //
+  // Type is EFI_HII_VARSTORE_EFI_VARIABLE or EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER
+  //
+
+  //
+  // Convert all hex digits in ConfigResp to lower case before searching.
+  //
+  HiiToLower (ConfigResp);
+
+  //
+  // 1. Directly use Question->BlockName to find.
+  //
+  RequestElement = StrStr (ConfigResp, Question->BlockName);
+  if (RequestElement != NULL) {
+    //
+    // Skip the "Question->BlockName&VALUE=" field.
+    //
+    RequestElement += StrLen (Question->BlockName) + StrLen (L"&VALUE=");
+    return RequestElement;
+  }
+
+  //
+  // 2. Change all hex digits in Question->BlockName to lower and compare again.
+  //
+  BlockData = AllocateCopyPool (StrSize (Question->BlockName), Question->BlockName);
+  ASSERT (BlockData != NULL);
+  HiiToLower (BlockData);
+  RequestElement = StrStr (ConfigResp, BlockData);
+  FreePool (BlockData);
+
+  if (RequestElement != NULL) {
+    //
+    // Skip the "Question->BlockName&VALUE=" field.
+    //
+    RequestElement += StrLen (Question->BlockName) + StrLen (L"&VALUE=");
+  }
+
+  return RequestElement;
+}
+
+/**
+  Get Question default value from AltCfg string.
+
+  @param  FormSet                The form set.
+  @param  Form                   The form
+  @param  Question               The question.
+  @param  DefaultValue           Default value.
+
+  @retval EFI_SUCCESS            Question is reset to default value.
+
+**/
+EFI_STATUS
+GetDefaultValueFromAltCfg (
+  IN     HII_FORMSET          *FormSet,
+  IN     HII_FORM             *Form,
+  IN     HII_STATEMENT        *Question,
+  OUT    HII_STATEMENT_VALUE  *DefaultValue
+  )
+{
+  HII_FORMSET_STORAGE      *Storage;
+  CHAR16                   *ConfigResp;
+  CHAR16                   *Value;
+  LIST_ENTRY               *Link;
+  HII_FORM_CONFIG_REQUEST  *ConfigInfo;
+
+  Storage = Question->Storage;
+  if ((Storage == NULL) || (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE)) {
+    return EFI_NOT_FOUND;
+  }
+
+  //
+  // Try to get AltCfg string from form. If not found it, then
+  // try to get it from formset.
+  //
+  ConfigResp = NULL;
+  Link       = GetFirstNode (&Form->ConfigRequestHead);
+  while (!IsNull (&Form->ConfigRequestHead, Link)) {
+    ConfigInfo = HII_FORM_CONFIG_REQUEST_FROM_LINK (Link);
+    Link       = GetNextNode (&Form->ConfigRequestHead, Link);
+
+    if (Storage == ConfigInfo->Storage) {
+      ConfigResp = ConfigInfo->ConfigAltResp;
+      break;
+    }
+  }
+
+  if (ConfigResp == NULL) {
+    return EFI_NOT_FOUND;
+  }
+
+  Value = GetOffsetFromConfigResp (Question, ConfigResp);
+  if (Value == NULL) {
+    return EFI_NOT_FOUND;
+  }
+
+  return BufferToValue (Question, Value, DefaultValue);
+}
+
+/**
+  Get default Id value used for browser.
+
+  @param  DefaultId              The default id value used by hii.
+
+  @retval Browser used default value.
+
+**/
+INTN
+GetDefaultIdForCallBack (
+  UINTN  DefaultId
+  )
+{
+  if (DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) {
+    return EFI_BROWSER_ACTION_DEFAULT_STANDARD;
+  } else if (DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) {
+    return EFI_BROWSER_ACTION_DEFAULT_MANUFACTURING;
+  } else if (DefaultId == EFI_HII_DEFAULT_CLASS_SAFE) {
+    return EFI_BROWSER_ACTION_DEFAULT_SAFE;
+  } else if ((DefaultId >= EFI_HII_DEFAULT_CLASS_PLATFORM_BEGIN) && (DefaultId < EFI_HII_DEFAULT_CLASS_PLATFORM_BEGIN + 0x1000)) {
+    return EFI_BROWSER_ACTION_DEFAULT_PLATFORM + DefaultId - EFI_HII_DEFAULT_CLASS_PLATFORM_BEGIN;
+  } else if ((DefaultId >= EFI_HII_DEFAULT_CLASS_HARDWARE_BEGIN) && (DefaultId < EFI_HII_DEFAULT_CLASS_HARDWARE_BEGIN + 0x1000)) {
+    return EFI_BROWSER_ACTION_DEFAULT_HARDWARE + DefaultId - EFI_HII_DEFAULT_CLASS_HARDWARE_BEGIN;
+  } else if ((DefaultId >= EFI_HII_DEFAULT_CLASS_FIRMWARE_BEGIN) && (DefaultId < EFI_HII_DEFAULT_CLASS_FIRMWARE_BEGIN + 0x1000)) {
+    return EFI_BROWSER_ACTION_DEFAULT_FIRMWARE + DefaultId - EFI_HII_DEFAULT_CLASS_FIRMWARE_BEGIN;
+  } else {
+    return -1;
+  }
+}
+
+/**
+  Get default value of question.
+
+  @param  FormSet                The form set.
+  @param  Form                   The form.
+  @param  Question               The question.
+  @param  DefaultId              The Class of the default.
+  @param  DefaultValue           The default value of given question.
+
+  @retval EFI_SUCCESS            Question is reset to default value.
+
+**/
+EFI_STATUS
+GetQuestionDefault (
+  IN HII_FORMSET           *FormSet,
+  IN HII_FORM              *Form,
+  IN HII_STATEMENT         *Question,
+  IN UINT16                DefaultId,
+  OUT HII_STATEMENT_VALUE  *DefaultValue
+  )
+{
+  EFI_STATUS                      Status;
+  LIST_ENTRY                      *Link;
+  HII_QUESTION_DEFAULT            *Default;
+  HII_QUESTION_OPTION             *Option;
+  HII_STATEMENT_VALUE             *HiiValue;
+  UINT8                           Index;
+  EFI_STRING                      StrValue;
+  EFI_HII_CONFIG_ACCESS_PROTOCOL  *ConfigAccess;
+  EFI_BROWSER_ACTION_REQUEST      ActionRequest;
+  INTN                            Action;
+  EFI_IFR_TYPE_VALUE              *TypeValue;
+  UINT16                          OriginalDefaultId;
+  HII_FORMSET_DEFAULTSTORE        *DefaultStore;
+  LIST_ENTRY                      *DefaultLink;
+
+  if ((FormSet == NULL) || (Form == NULL) || (Question == NULL) || (DefaultValue == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Status            = EFI_NOT_FOUND;
+  StrValue          = NULL;
+  OriginalDefaultId = DefaultId;
+  DefaultLink       = GetFirstNode (&FormSet->DefaultStoreListHead);
+
+  //
+  // Statement don't have storage, skip them
+  //
+  if (Question->QuestionId == 0) {
+    return Status;
+  }
+
+  //
+  // There are Five ways to specify default value for a Question:
+  //  1, use call back function (highest priority)
+  //  2, use ExtractConfig function
+  //  3, use nested EFI_IFR_DEFAULT
+  //  4, set flags of EFI_ONE_OF_OPTION (provide Standard and Manufacturing default)
+  //  5, set flags of EFI_IFR_CHECKBOX (provide Standard and Manufacturing default) (lowest priority)
+  //
+  CopyMem (DefaultValue, &Question->Value, sizeof (HII_STATEMENT_VALUE));
+ReGetDefault:
+  HiiValue  = DefaultValue;
+  TypeValue = &HiiValue->Value;
+  if (HiiValue->Type == EFI_IFR_TYPE_BUFFER) {
+    //
+    // For orderedlist, need to pass the BufferValue to Callback function.
+    //
+    DefaultValue->BufferLen = Question->Value.BufferLen;
+    DefaultValue->Buffer    = AllocateZeroPool (DefaultValue->BufferLen);
+    ASSERT (DefaultValue->Buffer != NULL);
+    if (DefaultValue->Buffer == NULL) {
+      return EFI_OUT_OF_RESOURCES;
+    }
+
+    TypeValue = (EFI_IFR_TYPE_VALUE *)DefaultValue->Buffer;
+  }
+
+  //
+  // Get Question defaut value from call back function.
+  // The string type of question cause HII driver to set string to its default value.
+  // So, we don't do this otherwise it will actually set question to default value.
+  // We only want to get default value of question.
+  //
+  if (HiiValue->Type != EFI_IFR_TYPE_STRING) {
+    ConfigAccess = FormSet->ConfigAccess;
+    Action       = GetDefaultIdForCallBack (DefaultId);
+    if ((Action > 0) && ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) && (ConfigAccess != NULL)) {
+      ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
+      Status        = ConfigAccess->Callback (
+                                      ConfigAccess,
+                                      Action,
+                                      Question->QuestionId,
+                                      HiiValue->Type,
+                                      TypeValue,
+                                      &ActionRequest
+                                      );
+      if (!EFI_ERROR (Status)) {
+        return Status;
+      }
+    }
+  }
+
+  //
+  // Get default value from altcfg string.
+  //
+  if (ConfigAccess != NULL) {
+    Status = GetDefaultValueFromAltCfg (FormSet, Form, Question, DefaultValue);
+    if (!EFI_ERROR (Status)) {
+      return Status;
+    }
+  }
+
+  //
+  // EFI_IFR_DEFAULT has highest priority
+  //
+  if (!IsListEmpty (&Question->DefaultListHead)) {
+    Link = GetFirstNode (&Question->DefaultListHead);
+    while (!IsNull (&Question->DefaultListHead, Link)) {
+      Default = HII_QUESTION_DEFAULT_FROM_LINK (Link);
+
+      if (Default->DefaultId == DefaultId) {
+        if (Default->ValueExpression != NULL) {
+          //
+          // Default is provided by an Expression, evaluate it
+          //
+          Status = EvaluateHiiExpression (FormSet, Form, Default->ValueExpression);
+          if (EFI_ERROR (Status)) {
+            return Status;
+          }
+
+          if (Default->ValueExpression->Result.Type == EFI_IFR_TYPE_BUFFER) {
+            ASSERT (HiiValue->Type == EFI_IFR_TYPE_BUFFER && DefaultValue->Buffer != NULL);
+            if (DefaultValue->BufferLen > Default->ValueExpression->Result.BufferLen) {
+              CopyMem (DefaultValue->Buffer, Default->ValueExpression->Result.Buffer, Default->ValueExpression->Result.BufferLen);
+              DefaultValue->BufferLen = Default->ValueExpression->Result.BufferLen;
+            } else {
+              CopyMem (DefaultValue->Buffer, Default->ValueExpression->Result.Buffer, DefaultValue->BufferLen);
+            }
+
+            FreePool (Default->ValueExpression->Result.Buffer);
+          }
+
+          HiiValue->Type = Default->ValueExpression->Result.Type;
+          CopyMem (&HiiValue->Value, &Default->ValueExpression->Result.Value, sizeof (EFI_IFR_TYPE_VALUE));
+        } else {
+          //
+          // Default value is embedded in EFI_IFR_DEFAULT
+          //
+          if (Default->Value.Type == EFI_IFR_TYPE_BUFFER) {
+            ASSERT (HiiValue->Buffer != NULL);
+            CopyMem (HiiValue->Buffer, Default->Value.Buffer, Default->Value.BufferLen);
+          } else {
+            CopyMem (HiiValue, &Default->Value, sizeof (EFI_HII_VALUE));
+          }
+        }
+
+        if (HiiValue->Type == EFI_IFR_TYPE_STRING) {
+          StrValue = HiiGetString (FormSet->HiiHandle, HiiValue->Value.string, NULL);
+          if (StrValue == NULL) {
+            return EFI_NOT_FOUND;
+          }
+
+          if (DefaultValue->BufferLen > StrSize (StrValue)) {
+            ZeroMem (DefaultValue->Buffer, DefaultValue->BufferLen);
+            CopyMem (DefaultValue->Buffer, StrValue, StrSize (StrValue));
+          } else {
+            CopyMem (DefaultValue->Buffer, StrValue, DefaultValue->BufferLen);
+          }
+        }
+
+        return EFI_SUCCESS;
+      }
+
+      Link = GetNextNode (&Question->DefaultListHead, Link);
+    }
+  }
+
+  //
+  // EFI_ONE_OF_OPTION
+  //
+  if ((Question->Operand == EFI_IFR_ONE_OF_OP) && !IsListEmpty (&Question->OptionListHead)) {
+    if (DefaultId <= EFI_HII_DEFAULT_CLASS_MANUFACTURING) {
+      //
+      // OneOfOption could only provide Standard and Manufacturing default
+      //
+      Link = GetFirstNode (&Question->OptionListHead);
+      while (!IsNull (&Question->OptionListHead, Link)) {
+        Option = HII_QUESTION_OPTION_FROM_LINK (Link);
+        Link   = GetNextNode (&Question->OptionListHead, Link);
+
+        if ((Option->SuppressExpression != NULL) &&
+            (EvaluateExpressionList (Option->SuppressExpression, FALSE, NULL, NULL) != ExpressFalse))
+        {
+          continue;
+        }
+
+        if (((DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) && ((Option->Flags & EFI_IFR_OPTION_DEFAULT) != 0)) ||
+            ((DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) && ((Option->Flags & EFI_IFR_OPTION_DEFAULT_MFG) != 0))
+            )
+        {
+          CopyMem (HiiValue, &Option->Value, sizeof (EFI_HII_VALUE));
+
+          return EFI_SUCCESS;
+        }
+      }
+    }
+  }
+
+  //
+  // EFI_IFR_CHECKBOX - lowest priority
+  //
+  if (Question->Operand == EFI_IFR_CHECKBOX_OP) {
+    if (DefaultId <= EFI_HII_DEFAULT_CLASS_MANUFACTURING) {
+      //
+      // Checkbox could only provide Standard and Manufacturing default
+      //
+      if (((DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) && ((Question->ExtraData.Flags & EFI_IFR_CHECKBOX_DEFAULT) != 0)) ||
+          ((DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) && ((Question->ExtraData.Flags & EFI_IFR_CHECKBOX_DEFAULT_MFG) != 0))
+          )
+      {
+        HiiValue->Value.b = TRUE;
+      }
+
+      return EFI_SUCCESS;
+    }
+  }
+
+  //
+  // For question without default value for current default Id, we try to re-get the default value form other default id in the DefaultStoreList.
+  // If get, will exit the function, if not, will choose next default id in the DefaultStoreList.
+  // The default id in DefaultStoreList are in ascending order to make sure choose the smallest default id every time.
+  //
+  while (!IsNull (&FormSet->DefaultStoreListHead, DefaultLink)) {
+    DefaultStore = HII_FORMSET_DEFAULTSTORE_FROM_LINK (DefaultLink);
+    DefaultLink  = GetNextNode (&FormSet->DefaultStoreListHead, DefaultLink);
+    DefaultId    = DefaultStore->DefaultId;
+    if (DefaultId == OriginalDefaultId) {
+      continue;
+    }
+
+    goto ReGetDefault;
+  }
+
+  //
+  // For Questions without default value for all the default id in the DefaultStoreList.
+  //
+  Status = EFI_NOT_FOUND;
+  switch (Question->Operand) {
+    case EFI_IFR_CHECKBOX_OP:
+      HiiValue->Value.b = FALSE;
+      Status            = EFI_SUCCESS;
+      break;
+
+    case EFI_IFR_NUMERIC_OP:
+      //
+      // Take minimum value as numeric default value
+      //
+      if ((Question->ExtraData.NumData.Flags & EFI_IFR_DISPLAY) == 0) {
+        //
+        // In EFI_IFR_DISPLAY_INT_DEC type, should check value with int* type.
+        //
+        switch (Question->ExtraData.NumData.Flags & EFI_IFR_NUMERIC_SIZE) {
+          case EFI_IFR_NUMERIC_SIZE_1:
+            if (((INT8)HiiValue->Value.u8 < (INT8)Question->ExtraData.NumData.Minimum) || ((INT8)HiiValue->Value.u8 > (INT8)Question->ExtraData.NumData.Maximum)) {
+              HiiValue->Value.u8 = (UINT8)Question->ExtraData.NumData.Minimum;
+              Status             = EFI_SUCCESS;
+            }
+
+            break;
+          case EFI_IFR_NUMERIC_SIZE_2:
+            if (((INT16)HiiValue->Value.u16 < (INT16)Question->ExtraData.NumData.Minimum) || ((INT16)HiiValue->Value.u16 > (INT16)Question->ExtraData.NumData.Maximum)) {
+              HiiValue->Value.u16 = (UINT16)Question->ExtraData.NumData.Minimum;
+              Status              = EFI_SUCCESS;
+            }
+
+            break;
+          case EFI_IFR_NUMERIC_SIZE_4:
+            if (((INT32)HiiValue->Value.u32 < (INT32)Question->ExtraData.NumData.Minimum) || ((INT32)HiiValue->Value.u32 > (INT32)Question->ExtraData.NumData.Maximum)) {
+              HiiValue->Value.u32 = (UINT32)Question->ExtraData.NumData.Minimum;
+              Status              = EFI_SUCCESS;
+            }
+
+            break;
+          case EFI_IFR_NUMERIC_SIZE_8:
+            if (((INT64)HiiValue->Value.u64 < (INT64)Question->ExtraData.NumData.Minimum) || ((INT64)HiiValue->Value.u64 > (INT64)Question->ExtraData.NumData.Maximum)) {
+              HiiValue->Value.u64 = Question->ExtraData.NumData.Minimum;
+              Status              = EFI_SUCCESS;
+            }
+
+            break;
+          default:
+            break;
+        }
+      } else {
+        if ((HiiValue->Value.u64 < Question->ExtraData.NumData.Minimum) || (HiiValue->Value.u64 > Question->ExtraData.NumData.Maximum)) {
+          HiiValue->Value.u64 = Question->ExtraData.NumData.Minimum;
+          Status              = EFI_SUCCESS;
+        }
+      }
+
+      break;
+
+    case EFI_IFR_ONE_OF_OP:
+      //
+      // Take first oneof option as oneof's default value
+      //
+      if (ValueToOption (Question, HiiValue) == NULL) {
+        Link = GetFirstNode (&Question->OptionListHead);
+        while (!IsNull (&Question->OptionListHead, Link)) {
+          Option = HII_QUESTION_OPTION_FROM_LINK (Link);
+          Link   = GetNextNode (&Question->OptionListHead, Link);
+
+          if ((Option->SuppressExpression != NULL) &&
+              (EvaluateExpressionList (Option->SuppressExpression, FALSE, NULL, NULL) != ExpressFalse))
+          {
+            continue;
+          }
+
+          CopyMem (HiiValue, &Option->Value, sizeof (EFI_HII_VALUE));
+          Status = EFI_SUCCESS;
+          break;
+        }
+      }
+
+      break;
+
+    case EFI_IFR_ORDERED_LIST_OP:
+      //
+      // Take option sequence in IFR as ordered list's default value
+      //
+      Index = 0;
+      Link  = GetFirstNode (&Question->OptionListHead);
+      while (!IsNull (&Question->OptionListHead, Link)) {
+        Status = EFI_SUCCESS;
+        Option = HII_QUESTION_OPTION_FROM_LINK (Link);
+        Link   = GetNextNode (&Question->OptionListHead, Link);
+
+        if ((Option->SuppressExpression != NULL) &&
+            (EvaluateExpressionList (Option->SuppressExpression, FALSE, NULL, NULL) != ExpressFalse))
+        {
+          continue;
+        }
+
+        SetArrayData (DefaultValue->Buffer, Question->Value.Type, Index, Option->Value.Value.u64);
+
+        Index++;
+        if (Index >= Question->ExtraData.OrderListData.MaxContainers) {
+          break;
+        }
+      }
+
+      break;
+
+    default:
+      break;
+  }
+
+  return Status;
+}
-- 
2.38.1.windows.1


^ permalink raw reply related	[flat|nested] 2+ messages in thread

* Re: [edk2-staging][PATCH 1/3] edk2-staging/RedfishPkg: Add interface to get question default value
  2022-12-07 14:09 [edk2-staging][PATCH 1/3] edk2-staging/RedfishPkg: Add interface to get question default value Nickle Wang
@ 2022-12-12  1:58 ` Chang, Abner
  0 siblings, 0 replies; 2+ messages in thread
From: Chang, Abner @ 2022-12-12  1:58 UTC (permalink / raw)
  To: Nickle Wang, devel@edk2.groups.io; +Cc: Igor Kulchytskyy, Nick Ramirez

[AMD Official Use Only - General]

Hi Nickle, comments in line.

> -----Original Message-----
> From: Nickle Wang <nicklew@nvidia.com>
> Sent: Wednesday, December 7, 2022 10:09 PM
> To: devel@edk2.groups.io
> Cc: Chang, Abner <Abner.Chang@amd.com>; Igor Kulchytskyy
> <igork@ami.com>; Nick Ramirez <nramirez@nvidia.com>
> Subject: [edk2-staging][PATCH 1/3] edk2-staging/RedfishPkg: Add interface to
> get question default value
> 
> Caution: This message originated from an External Source. Use proper caution
> when opening attachments, clicking links, or responding.
> 
> 
> Implement GetQuestionDefault() in HiiUtilityLib. Caller can get question default
> value from this interface. GetQuestionDefault() is created and modifed from
> SetupBrowserDxe\Setup.c under MdeModulePkg.
> 
> 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>
> ---
>  RedfishPkg/Include/Library/HiiUtilityLib.h    |  31 +-
>  .../Library/HiiUtilityLib/HiiExpression.c     |  77 +++
>  .../Library/HiiUtilityLib/HiiExpression.h     |  23 +
>  .../HiiUtilityLib/HiiUtilityInternal.c        | 614 ++++++++++++++++++
>  4 files changed, 728 insertions(+), 17 deletions(-)
> 
> diff --git a/RedfishPkg/Include/Library/HiiUtilityLib.h
> b/RedfishPkg/Include/Library/HiiUtilityLib.h
> index 1f164ba49c..f4be485423 100644
> --- a/RedfishPkg/Include/Library/HiiUtilityLib.h
> +++ b/RedfishPkg/Include/Library/HiiUtilityLib.h
> @@ -3,6 +3,7 @@
> 
>    Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
>    (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>
> +  Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
> 
>    SPDX-License-Identifier: BSD-2-Clause-Patent
> 
> @@ -1168,28 +1169,24 @@ GetHiiExpressionDependency (
>    );
> 
>  /**
> -  Evaluate the result of a HII expression.
> -
> -  If Expression is NULL, then ASSERT.
> +  Get default value of question.
> 
> -  @param  FormSet                FormSet associated with this expression.
> -  @param  Form                   Form associated with this expression.
> -  @param  Expression             Expression to be evaluated.
> +  @param  FormSet                The form set.
> +  @param  Form                   The form.
> +  @param  Question               The question.
> +  @param  DefaultId              The Class of the default.
> +  @param  DefaultValue           The default value of given question.
No [in, out] for the Doxygen parameter/
> 
> -  @retval EFI_SUCCESS            The expression evaluated successfuly
> -  @retval EFI_NOT_FOUND          The Question which referenced by a
> QuestionId
> -                                 could not be found.
> -  @retval EFI_OUT_OF_RESOURCES   There is not enough system memory to
> grow the
> -                                 stack.
> -  @retval EFI_ACCESS_DENIED      The pop operation underflowed the stack
> -  @retval EFI_INVALID_PARAMETER  Syntax error with the Expression
> +  @retval EFI_SUCCESS            Question is reset to default value.
> 
>  **/
>  EFI_STATUS
> -HpEvaluateHiiExpression (
> -  IN     HII_FORMSET       *FormSet,
> -  IN     HII_FORM          *Form,
> -  IN OUT HII_EXPRESSION    *Expression
> +GetQuestionDefault (
> +  IN HII_FORMSET           *FormSet,
> +  IN HII_FORM              *Form,
> +  IN HII_STATEMENT         *Question,
> +  IN UINT16                DefaultId,
> +  OUT HII_STATEMENT_VALUE  *DefaultValue
>    );
> 
>  #endif // _HII_UTILITY_LIB_
> diff --git a/RedfishPkg/Library/HiiUtilityLib/HiiExpression.c
> b/RedfishPkg/Library/HiiUtilityLib/HiiExpression.c
> index 7111b40acf..c6954587f5 100644
> --- a/RedfishPkg/Library/HiiUtilityLib/HiiExpression.c
> +++ b/RedfishPkg/Library/HiiUtilityLib/HiiExpression.c
> @@ -3,6 +3,7 @@
> 
>    Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
>    (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>
> +  Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
> 
>    SPDX-License-Identifier: BSD-2-Clause-Patent
> 
> @@ -1365,3 +1366,79 @@ GetHiiExpressionDependency (
>  Done:
>    return Status;
>  }
> +
> +/**
> +  Return the result of the expression list. Check the expression list
> +and
> +  return the highest priority express result.
> +  Priority: DisableIf > SuppressIf > GrayOutIf > FALSE
> +
> +  @param  ExpList             The input expression list.
> +  @param  Evaluate            Whether need to evaluate the expression first.
> +  @param  FormSet             FormSet associated with this expression.
> +  @param  Form                Form associated with this expression.
Just realize we don't have [in,out] for Doxygen @param throughout this file. Please just fix @params in the new added function. We can fix all others later.
> +
> +  @retval EXPRESS_RESULT      Return the higher priority express result.
> +                              DisableIf > SuppressIf > GrayOutIf >
> + FALSE
> +
> +**/
> +EXPRESS_RESULT
> +EvaluateExpressionList (
> +  IN HII_EXPRESSION_LIST *ExpList,
> +  IN BOOLEAN Evaluate,
> +  IN HII_FORMSET *FormSet, OPTIONAL
> +  IN HII_FORM    *Form OPTIONAL
> +  )
> +{
> +  UINTN           Index;
> +  EXPRESS_RESULT  ReturnVal;
> +  EXPRESS_RESULT  CompareOne;
> +  EFI_STATUS      Status;
> +
> +  if (ExpList == NULL) {
> +    return ExpressFalse;
> +  }
> +
> +  ASSERT (ExpList->Signature == HII_EXPRESSION_LIST_SIGNATURE);  Index
> + = 0;
> +
> +  //
> +  // Check whether need to evaluate the expression first.
> +  //
> +  if (Evaluate) {
> +    while (ExpList->Count > Index) {
> +      Status = EvaluateHiiExpression (FormSet, Form, ExpList-
> >Expression[Index++]);
> +      if (EFI_ERROR (Status)) {
> +        return ExpressFalse;
> +      }
> +    }
> +  }
> +
> +  //
> +  // Run the list of expressions.
> +  //
> +  ReturnVal = ExpressFalse;
> +  for (Index = 0; Index < ExpList->Count; Index++) {
> +    if (IsTrue (&ExpList->Expression[Index]->Result)) {
> +      switch (ExpList->Expression[Index]->Type) {
> +        case EFI_HII_EXPRESSION_SUPPRESS_IF:
> +          CompareOne = ExpressSuppress;
> +          break;
> +
> +        case EFI_HII_EXPRESSION_GRAY_OUT_IF:
> +          CompareOne = ExpressGrayOut;
> +          break;
> +
> +        case EFI_HII_EXPRESSION_DISABLE_IF:
> +          CompareOne = ExpressDisable;
> +          break;
> +
> +        default:
> +          return ExpressFalse;
> +      }
> +
> +      ReturnVal = ReturnVal < CompareOne ? CompareOne : ReturnVal;
> +    }
> +  }
> +
> +  return ReturnVal;
> +}
> diff --git a/RedfishPkg/Library/HiiUtilityLib/HiiExpression.h
> b/RedfishPkg/Library/HiiUtilityLib/HiiExpression.h
> index e96c07b4de..25a3a44b48 100644
> --- a/RedfishPkg/Library/HiiUtilityLib/HiiExpression.h
> +++ b/RedfishPkg/Library/HiiUtilityLib/HiiExpression.h
> @@ -3,6 +3,7 @@
> 
>    Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
>    (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>
> +  Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
> 
>    SPDX-License-Identifier: BSD-2-Clause-Patent
> 
> @@ -187,4 +188,26 @@ PopScope (
>    OUT UINT8    *Operand
>    );
> 
> +/**
> +  Return the result of the expression list. Check the expression list
> +and
> +  return the highest priority express result.
> +  Priority: DisableIf > SuppressIf > GrayOutIf > FALSE
> +
> +  @param  ExpList             The input expression list.
> +  @param  Evaluate            Whether need to evaluate the expression first.
> +  @param  FormSet             FormSet associated with this expression.
> +  @param  Form                Form associated with this expression.
Same, [in,out] is miseed.
> +
> +  @retval EXPRESS_RESULT      Return the higher priority express result.
> +                              DisableIf > SuppressIf > GrayOutIf >
> + FALSE
> +
> +**/
> +EXPRESS_RESULT
> +EvaluateExpressionList (
> +  IN HII_EXPRESSION_LIST *ExpList,
> +  IN BOOLEAN Evaluate,
> +  IN HII_FORMSET *FormSet, OPTIONAL
> +  IN HII_FORM    *Form OPTIONAL
> +  );
> +
>  #endif
> diff --git a/RedfishPkg/Library/HiiUtilityLib/HiiUtilityInternal.c
> b/RedfishPkg/Library/HiiUtilityLib/HiiUtilityInternal.c
> index 55b78315d1..b4dd61f360 100644
> --- a/RedfishPkg/Library/HiiUtilityLib/HiiUtilityInternal.c
> +++ b/RedfishPkg/Library/HiiUtilityLib/HiiUtilityInternal.c
> @@ -3,6 +3,7 @@
> 
>    Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
>    (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>
> +  Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
> 
>    SPDX-License-Identifier: BSD-2-Clause-Patent
> 
> @@ -5043,3 +5044,616 @@ Done:
> 
>    return Status;
>  }
> +
> +/**
> +  Set value of a data element in an Array by its Index.
> +
> +  @param  Array                  The data array.
> +  @param  Type                   Type of the data in this array.
> +  @param  Index                  Zero based index for data in this array.
> +  @param  Value                  The value to be set.
Same here.
> +
> +**/
> +VOID
> +SetArrayData (
> +  IN VOID    *Array,
> +  IN UINT8   Type,
> +  IN UINTN   Index,
> +  IN UINT64  Value
> +  )
> +{
> +  ASSERT (Array != NULL);
> +
> +  switch (Type) {
> +    case EFI_IFR_TYPE_NUM_SIZE_8:
> +      *(((UINT8 *)Array) + Index) = (UINT8)Value;
> +      break;
> +
> +    case EFI_IFR_TYPE_NUM_SIZE_16:
> +      *(((UINT16 *)Array) + Index) = (UINT16)Value;
> +      break;
> +
> +    case EFI_IFR_TYPE_NUM_SIZE_32:
> +      *(((UINT32 *)Array) + Index) = (UINT32)Value;
> +      break;
> +
> +    case EFI_IFR_TYPE_NUM_SIZE_64:
> +      *(((UINT64 *)Array) + Index) = (UINT64)Value;
> +      break;
> +
> +    default:
> +      break;
> +  }
> +}
> +
> +/**
> +  Search an Option of a Question by its value.
> +
> +  @param  Question               The Question
> +  @param  OptionValue            Value for Option to be searched.
> +
> +  @retval Pointer                Pointer to the found Option.
> +  @retval NULL                   Option not found.
> +
> +**/
> +HII_QUESTION_OPTION *
> +ValueToOption (
> +  IN HII_STATEMENT        *Question,
> +  IN HII_STATEMENT_VALUE  *OptionValue
> +  )
> +{
> +  LIST_ENTRY           *Link;
> +  HII_QUESTION_OPTION  *Option;
> +  EFI_HII_VALUE        Data1;
> +  EFI_HII_VALUE        Data2;
> +  INTN                 Result;
> +  EFI_STATUS           Status;
> +
> +  Status = HiiStatementValueToHiiValue (OptionValue, &Data1);
> + ASSERT_EFI_ERROR (Status);
> +
> +  Link = GetFirstNode (&Question->OptionListHead);  while (!IsNull
> + (&Question->OptionListHead, Link)) {
> +    Option = HII_QUESTION_OPTION_FROM_LINK (Link);
> +
> +    Status = HiiStatementValueToHiiValue (&Option->Value, &Data2);
> +    ASSERT_EFI_ERROR (Status);
> +
> +    if ((CompareHiiValue (&Data1, &Data2, &Result, NULL) == EFI_SUCCESS) &&
> (Result == 0)) {
> +      //
> +      // Check the suppressif condition, only a valid option can be return.
> +      //
> +      if ((Option->SuppressExpression == NULL) ||
> +          ((EvaluateExpressionList (Option->SuppressExpression, FALSE, NULL,
> NULL) == ExpressFalse)))
> +      {
The open curly bracket should be at the end of condition check one line above.
Abner

> +        return Option;
> +      }
> +    }
> +
> +    Link = GetNextNode (&Question->OptionListHead, Link);  }
> +
> +  return NULL;
> +}
> +
> +/**
> +  Find the point in the ConfigResp string for this question.
> +
> +  @param  Question               The question.
> +  @param  ConfigResp             Get ConfigResp string.
Same here. Please check all @param in the new added function in this file.
> +
> +  @retval  point to the offset where is for this question.
> +
> +**/
> +CHAR16 *
> +GetOffsetFromConfigResp (
> +  IN HII_STATEMENT  *Question,
> +  IN CHAR16         *ConfigResp
> +  )
> +{
> +  CHAR16  *RequestElement;
> +  CHAR16  *BlockData;
> +
> +  //
> +  // Type is EFI_HII_VARSTORE_NAME_VALUE.
> +  //
> +  if (Question->Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
> +    RequestElement = StrStr (ConfigResp, Question->VariableName);
> +    if (RequestElement != NULL) {
> +      //
> +      // Skip the "VariableName=" field.
> +      //
> +      RequestElement += StrLen (Question->VariableName) + 1;
> +    }
> +
> +    return RequestElement;
> +  }
> +
> +  //
> +  // Type is EFI_HII_VARSTORE_EFI_VARIABLE or
> + EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER
> +  //
> +
> +  //
> +  // Convert all hex digits in ConfigResp to lower case before searching.
> +  //
> +  HiiToLower (ConfigResp);
> +
> +  //
> +  // 1. Directly use Question->BlockName to find.
> +  //
> +  RequestElement = StrStr (ConfigResp, Question->BlockName);  if
> + (RequestElement != NULL) {
> +    //
> +    // Skip the "Question->BlockName&VALUE=" field.
> +    //
> +    RequestElement += StrLen (Question->BlockName) + StrLen (L"&VALUE=");
> +    return RequestElement;
> +  }
> +
> +  //
> +  // 2. Change all hex digits in Question->BlockName to lower and compare
> again.
> +  //
> +  BlockData = AllocateCopyPool (StrSize (Question->BlockName),
> + Question->BlockName);  ASSERT (BlockData != NULL);  HiiToLower
> + (BlockData);  RequestElement = StrStr (ConfigResp, BlockData);
> + FreePool (BlockData);
> +
> +  if (RequestElement != NULL) {
> +    //
> +    // Skip the "Question->BlockName&VALUE=" field.
> +    //
> +    RequestElement += StrLen (Question->BlockName) + StrLen
> + (L"&VALUE=");  }
> +
> +  return RequestElement;
> +}
> +
> +/**
> +  Get Question default value from AltCfg string.
> +
> +  @param  FormSet                The form set.
> +  @param  Form                   The form
> +  @param  Question               The question.
> +  @param  DefaultValue           Default value.
> +
> +  @retval EFI_SUCCESS            Question is reset to default value.
> +
> +**/
> +EFI_STATUS
> +GetDefaultValueFromAltCfg (
> +  IN     HII_FORMSET          *FormSet,
> +  IN     HII_FORM             *Form,
> +  IN     HII_STATEMENT        *Question,
> +  OUT    HII_STATEMENT_VALUE  *DefaultValue
> +  )
> +{
> +  HII_FORMSET_STORAGE      *Storage;
> +  CHAR16                   *ConfigResp;
> +  CHAR16                   *Value;
> +  LIST_ENTRY               *Link;
> +  HII_FORM_CONFIG_REQUEST  *ConfigInfo;
> +
> +  Storage = Question->Storage;
> +  if ((Storage == NULL) || (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE))
> {
> +    return EFI_NOT_FOUND;
> +  }
> +
> +  //
> +  // Try to get AltCfg string from form. If not found it, then  // try
> + to get it from formset.
> +  //
> +  ConfigResp = NULL;
> +  Link       = GetFirstNode (&Form->ConfigRequestHead);
> +  while (!IsNull (&Form->ConfigRequestHead, Link)) {
> +    ConfigInfo = HII_FORM_CONFIG_REQUEST_FROM_LINK (Link);
> +    Link       = GetNextNode (&Form->ConfigRequestHead, Link);
> +
> +    if (Storage == ConfigInfo->Storage) {
> +      ConfigResp = ConfigInfo->ConfigAltResp;
> +      break;
> +    }
> +  }
> +
> +  if (ConfigResp == NULL) {
> +    return EFI_NOT_FOUND;
> +  }
> +
> +  Value = GetOffsetFromConfigResp (Question, ConfigResp);  if (Value ==
> + NULL) {
> +    return EFI_NOT_FOUND;
> +  }
> +
> +  return BufferToValue (Question, Value, DefaultValue); }
> +
> +/**
> +  Get default Id value used for browser.
> +
> +  @param  DefaultId              The default id value used by hii.
> +
> +  @retval Browser used default value.
> +
> +**/
> +INTN
> +GetDefaultIdForCallBack (
> +  UINTN  DefaultId
> +  )
> +{
> +  if (DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) {
> +    return EFI_BROWSER_ACTION_DEFAULT_STANDARD;
> +  } else if (DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) {
> +    return EFI_BROWSER_ACTION_DEFAULT_MANUFACTURING;
> +  } else if (DefaultId == EFI_HII_DEFAULT_CLASS_SAFE) {
> +    return EFI_BROWSER_ACTION_DEFAULT_SAFE;
> +  } else if ((DefaultId >= EFI_HII_DEFAULT_CLASS_PLATFORM_BEGIN) &&
> (DefaultId < EFI_HII_DEFAULT_CLASS_PLATFORM_BEGIN + 0x1000)) {
> +    return EFI_BROWSER_ACTION_DEFAULT_PLATFORM + DefaultId -
> +EFI_HII_DEFAULT_CLASS_PLATFORM_BEGIN;
> +  } else if ((DefaultId >= EFI_HII_DEFAULT_CLASS_HARDWARE_BEGIN) &&
> (DefaultId < EFI_HII_DEFAULT_CLASS_HARDWARE_BEGIN + 0x1000)) {
> +    return EFI_BROWSER_ACTION_DEFAULT_HARDWARE + DefaultId -
> +EFI_HII_DEFAULT_CLASS_HARDWARE_BEGIN;
> +  } else if ((DefaultId >= EFI_HII_DEFAULT_CLASS_FIRMWARE_BEGIN) &&
> (DefaultId < EFI_HII_DEFAULT_CLASS_FIRMWARE_BEGIN + 0x1000)) {
> +    return EFI_BROWSER_ACTION_DEFAULT_FIRMWARE + DefaultId -
> +EFI_HII_DEFAULT_CLASS_FIRMWARE_BEGIN;
> +  } else {
> +    return -1;
> +  }
> +}
> +
> +/**
> +  Get default value of question.
> +
> +  @param  FormSet                The form set.
> +  @param  Form                   The form.
> +  @param  Question               The question.
> +  @param  DefaultId              The Class of the default.
> +  @param  DefaultValue           The default value of given question.
> +
> +  @retval EFI_SUCCESS            Question is reset to default value.
> +
> +**/
> +EFI_STATUS
> +GetQuestionDefault (
> +  IN HII_FORMSET           *FormSet,
> +  IN HII_FORM              *Form,
> +  IN HII_STATEMENT         *Question,
> +  IN UINT16                DefaultId,
> +  OUT HII_STATEMENT_VALUE  *DefaultValue
> +  )
> +{
> +  EFI_STATUS                      Status;
> +  LIST_ENTRY                      *Link;
> +  HII_QUESTION_DEFAULT            *Default;
> +  HII_QUESTION_OPTION             *Option;
> +  HII_STATEMENT_VALUE             *HiiValue;
> +  UINT8                           Index;
> +  EFI_STRING                      StrValue;
> +  EFI_HII_CONFIG_ACCESS_PROTOCOL  *ConfigAccess;
> +  EFI_BROWSER_ACTION_REQUEST      ActionRequest;
> +  INTN                            Action;
> +  EFI_IFR_TYPE_VALUE              *TypeValue;
> +  UINT16                          OriginalDefaultId;
> +  HII_FORMSET_DEFAULTSTORE        *DefaultStore;
> +  LIST_ENTRY                      *DefaultLink;
> +
> +  if ((FormSet == NULL) || (Form == NULL) || (Question == NULL) ||
> (DefaultValue == NULL)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  Status            = EFI_NOT_FOUND;
> +  StrValue          = NULL;
> +  OriginalDefaultId = DefaultId;
> +  DefaultLink       = GetFirstNode (&FormSet->DefaultStoreListHead);
> +
> +  //
> +  // Statement don't have storage, skip them  //  if
> + (Question->QuestionId == 0) {
> +    return Status;
> +  }
> +
> +  //
> +  // There are Five ways to specify default value for a Question:
> +  //  1, use call back function (highest priority)
> +  //  2, use ExtractConfig function
> +  //  3, use nested EFI_IFR_DEFAULT
> +  //  4, set flags of EFI_ONE_OF_OPTION (provide Standard and
> +Manufacturing default)
> +  //  5, set flags of EFI_IFR_CHECKBOX (provide Standard and
> +Manufacturing default) (lowest priority)
> +  //
> +  CopyMem (DefaultValue, &Question->Value, sizeof
> +(HII_STATEMENT_VALUE));
> +ReGetDefault:
> +  HiiValue  = DefaultValue;
> +  TypeValue = &HiiValue->Value;
> +  if (HiiValue->Type == EFI_IFR_TYPE_BUFFER) {
> +    //
> +    // For orderedlist, need to pass the BufferValue to Callback function.
> +    //
> +    DefaultValue->BufferLen = Question->Value.BufferLen;
> +    DefaultValue->Buffer    = AllocateZeroPool (DefaultValue->BufferLen);
> +    ASSERT (DefaultValue->Buffer != NULL);
> +    if (DefaultValue->Buffer == NULL) {
> +      return EFI_OUT_OF_RESOURCES;
> +    }
> +
> +    TypeValue = (EFI_IFR_TYPE_VALUE *)DefaultValue->Buffer;  }
> +
> +  //
> +  // Get Question defaut value from call back function.
> +  // The string type of question cause HII driver to set string to its default value.
> +  // So, we don't do this otherwise it will actually set question to default value.
> +  // We only want to get default value of question.
> +  //
> +  if (HiiValue->Type != EFI_IFR_TYPE_STRING) {
> +    ConfigAccess = FormSet->ConfigAccess;
> +    Action       = GetDefaultIdForCallBack (DefaultId);
> +    if ((Action > 0) && ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) !=
> 0) && (ConfigAccess != NULL)) {
> +      ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
> +      Status        = ConfigAccess->Callback (
> +                                      ConfigAccess,
> +                                      Action,
> +                                      Question->QuestionId,
> +                                      HiiValue->Type,
> +                                      TypeValue,
> +                                      &ActionRequest
> +                                      );
> +      if (!EFI_ERROR (Status)) {
> +        return Status;
> +      }
> +    }
> +  }
> +
> +  //
> +  // Get default value from altcfg string.
> +  //
> +  if (ConfigAccess != NULL) {
> +    Status = GetDefaultValueFromAltCfg (FormSet, Form, Question,
> DefaultValue);
> +    if (!EFI_ERROR (Status)) {
> +      return Status;
> +    }
> +  }
> +
> +  //
> +  // EFI_IFR_DEFAULT has highest priority  //  if (!IsListEmpty
> + (&Question->DefaultListHead)) {
> +    Link = GetFirstNode (&Question->DefaultListHead);
> +    while (!IsNull (&Question->DefaultListHead, Link)) {
> +      Default = HII_QUESTION_DEFAULT_FROM_LINK (Link);
> +
> +      if (Default->DefaultId == DefaultId) {
> +        if (Default->ValueExpression != NULL) {
> +          //
> +          // Default is provided by an Expression, evaluate it
> +          //
> +          Status = EvaluateHiiExpression (FormSet, Form, Default-
> >ValueExpression);
> +          if (EFI_ERROR (Status)) {
> +            return Status;
> +          }
> +
> +          if (Default->ValueExpression->Result.Type == EFI_IFR_TYPE_BUFFER) {
> +            ASSERT (HiiValue->Type == EFI_IFR_TYPE_BUFFER && DefaultValue-
> >Buffer != NULL);
> +            if (DefaultValue->BufferLen > Default->ValueExpression-
> >Result.BufferLen) {
> +              CopyMem (DefaultValue->Buffer, Default->ValueExpression-
> >Result.Buffer, Default->ValueExpression->Result.BufferLen);
> +              DefaultValue->BufferLen = Default->ValueExpression-
> >Result.BufferLen;
> +            } else {
> +              CopyMem (DefaultValue->Buffer, Default->ValueExpression-
> >Result.Buffer, DefaultValue->BufferLen);
> +            }
> +
> +            FreePool (Default->ValueExpression->Result.Buffer);
> +          }
> +
> +          HiiValue->Type = Default->ValueExpression->Result.Type;
> +          CopyMem (&HiiValue->Value, &Default->ValueExpression->Result.Value,
> sizeof (EFI_IFR_TYPE_VALUE));
> +        } else {
> +          //
> +          // Default value is embedded in EFI_IFR_DEFAULT
> +          //
> +          if (Default->Value.Type == EFI_IFR_TYPE_BUFFER) {
> +            ASSERT (HiiValue->Buffer != NULL);
> +            CopyMem (HiiValue->Buffer, Default->Value.Buffer, Default-
> >Value.BufferLen);
> +          } else {
> +            CopyMem (HiiValue, &Default->Value, sizeof (EFI_HII_VALUE));
> +          }
> +        }
> +
> +        if (HiiValue->Type == EFI_IFR_TYPE_STRING) {
> +          StrValue = HiiGetString (FormSet->HiiHandle, HiiValue->Value.string,
> NULL);
> +          if (StrValue == NULL) {
> +            return EFI_NOT_FOUND;
> +          }
> +
> +          if (DefaultValue->BufferLen > StrSize (StrValue)) {
> +            ZeroMem (DefaultValue->Buffer, DefaultValue->BufferLen);
> +            CopyMem (DefaultValue->Buffer, StrValue, StrSize (StrValue));
> +          } else {
> +            CopyMem (DefaultValue->Buffer, StrValue, DefaultValue->BufferLen);
> +          }
> +        }
> +
> +        return EFI_SUCCESS;
> +      }
> +
> +      Link = GetNextNode (&Question->DefaultListHead, Link);
> +    }
> +  }
> +
> +  //
> +  // EFI_ONE_OF_OPTION
> +  //
> +  if ((Question->Operand == EFI_IFR_ONE_OF_OP) && !IsListEmpty (&Question-
> >OptionListHead)) {
> +    if (DefaultId <= EFI_HII_DEFAULT_CLASS_MANUFACTURING) {
> +      //
> +      // OneOfOption could only provide Standard and Manufacturing default
> +      //
> +      Link = GetFirstNode (&Question->OptionListHead);
> +      while (!IsNull (&Question->OptionListHead, Link)) {
> +        Option = HII_QUESTION_OPTION_FROM_LINK (Link);
> +        Link   = GetNextNode (&Question->OptionListHead, Link);
> +
> +        if ((Option->SuppressExpression != NULL) &&
> +            (EvaluateExpressionList (Option->SuppressExpression, FALSE, NULL,
> NULL) != ExpressFalse))
> +        {
> +          continue;
> +        }
> +
> +        if (((DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) && ((Option->Flags
> & EFI_IFR_OPTION_DEFAULT) != 0)) ||
> +            ((DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) &&
> ((Option->Flags & EFI_IFR_OPTION_DEFAULT_MFG) != 0))
> +            )
> +        {
> +          CopyMem (HiiValue, &Option->Value, sizeof (EFI_HII_VALUE));
> +
> +          return EFI_SUCCESS;
> +        }
> +      }
> +    }
> +  }
> +
> +  //
> +  // EFI_IFR_CHECKBOX - lowest priority  //  if (Question->Operand ==
> + EFI_IFR_CHECKBOX_OP) {
> +    if (DefaultId <= EFI_HII_DEFAULT_CLASS_MANUFACTURING) {
> +      //
> +      // Checkbox could only provide Standard and Manufacturing default
> +      //
> +      if (((DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) && ((Question-
> >ExtraData.Flags & EFI_IFR_CHECKBOX_DEFAULT) != 0)) ||
> +          ((DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) &&
> ((Question->ExtraData.Flags & EFI_IFR_CHECKBOX_DEFAULT_MFG) != 0))
> +          )
> +      {
> +        HiiValue->Value.b = TRUE;
> +      }
> +
> +      return EFI_SUCCESS;
> +    }
> +  }
> +
> +  //
> +  // For question without default value for current default Id, we try to re-get
> the default value form other default id in the DefaultStoreList.
> +  // If get, will exit the function, if not, will choose next default id in the
> DefaultStoreList.
> +  // The default id in DefaultStoreList are in ascending order to make sure
> choose the smallest default id every time.
> +  //
> +  while (!IsNull (&FormSet->DefaultStoreListHead, DefaultLink)) {
> +    DefaultStore = HII_FORMSET_DEFAULTSTORE_FROM_LINK (DefaultLink);
> +    DefaultLink  = GetNextNode (&FormSet->DefaultStoreListHead, DefaultLink);
> +    DefaultId    = DefaultStore->DefaultId;
> +    if (DefaultId == OriginalDefaultId) {
> +      continue;
> +    }
> +
> +    goto ReGetDefault;
> +  }
> +
> +  //
> +  // For Questions without default value for all the default id in the
> DefaultStoreList.
> +  //
> +  Status = EFI_NOT_FOUND;
> +  switch (Question->Operand) {
> +    case EFI_IFR_CHECKBOX_OP:
> +      HiiValue->Value.b = FALSE;
> +      Status            = EFI_SUCCESS;
> +      break;
> +
> +    case EFI_IFR_NUMERIC_OP:
> +      //
> +      // Take minimum value as numeric default value
> +      //
> +      if ((Question->ExtraData.NumData.Flags & EFI_IFR_DISPLAY) == 0) {
> +        //
> +        // In EFI_IFR_DISPLAY_INT_DEC type, should check value with int* type.
> +        //
> +        switch (Question->ExtraData.NumData.Flags & EFI_IFR_NUMERIC_SIZE) {
> +          case EFI_IFR_NUMERIC_SIZE_1:
> +            if (((INT8)HiiValue->Value.u8 < (INT8)Question-
> >ExtraData.NumData.Minimum) || ((INT8)HiiValue->Value.u8 > (INT8)Question-
> >ExtraData.NumData.Maximum)) {
> +              HiiValue->Value.u8 = (UINT8)Question->ExtraData.NumData.Minimum;
> +              Status             = EFI_SUCCESS;
> +            }
> +
> +            break;
> +          case EFI_IFR_NUMERIC_SIZE_2:
> +            if (((INT16)HiiValue->Value.u16 < (INT16)Question-
> >ExtraData.NumData.Minimum) || ((INT16)HiiValue->Value.u16 >
> (INT16)Question->ExtraData.NumData.Maximum)) {
> +              HiiValue->Value.u16 = (UINT16)Question-
> >ExtraData.NumData.Minimum;
> +              Status              = EFI_SUCCESS;
> +            }
> +
> +            break;
> +          case EFI_IFR_NUMERIC_SIZE_4:
> +            if (((INT32)HiiValue->Value.u32 < (INT32)Question-
> >ExtraData.NumData.Minimum) || ((INT32)HiiValue->Value.u32 >
> (INT32)Question->ExtraData.NumData.Maximum)) {
> +              HiiValue->Value.u32 = (UINT32)Question-
> >ExtraData.NumData.Minimum;
> +              Status              = EFI_SUCCESS;
> +            }
> +
> +            break;
> +          case EFI_IFR_NUMERIC_SIZE_8:
> +            if (((INT64)HiiValue->Value.u64 < (INT64)Question-
> >ExtraData.NumData.Minimum) || ((INT64)HiiValue->Value.u64 >
> (INT64)Question->ExtraData.NumData.Maximum)) {
> +              HiiValue->Value.u64 = Question->ExtraData.NumData.Minimum;
> +              Status              = EFI_SUCCESS;
> +            }
> +
> +            break;
> +          default:
> +            break;
> +        }
> +      } else {
> +        if ((HiiValue->Value.u64 < Question->ExtraData.NumData.Minimum) ||
> (HiiValue->Value.u64 > Question->ExtraData.NumData.Maximum)) {
> +          HiiValue->Value.u64 = Question->ExtraData.NumData.Minimum;
> +          Status              = EFI_SUCCESS;
> +        }
> +      }
> +
> +      break;
> +
> +    case EFI_IFR_ONE_OF_OP:
> +      //
> +      // Take first oneof option as oneof's default value
> +      //
> +      if (ValueToOption (Question, HiiValue) == NULL) {
> +        Link = GetFirstNode (&Question->OptionListHead);
> +        while (!IsNull (&Question->OptionListHead, Link)) {
> +          Option = HII_QUESTION_OPTION_FROM_LINK (Link);
> +          Link   = GetNextNode (&Question->OptionListHead, Link);
> +
> +          if ((Option->SuppressExpression != NULL) &&
> +              (EvaluateExpressionList (Option->SuppressExpression, FALSE, NULL,
> NULL) != ExpressFalse))
> +          {
> +            continue;
> +          }
> +
> +          CopyMem (HiiValue, &Option->Value, sizeof (EFI_HII_VALUE));
> +          Status = EFI_SUCCESS;
> +          break;
> +        }
> +      }
> +
> +      break;
> +
> +    case EFI_IFR_ORDERED_LIST_OP:
> +      //
> +      // Take option sequence in IFR as ordered list's default value
> +      //
> +      Index = 0;
> +      Link  = GetFirstNode (&Question->OptionListHead);
> +      while (!IsNull (&Question->OptionListHead, Link)) {
> +        Status = EFI_SUCCESS;
> +        Option = HII_QUESTION_OPTION_FROM_LINK (Link);
> +        Link   = GetNextNode (&Question->OptionListHead, Link);
> +
> +        if ((Option->SuppressExpression != NULL) &&
> +            (EvaluateExpressionList (Option->SuppressExpression, FALSE, NULL,
> NULL) != ExpressFalse))
> +        {
> +          continue;
> +        }
> +
> +        SetArrayData (DefaultValue->Buffer, Question->Value.Type,
> + Index, Option->Value.Value.u64);
> +
> +        Index++;
> +        if (Index >= Question->ExtraData.OrderListData.MaxContainers) {
> +          break;
> +        }
> +      }
> +
> +      break;
> +
> +    default:
> +      break;
> +  }
> +
> +  return Status;
> +}
> --
> 2.38.1.windows.1

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2022-12-12  1:58 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2022-12-07 14:09 [edk2-staging][PATCH 1/3] edk2-staging/RedfishPkg: Add interface to get question default value Nickle Wang
2022-12-12  1:58 ` Chang, Abner

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox