blob: 5deea2a1351b07f9f866c9ce82e088e4dce8cd13 [file] [log] [blame]
John Wedigdd9478d2023-12-08 14:44:53 -08001
John Wedig376d7812024-11-11 16:45:53 -08002#include "absl/flags/flag.h"
3#include "absl/flags/parse.h"
4
John Wedigdd9478d2023-12-08 14:44:53 -08005#include <boost/asio/io_context.hpp>
6#include <boost/asio/steady_timer.hpp>
7#include <phosphor-logging/lg2.hpp>
8#include <sdbusplus/asio/connection.hpp>
9#include <sdbusplus/asio/property.hpp>
10#include <sdbusplus/bus.hpp>
11#include <sdbusplus/bus/match.hpp>
12
John Wedig376d7812024-11-11 16:45:53 -080013#include <format>
14
15ABSL_FLAG(std::string, host_label, "0",
16 "Label for the host in question. Usually this is an integer.");
17
John Wedigdd9478d2023-12-08 14:44:53 -080018const constexpr char* OperatingSystemService =
John Wedig376d7812024-11-11 16:45:53 -080019 "xyz.openbmc_project.State.OperatingSystem{}";
John Wedigdd9478d2023-12-08 14:44:53 -080020const constexpr char* OperatingSystemPath = "/xyz/openbmc_project/state/os";
21const constexpr char* OperatingSystemStatusInterface =
22 "xyz.openbmc_project.State.OperatingSystem.Status";
23const constexpr char* OperatingSystemStateProperty = "OperatingSystemState";
24const constexpr char* OperatingSystemStateStandby =
25 "xyz.openbmc_project.State.OperatingSystem.Status.OSStatus.Standby";
26const constexpr char* OperatingSystemStateInactive =
27 "xyz.openbmc_project.State.OperatingSystem.Status.OSStatus.Inactive";
John Wedig376d7812024-11-11 16:45:53 -080028const constexpr char* BareMetalActiveTargetTemplate =
29 "gbmc-bare-metal-active@{}.target";
John Wedigdd9478d2023-12-08 14:44:53 -080030
31const constexpr char* SystemdService = "org.freedesktop.systemd1";
32const constexpr char* SystemdManagerObject = "/org/freedesktop/systemd1";
33const constexpr char* SystemdManagerInterface =
34 "org.freedesktop.systemd1.Manager";
35
John Wedig376d7812024-11-11 16:45:53 -080036void setUnitStatus(sdbusplus::asio::connection& bus, bool status,
37 const std::string& host_instance)
John Wedigdd9478d2023-12-08 14:44:53 -080038{
39 auto method = bus.new_method_call(SystemdService, SystemdManagerObject,
40 SystemdManagerInterface,
41 status ? "StartUnit" : "StopUnit");
John Wedig376d7812024-11-11 16:45:53 -080042 method.append(std::format(BareMetalActiveTargetTemplate, host_instance),
43 "replace");
John Wedigdd9478d2023-12-08 14:44:53 -080044
45 bus.call(method);
46}
47
John Wedigdd9478d2023-12-08 14:44:53 -080048void checkPostComplete(sdbusplus::asio::connection& bus,
John Wedig376d7812024-11-11 16:45:53 -080049 const std::string& state, bool action,
50 const std::string& host_instance)
John Wedigdd9478d2023-12-08 14:44:53 -080051{
52 sdbusplus::asio::getProperty<std::string>(
John Wedig376d7812024-11-11 16:45:53 -080053 bus, std::format(OperatingSystemService, host_instance),
54 OperatingSystemPath, OperatingSystemStatusInterface,
55 OperatingSystemStateProperty,
Yuxiao Zhang88009842024-01-04 14:52:38 -080056 [&, state, action](const boost::system::error_code& ec,
57 const std::string& postCompleteState) {
Patrick Williamsc66ebc32024-08-16 15:21:56 -040058 if (ec)
59 {
60 lg2::error("Error when checking Post Complete GPIO state");
61 return;
62 }
John Wedigdd9478d2023-12-08 14:44:53 -080063
Patrick Williamsc66ebc32024-08-16 15:21:56 -040064 lg2::info("Post Complete state is {STATE}", "STATE",
65 postCompleteState);
Yuxiao Zhang88009842024-01-04 14:52:38 -080066
Patrick Williamsc66ebc32024-08-16 15:21:56 -040067 /*
68 * If state is Standby, enable the bare-metal-active systemd
69 * target.
70 * If state is Inactive, no-op cause IPMI is enabled by default.
71 */
72 if (postCompleteState == state)
73 {
John Wedig376d7812024-11-11 16:45:53 -080074 setUnitStatus(bus, action, host_instance);
Patrick Williamsc66ebc32024-08-16 15:21:56 -040075 }
76 });
John Wedigdd9478d2023-12-08 14:44:53 -080077}
78
79/* This only gets called once on startup. */
John Wedig376d7812024-11-11 16:45:53 -080080void checkPostCompleteStartup(sdbusplus::asio::connection& bus,
81 const std::string& host_instance)
John Wedigdd9478d2023-12-08 14:44:53 -080082{
John Wedig376d7812024-11-11 16:45:53 -080083 checkPostComplete(bus, OperatingSystemStateStandby, true, host_instance);
John Wedigdd9478d2023-12-08 14:44:53 -080084}
85
86/* Gets called when a GPIO state change is detected. */
John Wedig376d7812024-11-11 16:45:53 -080087void checkPostCompleteEvent(sdbusplus::asio::connection& bus,
88 const std::string& host_instance)
John Wedigdd9478d2023-12-08 14:44:53 -080089{
John Wedig376d7812024-11-11 16:45:53 -080090 checkPostComplete(bus, OperatingSystemStateInactive, false, host_instance);
John Wedigdd9478d2023-12-08 14:44:53 -080091}
92
John Wedig376d7812024-11-11 16:45:53 -080093int main(int argc, char** argv)
John Wedigdd9478d2023-12-08 14:44:53 -080094{
John Wedig376d7812024-11-11 16:45:53 -080095 absl::ParseCommandLine(argc, argv);
96 std::string host_label = absl::GetFlag(FLAGS_host_label);
97
John Wedigdd9478d2023-12-08 14:44:53 -080098 try
99 {
100 /* Setup connection to dbus. */
101 boost::asio::io_context io;
102 auto conn = sdbusplus::asio::connection(io);
103
104 /* check IPMI status at startup */
John Wedig376d7812024-11-11 16:45:53 -0800105 checkPostCompleteStartup(conn, host_label);
John Wedigdd9478d2023-12-08 14:44:53 -0800106 /*
107 * Set up an event handler to process Post Complete GPIO state changes.
108 */
109 boost::asio::steady_timer filterTimer(io);
110
111 auto match = std::make_unique<sdbusplus::bus::match_t>(
112 static_cast<sdbusplus::bus_t&>(conn),
113 std::format(
114 "type='signal',member='PropertiesChanged',path_namespace='"
115 "/xyz/openbmc_project/state/os',arg0namespace='{}'",
116 OperatingSystemStatusInterface),
117 [&](sdbusplus::message_t& message) {
Patrick Williamsc66ebc32024-08-16 15:21:56 -0400118 if (message.is_method_error())
John Wedigdd9478d2023-12-08 14:44:53 -0800119 {
Patrick Williamsc66ebc32024-08-16 15:21:56 -0400120 lg2::error("eventHandler callback method error");
John Wedigdd9478d2023-12-08 14:44:53 -0800121 return;
122 }
123
124 /*
Patrick Williamsc66ebc32024-08-16 15:21:56 -0400125 * This implicitly cancels the timer, if it's already pending.
126 * If there's a burst of events within a short period, we want
127 * to handle them all at once. So, we will wait this long for no
128 * more events to occur, before processing them.
John Wedigdd9478d2023-12-08 14:44:53 -0800129 */
Patrick Williamsc66ebc32024-08-16 15:21:56 -0400130 filterTimer.expires_from_now(std::chrono::seconds(1));
131
132 filterTimer.async_wait(
133 [&](const boost::system::error_code& ec) {
134 if (ec == boost::asio::error::operation_aborted)
135 {
136 /* we were canceled */
137 return;
138 }
139 if (ec)
140 {
141 lg2::error("timer error");
142 return;
143 }
144
145 /*
146 * Stop the bare metal active target if the post
147 * complete got deasserted.
148 */
John Wedig376d7812024-11-11 16:45:53 -0800149 checkPostCompleteEvent(conn, host_label);
Patrick Williamsc66ebc32024-08-16 15:21:56 -0400150 });
John Wedigdd9478d2023-12-08 14:44:53 -0800151 });
John Wedigdd9478d2023-12-08 14:44:53 -0800152
153 io.run();
154 return 0;
155 }
156 catch (const std::exception& e)
157 {
158 lg2::error(e.what(), "REDFISH_MESSAGE_ID",
159 std::string("OpenBMC.1.0.ServiceException"));
160
161 return 2;
162 }
163 return 1;
164}