Add depex support in bios.xml parsing.

Added logic to execute depex expression for every knob in bios.xml.
knob is added to BiosAttributeRegistry only if depex evaluation result
is TRUE.

Tested:
By giving GET Request to
'redfish/v1/Registries/BiosAttributeRegistry/BiosAttributeRegistry'.
Output sample showing few knobs added becuase depex evaluation result
was TRUE:

{
    "AttributeName": "AEPErrorInjEn",
    "CurrentValue": "0x00",
    "DefaultValue": "0x00",
    "DisplayName": "AEPErrorInjEn",
    "HelpText": "Enable/Disable PMem Error Injection",
    "MenuPath": "./",
    "ReadOnly": false,
    "Type": "String",
    "Value": [
        {
            "OneOf": "0x0"
        },
        {
            "OneOf": "0x1"
        }
    ]
}
{
    "AttributeName": "wrVrefCenter",
    "CurrentValue": "0x01",
    "DefaultValue": "0x01",
    "DisplayName": "wrVrefCenter",
    "HelpText": "Write Vref Centering Disable/Enable",
    "MenuPath": "./",
    "ReadOnly": false,
    "Type": "String",
    "Value": [
        {
            "OneOf": "0x0"
        },
        {
            "OneOf": "0x1"
        }
    ]
}

Following are few knobs rejected becuase depex evaluation
result was FALSE:

<knob  type="scalar" setupType="oneof" name="PfrProvision"
varstoreIndex="04" prompt="PFR Provision"
description="Selectable if PFR is not locked." size="1"
offset="0x0126"
depex="Sif( PfrSupported _EQU_ 0 ) _AND_ Gif( PfrLockStatus _EQU_ 1 OR
PfrProvisionStatus _EQU_ 1 )"
default="0x00" CurrentVal="0x00">
    <options>
        <option text="Disable" value="0x0"/>
        <option text="Enable" value="0x1"/>
    </options>
</knob>

<knob  type="scalar" setupType="oneof" name="SataHotPlugController0_0"
varstoreIndex="01" prompt="
Hot Plug" description="Designates this port as Hot Pluggable." size="1"
offset="0x0119"
depex="Sif( PchSata_0 _EQU_ 0 ) _AND_
Sif( SataExternalController0_0 _EQU_ 1 )" default="0x00"
CurrentVal="0x00">
    <options>
        <option text="Disabled" value="0x0"/>
        <option text="Enabled" value="0x1"/>
    </options>
</knob>

Signed-off-by: Arun Lal K M <arun.lal@intel.com>
Change-Id: Iff1ea01fb06200e21cc7f2a2e0fdfdff70376581
diff --git a/include/biosxml.hpp b/include/biosxml.hpp
new file mode 100644
index 0000000..c5be53c
--- /dev/null
+++ b/include/biosxml.hpp
@@ -0,0 +1,884 @@
+#pragma once

+

+#include "tinyxml2.h"

+

+#include <phosphor-logging/elog-errors.hpp>

+#include <phosphor-logging/log.hpp>

+

+#include <map>

+#include <sstream>

+#include <stack>

+#include <string>

+#include <variant>

+#include <vector>

+

+std::string mapAttrTypeToRedfish(const std::string_view typeDbus)

+{

+    std::string ret;

+    if (typeDbus == "xyz.openbmc_project.BIOSConfig.Manager."

+                    "AttributeType.Enumeration")

+    {

+        ret = "Enumeration";

+    }

+    else if (typeDbus == "xyz.openbmc_project.BIOSConfig."

+                         "Manager.AttributeType.String")

+    {

+        ret = "String";

+    }

+    else if (typeDbus == "xyz.openbmc_project.BIOSConfig."

+                         "Manager.AttributeType.Password")

+    {

+        ret = "Password";

+    }

+    else if (typeDbus == "xyz.openbmc_project.BIOSConfig."

+                         "Manager.AttributeType.Integer")

+    {

+        ret = "Integer";

+    }

+    else if (typeDbus == "xyz.openbmc_project.BIOSConfig."

+                         "Manager.AttributeType.Boolean")

+    {

+        ret = "Boolean";

+    }

+    else

+    {

+        ret = "UNKNOWN";

+    }

+

+    return ret;

+}

+

+namespace bios

+{

+/* Can hold one 'option'

+ * For example

+ *  <option text="TIS" value="0x0"/>

+ */

+using OptionType = std::tuple<std::string, std::variant<int64_t, std::string>>;

+

+/* Can hold one 'options'

+ * For example

+ *  <options>

+ *		<option text="TIS" value="0x0"/>

+ *		<option text="PTP FIFO" value="0x1"/>

+ *		<option text="PTP CRB" value="0x2"/>

+ *	</options>

+ */

+using OptionTypeVector = std::vector<OptionType>;

+

+/* Can hold one 'knob'

+ * For example

+ *  <knob  type="scalar" setupType="oneof" name="TpmDeviceInterfaceAttempt"

+ *  varstoreIndex="14" prompt="Attempt PTP TPM Device Interface"

+ *  description="Attempt PTP TPM Device Interface: PTP FIFO, PTP CRB" size="1"

+ *  offset="0x0005" depex="Sif( _LIST_ TpmDevice _EQU_ 0 1 ) _AND_ Sif(

+ *  TpmDeviceInterfacePtpFifoSupported _EQU_ 0 OR

+ *  TpmDeviceInterfacePtpCrbSupported _EQU_ 0 )" default="0x00"

+ *CurrentVal="0x00"> <options> <option text="TIS" value="0x0"/> <option

+ *text="PTP FIFO" value="0x1"/> <option text="PTP CRB" value="0x2"/>

+ *		</options>

+ *	</knob>

+ */

+using BiosBaseTableTypeEntry =

+    std::tuple<std::string, bool, std::string, std::string, std::string,

+               std::variant<int64_t, std::string>,

+               std::variant<int64_t, std::string>, OptionTypeVector>;

+

+/* Can hold one 'biosknobs'

+ * biosknobs has array of 'knob' */

+using BiosBaseTableType = std::map<std::string, BiosBaseTableTypeEntry>;

+

+namespace knob

+{

+/* These are the operators we support in a 'depex' expression

+ * Note: We also support '_LIST_', 'Sif', 'Gif', 'Dif', and 'NOT'. But they are

+ * handeled sepeartely. */

+enum class DepexOperators

+{

+    unknown = 0,

+    OR,

+    AND,

+    LTE,

+    LT,

+    EQU,

+    NEQ,

+    MODULO

+};

+

+namespace option

+{

+/* Can hold one 'option' */

+struct option

+{

+    option(std::string text, std::string value) :

+        text(std::move(text)), value(std::move(value))

+    {}

+

+    std::string text;

+    std::string value;

+};

+} // namespace option

+

+/* Can hold one 'knob' */

+struct knob

+{

+    knob(std::string nameStr, std::string currentValStr, int currentVal,

+         std::string descriptionStr, std::string defaultStr,

+         std::string promptStr, std::string depexStr,

+         std::string& setupTypeStr) :

+        nameStr(std::move(nameStr)),

+        currentValStr(std::move(currentValStr)), currentVal(currentVal),

+        descriptionStr(std::move(descriptionStr)),

+        defaultStr(std::move(defaultStr)), promptStr(std::move(promptStr)),

+        depexStr(std::move(depexStr)), depex(false),

+        readOnly(("ReadOnly" == setupTypeStr) ? true : false)

+    {}

+

+    bool depex;

+    bool readOnly;

+    int currentVal;

+

+    std::string nameStr;

+    std::string currentValStr;

+    std::string descriptionStr;

+    std::string defaultStr;

+    std::string promptStr;

+    std::string depexStr;

+

+    /* Can hold one 'options' */

+    std::vector<option::option> options;

+};

+} // namespace knob

+

+/* Class capable of computing 'depex' expression. */

+class Depex

+{

+  public:

+    Depex(std::vector<knob::knob>& knobs) : mKnobs(knobs)

+    {}

+

+    /* Compute 'depex' expression of all knobs in 'biosknobs'. */

+    void compute()

+    {

+        mError.clear();

+

+        for (auto& knob : mKnobs)

+        {

+            /* if 'depex' == "TRUE" no need to execute expression. */

+            if ("TRUE" == knob.depexStr)

+            {

+                knob.depex = true;

+            }

+            else if (!knob.readOnly)

+            {

+                int value = 0;

+

+                if (!evaluateExpression(knob.depexStr, value))

+                {

+                    mError.emplace_back("bad depex: " + knob.depexStr +

+                                        " in knob: " + knob.nameStr);

+                }

+                else

+                {

+                    if (value)

+                    {

+                        knob.depex = true;

+                    }

+                }

+            }

+        }

+    }

+

+    /* Returns the number of 'knob's which have a bad 'depex' expression. */

+    size_t getErrorCount()

+    {

+        return mError.size();

+    }

+

+    /* Prints all the 'knob's which have a bad 'depex' expression. */

+    void printError()

+    {

+        for (auto& error : mError)

+        {

+            phosphor::logging::log<phosphor::logging::level::ERR>(

+                error.c_str());

+        }

+    }

+

+  private:

+    /* Returns 'true' if the argument string is a number. */

+    bool isNumber(const std::string& s)

+    {

+        return !s.empty() &&

+               std::find_if(s.begin(), s.end(), [](unsigned char c) {

+                   return !std::isdigit(c);

+               }) == s.end();

+    }

+

+    /* Returns 'true' if the argument string is hex representation of a number.

+     */

+    bool isHexNotation(std::string const& s)

+    {

+        return s.compare(0, 2, "0x") == 0 && s.size() > 2 &&

+               s.find_first_not_of("0123456789abcdefABCDEF", 2) ==

+                   std::string::npos;

+    }

+

+    /* Function to find current value of a 'knob'

+     * search is done using 'knob' attribute 'name' */

+    bool getValue(std::string& variableName, int& value)

+    {

+        for (auto& knob : mKnobs)

+        {

+            if (knob.nameStr == variableName)

+            {

+                value = knob.currentVal;

+                return true;

+            }

+        }

+

+        std::string error =

+            "Unable to find knob: " + variableName + " in knob list\n";

+        phosphor::logging::log<phosphor::logging::level::ERR>(error.c_str());

+

+        return false;

+    }

+

+    /* Get the expression enclosed within brackets, i.e., between '(' and ')' */

+    bool getSubExpression(const std::string& expression,

+                          std::string& subExpression, size_t& i)

+    {

+        int level = 1;

+        subExpression.clear();

+

+        for (; i < expression.length(); i++)

+        {

+            if (expression[i] == '(')

+            {

+                ++level;

+            }

+            else if (expression[i] == ')')

+            {

+                --level;

+                if (level == 0)

+                {

+                    break;

+                }

+            }

+

+            subExpression.push_back(expression[i]);

+        }

+

+        if (!subExpression.empty())

+        {

+            return true;

+        }

+

+        return false;

+    }

+

+    /* Function to handle operator '_LIST_'

+     * Convert a '_LIST_' expression to a normal expression

+     * Example "_LIST_ VariableA _EQU_ 0 1" is converted to "VariableA _EQU_ 0

+     * OR VariableA _EQU_ 1" */

+    bool getListExpression(const std::string& expression,

+                           std::string& subExpression, size_t& i)

+    {

+        subExpression.clear();

+

+        int cnt = 0;

+        std::string variableStr;

+        std::string operatorStr;

+

+        for (; i < expression.length(); i++)

+        {

+            if (expression[i] == '(')

+            {

+                return false;

+            }

+            else if (expression[i] == ')')

+            {

+                break;

+            }

+            else if (expression[i] == ' ')

+            {

+                /* whitespace */

+                continue;

+            }

+            else

+            {

+                std::string word;

+

+                /* Get the next word in expression string */

+                while ((i < expression.length()) && (expression[i] != ' '))

+                {

+                    word.push_back(expression[i++]);

+                }

+

+                if (word == "_OR_" || word == "OR" || word == "_AND_" ||

+                    word == "AND" || word == "NOT")

+                {

+                    i = i - word.length();

+                    break;

+                }

+

+                ++cnt;

+

+                if (cnt == 1)

+                {

+                    variableStr = word;

+                }

+                else if (cnt == 2)

+                {

+                    operatorStr = word;

+                }

+                else

+                {

+                    if (cnt > 3)

+                    {

+                        subExpression += " OR ";

+                    }

+

+                    subExpression += "( ";

+                    subExpression += variableStr;

+                    subExpression += " ";

+                    subExpression += operatorStr;

+                    subExpression += " ";

+                    subExpression += word;

+                    subExpression += " )";

+                }

+            }

+        }

+

+        if (!subExpression.empty())

+        {

+            return true;

+        }

+

+        return false;

+    }

+

+    /* Function to handle operator 'NOT'

+     * 1) Find the variable

+     * 2) apply NOT on the variable */

+    bool getNotValue(const std::string& expression, size_t& i, int& value)

+    {

+        std::string word;

+

+        for (; i < expression.length(); i++)

+        {

+            if (expression[i] == ' ')

+            {

+                /* whitespace */

+                continue;

+            }

+            else

+            {

+                /* Get the next word in expression string */

+                while ((i < expression.length()) && (expression[i] != ' '))

+                {

+                    word.push_back(expression[i++]);

+                }

+

+                break;

+            }

+        }

+

+        if (!word.empty())

+        {

+            if (getValue(word, value))

+            {

+                value = !value;

+                return true;

+            }

+        }

+

+        return false;

+    }

+

+    /* 1) Pop one operator from operator stack, example 'OR'

+     * 2) Pop two variable from variable stack, example VarA and VarB

+     * 3) Push back result of 'VarA OR VarB' to variable stack

+     * 4) Repeat till operator stack is empty

+     *

+     * The last variable in variable stack is the output of the expression. */

+    bool evaluateExprStack(std::stack<int>& values,

+                           std::stack<knob::DepexOperators>& operators,

+                           int& output)

+    {

+        if (values.size() != (operators.size() + 1))

+        {

+            return false;

+        }

+

+        while (!operators.empty())

+        {

+            int b = values.top();

+            values.pop();

+

+            int a = values.top();

+            values.pop();

+

+            switch (operators.top())

+            {

+                case knob::DepexOperators::OR:

+                    values.emplace(a | b);

+                    break;

+

+                case knob::DepexOperators::AND:

+                    values.emplace(a & b);

+                    break;

+

+                case knob::DepexOperators::EQU:

+                    if (a == b)

+                    {

+                        values.emplace(1);

+                        break;

+                    }

+

+                    values.emplace(0);

+                    break;

+

+                case knob::DepexOperators::NEQ:

+                    if (a != b)

+                    {

+                        values.emplace(1);

+                        break;

+                    }

+

+                    values.emplace(0);

+                    break;

+

+                case knob::DepexOperators::LTE:

+                    if (a <= b)

+                    {

+                        values.emplace(1);

+                        break;

+                    }

+

+                    values.emplace(0);

+                    break;

+

+                case knob::DepexOperators::LT:

+                    if (a < b)

+                    {

+                        values.emplace(1);

+                        break;

+                    }

+

+                    values.emplace(0);

+                    break;

+

+                case knob::DepexOperators::MODULO:

+                    if (b == 0)

+                    {

+                        return false;

+                    }

+                    values.emplace(a % b);

+                    break;

+

+                default:

+                    return false;

+            }

+

+            operators.pop();

+        }

+

+        if (values.size() == 1)

+        {

+            output = values.top();

+            values.pop();

+

+            return true;

+        }

+

+        return false;

+    }

+

+    /* Evaluvate one 'depex' expression

+     * 1) Find a word in expression string

+     * 2) If word is a variable push to variable stack

+     * 3) If word is a operator push to operator stack

+     *

+     * Execute the stack at end to get the result of expression. */

+    bool evaluateExpression(const std::string& expression, int& output)

+    {

+        if (expression.empty())

+        {

+            return false;

+        }

+

+        size_t i;

+        int value;

+        std::stack<int> values;

+        std::stack<knob::DepexOperators> operators;

+        std::string subExpression;

+

+        for (i = 0; i < expression.length(); i++)

+        {

+            if (expression[i] == ' ')

+            {

+                /* whitespace */

+                continue;

+            }

+            else

+            {

+                std::string word;

+

+                /* Get the next word in expression string */

+                while ((i < expression.length()) && (expression[i] != ' '))

+                {

+                    word.push_back(expression[i++]);

+                }

+

+                if (word == "_OR_" || word == "OR")

+                {

+                    /* OR and AND has more precedence than other operators

+                     * To handle statements like "a != b or c != d"

+                     * we need to execute, for above example, both '!=' before

+                     * 'or' */

+                    if (!operators.empty())

+                    {

+                        if (!evaluateExprStack(values, operators, value))

+                        {

+                            return false;

+                        }

+

+                        values.emplace(value);

+                    }

+

+                    operators.emplace(knob::DepexOperators::OR);

+                }

+                else if (word == "_AND_" || word == "AND")

+                {

+                    /* OR and AND has more precedence than other operators

+                     * To handle statements like "a == b and c == d"

+                     * we need to execute, for above example, both '==' before

+                     * 'and' */

+                    if (!operators.empty())

+                    {

+                        if (!evaluateExprStack(values, operators, value))

+                        {

+                            return false;

+                        }

+

+                        values.emplace(value);

+                    }

+

+                    operators.emplace(knob::DepexOperators::AND);

+                }

+                else if (word == "_LTE_")

+                {

+                    operators.emplace(knob::DepexOperators::LTE);

+                }

+                else if (word == "_LT_")

+                {

+                    operators.emplace(knob::DepexOperators::LT);

+                }

+                else if (word == "_NEQ_")

+                {

+                    operators.emplace(knob::DepexOperators::NEQ);

+                }

+                else if (word == "_EQU_")

+                {

+                    operators.emplace(knob::DepexOperators::EQU);

+                }

+                else if (word == "%")

+                {

+                    operators.emplace(knob::DepexOperators::MODULO);

+                }

+                else

+                {

+                    /* Handle 'Sif(', 'Gif(', 'Dif(' and '('

+                     * by taking the inner/sub expression and evaluating it */

+                    if (word.back() == '(')

+                    {

+                        if (!getSubExpression(expression, subExpression, i))

+                            break;

+

+                        if (!evaluateExpression(subExpression, value))

+                            break;

+                    }

+                    else if (word == "_LIST_")

+                    {

+                        if (!getListExpression(expression, subExpression, i))

+                            break;

+

+                        --i;

+

+                        if (!evaluateExpression(subExpression, value))

+                            break;

+                    }

+                    else if (word == "NOT")

+                    {

+                        if (!getNotValue(expression, i, value))

+                            break;

+                    }

+                    else if (isNumber(word) || isHexNotation(word))

+                    {

+                        try

+                        {

+                            value = std::stoi(word);

+                        }

+                        catch (std::exception& ex)

+                        {

+                            phosphor::logging::log<

+                                phosphor::logging::level::ERR>(ex.what());

+                            return false;

+                        }

+                    }

+                    else

+                    {

+                        if (!getValue(word, value))

+                            break;

+                    }

+

+                    values.emplace(value);

+                }

+            }

+        }

+

+        if (i == expression.length())

+        {

+            if (evaluateExprStack(values, operators, output))

+            {

+                return true;

+            }

+        }

+

+        return false;

+    }

+

+  private:

+    /* To store all 'knob's in 'biosknobs' */

+    std::vector<knob::knob>& mKnobs;

+

+    /* To store all bad 'depex' expression */

+    std::vector<std::string> mError;

+};

+

+class Xml

+{

+  public:

+    Xml(const char* filePath) : mDepex(std::make_unique<Depex>(mKnobs))

+    {

+        if (!getKnobs(filePath))

+        {

+            std::string error =

+                "Unable to get knobs in file: " + std::string(filePath);

+            throw std::runtime_error(error);

+        }

+    }

+

+    /* Fill Bios table with all 'knob's which have output of 'depex' expression

+     * as 'true' */

+    bool getBaseTable(bios::BiosBaseTableType& baseTable)

+    {

+        baseTable.clear();

+

+        for (auto& knob : mKnobs)

+        {

+            if (knob.depex)

+            {

+                std::string text =

+                    "xyz.openbmc_project.BIOSConfig.Manager.BoundType.OneOf";

+                bios::OptionTypeVector options;

+

+                for (auto& option : knob.options)

+                {

+                    options.emplace_back(text, option.value);

+                }

+

+                bios::BiosBaseTableTypeEntry baseTableEntry = std::make_tuple(

+                    "xyz.openbmc_project.BIOSConfig.Manager.AttributeType."

+                    "String",

+                    false, knob.nameStr, knob.descriptionStr, "./",

+                    knob.currentValStr, knob.defaultStr, options);

+

+                baseTable.emplace(knob.nameStr, baseTableEntry);

+            }

+        }

+

+        if (!baseTable.empty())

+        {

+            return true;

+        }

+

+        return false;

+    }

+

+    /* Execute all 'depex' expression */

+    bool doDepexCompute()

+    {

+        mDepex->compute();

+

+        if (mDepex->getErrorCount())

+        {

+            mDepex->printError();

+            return false;

+        }

+

+        return true;

+    }

+

+  private:

+    /* Get 'option' */

+    void getOption(tinyxml2::XMLElement* pOption)

+    {

+        if (pOption)

+        {

+            std::string valueStr;

+            std::string textStr;

+

+            if (pOption->Attribute("text"))

+                valueStr = pOption->Attribute("text");

+

+            if (pOption->Attribute("value"))

+                textStr = pOption->Attribute("value");

+

+            mKnobs.back().options.emplace_back(pOption->Attribute("text"),

+                                               pOption->Attribute("value"));

+        }

+    }

+

+    /* Get 'options' */

+    void getOptions(tinyxml2::XMLElement* pKnob)

+    {

+        uint16_t reserveCnt = 0;

+

+        /* Get node options inside knob */

+        tinyxml2::XMLElement* pOptions = pKnob->FirstChildElement("options");

+

+        if (pOptions)

+        {

+            for (tinyxml2::XMLElement* pOption =

+                     pOptions->FirstChildElement("option");

+                 pOption; pOption = pOption->NextSiblingElement("option"))

+            {

+                ++reserveCnt;

+            }

+

+            mKnobs.back().options.reserve(reserveCnt);

+

+            /* Loop through all option inside options */

+            for (tinyxml2::XMLElement* pOption =

+                     pOptions->FirstChildElement("option");

+                 pOption; pOption = pOption->NextSiblingElement("option"))

+            {

+                getOption(pOption);

+            }

+        }

+    }

+

+    /* Get 'knob' */

+    void getKnob(tinyxml2::XMLElement* pKnob)

+    {

+        if (pKnob)

+        {

+            int currentVal = 0;

+            std::string nameStr;

+            std::string currentValStr;

+            std::string descriptionStr;

+            std::string defaultStr;

+            std::string depexStr;

+            std::string promptStr;

+            std::string setupTypeStr;

+

+            if (!pKnob->Attribute("name") || !pKnob->Attribute("CurrentVal"))

+            {

+                return;

+            }

+

+            nameStr = pKnob->Attribute("name");

+            currentValStr = pKnob->Attribute("CurrentVal");

+

+            try

+            {

+                currentVal = std::stoi(currentValStr);

+            }

+            catch (std::exception& ex)

+            {

+                phosphor::logging::log<phosphor::logging::level::ERR>(

+                    ex.what());

+                return;

+            }

+

+            if (pKnob->Attribute("description"))

+                descriptionStr = pKnob->Attribute("description");

+

+            if (pKnob->Attribute("default"))

+                defaultStr = pKnob->Attribute("default");

+

+            if (pKnob->Attribute("depex"))

+                depexStr = pKnob->Attribute("depex");

+

+            if (pKnob->Attribute("prompt"))

+                promptStr = pKnob->Attribute("prompt");

+

+            if (pKnob->Attribute("setupType"))

+                setupTypeStr = pKnob->Attribute("setupType");

+

+            mKnobs.emplace_back(nameStr, currentValStr, currentVal,

+                                descriptionStr, defaultStr, promptStr, depexStr,

+                                setupTypeStr);

+

+            getOptions(pKnob);

+        }

+    }

+

+    /* Get 'biosknobs' */

+    bool getKnobs(const char* biosXmlFilePath)

+    {

+        uint16_t reserveCnt = 0;

+

+        mKnobs.clear();

+

+        tinyxml2::XMLDocument biosXml;

+

+        /* Load the XML file into the Doc instance */

+        biosXml.LoadFile(biosXmlFilePath);

+

+        /* Get 'SYSTEM' */

+        tinyxml2::XMLElement* pRootElement = biosXml.RootElement();

+        if (pRootElement)

+        {

+            /* Get 'biosknobs' inside 'SYSTEM' */

+            tinyxml2::XMLElement* pBiosknobs =

+                pRootElement->FirstChildElement("biosknobs");

+            if (pBiosknobs)

+            {

+                for (tinyxml2::XMLElement* pKnob =

+                         pBiosknobs->FirstChildElement("knob");

+                     pKnob; pKnob = pKnob->NextSiblingElement("knob"))

+                {

+                    ++reserveCnt;

+                }

+

+                /* reserve before emplace_back will avoids realloc(s) */

+                mKnobs.reserve(reserveCnt);

+

+                for (tinyxml2::XMLElement* pKnob =

+                         pBiosknobs->FirstChildElement("knob");

+                     pKnob; pKnob = pKnob->NextSiblingElement("knob"))

+                {

+                    getKnob(pKnob);

+                }

+            }

+        }

+

+        if (!mKnobs.empty())

+        {

+            return true;

+        }

+

+        return false;

+    }

+

+  private:

+    /* To store all 'knob's in 'biosknobs' */

+    std::vector<knob::knob> mKnobs;

+

+    /* Object of Depex class to compute 'depex' expression */

+    std::unique_ptr<Depex> mDepex;

+};

+} // namespace bios

diff --git a/src/biosconfigcommands.cpp b/src/biosconfigcommands.cpp
index 6734745..6d48f8f 100644
--- a/src/biosconfigcommands.cpp
+++ b/src/biosconfigcommands.cpp
@@ -14,8 +14,9 @@
 // limitations under the License.
 */
 
+#include "biosxml.hpp"
+
 #include <openssl/sha.h>
-#include <tinyxml2.h>
 
 #include <biosconfigcommands.hpp>
 #include <boost/crc.hpp>
@@ -28,8 +29,6 @@
 #include <ipmid/utils.hpp>
 #include <nlohmann/json.hpp>
 #include <oemcommands.hpp>
-#include <phosphor-logging/elog-errors.hpp>
-#include <phosphor-logging/log.hpp>
 #include <sdbusplus/bus.hpp>
 #include <sdbusplus/message/types.hpp>
 
@@ -72,16 +71,8 @@
               description,menuPath,current,default,
               array{struct{optionstring,optionvalue}}}}
 */
-using BiosBaseTableType =
-    std::map<std::string,
-             std::tuple<std::string, bool, std::string, std::string,
-                        std::string, std::variant<int64_t, std::string>,
-                        std::variant<int64_t, std::string>,
-                        std::vector<std::tuple<
-                            std::string, std::variant<int64_t, std::string>>>>>;
-using OptionType =
-    std::vector<std::tuple<std::string, std::variant<int64_t, std::string>>>;
-BiosBaseTableType attributesData;
+
+bios::BiosBaseTableType attributesData;
 
 NVOOBdata gNVOOBdata;
 
@@ -118,24 +109,44 @@
 /** @brief implement to set the BaseBIOSTable property
  *  @returns status
  */
-static int sendAllAttributes(ipmi::Context::ptr ctx)
+static bool sendAllAttributes(std::string service)
 {
-    boost::system::error_code ec;
-    std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
-    std::string service =
-        getService(*dbus, biosConfigIntf, biosConfigBaseMgrPath);
-    ec.clear();
-    ctx->bus->yield_method_call<>(
-        ctx->yield, ec, service, biosConfigBaseMgrPath,
-        "org.freedesktop.DBus.Properties", "Set", biosConfigIntf,
-        "BaseBIOSTable", std::variant<BiosBaseTableType>(attributesData));
-    if (ec)
+    std::shared_ptr<sdbusplus::asio::connection> pSdBusPlus = getSdBus();
+
+    if (pSdBusPlus)
     {
-        phosphor::logging::log<phosphor::logging::level::ERR>(
-            "Failed to sendAllAttributes");
-        return -1;
+        try
+        {
+            pSdBusPlus->async_method_call(
+                [](const boost::system::error_code ec) {
+                    /* No more need to keep attributes data in memory */
+                    attributesData.clear();
+
+                    if (ec)
+                    {
+                        phosphor::logging::log<phosphor::logging::level::ERR>(
+                            "sendAllAttributes error: send all attributes - "
+                            "failed");
+                        return;
+                    }
+
+                    phosphor::logging::log<phosphor::logging::level::INFO>(
+                        "sendAllAttributes: send all attributes - done");
+                },
+                service, biosConfigBaseMgrPath,
+                "org.freedesktop.DBus.Properties", "Set", biosConfigIntf,
+                "BaseBIOSTable",
+                std::variant<bios::BiosBaseTableType>(attributesData));
+
+            return true;
+        }
+        catch (std::exception& ex)
+        {
+            phosphor::logging::log<phosphor::logging::level::ERR>(ex.what());
+        }
     }
-    return 0;
+
+    return false;
 }
 
 /** @brief implement to flush the updated data in nv space
@@ -221,95 +232,66 @@
     }
 }
 
-/** @brief implement generate naive- dbus from XML file
- *  @returns status
+/** @brief Get attributes data (bios base table) from bios.xml
  */
-static int generateAttributesData()
+static bool generateAttributesData()
 {
-    // Open the bios.xml and parse it
-    // Extract the needed data and store it in AttributesData variable
-    // Close the bios.xml
-    phosphor::logging::log<phosphor::logging::level::ERR>(
-        "generateAttributesData");
-    tinyxml2::XMLDocument xmlDoc;
+    try
+    {
+        bios::Xml biosxml(biosXMLFilePath);
 
-    xmlDoc.LoadFile(biosXMLFilePath);
-    tinyxml2::XMLNode* pRoot = xmlDoc.FirstChild();
-    if (pRoot == nullptr)
-    {
-        return ipmi::ccUnspecifiedError;
-    }
-    tinyxml2::XMLElement* pElement = pRoot->FirstChildElement("biosknobs");
-    if (pElement == nullptr)
-    {
-        return ipmi::ccUnspecifiedError;
-    }
-    tinyxml2::XMLElement* pKnobsElement = pElement->FirstChildElement("knob");
-
-    while (pKnobsElement != nullptr)
-    {
-        bool readOnlyStatus = false;
-        std::string attrType =
-            "xyz.openbmc_project.BIOSConfig.Manager.AttributeType.String";
-        std::string name, curvalue, dname, menupath, defaultvalue, description;
-        name = pKnobsElement->Attribute("name")
-                   ? pKnobsElement->Attribute("name")
-                   : "";
-        curvalue = pKnobsElement->Attribute("CurrentVal")
-                       ? pKnobsElement->Attribute("CurrentVal")
-                       : "";
-        dname = pKnobsElement->Attribute("prompt")
-                    ? pKnobsElement->Attribute("prompt")
-                    : "";
-        menupath = pKnobsElement->Attribute("SetupPgPtr")
-                       ? pKnobsElement->Attribute("SetupPgPtr")
-                       : "";
-        defaultvalue = pKnobsElement->Attribute("default")
-                           ? pKnobsElement->Attribute("default")
-                           : "";
-        description = pKnobsElement->Attribute("description")
-                          ? pKnobsElement->Attribute("description")
-                          : "";
-        if (!name.empty() && !curvalue.empty() && !dname.empty() &&
-            !menupath.empty() && !defaultvalue.empty())
+        if (!biosxml.doDepexCompute())
         {
-            std::string rootPath = "./" + std::string(menupath);
-
-            OptionType optionArray;
-            tinyxml2::XMLElement* pOptionsElement =
-                pKnobsElement->FirstChildElement("options");
-            nlohmann::json optionsArray = nlohmann::json::array();
-            if (pOptionsElement != nullptr)
-            {
-                tinyxml2::XMLElement* pOptionElement =
-                    pOptionsElement->FirstChildElement("option");
-                while (pOptionElement != nullptr)
-                {
-                    const std::string optType =
-                        "xyz.openbmc_project.BIOSConfig.Manager.BoundType."
-                        "OneOf";
-                    const std::string attrValue =
-                        pOptionElement->Attribute("value");
-                    if (!optType.empty() && !attrValue.empty())
-                    {
-
-                        optionArray.push_back(
-                            std::make_pair(optType, attrValue));
-                    }
-                    pOptionElement =
-                        pOptionElement->NextSiblingElement("option");
-                }
-            }
-
-            attributesData.emplace(std::make_pair(
-                name, std::make_tuple(attrType, readOnlyStatus, dname,
-                                      description, rootPath, curvalue,
-                                      defaultvalue, optionArray)));
+            phosphor::logging::log<phosphor::logging::level::ERR>(
+                "'depex' compute failed");
         }
-        pKnobsElement = pKnobsElement->NextSiblingElement("knob");
+
+        if (!biosxml.getBaseTable(attributesData))
+        {
+            phosphor::logging::log<phosphor::logging::level::ERR>(
+                "Failed to get bios base table");
+        }
+    }
+    catch (std::exception& ex)
+    {
+        phosphor::logging::log<phosphor::logging::level::ERR>(ex.what());
+        return false;
     }
 
-    return ipmi::ccSuccess;
+    return true;
+}
+
+/** @brief Generate attributes data from bios.xml
+ * and send attributes data (bios base table) to dbus using set method.
+ */
+static void generateAndSendAttributesData(std::string service,
+                                          uint8_t payloadType)
+{
+    if (!generateAttributesData())
+    {
+        phosphor::logging::log<phosphor::logging::level::ERR>(
+            "generateAndSendAttributesData: generateAttributesData - failed");
+        gNVOOBdata.payloadInfo[payloadType].payloadStatus =
+            static_cast<uint8_t>(ipmi::PStatus::Corrupted);
+        return;
+    }
+
+    phosphor::logging::log<phosphor::logging::level::INFO>(
+        "generateAndSendAttributesData : generateAttributesData is done");
+
+    if (!sendAllAttributes(service))
+    {
+        phosphor::logging::log<phosphor::logging::level::ERR>(
+            "generateAndSendAttributesData: sendAllAttributes - failed");
+        gNVOOBdata.payloadInfo[payloadType].payloadStatus =
+            static_cast<uint8_t>(ipmi::PStatus::Corrupted);
+        return;
+    }
+
+    phosphor::logging::log<phosphor::logging::level::INFO>(
+        "generateAndSendAttributesData : sendAllAttributes is done");
+    gNVOOBdata.payloadInfo[payloadType].payloadStatus =
+        static_cast<uint8_t>(ipmi::PStatus::Valid);
 }
 
 /** @brief implement executing the linux command to uncompress and generate the
@@ -599,30 +581,26 @@
                 }
                 phosphor::logging::log<phosphor::logging::level::INFO>(
                     " ipmiOEMSetPayload : Convert XML into native-dbus DONE");
-                response = generateAttributesData();
-                if (response)
-                {
-                    phosphor::logging::log<phosphor::logging::level::ERR>(
-                        "ipmiOEMSetPayload: generateAttributesData - failed");
-                    gNVOOBdata.payloadInfo[payloadType].payloadStatus =
-                        static_cast<uint8_t>(ipmi::PStatus::Corrupted);
-                    return ipmi::responseResponseError();
-                }
 
-                phosphor::logging::log<phosphor::logging::level::INFO>(
-                    " ipmiOEMSetPayload : BaseBIOSTable Property  is set");
-                response = sendAllAttributes(ctx);
-                if (response)
+                /* So that we don't block the call */
+                auto io = getIoContext();
+                auto dbus = getSdBus();
+                if (io && dbus)
                 {
-                    phosphor::logging::log<phosphor::logging::level::ERR>(
-                        "ipmiOEMSetPayload: sendAllAttributes - failed");
-                    gNVOOBdata.payloadInfo[payloadType].payloadStatus =
-                        static_cast<uint8_t>(ipmi::PStatus::Corrupted);
+                    std::string service = getService(*dbus, biosConfigIntf,
+                                                     biosConfigBaseMgrPath);
+
+                    boost::asio::post(*io, [service, payloadType] {
+                        generateAndSendAttributesData(service, payloadType);
+                    });
+                }
+                else
+                {
+                    phosphor::logging::log<phosphor::logging::level::INFO>(
+                        "ipmiOEMSetPayload: Unable to get io context or sdbus");
                     return ipmi::responseResponseError();
                 }
             }
-            gNVOOBdata.payloadInfo[payloadType].payloadStatus =
-                static_cast<uint8_t>(ipmi::PStatus::Valid);
 
             struct stat filestat;