1 2 #include <boost/asio/io_context.hpp> 3 #include <boost/asio/steady_timer.hpp> 4 #include <phosphor-logging/lg2.hpp> 5 #include <sdbusplus/asio/connection.hpp> 6 #include <sdbusplus/asio/property.hpp> 7 #include <sdbusplus/bus.hpp> 8 #include <sdbusplus/bus/match.hpp> 9 10 const constexpr char* OperatingSystemService = 11 "xyz.openbmc_project.State.OperatingSystem"; 12 const constexpr char* OperatingSystemPath = "/xyz/openbmc_project/state/os"; 13 const constexpr char* OperatingSystemStatusInterface = 14 "xyz.openbmc_project.State.OperatingSystem.Status"; 15 const constexpr char* OperatingSystemStateProperty = "OperatingSystemState"; 16 const constexpr char* OperatingSystemStateStandby = 17 "xyz.openbmc_project.State.OperatingSystem.Status.OSStatus.Standby"; 18 const constexpr char* OperatingSystemStateInactive = 19 "xyz.openbmc_project.State.OperatingSystem.Status.OSStatus.Inactive"; 20 const constexpr char* BareMetalActiveTarget = "gbmc-bare-metal-active.target"; 21 22 const constexpr char* SystemdService = "org.freedesktop.systemd1"; 23 const constexpr char* SystemdManagerObject = "/org/freedesktop/systemd1"; 24 const constexpr char* SystemdManagerInterface = 25 "org.freedesktop.systemd1.Manager"; 26 27 void setUnitStatus(sdbusplus::asio::connection& bus, bool status) 28 { 29 auto method = bus.new_method_call(SystemdService, SystemdManagerObject, 30 SystemdManagerInterface, 31 status ? "StartUnit" : "StopUnit"); 32 method.append(BareMetalActiveTarget, "replace"); 33 34 bus.call(method); 35 } 36 37 void checkPostComplete(sdbusplus::asio::connection& bus, 38 const std::string& state, bool action) 39 { 40 sdbusplus::asio::getProperty<std::string>( 41 bus, OperatingSystemService, OperatingSystemPath, 42 OperatingSystemStatusInterface, OperatingSystemStateProperty, 43 [&, state, action](const boost::system::error_code& ec, 44 const std::string& postCompleteState) { 45 if (ec) 46 { 47 lg2::error("Error when checking Post Complete GPIO state"); 48 return; 49 } 50 51 lg2::info("Post Complete state is {STATE}", "STATE", 52 postCompleteState); 53 54 /* 55 * If state is Standby, enable the bare-metal-active systemd 56 * target. 57 * If state is Inactive, no-op cause IPMI is enabled by default. 58 */ 59 if (postCompleteState == state) 60 { 61 setUnitStatus(bus, action); 62 } 63 }); 64 } 65 66 /* This only gets called once on startup. */ 67 void checkPostCompleteStartup(sdbusplus::asio::connection& bus) 68 { 69 checkPostComplete(bus, OperatingSystemStateStandby, true); 70 } 71 72 /* Gets called when a GPIO state change is detected. */ 73 void checkPostCompleteEvent(sdbusplus::asio::connection& bus) 74 { 75 checkPostComplete(bus, OperatingSystemStateInactive, false); 76 } 77 78 int main() 79 { 80 try 81 { 82 /* Setup connection to dbus. */ 83 boost::asio::io_context io; 84 auto conn = sdbusplus::asio::connection(io); 85 86 /* check IPMI status at startup */ 87 checkPostCompleteStartup(conn); 88 /* 89 * Set up an event handler to process Post Complete GPIO state changes. 90 */ 91 boost::asio::steady_timer filterTimer(io); 92 93 auto match = std::make_unique<sdbusplus::bus::match_t>( 94 static_cast<sdbusplus::bus_t&>(conn), 95 std::format( 96 "type='signal',member='PropertiesChanged',path_namespace='" 97 "/xyz/openbmc_project/state/os',arg0namespace='{}'", 98 OperatingSystemStatusInterface), 99 [&](sdbusplus::message_t& message) { 100 if (message.is_method_error()) 101 { 102 lg2::error("eventHandler callback method error"); 103 return; 104 } 105 106 /* 107 * This implicitly cancels the timer, if it's already pending. 108 * If there's a burst of events within a short period, we want 109 * to handle them all at once. So, we will wait this long for no 110 * more events to occur, before processing them. 111 */ 112 filterTimer.expires_from_now(std::chrono::seconds(1)); 113 114 filterTimer.async_wait( 115 [&](const boost::system::error_code& ec) { 116 if (ec == boost::asio::error::operation_aborted) 117 { 118 /* we were canceled */ 119 return; 120 } 121 if (ec) 122 { 123 lg2::error("timer error"); 124 return; 125 } 126 127 /* 128 * Stop the bare metal active target if the post 129 * complete got deasserted. 130 */ 131 checkPostCompleteEvent(conn); 132 }); 133 }); 134 135 io.run(); 136 return 0; 137 } 138 catch (const std::exception& e) 139 { 140 lg2::error(e.what(), "REDFISH_MESSAGE_ID", 141 std::string("OpenBMC.1.0.ServiceException")); 142 143 return 2; 144 } 145 return 1; 146 } 147