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/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;