PFR: Setting BMC boot finished checkpoint
Adding support to monitor the StartupFinished systemd
signal and setting the "bmc boot finished" checkpoint
to cpld.
Tested:
Did BMC reset and cross verified bmc boot finished
check-point properly set or not.
Change-Id: I14e6aa8b364b28da6cd6b2473cde8502d1ebd77c
Signed-off-by: AppaRao Puli <apparao.puli@linux.intel.com>
diff --git a/service/src/mainapp.cpp b/service/src/mainapp.cpp
index 7be7a45..cc5f9ff 100644
--- a/service/src/mainapp.cpp
+++ b/service/src/mainapp.cpp
@@ -18,6 +18,7 @@
#include "pfr_mgr.hpp"
#include "pfr.hpp"
+#include <boost/asio.hpp>
static std::array<std::string, 5> listVersionPaths = {
"bmc_active", "bmc_recovery", "bios_active", "bios_recovery", "cpld"};
@@ -32,7 +33,11 @@
static uint8_t lastMinorErr = 0;
static bool stateTimerRunning = false;
+bool finishedSettingChkPoint = false;
+static constexpr uint8_t bmcBootFinishedChkPoint = 0x09;
+
std::unique_ptr<boost::asio::steady_timer> stateTimer = nullptr;
+std::unique_ptr<boost::asio::steady_timer> initTimer = nullptr;
// Recovery reason map. { <CPLD association>, <Recovery Reason> }
static std::map<uint8_t, std::string> recoveryReasonMap = {
@@ -185,12 +190,64 @@
});
}
+void checkAndSetCheckpoint(sdbusplus::asio::object_server& server,
+ std::shared_ptr<sdbusplus::asio::connection>& conn)
+{
+ // Check whether systemd completed all the loading.
+ conn->async_method_call(
+ [&server, &conn](boost::system::error_code ec,
+ const std::variant<uint64_t>& value) {
+ if (ec)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "async_method_call error: FinishTimestamp failed");
+ return;
+ }
+ if (std::get<uint64_t>(value))
+ {
+ if (!finishedSettingChkPoint)
+ {
+ finishedSettingChkPoint = true;
+ intel::pfr::setBMCBootCheckpoint(bmcBootFinishedChkPoint);
+ }
+ }
+ else
+ {
+ // FIX-ME: Latest up-stream sync caused issue in receiving
+ // StartupFinished signal. Unable to get StartupFinished signal
+ // from systemd1 hence using poll method too, to trigger it
+ // properly.
+ constexpr size_t pollTimeout = 10; // seconds
+ initTimer->expires_after(std::chrono::seconds(pollTimeout));
+ initTimer->async_wait([&server, &conn](
+ const boost::system::error_code& ec) {
+ if (ec == boost::asio::error::operation_aborted)
+ {
+ // Timer reset.
+ return;
+ }
+ if (ec)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "Set boot Checkpoint - async wait error.");
+ return;
+ }
+ checkAndSetCheckpoint(server, conn);
+ });
+ }
+ },
+ "org.freedesktop.systemd1", "/org/freedesktop/systemd1",
+ "org.freedesktop.DBus.Properties", "Get",
+ "org.freedesktop.systemd1.Manager", "FinishTimestamp");
+}
+
int main()
{
// setup connection to dbus
boost::asio::io_service io;
auto conn = std::make_shared<sdbusplus::asio::connection>(io);
stateTimer = std::make_unique<boost::asio::steady_timer>(io);
+ initTimer = std::make_unique<boost::asio::steady_timer>(io);
conn->request_name("xyz.openbmc_project.Intel.PFR.Manager");
auto server = sdbusplus::asio::object_server(conn, true);
@@ -203,6 +260,22 @@
intel::pfr::PfrVersion obj(server, conn, path);
}
+ // Monitor Boot finished signal and set the checkpoint 9 to
+ // notify CPLD about BMC boot finish.
+ auto bootFinishedSignal = std::make_unique<sdbusplus::bus::match::match>(
+ static_cast<sdbusplus::bus::bus&>(*conn),
+ "type='signal',"
+ "member='StartupFinished',path='/org/freedesktop/systemd1',"
+ "interface='org.freedesktop.systemd1.Manager'",
+ [&server, &conn](sdbusplus::message::message& msg) {
+ if (!finishedSettingChkPoint)
+ {
+ finishedSettingChkPoint = true;
+ intel::pfr::setBMCBootCheckpoint(bmcBootFinishedChkPoint);
+ }
+ });
+ checkAndSetCheckpoint(server, conn);
+
// Capture the Chassis state and Start the monitor timer
// if state changed to 'On'. Run timer until OS boot.
// Stop timer if state changed to 'Off'.