Static layout: Implement factory reset

Tested: Verify the partitions hard-coded are cleared during factory
        reset.

Change-Id: I70febe5f8245a299d4e2a782414662dbf09e84cb
Signed-off-by: Lei YU <mine260309@gmail.com>
diff --git a/static/item_updater_static.cpp b/static/item_updater_static.cpp
index 6ab1f91..0234255 100644
--- a/static/item_updater_static.cpp
+++ b/static/item_updater_static.cpp
@@ -5,6 +5,7 @@
 #include "activation_static.hpp"
 #include "version.hpp"
 
+#include <array>
 #include <cstring>
 #include <filesystem>
 #include <fstream>
@@ -113,6 +114,24 @@
     return version;
 }
 
+inline void pnorClear(const std::string& part, bool shouldEcc = true)
+{
+    int rc;
+    std::tie(rc, std::ignore) =
+        pflash("-P", part, shouldEcc ? "-c" : "-e", "-f >/dev/null");
+    if (rc != 0)
+    {
+        log<level::ERR>("Failed to clear partition",
+                        entry("PART=%s", part.c_str()),
+                        entry("RETURNCODE=%d", rc));
+    }
+    else
+    {
+        log<level::INFO>("Clear partition successfully",
+                         entry("PART=%s", part.c_str()));
+    }
+}
+
 } // namespace utils
 
 namespace openpower
@@ -223,6 +242,60 @@
 
 void ItemUpdaterStatic::reset()
 {
+    // The pair contains the partition name and if it should use ECC clear
+    using PartClear = std::pair<const char*, bool>;
+    constexpr std::array<PartClear, 11> partitions = {{
+        {"HBEL", true},
+        {"GUARD", true},
+        {"NVRAM", false},
+        {"DJVPD", true},
+        {"MVPD", true},
+        {"CVPD", true},
+        {"FIRDATA", true},
+        {"BMC_INV", false},
+        {"ATTR_TMP", false},
+        {"ATTR_PERM", true},
+        {"HB_VOLATILE", true},
+    }};
+
+    std::vector<uint8_t> mboxdArgs;
+
+    // Suspend mboxd - no args required.
+    auto dbusCall = bus.new_method_call(MBOXD_INTERFACE, MBOXD_PATH,
+                                        MBOXD_INTERFACE, "cmd");
+    dbusCall.append(static_cast<uint8_t>(3), mboxdArgs);
+
+    try
+    {
+        bus.call_noreply(dbusCall);
+    }
+    catch (const SdBusError& e)
+    {
+        log<level::ERR>("Error in mboxd suspend call",
+                        entry("ERROR=%s", e.what()));
+        elog<InternalFailure>();
+    }
+    for (auto p : partitions)
+    {
+        utils::pnorClear(p.first, p.second);
+    }
+
+    // Resume mboxd with arg 1, indicating that the flash was modified.
+    dbusCall = bus.new_method_call(MBOXD_INTERFACE, MBOXD_PATH, MBOXD_INTERFACE,
+                                   "cmd");
+    mboxdArgs.push_back(1);
+    dbusCall.append(static_cast<uint8_t>(4), mboxdArgs);
+
+    try
+    {
+        bus.call_noreply(dbusCall);
+    }
+    catch (const SdBusError& e)
+    {
+        log<level::ERR>("Error in mboxd resume call",
+                        entry("ERROR=%s", e.what()));
+        elog<InternalFailure>();
+    }
 }
 
 bool ItemUpdaterStatic::isVersionFunctional(const std::string& versionId)
@@ -267,7 +340,6 @@
 {
     // Clear gard partition
     std::vector<uint8_t> mboxdArgs;
-    int rc;
 
     auto dbusCall = bus.new_method_call(MBOXD_INTERFACE, MBOXD_PATH,
                                         MBOXD_INTERFACE, "cmd");
@@ -286,15 +358,7 @@
     }
 
     // Clear guard partition
-    std::tie(rc, std::ignore) = utils::pflash("-P GUARD -c -f >/dev/null");
-    if (rc != 0)
-    {
-        log<level::ERR>("Failed to clear GUARD", entry("RETURNCODE=%d", rc));
-    }
-    else
-    {
-        log<level::INFO>("Clear GUARD successfully");
-    }
+    utils::pnorClear("GUARD");
 
     dbusCall = bus.new_method_call(MBOXD_INTERFACE, MBOXD_PATH, MBOXD_INTERFACE,
                                    "cmd");