Fix support for Get Payload.

Get Payload is split into two as follows:
1) Get Payload Info (ipmitool raw 0x30 0xd6 0 1):
Return info of Payload1 (pending list) data

2) Get Payload data (ipmitool raw 0x30 0xd6 1 1):
Return Payload1 (pending list) data.

Note: Pending list is the BIOS knobs edited by patch to
https://<IP>/redfish/v1/Systems/system/Bios/Settings,
which is stored in BMC.

Tested:
Step 1)
Patch to https://<IP>/redfish/v1/Systems/system/Bios/Settings
with the following data:
{
  "data":{
    "Ce2LmLoggingEn": "0x0",
    "CoreCrashLogDisable": "0x1",
    "CpuCrashLogClear": "0x0",
    "DfxEadrDebugLogs": "0x1",
    "DfxFadrDebugLogs": "0x1",
    "WheaLogMemoryEn": "0x1"
    }
}

Step 2)
Give command ipmitool raw 0x30 0xd6 0 1

Response:
 00 00 01 7e 00 00 00 08 4c d3 e9 00 01 a8 9e 00
 00

Step 3)
Give command ipmitool raw 0x30 0xd6 1 1 0x09 0 0 0 0x7e 0 0 0

Response:
 01 75 00 00 00 89 51 07 a0 69 6e 67 45 6e 3d 30
 78 30 0a 43 6f 72 65 43 72 61 73 68 4c 6f 67 44
 69 73 61 62 6c 65 3d 30 78 31 0a 43 70 75 43 72
 61 73 68 4c 6f 67 43 6c 65 61 72 3d 30 78 30 0a
 44 66 78 45 61 64 72 44 65 62 75 67 4c 6f 67 73
 3d 30 78 31 0a 44 66 78 46 61 64 72 44 65 62 75
 67 4c 6f 67 73 3d 30 78 31 0a 57 68 65 61 4c 6f
 67 4d 65 6d 6f 72 79 45 6e 3d 30 78 31 0a

Signed-off-by: Arun Lal K M <arun.lal@intel.com>
Change-Id: I6a3bec66f78c2c9b6296e3dbba7743971b372f75
diff --git a/include/biosxml.hpp b/include/biosxml.hpp
index c5be53c..4e41e61 100644
--- a/include/biosxml.hpp
+++ b/include/biosxml.hpp
@@ -12,42 +12,6 @@
 #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'

diff --git a/src/biosconfigcommands.cpp b/src/biosconfigcommands.cpp
index 6d48f8f..31c1425 100644
--- a/src/biosconfigcommands.cpp
+++ b/src/biosconfigcommands.cpp
@@ -37,6 +37,7 @@
 
 namespace ipmi
 {
+static bool flushNVOOBdata();
 static void registerBIOSConfigFunctions() __attribute__((constructor));
 
 // Define BIOS config related Completion Code
@@ -106,6 +107,282 @@
     GetPayloadStatus = 2
 };
 
+namespace payload1
+{
+
+enum class AttributesType : uint8_t
+{
+    unknown = 0,
+    string,
+    integer
+};
+
+using PendingAttributesType =
+    std::map<std::string,
+             std::tuple<std::string, std::variant<int64_t, std::string>>>;
+
+AttributesType getAttrType(const std::string_view typeDbus)
+{
+    if (typeDbus == "xyz.openbmc_project.BIOSConfig.Manager."
+                    "AttributeType.String")
+    {
+        return AttributesType::string;
+    }
+    else if (typeDbus == "xyz.openbmc_project.BIOSConfig."
+                         "Manager.AttributeType.Integer")
+    {
+        return AttributesType::integer;
+    }
+
+    return AttributesType::unknown;
+}
+
+bool fillPayloadData(std::string& payloadData,
+                     const std::variant<int64_t, std::string>& attributes,
+                     const std::string_view key, AttributesType& attrType)
+{
+    payloadData += key;
+    payloadData += '=';
+
+    if (attrType == AttributesType::string)
+    {
+        if (!std::holds_alternative<std::string>(attributes))
+        {
+            phosphor::logging::log<phosphor::logging::level::ERR>(
+                "fillPayloadData: No string data in attributes");
+            return false;
+        }
+        payloadData += std::get<std::string>(attributes);
+    }
+    else if (attrType == AttributesType::integer)
+    {
+        if (!std::holds_alternative<int64_t>(attributes))
+        {
+            phosphor::logging::log<phosphor::logging::level::ERR>(
+                "fillPayloadData: No int64_t data in attributes");
+            return false;
+        }
+        payloadData += std::to_string(std::get<int64_t>(attributes));
+    }
+    else
+    {
+        phosphor::logging::log<phosphor::logging::level::ERR>(
+            "fillPayloadData: Unsupported attribute type");
+        return false;
+    }
+
+    payloadData += '\n';
+
+    return true;
+}
+
+bool getPendingList(ipmi::Context::ptr ctx, std::string& payloadData)
+{
+    std::variant<PendingAttributesType> pendingAttributesData;
+    boost::system::error_code ec;
+
+    payloadData.clear();
+
+    auto dbus = getSdBus();
+    if (!dbus)
+    {
+        phosphor::logging::log<phosphor::logging::level::ERR>(
+            "getPendingList: getSdBus() failed");
+        return false;
+    }
+
+    std::string service =
+        getService(*dbus, biosConfigIntf, biosConfigBaseMgrPath);
+
+    try
+    {
+        pendingAttributesData =
+            dbus->yield_method_call<std::variant<PendingAttributesType>>(
+                ctx->yield, ec, service,
+                "/xyz/openbmc_project/bios_config/manager",
+                "org.freedesktop.DBus.Properties", "Get",
+                "xyz.openbmc_project.BIOSConfig.Manager", "PendingAttributes");
+    }
+    catch (std::exception& ex)
+    {
+        phosphor::logging::log<phosphor::logging::level::ERR>(ex.what());
+        return false;
+    }
+
+    if (ec)
+    {
+        std::string err = "getPendingList: error while trying to get "
+                          "PendingAttributes, error = ";
+        err += ec.message();
+
+        phosphor::logging::log<phosphor::logging::level::ERR>(err.c_str());
+
+        return false;
+    }
+
+    const PendingAttributesType* pendingAttributes =
+        std::get_if<PendingAttributesType>(&pendingAttributesData);
+    if (!pendingAttributes)
+    {
+        phosphor::logging::log<phosphor::logging::level::ERR>(
+            "getPendingList: pendingAttributes is null");
+        return false;
+    }
+
+    for (const auto& [key, attributes] : *pendingAttributes)
+    {
+        const std::string& itemType = std::get<0>(attributes);
+        AttributesType attrType = getAttrType(itemType);
+
+        if (!fillPayloadData(payloadData, std::get<1>(attributes), key,
+                             attrType))
+        {
+            return false;
+        }
+    }
+
+    if (payloadData.empty())
+    {
+        phosphor::logging::log<phosphor::logging::level::ERR>(
+            "getPendingList: payloadData is empty");
+        return false;
+    }
+
+    return true;
+}
+bool updatePayloadFile(std::string& payloadFilePath, std::string payloadData)
+{
+    std::ofstream payloadFile(payloadFilePath,
+                              std::ios::out | std::ios::binary);
+
+    payloadFile << payloadData;
+
+    if (!payloadFile.good())
+    {
+        return false;
+    }
+
+    return true;
+}
+
+bool computeCheckSum(std::string& payloadFilePath,
+                     boost::crc_32_type& calcChecksum)
+{
+    std::ifstream payloadFile(payloadFilePath.c_str(),
+                              std::ios::in | std::ios::binary | std::ios::ate);
+
+    if (!payloadFile.good())
+    {
+        phosphor::logging::log<phosphor::logging::level::ERR>(
+            "computeCheckSum: Cannot open Payload1 file");
+        return false;
+    }
+
+    payloadFile.seekg(0, payloadFile.end);
+    int length = payloadFile.tellg();
+    payloadFile.seekg(0, payloadFile.beg);
+
+    if (maxGetPayloadDataSize < length)
+    {
+        phosphor::logging::log<phosphor::logging::level::ERR>(
+            "computeCheckSum: length > maxGetPayloadDataSize");
+        return false;
+    }
+
+    std::unique_ptr<char[]> payloadBuffer(new char[length]);
+
+    payloadFile.read(payloadBuffer.get(), length);
+    uint32_t readCount = payloadFile.gcount();
+
+    calcChecksum.process_bytes(payloadBuffer.get(), readCount);
+
+    return true;
+}
+
+bool updatePayloadInfo(std::string& payloadFilePath)
+{
+    boost::crc_32_type calcChecksum;
+
+    uint8_t payloadType = static_cast<uint8_t>(ipmi::PType::IntelXMLType1);
+    auto& payloadInfo = gNVOOBdata.payloadInfo[payloadType];
+
+    if (!computeCheckSum(payloadFilePath, calcChecksum))
+    {
+        phosphor::logging::log<phosphor::logging::level::ERR>(
+            "updatePayloadInfo: Cannot compute checksum for Payload1 file");
+        return false;
+    }
+
+    payloadInfo.payloadVersion = 0;
+    payloadInfo.payloadflag = 0;
+    payloadInfo.payloadReservationID = rand();
+
+    payloadInfo.payloadType = payloadType;
+
+    payloadInfo.payloadTotalChecksum = calcChecksum.checksum();
+    payloadInfo.payloadCurrentChecksum = payloadInfo.payloadTotalChecksum;
+
+    payloadInfo.payloadStatus = (static_cast<uint8_t>(ipmi::PStatus::Valid));
+
+    struct stat filestat;
+    /* Get entry's information. */
+    if (!stat(payloadFilePath.c_str(), &filestat))
+    {
+        payloadInfo.payloadTimeStamp = filestat.st_mtime;
+        payloadInfo.payloadTotalSize = filestat.st_size;
+        payloadInfo.payloadCurrentSize = filestat.st_size;
+        payloadInfo.actualTotalPayloadWritten = filestat.st_size;
+    }
+    else
+    {
+        phosphor::logging::log<phosphor::logging::level::ERR>(
+            "updatePayloadInfo: Cannot get file status for Payload1 file");
+        return false;
+    }
+
+    if (!flushNVOOBdata())
+    {
+        phosphor::logging::log<phosphor::logging::level::ERR>(
+            "updatePayloadInfo: flushNVOOBdata failed");
+        return false;
+    }
+
+    return true;
+}
+
+bool update(ipmi::Context::ptr ctx)
+{
+    std::string payloadFilePath =
+        "/var/oob/Payload" +
+        std::to_string(static_cast<uint8_t>(ipmi::PType::IntelXMLType1));
+
+    std::string payloadData;
+
+    if (!getPendingList(ctx, payloadData))
+    {
+        phosphor::logging::log<phosphor::logging::level::ERR>(
+            "payload1::update : getPendingList() failed");
+        return false;
+    }
+
+    if (!updatePayloadFile(payloadFilePath, payloadData))
+    {
+        phosphor::logging::log<phosphor::logging::level::ERR>(
+            "payload1::update : updatePayloadFile() failed");
+        return false;
+    }
+
+    if (!updatePayloadInfo(payloadFilePath))
+    {
+        phosphor::logging::log<phosphor::logging::level::ERR>(
+            "payload1::update : updatePayloadInfo() failed");
+        return false;
+    }
+
+    return true;
+}
+} // namespace payload1
+
 /** @brief implement to set the BaseBIOSTable property
  *  @returns status
  */
@@ -152,17 +429,20 @@
 /** @brief implement to flush the updated data in nv space
  *  @returns status
  */
-static uint8_t flushNVOOBdata()
+static bool flushNVOOBdata()
 {
     std::ofstream outFile(biosConfigNVPath, std::ios::binary);
-    if (outFile.good())
+
+    outFile.seekp(std::ios_base::beg);
+    const char* writedata = reinterpret_cast<const char*>(&gNVOOBdata);
+    outFile.write(writedata, sizeof(struct NVOOBdata));
+
+    if (!outFile.good())
     {
-        outFile.seekp(std::ios_base::beg);
-        const char* writedata = reinterpret_cast<const char*>(&gNVOOBdata);
-        outFile.write(writedata, sizeof(struct NVOOBdata));
-        outFile.close();
+        return false;
     }
-    return 0;
+
+    return true;
 }
 
 /** @brief implement to get the System State
@@ -399,7 +679,6 @@
     }
     else
     {
-
         return ipmi::response(ipmiCCNotSupportedInCurrentState);
     }
 }
@@ -495,6 +774,8 @@
             if (pPayloadInProgress->payloadReservationID !=
                 payloadInfo.payloadReservationID)
             {
+                phosphor::logging::log<phosphor::logging::level::ERR>(
+                    "BIOS Config Payload reservation ID is not correct");
                 return ipmi::responseInvalidReservationId();
             }
             payloadInfo.payloadCurrentSize =
@@ -550,7 +831,6 @@
             if (gNVOOBdata.payloadInfo[payloadType].actualTotalPayloadWritten !=
                 gNVOOBdata.payloadInfo[payloadType].payloadTotalSize)
             {
-
                 return ipmi::response(ipmiCCPayloadPayloadInComplete);
             }
             std::string tempFilePath =
@@ -665,13 +945,23 @@
         return ipmi::responseInvalidFieldRequest();
     }
 
+    if (payloadType == static_cast<uint8_t>(ipmi::PType::IntelXMLType1))
+    {
+        if (!payload1::update(ctx))
+        {
+            phosphor::logging::log<phosphor::logging::level::ERR>(
+                "ipmiOEMGetPayload: unable to update NVOOBdata for payloadType "
+                "= IntelXMLType1");
+            return ipmi::response(ipmi::ccUnspecifiedError);
+        }
+    }
+
     struct PayloadInfo res = gNVOOBdata.payloadInfo[payloadType];
 
     switch (static_cast<GetPayloadParameter>(paramSel))
     {
         case ipmi::GetPayloadParameter::GetPayloadInfo:
         {
-
             std::string payloadFilePath =
                 "/var/oob/Payload" + std::to_string(payloadType);
 
@@ -680,12 +970,12 @@
 
             if (!ifs.good())
             {
-
                 phosphor::logging::log<phosphor::logging::level::ERR>(
                     "ipmiOEMGetPayload: Payload File Error");
                 // File does not exist code here
                 return ipmi::response(ipmi::ccUnspecifiedError);
             }
+
             ifs.close();
             retValue.pack(res.payloadVersion);
             retValue.pack(payloadType);
@@ -720,7 +1010,6 @@
 
                 if (!ifs.good())
                 {
-
                     phosphor::logging::log<phosphor::logging::level::ERR>(
                         "ipmiOEMGetPayload: Payload File Error");
                     // File does not exist code here
@@ -752,6 +1041,7 @@
                 {
                     retValue.pack(Buffer.at(i));
                 }
+
                 return ipmi::responseSuccess(std::move(retValue));
             }
             else