bmc: implement reboot update mechanism
Implement an update mechanism that simply triggers a reboot of the BMC.
This implementation isn't tied into anything in the firmware handler
yet.
Signed-off-by: Patrick Venture <venture@google.com>
Change-Id: I116d4f631a44e7a4a999cf8ad403a00935f58710
diff --git a/Makefile.am b/Makefile.am
index cc7f110..6e03b0a 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -43,7 +43,8 @@
firmware_handler.cpp \
file_handler.cpp \
internal/sys.cpp \
- verify_systemd.cpp
+ verify_systemd.cpp \
+ update_systemd.cpp
if ENABLE_LPC_BRIDGE
libfirmwareblob_common_la_SOURCES += lpc_handler.cpp
diff --git a/README.md b/README.md
index 25686fe..5af6f97 100644
--- a/README.md
+++ b/README.md
@@ -104,3 +104,4 @@
`HASH_FILENAME` | `/tmp/bmc.sig` | The file to use for the hash provided.
`VERIFY_STATUS_FILENAME` | `/tmp/bmc.verify` | The file checked for the verification status.
`VERIFY_DBUS_SERVICE` | `verify_image.service` | The systemd service started for verification.
+`UPDATE_DBUS_SERVICE` | `update-bmc.service` | The systemd service started for updating the BMC.
diff --git a/configure.ac b/configure.ac
index 02e6447..45380fd 100644
--- a/configure.ac
+++ b/configure.ac
@@ -81,6 +81,14 @@
)
AM_CONDITIONAL([BUILD_HOST_TOOL], [test "x$enable_build_host_tool" != "xno"])
+# Enable the reboot update mechanism
+AC_ARG_ENABLE([reboot-update],
+ AS_HELP_STRING([--enable-reboot-update],
+ [Enable use of reboot update mechanism.]))
+AS_IF([test "x$enable_reboot_update" = "xyes"], [
+ AX_APPEND_COMPILE_FLAGS([-DENABLE_REBOOT_UPDATE], [CXXFLAGS])
+])
+
# Enable static layout for firmware image staging.
AC_ARG_ENABLE([static-layout],
AS_HELP_STRING([--enable-static-layout],
@@ -175,11 +183,15 @@
AS_IF([test "xVERIFY_STATUS_FILENAME" == "x"], [VERIFY_STATUS_FILENAME="/tmp/bmc.verify"])
AC_DEFINE_UNQUOTED([VERIFY_STATUS_FILENAME], ["$VERIFY_STATUS_FILENAME"], [The file checked for the verification status.])
-# VERIFY_DBUS_SERVICE
AC_ARG_VAR(VERIFY_DBUS_SERVICE, [The systemd service started for verification.])
AS_IF([test "xVERIFY_DBUS_SERVICE" == "x"], [VERIFY_DBUS_SERVICE="verify_image.service"])
AC_DEFINE_UNQUOTED([VERIFY_DBUS_SERVICE], ["$VERIFY_DBUS_SERVICE"], [The systemd service started for verification.])
+AC_ARG_VAR(UPDATE_DBUS_SERVICE, [The systemd service started for updating the BMC.])
+AS_IF([test "xUPDATE_DBUS_SERVICE" == "x"], [UPDATE_DBUS_SERVICE="update-bmc.service"])
+AC_DEFINE_UNQUOTED([UPDATE_DBUS_SERVICE], ["$UPDATE_DBUS_SERVICE"], [The systemd service started for updating the BMC.])
+
+
AC_CHECK_HEADER(linux/ipmi.h, [HAVE_LINUX_IPMI_H=""], [HAVE_LINUX_IPMI_H="-I linux/ipmi.h"])
AS_IF([test "$HAVE_LINUX_IPMI_H" != ""],
AC_MSG_WARN([Could not find linux/ipmi.h: Attempting to download locally for building from openbmc/linux/+/dev-4.18])
diff --git a/main.cpp b/main.cpp
index 00ced2a..7e9b5a3 100644
--- a/main.cpp
+++ b/main.cpp
@@ -23,6 +23,7 @@
#include "lpc_handler.hpp"
#include "lpc_nuvoton.hpp"
#include "pci_handler.hpp"
+#include "update_systemd.hpp"
#include "util.hpp"
#include "verify.hpp"
#include "verify_systemd.hpp"
@@ -99,6 +100,17 @@
{
using namespace phosphor::logging;
+#ifdef ENABLE_REBOOT_UPDATE
+ static constexpr auto rebootTarget = "reboot.target";
+ static constexpr auto rebootMode = "replace-irreversibly";
+
+ auto updater = ipmi_flash::SystemdUpdateMechanism::CreateSystemdUpdate(
+ sdbusplus::bus::new_default(), rebootTarget, rebootMode);
+#else
+ auto updater = ipmi_flash::SystemdUpdateMechanism::CreateSystemdUpdate(
+ sdbusplus::bus::new_default(), UPDATE_DBUS_SERVICE);
+#endif
+
auto handler = ipmi_flash::FirmwareBlobHandler::CreateFirmwareBlobHandler(
ipmi_flash::supportedFirmware, ipmi_flash::supportedTransports,
ipmi_flash::SystemdVerification::CreateVerification(
diff --git a/update_systemd.cpp b/update_systemd.cpp
new file mode 100644
index 0000000..0802f43
--- /dev/null
+++ b/update_systemd.cpp
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2019 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "update_systemd.hpp"
+
+#include "status.hpp"
+#include "update.hpp"
+
+#include <memory>
+#include <sdbusplus/bus.hpp>
+#include <string>
+
+namespace ipmi_flash
+{
+
+std::unique_ptr<UpdateInterface>
+ SystemdUpdateMechanism::CreateSystemdUpdate(sdbusplus::bus::bus&& bus,
+ const std::string& target,
+ const std::string& mode)
+{
+ return std::make_unique<SystemdUpdateMechanism>(std::move(bus), target,
+ mode);
+}
+
+bool SystemdUpdateMechanism::triggerUpdate()
+{
+ /* TODO: Add a util method for triggering a service with optional additional
+ * parameter. */
+ static constexpr auto systemdService = "org.freedesktop.systemd1";
+ static constexpr auto systemdRoot = "/org/freedesktop/systemd1";
+ static constexpr auto systemdInterface = "org.freedesktop.systemd1.Manager";
+
+ auto method = bus.new_method_call(systemdService, systemdRoot,
+ systemdInterface, "StartUnit");
+ method.append(target);
+
+ if (!mode.empty())
+ {
+ method.append(mode);
+ }
+
+ try
+ {
+ bus.call_noreply(method);
+ return true;
+ }
+ catch (const sdbusplus::exception::SdBusError& ex)
+ {
+ return false;
+ }
+}
+
+void SystemdUpdateMechanism::abortUpdate()
+{
+ return;
+}
+
+UpdateStatus SystemdUpdateMechanism::status()
+{
+ /* For now, don't check if the target failed. */
+ return UpdateStatus::running;
+}
+
+} // namespace ipmi_flash
diff --git a/update_systemd.hpp b/update_systemd.hpp
new file mode 100644
index 0000000..47c8d67
--- /dev/null
+++ b/update_systemd.hpp
@@ -0,0 +1,46 @@
+#pragma once
+
+#include "update.hpp"
+
+#include <memory>
+#include <sdbusplus/bus.hpp>
+#include <string>
+
+namespace ipmi_flash
+{
+
+/**
+ * Implements the update interface by simply triggering a systemd unit.
+ */
+class SystemdUpdateMechanism : public UpdateInterface
+{
+ public:
+ static std::unique_ptr<UpdateInterface>
+ CreateSystemdUpdate(sdbusplus::bus::bus&& bus,
+ const std::string& target,
+ const std::string& mode = "");
+
+ SystemdUpdateMechanism(sdbusplus::bus::bus&& bus, const std::string& target,
+ const std::string& mode) :
+ bus(std::move(bus)),
+ target(target), mode(mode)
+ {
+ }
+
+ ~SystemdUpdateMechanism() = default;
+ SystemdUpdateMechanism(const SystemdUpdateMechanism&) = delete;
+ SystemdUpdateMechanism& operator=(const SystemdUpdateMechanism&) = delete;
+ SystemdUpdateMechanism(SystemdUpdateMechanism&&) = default;
+ SystemdUpdateMechanism& operator=(SystemdUpdateMechanism&&) = default;
+
+ bool triggerUpdate() override;
+ void abortUpdate() override;
+ UpdateStatus status() override;
+
+ private:
+ sdbusplus::bus::bus bus;
+ const std::string target;
+ const std::string mode;
+};
+
+} // namespace ipmi_flash