oem-ibm: Sync boot side file with bios attributes

This change adds support to update the boot side file to keep it
in sync with boot side bios attributes

Change-Id: I2bea293500c69a883f400ddaadc436705bbe5ab4
Signed-off-by: Archana Kakani <archana.kakani@ibm.com>
diff --git a/common/types.hpp b/common/types.hpp
index 2c1b319..b61184f 100644
--- a/common/types.hpp
+++ b/common/types.hpp
@@ -4,6 +4,7 @@
 
 #include <bitset>
 #include <cstdint>
+#include <functional>
 #include <map>
 #include <memory>
 #include <set>
@@ -234,4 +235,30 @@
 
 } // namespace pdr
 
+namespace bios
+{
+
+using AttributeName = std::string;
+using AttributeType = std::string;
+using ReadonlyStatus = bool;
+using DisplayName = std::string;
+using Description = std::string;
+using MenuPath = std::string;
+using CurrentValue = std::variant<int64_t, std::string>;
+using DefaultValue = std::variant<int64_t, std::string>;
+using OptionString = std::string;
+using OptionValue = std::variant<int64_t, std::string>;
+using ValueDisplayName = std::string;
+using Option =
+    std::vector<std::tuple<OptionString, OptionValue, ValueDisplayName>>;
+using BIOSTableObj =
+    std::tuple<AttributeType, ReadonlyStatus, DisplayName, Description,
+               MenuPath, CurrentValue, DefaultValue, Option>;
+using BaseBIOSTable = std::map<AttributeName, BIOSTableObj>;
+using PendingObj = std::tuple<AttributeType, CurrentValue>;
+using PendingAttributes = std::map<AttributeName, PendingObj>;
+using Callback = std::function<void()>;
+
+} // namespace bios
+
 } // namespace pldm
diff --git a/libpldmresponder/bios.hpp b/libpldmresponder/bios.hpp
index eab143e..d6d7bbb 100644
--- a/libpldmresponder/bios.hpp
+++ b/libpldmresponder/bios.hpp
@@ -92,6 +92,17 @@
     Response setBIOSAttributeCurrentValue(const pldm_msg* request,
                                           size_t payloadLength);
 
+    pldm::responder::oem_bios::Handler* oemBiosHandler = nullptr;
+
+    /** @brief Set OEM bios handler
+     *
+     *  @param[in] oemBiosHandler - OEM Bios handler
+     */
+    inline void setOemBiosHandler(pldm::responder::oem_bios::Handler* handler)
+    {
+        biosConfig.setOemBiosHandler(handler);
+    }
+
   private:
     BIOSConfig biosConfig;
 };
diff --git a/libpldmresponder/bios_config.cpp b/libpldmresponder/bios_config.cpp
index cabb0bd..6b1b918 100644
--- a/libpldmresponder/bios_config.cpp
+++ b/libpldmresponder/bios_config.cpp
@@ -522,6 +522,10 @@
         auto method = bus.new_method_call(service.c_str(), biosConfigPath,
                                           dbusProperties, "Set");
         std::variant<BaseBIOSTable> value = baseBIOSTableMaps;
+        if (oemBiosHandler)
+        {
+            oemBiosHandler->processOEMBaseBiosTable(baseBIOSTableMaps);
+        }
         method.append(biosConfigInterface, biosConfigPropertyName, value);
         bus.call_noreply(method, dbusTimeout);
     }
diff --git a/libpldmresponder/bios_config.hpp b/libpldmresponder/bios_config.hpp
index 05f960d..db8b303 100644
--- a/libpldmresponder/bios_config.hpp
+++ b/libpldmresponder/bios_config.hpp
@@ -3,6 +3,7 @@
 #include "bios_attribute.hpp"
 #include "bios_table.hpp"
 #include "common/instance_id.hpp"
+#include "common/types.hpp"
 #include "oem_handler.hpp"
 #include "platform_config.hpp"
 #include "requester/handler.hpp"
@@ -12,7 +13,6 @@
 #include <nlohmann/json.hpp>
 #include <phosphor-logging/lg2.hpp>
 
-#include <functional>
 #include <iostream>
 #include <memory>
 #include <optional>
@@ -38,27 +38,7 @@
     OneOf
 };
 
-using AttributeName = std::string;
-using AttributeType = std::string;
-using ReadonlyStatus = bool;
-using DisplayName = std::string;
-using Description = std::string;
-using MenuPath = std::string;
-using CurrentValue = std::variant<int64_t, std::string>;
-using DefaultValue = std::variant<int64_t, std::string>;
-using OptionString = std::string;
-using OptionValue = std::variant<int64_t, std::string>;
-using ValueDisplayName = std::string;
-using Option =
-    std::vector<std::tuple<OptionString, OptionValue, ValueDisplayName>>;
-using BIOSTableObj =
-    std::tuple<AttributeType, ReadonlyStatus, DisplayName, Description,
-               MenuPath, CurrentValue, DefaultValue, Option>;
-using BaseBIOSTable = std::map<AttributeName, BIOSTableObj>;
-
-using PendingObj = std::tuple<AttributeType, CurrentValue>;
-using PendingAttributes = std::map<AttributeName, PendingObj>;
-using Callback = std::function<void()>;
+using namespace pldm::bios;
 
 /** @class BIOSConfig
  *  @brief Manager BIOS Attributes
@@ -140,6 +120,15 @@
      */
     void initBIOSAttributes(const std::string& sysType, bool registerService);
 
+    /** @brief Set OEM bios handler
+     *
+     *  @param[in] oemBiosHandler - OEM Bios handler
+     */
+    inline void setOemBiosHandler(pldm::responder::oem_bios::Handler* handler)
+    {
+        oemBiosHandler = handler;
+    }
+
   private:
     /** @enum Index into the fields in the BaseBIOSTable
      */
@@ -159,6 +148,7 @@
     const fs::path tableDir;
     pldm::utils::DBusHandler* const dbusHandler;
     BaseBIOSTable baseBIOSTableMaps;
+    pldm::responder::oem_bios::Handler* oemBiosHandler = nullptr;
 
     /** @brief MCTP EID of host firmware */
     uint8_t eid;
diff --git a/libpldmresponder/oem_handler.hpp b/libpldmresponder/oem_handler.hpp
index d8ca132..9e131ee 100644
--- a/libpldmresponder/oem_handler.hpp
+++ b/libpldmresponder/oem_handler.hpp
@@ -185,6 +185,26 @@
 
 } // namespace oem_utils
 
+namespace oem_bios
+{
+using namespace pldm::utils;
+
+class Handler : public CmdHandler
+{
+  public:
+    Handler() {}
+
+    /** @brief Process BaseBiosTable and update the locally cached attributes
+     *  @param[in] biosTable - Bios table
+     */
+    virtual void processOEMBaseBiosTable(
+        const pldm::bios::BaseBIOSTable& biosTable) = 0;
+
+    virtual ~Handler() = default;
+};
+
+} // namespace oem_bios
+
 } // namespace responder
 
 } // namespace pldm
diff --git a/oem/ibm/libpldmresponder/inband_code_update.cpp b/oem/ibm/libpldmresponder/inband_code_update.cpp
index 855258d..d031855 100644
--- a/oem/ibm/libpldmresponder/inband_code_update.cpp
+++ b/oem/ibm/libpldmresponder/inband_code_update.cpp
@@ -24,6 +24,7 @@
 namespace responder
 {
 using namespace oem_ibm_platform;
+using namespace oem_ibm_bios;
 
 /** @brief Directory where the lid files without a header are stored */
 auto lidDirPath = fs::path(LID_STAGING_DIR) / "lid";
@@ -40,9 +41,6 @@
 /** @brief The file name of the hostfw image */
 constexpr auto hostfwImageName = "image-hostfw";
 
-/** @brief The filename of the file where bootside data will be saved */
-constexpr auto bootSideFileName = "bootSide";
-
 /** @brief The path to the code update tarball file */
 auto tarImagePath = fs::path(imageDirPath) / tarImageName;
 
@@ -59,9 +57,6 @@
 /** @brief Next boot side */
 constexpr auto bootNextSideAttrName = "fw_boot_side";
 
-/** @brief The filepath of file where bootside data will be saved */
-auto bootSideDirPath = fs::path("/var/lib/pldm/") / bootSideFileName;
-
 std::string CodeUpdate::fetchCurrentBootSide()
 {
     return currBootSide;
@@ -202,6 +197,7 @@
     static constexpr auto activeObjPath =
         "/xyz/openbmc_project/software/active";
     static constexpr auto propIntf = "org.freedesktop.DBus.Properties";
+    static constexpr auto pathIntf = "xyz.openbmc_project.Common.FilePath";
 
     auto& bus = dBusIntf->getBus();
     try
@@ -215,6 +211,9 @@
         reply.read(paths);
 
         runningVersion = std::get<std::vector<std::string>>(paths)[0];
+        auto runningPathPropValue = dBusIntf->getDbusPropertyVariant(
+            runningVersion.c_str(), "Path", pathIntf);
+        const auto& runningPath = std::get<std::string>(runningPathPropValue);
 
         auto method1 =
             bus.new_method_call(mapperService, activeObjPath, propIntf, "Get");
@@ -249,12 +248,13 @@
             else
             {
                 info(
-                    "Boot side is not initialized yet, so setting default value");
+                    "Boot side is not initialized yet, so setting default value(Temp). Request was ignored to set the Boot side to {SIDE}",
+                    "SIDE", nextBootSideBiosValue);
                 nextBootSideBiosValue = "Temp";
             }
             pldmBootSideData.current_boot_side = nextBootSideBiosValue;
             pldmBootSideData.next_boot_side = nextBootSideBiosValue;
-            pldmBootSideData.running_version_object = runningVersion;
+            pldmBootSideData.running_version_object = runningPath;
 
             writeBootSideFile(pldmBootSideData);
             biosAttrList.emplace_back(std::make_pair(
@@ -270,11 +270,11 @@
         else
         {
             pldm_boot_side_data pldmBootSideData = readBootSideFile();
-            if (pldmBootSideData.running_version_object != runningVersion)
+            if (pldmBootSideData.running_version_object != runningPath)
             {
                 info(
                     "BMC have booted with the new image runningPath={RUNN_PATH}",
-                    "RUNN_PATH", runningVersion.c_str());
+                    "RUNN_PATH", runningPath.c_str());
                 info("Previous Image was: {RUNN_VERS}", "RUNN_VERS",
                      pldmBootSideData.running_version_object);
                 auto current_boot_side =
@@ -282,7 +282,7 @@
                                                                   : "Temp");
                 pldmBootSideData.current_boot_side = current_boot_side;
                 pldmBootSideData.next_boot_side = current_boot_side;
-                pldmBootSideData.running_version_object = runningVersion;
+                pldmBootSideData.running_version_object = runningPath;
                 writeBootSideFile(pldmBootSideData);
                 biosAttrList.emplace_back(std::make_pair(
                     bootSideAttrName,
@@ -489,12 +489,12 @@
 {
     try
     {
-        fs::create_directories(bootSideDirPath.parent_path());
+        fs::create_directories(fs::path(bootSideDirPath).parent_path());
         std::ofstream writeFile(bootSideDirPath, std::ios::out);
         if (!writeFile.is_open())
         {
             error("Failed to open bootside file {FILE} for writing", "FILE",
-                  bootSideDirPath.string());
+                  bootSideDirPath);
             return;
         }
 
@@ -527,7 +527,7 @@
 {
     pldm_boot_side_data pldmBootSideDataRead{};
 
-    std::ifstream readFile(bootSideDirPath.string(), std::ios::in);
+    std::ifstream readFile(bootSideDirPath, std::ios::in);
 
     if (!readFile)
     {
@@ -551,6 +551,7 @@
 void CodeUpdate::processPriorityChangeNotification(
     const DbusChangedProps& chProperties)
 {
+    error("Processing priority change notification");
     static constexpr auto propName = "Priority";
     const auto it = chProperties.find(propName);
     if (it == chProperties.end())
@@ -558,8 +559,31 @@
         return;
     }
     uint8_t newVal = std::get<uint8_t>(it->second);
-    nextBootSide = (newVal == 0) ? currBootSide
-                                 : ((currBootSide == Tside) ? Pside : Tside);
+
+    pldm_boot_side_data pldmBootSideData = readBootSideFile();
+    pldmBootSideData.next_boot_side =
+        (newVal == 0)
+            ? pldmBootSideData.current_boot_side
+            : ((pldmBootSideData.current_boot_side == "Temp") ? "Perm"
+                                                              : "Temp");
+    writeBootSideFile(pldmBootSideData);
+    nextBootSide = (pldmBootSideData.next_boot_side == "Temp" ? Tside : Pside);
+    std::string currNextBootSide;
+    auto attributeValue = getBiosAttrValue<std::string>(bootNextSideAttrName);
+    if (attributeValue.has_value())
+    {
+        currNextBootSide = attributeValue.value();
+    }
+
+    if (currNextBootSide == nextBootSide)
+    {
+        return;
+    }
+    PendingAttributesList biosAttrList;
+    biosAttrList.push_back(std::make_pair(
+        bootNextSideAttrName,
+        std::make_tuple(EnumAttribute, pldmBootSideData.next_boot_side)));
+    setBiosAttr(biosAttrList);
 }
 
 void CodeUpdate::setOemPlatformHandler(
diff --git a/oem/ibm/libpldmresponder/oem_ibm_handler.hpp b/oem/ibm/libpldmresponder/oem_ibm_handler.hpp
index 52769ab..380a256 100644
--- a/oem/ibm/libpldmresponder/oem_ibm_handler.hpp
+++ b/oem/ibm/libpldmresponder/oem_ibm_handler.hpp
@@ -3,6 +3,7 @@
 #include "collect_slot_vpd.hpp"
 #include "common/utils.hpp"
 #include "inband_code_update.hpp"
+#include "libpldmresponder/bios_config.hpp"
 #include "libpldmresponder/oem_handler.hpp"
 #include "libpldmresponder/pdr_utils.hpp"
 #include "libpldmresponder/platform.hpp"
@@ -24,26 +25,11 @@
 {
 using ObjectPath = std::string;
 using AssociatedEntityMap = std::map<ObjectPath, pldm_entity>;
+using namespace pldm::bios;
+using namespace pldm::utils;
+
 namespace oem_ibm_platform
 {
-using AttributeName = std::string;
-using AttributeType = std::string;
-using ReadonlyStatus = bool;
-using DisplayName = std::string;
-using Description = std::string;
-using MenuPath = std::string;
-using CurrentValue = std::variant<int64_t, std::string>;
-using DefaultValue = std::variant<int64_t, std::string>;
-using OptionString = std::string;
-using OptionValue = std::variant<int64_t, std::string>;
-using Option = std::vector<std::tuple<OptionString, OptionValue>>;
-using BIOSTableObj =
-    std::tuple<AttributeType, ReadonlyStatus, DisplayName, Description,
-               MenuPath, CurrentValue, DefaultValue, Option>;
-using BaseBIOSTable = std::map<AttributeName, BIOSTableObj>;
-using PendingObj = std::tuple<AttributeType, CurrentValue>;
-using PendingAttributes = std::map<AttributeName, PendingObj>;
-
 constexpr uint16_t ENTITY_INSTANCE_0 = 0;
 constexpr uint16_t ENTITY_INSTANCE_1 = 1;
 
@@ -455,6 +441,59 @@
 
 } // namespace oem_ibm_platform
 
+namespace oem_ibm_bios
+{
+/** @brief The file where bootside data will be saved */
+constexpr auto bootSideDirPath = "/var/lib/pldm/bootSide";
+
+class Handler : public oem_bios::Handler
+{
+  public:
+    Handler() {}
+
+    void processOEMBaseBiosTable(const BaseBIOSTable& biosTable)
+    {
+        for (const auto& [attrName, biostabObj] : biosTable)
+        {
+            // The additional check to see if /var/lib/pldm/bootSide file exists
+            // is added to make sure we are doing the fw_boot_side setting after
+            // the base bios table is initialised.
+            if ((attrName == "fw_boot_side") && fs::exists(bootSideDirPath))
+            {
+                PendingAttributesList biosAttrList;
+
+                std::string nextBootSide =
+                    std::get<std::string>(std::get<5>(biostabObj));
+
+                std::string currNextBootSide;
+                auto attributeValue =
+                    getBiosAttrValue<std::string>("fw_boot_side");
+
+                if (attributeValue.has_value())
+                {
+                    currNextBootSide = attributeValue.value();
+                }
+                else
+                {
+                    info(
+                        "Boot side is not initialized yet, so setting default value");
+                    currNextBootSide = "Temp";
+                }
+
+                if (currNextBootSide != nextBootSide)
+                {
+                    biosAttrList.emplace_back(std::make_pair(
+                        attrName,
+                        std::make_tuple(EnumAttribute, nextBootSide)));
+                    setBiosAttr(biosAttrList);
+                }
+            }
+        }
+    }
+};
+
+} // namespace oem_ibm_bios
+
 } // namespace responder
 
 } // namespace pldm
diff --git a/pldmd/oem_ibm.hpp b/pldmd/oem_ibm.hpp
index 3f5802b..e3fbddf 100644
--- a/pldmd/oem_ibm.hpp
+++ b/pldmd/oem_ibm.hpp
@@ -52,6 +52,7 @@
      * @param[in] platformHandler - platformHandler handler
      * @param[in] fruHandler - fruHandler handler
      * @param[in] baseHandler - baseHandler handler
+     * @param[in] biosHandler - biosHandler handler
      * @param[in] reqHandler - reqHandler handler
      */
     explicit OemIBM(
@@ -62,6 +63,7 @@
         responder::platform::Handler* platformHandler,
         responder::fru::Handler* fruHandler,
         responder::base::Handler* baseHandler,
+        responder::bios::Handler* biosHandler,
         pldm::requester::Handler<pldm::requester::Request>* reqHandler) :
         dBusIntf(dBusIntf), mctp_fd(mctp_fd), mctp_eid(mctp_eid), repo(repo),
         instanceIdDb(instanceIdDb), event(event), invoker(invoker),
@@ -73,6 +75,9 @@
         createOemIbmFruHandler();
         oemIbmFruHandler->setIBMFruHandler(fruHandler);
 
+        createOemIbmBiosHandler();
+        biosHandler->setOemBiosHandler(oemIbmBiosHandler.get());
+
         createCodeUpdate();
         createSlotHandler();
         createOemPlatformHandler();
@@ -119,6 +124,13 @@
             instanceIdDb, event, reqHandler);
     }
 
+    /** @brief Method for creating oemIbmBiosHandler */
+    void createOemIbmBiosHandler()
+    {
+        oemIbmBiosHandler =
+            std::make_unique<responder::oem_ibm_bios::Handler>();
+    }
+
     /** @brief Method for creating oemIbmPlatformHandler */
     void createOemIbmPlatformHandler()
     {
@@ -211,6 +223,9 @@
     /** @brief oem IBM Fru handler*/
     pldm::responder::oem_ibm_fru::Handler* oemIbmFruHandler = nullptr;
 
+    /** @brief pointer to the oem IBM Bios handler*/
+    std::unique_ptr<responder::oem_bios::Handler> oemIbmBiosHandler{};
+
     std::unique_ptr<pldm::led::HostLampTest> hostLampTest;
 
     /** @brief oem IBM Utils handler*/
diff --git a/pldmd/pldmd.cpp b/pldmd/pldmd.cpp
index ba448e6..ac9db67 100644
--- a/pldmd/pldmd.cpp
+++ b/pldmd/pldmd.cpp
@@ -307,7 +307,7 @@
         platformConfigHandler.get(), &reqHandler, event, true,
         addOnEventHandlers);
 
-    auto biosHandler = std::make_unique<bios::Handler>(
+    auto biosHandler = std::make_unique<pldm::responder::bios::Handler>(
         pldmTransport.getEventSource(), hostEID, &instanceIdDb, &reqHandler,
         platformConfigHandler.get(), requestPLDMServiceName);
 
@@ -326,7 +326,7 @@
         &dbusHandler, pldmTransport.getEventSource(), hostEID, pdrRepo.get(),
         instanceIdDb, event, invoker, hostPDRHandler.get(),
         platformHandler.get(), fruHandler.get(), baseHandler.get(),
-        &reqHandler);
+        biosHandler.get(), &reqHandler);
 #endif
 
     invoker.registerHandler(PLDM_BIOS, std::move(biosHandler));