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