firmware-update: fix for firmware update

updated firmware update module to support for KCS and USB

Tested:
Tested firmware update utility for USB and KCS

Signed-off-by: anil kumar appana <anil.kumarx.appana@intel.com>
Change-Id: I129cd8456eda369386ccdb13d5136708a50f87d1
diff --git a/src/firmware-update.cpp b/src/firmware-update.cpp
index 1095338..95d01f7 100644
--- a/src/firmware-update.cpp
+++ b/src/firmware-update.cpp
@@ -26,6 +26,8 @@
 #include <sdbusplus/timer.hpp>
 #include <sstream>
 
+static constexpr char *secondaryFitImageStartAddr = "22480000";
+static uint8_t getActiveBootImage(void);
 static void register_netfn_firmware_functions() __attribute__((constructor));
 
 // oem return code for firmware update control
@@ -81,24 +83,6 @@
         FW_STATE_ERROR = 0x0f,
         FW_STATE_AC_CYCLE_REQUIRED = 0x83,
     };
-    fw_update_status_cache() : _bus(getSdBus())
-    {
-        _match = std::make_shared<sdbusplus::bus::match::match>(
-            *_bus,
-            sdbusplus::bus::match::rules::propertiesChanged(
-                FW_UPDATE_SERVER_PATH, FW_UPDATE_INTERFACE),
-            [&](sdbusplus::message::message &msg) {
-                if (DEBUG)
-                    std::cerr << "propertiesChanged lambda\n";
-                std::map<std::string, ipmi::DbusVariant> props;
-                std::vector<std::string> inval;
-                std::string iface;
-                msg.read(iface, props, inval);
-                _parse_props(props);
-            });
-        _initial_fetch();
-    }
-
     uint8_t state()
     {
         if (DEBUG)
@@ -119,7 +103,6 @@
     {
         return _msg;
     }
-#ifdef UPDATER_ENABLED
     std::string get_software_obj_path()
     {
         return _software_obj_path;
@@ -148,10 +131,38 @@
     {
         std::cerr << "activation_timer_timout(): increase percentage...\n";
         _percent = _percent + 5;
-        std::cerr << "_percent = " << std::string((char *)&_percent) << "\n";
+        if (_percent >= 95)
+        {
+            /*changing the state to ready to update firmware utility */
+            _state = FW_STATE_READY;
+        }
+        std::cerr << " _percent = " << (int)_percent << "\n";
         return _percent;
     }
-#endif
+    /* API for changing state to ERROR  */
+    void firmwareUpdateAbortState()
+    {
+        unlink(FIRMWARE_BUFFER_FILE);
+        // changing the state to error
+        _state = FW_STATE_ERROR;
+    }
+    void setDeferRestart(bool deferRestart)
+    {
+        _deferRestart = deferRestart;
+    }
+    void setInhibitDowngrade(bool inhibitDowngrade)
+    {
+        _inhibitDowngrade = inhibitDowngrade;
+    }
+    bool getDeferRestart()
+    {
+        return _deferRestart;
+    }
+    bool getInhibitDowngrade()
+    {
+        return _inhibitDowngrade;
+    }
+
   protected:
     void _parse_props(std::map<std::string, ipmi::DbusVariant> &properties)
     {
@@ -218,36 +229,13 @@
         if (DEBUG)
             std::cerr << '\n';
     }
-    void _initial_fetch()
-    {
-#ifndef UPDATER_ENABLED
-        auto method = _bus->new_method_call(
-            FW_UPDATE_SERVER_DBUS_NAME, FW_UPDATE_SERVER_PATH,
-            "org.freedesktop.DBus.Properties", "GetAll");
-        method.append(FW_UPDATE_INTERFACE);
-        if (DEBUG)
-            std::cerr << "fetch fw status via dbus...\n";
-        try
-        {
-            auto reply = _bus->call(method);
-
-            std::map<std::string, ipmi::DbusVariant> properties;
-            reply.read(properties);
-            _parse_props(properties);
-        }
-        catch (sdbusplus::exception::SdBusError &e)
-        {
-            std::cerr << "Failed in _initial_fetch(): SDBus Error: " << e.what()
-                      << "\n";
-            return;
-        }
-#endif
-    }
 
     std::shared_ptr<sdbusplus::asio::connection> _bus;
     std::shared_ptr<sdbusplus::bus::match::match> _match;
     uint8_t _state = 0;
     uint8_t _percent = 0;
+    bool _deferRestart = false;
+    bool _inhibitDowngrade = false;
     std::string _msg;
 
   private:
@@ -378,15 +366,12 @@
             rc = IPMI_CC_INVALID_FIELD_REQUEST;
             break;
         case fw_update_status_cache::FW_STATE_DOWNLOAD:
-            unlink(FIRMWARE_BUFFER_FILE);
         case fw_update_status_cache::FW_STATE_VERIFY:
             break;
         case fw_update_status_cache::FW_STATE_WRITE:
-            rc = IPMI_CC_INVALID_FIELD_REQUEST;
             break;
         case fw_update_status_cache::FW_STATE_READY:
         case fw_update_status_cache::FW_STATE_ERROR:
-            unlink(FIRMWARE_BUFFER_FILE);
             break;
         case fw_update_status_cache::FW_STATE_AC_CYCLE_REQUIRED:
             rc = IPMI_CC_INVALID_FIELD_REQUEST;
@@ -394,25 +379,7 @@
     }
     if (rc == IPMI_CC_OK)
     {
-        std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus();
-        // attempt to reset the state machine -- this may fail
-        auto method = bus->new_method_call(
-            FW_UPDATE_SERVER_DBUS_NAME, FW_UPDATE_SERVER_PATH,
-            "org.freedesktop.DBus.Properties", "Abort");
-        try
-        {
-            auto reply = bus->call(method);
-
-            ipmi::DbusVariant retval;
-            reply.read(retval);
-            if (std::get<int>(retval) != 0)
-                rc = IPMI_CC_INVALID_FIELD_REQUEST;
-        }
-        catch (sdbusplus::exception::SdBusError &e)
-        {
-            std::cerr << "SDBus Error: " << e.what() << "\n";
-            return IPMI_CC_UNSPECIFIED_ERROR;
-        }
+        fw_update_status.firmwareUpdateAbortState();
     }
 
     return rc;
@@ -425,7 +392,6 @@
     if (DEBUG)
         std::cerr << "request start firmware update()\n";
 
-#ifdef UPDATER_ENABLED
     // fwupdate URIs start with file:// or usb:// or tftp:// etc. By the time
     // the code gets to this point, the file should be transferred start the
     // request (creating a new file in /tmp/images causes the update manager to
@@ -435,59 +401,6 @@
     std::filesystem::rename(
         uri, "/tmp/images/" +
                  boost::uuids::to_string(boost::uuids::random_generator()()));
-#else
-    std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus();
-    auto method =
-        bus->new_method_call(FW_UPDATE_SERVER_DBUS_NAME, FW_UPDATE_SERVER_PATH,
-                             FW_UPDATE_INTERFACE, "start");
-    if (DEBUG)
-        std::cerr << "fwupdate1.start: " << uri << '\n';
-    method.append(uri);
-    try
-    {
-        auto reply = bus->call(method);
-
-        uint32_t retval;
-        reply.read(retval);
-        if (retval != 0)
-        {
-            if (DEBUG)
-                std::cerr << "method returned non-zero: " << retval << "\n";
-            return false;
-        }
-        return true;
-    }
-    catch (sdbusplus::exception::SdBusError &e)
-    {
-        std::cerr << "SDBus Error: " << e.what();
-        return false;
-    }
-#endif
-    return true;
-}
-
-static bool request_abort_firmware_update()
-{
-    std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus();
-    auto method =
-        bus->new_method_call(FW_UPDATE_SERVER_DBUS_NAME, FW_UPDATE_SERVER_PATH,
-                             FW_UPDATE_INTERFACE, "abort");
-    try
-    {
-        auto reply = bus->call(method);
-
-        unlink(FIRMWARE_BUFFER_FILE);
-        uint32_t retval;
-        reply.read(retval);
-        if (retval != 0)
-            return false;
-    }
-    catch (sdbusplus::exception::SdBusError &e)
-    {
-        std::cerr << "SDBus Error: " << e.what() << "\n";
-        unlink(FIRMWARE_BUFFER_FILE);
-        return false;
-    }
     return true;
 }
 
@@ -578,32 +491,40 @@
 
 std::shared_ptr<transfer_hash_check> xfer_hash_check;
 
-#ifdef UPDATER_ENABLED
 static void activate_image(const char *obj_path)
 {
-    if (DEBUG)
+    // If flag is false  means to reboot
+    if (fw_update_status.getDeferRestart() == false)
     {
-        std::cerr << "activateImage()...\n";
-        std::cerr << "obj_path = " << obj_path << "\n";
-    }
-    std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus();
-    auto method_call = bus->new_method_call(
-        "xyz.openbmc_project.Software.BMC.Updater", obj_path,
-        "org.freedesktop.DBus.Properties", "Set");
-    method_call.append(
-        "xyz.openbmc_project.Software.Activation", "RequestedActivation",
-        std::variant<std::string>("xyz.openbmc_project.Software.Activation."
-                                  "RequestedActivations.Active"));
 
-    try
-    {
-        auto method_call_reply = bus->call(method_call);
+        if (DEBUG)
+        {
+            std::cerr << "activateImage()...\n";
+            std::cerr << "obj_path = " << obj_path << "\n";
+        }
+        phosphor::logging::log<phosphor::logging::level::INFO>(
+            "activating Image: ",
+            phosphor::logging::entry("OBJPATH =%s", obj_path));
+        std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus();
+        bus->async_method_call(
+            [](const boost::system::error_code ec) {
+                if (ec)
+                {
+                    phosphor::logging::log<phosphor::logging::level::ERR>(
+                        "async_method_call error: activate_image failed");
+                    return;
+                }
+            },
+            "xyz.openbmc_project.Software.BMC.Updater", obj_path,
+            "org.freedesktop.DBus.Properties", "Set",
+            "xyz.openbmc_project.Software.Activation", "RequestedActivation",
+            std::variant<std::string>("xyz.openbmc_project.Software.Activation."
+                                      "RequestedActivations.Active"));
     }
-    catch (sdbusplus::exception::SdBusError &e)
+    else
     {
-        std::cerr << "Failed in activate_image(): SDBus Error: " << e.what()
-                  << "\n";
-        return;
+        phosphor::logging::log<phosphor::logging::level::INFO>(
+            "Firmware image activation is deferred.");
     }
 }
 
@@ -693,7 +614,6 @@
         "member='InterfacesAdded',path='/xyz/openbmc_project/software'",
         callback);
 }
-#endif
 
 class MappedFile
 {
@@ -979,13 +899,7 @@
                     rc = IPMI_CC_USB_ATTACH_FAIL;
                 }
             }
-            if (!request_abort_firmware_update())
-            {
-                if (DEBUG)
-                    std::cerr
-                        << "abort_start_firmware_update returns failure\n";
-                rc = IPMI_CC_UNSPECIFIED_ERROR;
-            }
+            fw_update_status.firmwareUpdateAbortState();
             controls |= controls_transfer_aborted;
             break;
         case fw_update_control_request::CTRL_SET_FILENAME:
@@ -1311,50 +1225,9 @@
     //          1 - primary, 2 - secondary
 
     auto info = reinterpret_cast<struct fw_execution_context *>(response);
-    std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus();
-    auto method =
-        bus->new_method_call(FW_UPDATE_SERVER_DBUS_NAME, FW_UPDATE_SERVER_PATH,
-                             "org.freedesktop.DBus.Properties", "GetAll");
-    method.append(FW_UPDATE_SECURITY_INTERFACE);
-    int active_img;
-    bool safe_mode;
-    std::string cert;
-    try
-    {
-        auto reply = bus->call(method);
+    info->context = EXEC_CTX_FULL_LINUX;
 
-        if (!reply.is_method_error())
-        {
-            std::vector<std::pair<std::string, ipmi::DbusVariant>> properties;
-            reply.read(properties);
-
-            for (const auto &t : properties)
-            {
-                auto key = t.first;
-                auto value = t.second;
-                if (key == "active_partition")
-                {
-                    active_img = std::get<int>(value);
-                }
-                else if (key == "safe_mode")
-                {
-                    safe_mode = std::get<bool>(value);
-                }
-            }
-        }
-    }
-    catch (sdbusplus::exception::SdBusError &e)
-    {
-        std::cerr << "SDBus Error: " << e.what();
-        return IPMI_CC_UNSPECIFIED_ERROR;
-    }
-
-    if (safe_mode)
-        info->context = EXEC_CTX_SAFE_MODE_LINUX;
-    else
-        info->context = EXEC_CTX_FULL_LINUX;
-
-    info->image_selection = active_img;
+    info->image_selection = getActiveBootImage();
 
     // Status code.
     ipmi_ret_t rc = IPMI_CC_OK;
@@ -1363,6 +1236,43 @@
     return rc;
 }
 
+uint8_t getActiveBootImage(void)
+{
+    // 0x01 -  primaryImage
+    constexpr uint8_t primaryImage = 0x01;
+    // 0x02 -  secondaryImage
+    constexpr uint8_t secondaryImage = 0x02;
+    uint8_t bootImage = primaryImage;
+
+    std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus();
+    auto method = bus->new_method_call(
+        "xyz.openbmc_project.U_Boot.Environment.Manager",
+        "/xyz/openbmc_project/u_boot/environment/mgr",
+        "xyz.openbmc_project.U_Boot.Environment.Manager", "Read");
+    method.append("bootcmd");
+    std::string value;
+    try
+    {
+        auto reply = bus->call(method);
+        reply.read(value);
+    }
+    catch (sdbusplus::exception::SdBusError &e)
+    {
+        std::cerr << "SDBus Error: " << e.what();
+        return IPMI_CC_UNSPECIFIED_ERROR;
+    }
+    /* cheking for secondary FitImage Address 22480000  */
+    if (value.find(secondaryFitImageStartAddr) != std::string::npos)
+    {
+        bootImage = secondaryImage;
+    }
+    else
+    {
+        bootImage = primaryImage;
+    }
+
+    return bootImage;
+}
 /** @brief implements firmware get status command
  *  @parameter
  *   -  none
@@ -1402,33 +1312,6 @@
     uint8_t options;
 } __attribute__((packed));
 
-bool fw_update_set_dbus_property(const std::string &path,
-                                 const std::string &iface,
-                                 const std::string &name,
-                                 ipmi::DbusVariant value)
-{
-    std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus();
-    auto method =
-        bus->new_method_call(FW_UPDATE_SERVER_DBUS_NAME, path.c_str(),
-                             "org.freedesktop.DBus.Properties", "Set");
-    method.append(iface, name, value);
-    try
-    {
-        auto reply = bus->call(method);
-        auto err = reply.is_method_error();
-        if (err)
-            if (DEBUG)
-                std::cerr << "failed to set prop " << path << '/' << iface
-                          << '.' << name << '\n';
-        return err;
-    }
-    catch (sdbusplus::exception::SdBusError &e)
-    {
-        std::cerr << "SDBus Error: " << e.what();
-        return false;
-    }
-}
-
 uint32_t fw_update_options = 0;
 static ipmi_ret_t ipmi_firmware_update_options(
     ipmi_netfn_t netfn, ipmi_cmd_t cmd, ipmi_request_t request,
@@ -1456,16 +1339,15 @@
         if (fw_options->options & FW_UPDATE_OPTIONS_NO_DOWNREV)
         {
             fw_update_options |= FW_UPDATE_OPTIONS_NO_DOWNREV;
+            /*setting flag to flase for deferring downgrade support*/
+            fw_update_status.setInhibitDowngrade(true);
         }
         else
         {
             fw_update_options &= ~FW_UPDATE_OPTIONS_NO_DOWNREV;
-            // send dbus
+            /*setting flag to true for downgrade support*/
+            fw_update_status.setInhibitDowngrade(false);
         }
-        const char *name = "inhibit_downgrade";
-        fw_update_set_dbus_property(
-            path, iface, name,
-            (bool)(!!(fw_update_options & FW_UPDATE_OPTIONS_NO_DOWNREV)));
     }
     if ((fw_options->mask & FW_UPDATE_OPTIONS_DEFER_RESTART) &&
         (fw_options->options & FW_UPDATE_OPTIONS_DEFER_RESTART) !=
@@ -1474,15 +1356,15 @@
         if (fw_options->options & FW_UPDATE_OPTIONS_DEFER_RESTART)
         {
             fw_update_options |= FW_UPDATE_OPTIONS_DEFER_RESTART;
+            /* setting flag to true to stop image activation */
+            fw_update_status.setDeferRestart(true);
         }
         else
         {
+            /* setting flag to false for image activation */
             fw_update_options &= ~FW_UPDATE_OPTIONS_DEFER_RESTART;
+            fw_update_status.setDeferRestart(false);
         }
-        const char *name = "defer_restart";
-        fw_update_set_dbus_property(
-            path, iface, name,
-            (bool)(!!(fw_update_options & FW_UPDATE_OPTIONS_DEFER_RESTART)));
     }
     if (fw_options->mask & FW_UPDATE_OPTIONS_SHA2_CHECK)
     {