Add support for Bios update

Added support for Bios upgrade, this is just first stage where there
is no version check or image verify but later on these features will
also be added.

Currently, this expect a bios image to be copied with manifest file
having version and provide a system unit file to be executed.

To enable this feature need to enable config option
--enable-host_bios_upgrade via bbappend.

Change-Id: If96fe71bad9dc8b187570e9dbbfaac9e9e09e3d1
Signed-off-by: Vijay Khemka <vijaykhemka@fb.com>
diff --git a/activation.cpp b/activation.cpp
index 2966b2f..4b715e4 100644
--- a/activation.cpp
+++ b/activation.cpp
@@ -87,6 +87,30 @@
 
     if (value == softwareServer::Activation::Activations::Activating)
     {
+
+#ifdef HOST_BIOS_UPGRADE
+        auto purpose = parent.versions.find(versionId)->second->purpose();
+        if (purpose == VersionPurpose::Host)
+        {
+            if (!activationProgress)
+            {
+                activationProgress =
+                    std::make_unique<ActivationProgress>(bus, path);
+            }
+
+            // Enable systemd signals
+            subscribeToSystemdSignals();
+
+            // Set initial progress
+            activationProgress->progress(20);
+
+            // Initiate image writing to flash
+            flashWriteHost();
+
+            return softwareServer::Activation::activation(value);
+        }
+#endif
+
 #ifdef UBIFS_LAYOUT
         if (rwVolumeCreated == false && roVolumeCreated == false)
         {
@@ -283,6 +307,15 @@
         return;
     }
 
+#ifdef HOST_BIOS_UPGRADE
+    auto purpose = parent.versions.find(versionId)->second->purpose();
+    if (purpose == VersionPurpose::Host)
+    {
+        onStateChangesBios(msg);
+        return;
+    }
+#endif
+
     onStateChanges(msg);
 
     return;
@@ -365,6 +398,68 @@
     return false;
 }
 
+#ifdef HOST_BIOS_UPGRADE
+void Activation::flashWriteHost()
+{
+    auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
+                                      SYSTEMD_INTERFACE, "StartUnit");
+    auto biosServiceFile = "obmc-flash-host-bios@" + versionId + ".service";
+    method.append(biosServiceFile, "replace");
+    try
+    {
+        auto reply = bus.call(method);
+    }
+    catch (const SdBusError& e)
+    {
+        log<level::ERR>("Error in trying to upgrade Host Bios.");
+        report<InternalFailure>();
+    }
+}
+
+void Activation::onStateChangesBios(sdbusplus::message::message& msg)
+{
+    uint32_t newStateID{};
+    sdbusplus::message::object_path newStateObjPath;
+    std::string newStateUnit{};
+    std::string newStateResult{};
+
+    // Read the msg and populate each variable
+    msg.read(newStateID, newStateObjPath, newStateUnit, newStateResult);
+
+    auto biosServiceFile = "obmc-flash-host-bios@" + versionId + ".service";
+
+    if (newStateUnit == biosServiceFile)
+    {
+        // unsubscribe to systemd signals
+        unsubscribeFromSystemdSignals();
+
+        // Remove version object from image manager
+        deleteImageManagerObject();
+
+        if (newStateResult == "done")
+        {
+            // Set activation progress to 100
+            activationProgress->progress(100);
+
+            // Set Activation value to active
+            activation(softwareServer::Activation::Activations::Active);
+
+            log<level::INFO>("Bios upgrade completed successfully.");
+        }
+        else if (newStateResult == "failed")
+        {
+            // Set Activation value to Failed
+            activation(softwareServer::Activation::Activations::Failed);
+
+            log<level::ERR>("Bios upgrade failed.");
+        }
+    }
+
+    return;
+}
+
+#endif
+
 void Activation::rebootBmc()
 {
     auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
diff --git a/activation.hpp b/activation.hpp
index e87d20c..8133b99 100644
--- a/activation.hpp
+++ b/activation.hpp
@@ -266,6 +266,14 @@
     /** @brief Overloaded write flash function */
     void flashWrite() override;
 
+#ifdef HOST_BIOS_UPGRADE
+    /* @brief write to Host flash function */
+    void flashWriteHost();
+
+    /** @brief Function that acts on Bios upgrade service file state changes */
+    void onStateChangesBios(sdbusplus::message::message&);
+#endif
+
     /** @brief Overloaded function that acts on service file state changes */
     void onStateChanges(sdbusplus::message::message&) override;
 
diff --git a/configure.ac b/configure.ac
index 7f52361..403ea8d 100755
--- a/configure.ac
+++ b/configure.ac
@@ -184,6 +184,13 @@
     [AC_DEFINE([UBIFS_LAYOUT],[],[Enable ubifs support.])])
 AM_CONDITIONAL([UBIFS_LAYOUT], [test "x$enable_ubifs_layout" == "xyes"])
 
+# setup host bios upgrade support
+AC_ARG_ENABLE([host_bios_upgrade],
+    AS_HELP_STRING([--enable-host_bios_upgrade], [Enable host bios upgrade support.]))
+AS_IF([test "x$enable_host_bios_upgrade" == "xyes"], \
+    [AC_DEFINE([HOST_BIOS_UPGRADE],[],[Enable host bios upgrade support.])])
+AM_CONDITIONAL([HOST_BIOS_UPGRADE], [test "x$enable_host_bios_upgrade" == "xyes"])
+
 # Check for header files.
 AC_CHECK_HEADER(systemd/sd-bus.h, ,[AC_MSG_ERROR([Could not find systemd/sd-bus.h...systemd development package required])])
 AC_CHECK_HEADER(sdbusplus/server.hpp, ,[AC_MSG_ERROR([Could not find sdbusplus/server.hpp...openbmc/sdbusplus package required])])
diff --git a/item_updater.cpp b/item_updater.cpp
index 2cd9c39..4f2b833 100644
--- a/item_updater.cpp
+++ b/item_updater.cpp
@@ -64,6 +64,9 @@
                     auto value = SVersion::convertVersionPurposeFromString(
                         variant_ns::get<std::string>(property.second));
                     if (value == VersionPurpose::BMC ||
+#ifdef HOST_BIOS_UPGRADE
+                        value == VersionPurpose::Host ||
+#endif
                         value == VersionPurpose::System)
                     {
                         purpose = value;
@@ -107,8 +110,12 @@
     {
         // Determine the Activation state by processing the given image dir.
         auto activationState = server::Activation::Activations::Invalid;
-        ItemUpdater::ActivationStatus result =
-            ItemUpdater::validateSquashFSImage(filePath);
+        ItemUpdater::ActivationStatus result;
+        if (purpose == VersionPurpose::BMC || purpose == VersionPurpose::System)
+            result = ItemUpdater::validateSquashFSImage(filePath);
+        else
+            result = ItemUpdater::ActivationStatus::ready;
+
         AssociationList associations = {};
 
         if (result == ItemUpdater::ActivationStatus::ready)