1dd9478ddSJohn Wedig 2376d781cSJohn Wedig #include "absl/flags/flag.h" 3376d781cSJohn Wedig #include "absl/flags/parse.h" 4376d781cSJohn Wedig 5815c8873SJohn Wedig #include "host_gpio_monitor_conf.hpp" 6815c8873SJohn Wedig 7*c9a43a30SJohn Wedig #include <systemd/sd-daemon.h> 8*c9a43a30SJohn Wedig 9dd9478ddSJohn Wedig #include <boost/asio/io_context.hpp> 10dd9478ddSJohn Wedig #include <boost/asio/steady_timer.hpp> 11dd9478ddSJohn Wedig #include <phosphor-logging/lg2.hpp> 12dd9478ddSJohn Wedig #include <sdbusplus/asio/connection.hpp> 13dd9478ddSJohn Wedig #include <sdbusplus/asio/property.hpp> 14dd9478ddSJohn Wedig #include <sdbusplus/bus.hpp> 15dd9478ddSJohn Wedig #include <sdbusplus/bus/match.hpp> 16dd9478ddSJohn Wedig 17376d781cSJohn Wedig #include <format> 18376d781cSJohn Wedig 19376d781cSJohn Wedig ABSL_FLAG(std::string, host_label, "0", 20376d781cSJohn Wedig "Label for the host in question. Usually this is an integer."); 21376d781cSJohn Wedig 22dd9478ddSJohn Wedig const constexpr char* OperatingSystemStateInactive = 23dd9478ddSJohn Wedig "xyz.openbmc_project.State.OperatingSystem.Status.OSStatus.Inactive"; 24376d781cSJohn Wedig const constexpr char* BareMetalActiveTargetTemplate = 25376d781cSJohn Wedig "gbmc-bare-metal-active@{}.target"; 26dd9478ddSJohn Wedig 27dd9478ddSJohn Wedig const constexpr char* SystemdService = "org.freedesktop.systemd1"; 28dd9478ddSJohn Wedig const constexpr char* SystemdManagerObject = "/org/freedesktop/systemd1"; 29dd9478ddSJohn Wedig const constexpr char* SystemdManagerInterface = 30dd9478ddSJohn Wedig "org.freedesktop.systemd1.Manager"; 31dd9478ddSJohn Wedig 32376d781cSJohn Wedig void setUnitStatus(sdbusplus::asio::connection& bus, bool status, 33376d781cSJohn Wedig const std::string& host_instance) 34dd9478ddSJohn Wedig { 35dd9478ddSJohn Wedig auto method = bus.new_method_call(SystemdService, SystemdManagerObject, 36dd9478ddSJohn Wedig SystemdManagerInterface, 37dd9478ddSJohn Wedig status ? "StartUnit" : "StopUnit"); 38376d781cSJohn Wedig method.append(std::format(BareMetalActiveTargetTemplate, host_instance), 39376d781cSJohn Wedig "replace"); 40dd9478ddSJohn Wedig 41dd9478ddSJohn Wedig bus.call(method); 42dd9478ddSJohn Wedig } 43dd9478ddSJohn Wedig 44dd9478ddSJohn Wedig void checkPostComplete(sdbusplus::asio::connection& bus, 45376d781cSJohn Wedig const std::string& state, bool action, 46376d781cSJohn Wedig const std::string& host_instance) 47dd9478ddSJohn Wedig { 48dd9478ddSJohn Wedig sdbusplus::asio::getProperty<std::string>( 49815c8873SJohn Wedig bus, std::format(DBUS_SERVICE_NAME, host_instance), 50815c8873SJohn Wedig std::format(DBUS_OBJECT_PATH, host_instance), DBUS_INTERFACE, 51815c8873SJohn Wedig DBUS_PROPERTY_NAME, 528800984dSYuxiao Zhang [&, state, action](const boost::system::error_code& ec, 53dd9478ddSJohn Wedig const std::string& postCompleteState) { 54dd9478ddSJohn Wedig if (ec) 55dd9478ddSJohn Wedig { 56dd9478ddSJohn Wedig lg2::error("Error when checking Post Complete GPIO state"); 57dd9478ddSJohn Wedig return; 58dd9478ddSJohn Wedig } 59dd9478ddSJohn Wedig 60c66ebc35SPatrick Williams lg2::info("Post Complete state is {STATE}", "STATE", 61c66ebc35SPatrick Williams postCompleteState); 628800984dSYuxiao Zhang 63dd9478ddSJohn Wedig /* 64815c8873SJohn Wedig * If the host OS is running (e.g. OperatingSystemState is Standby), 65815c8873SJohn Wedig * enable the bare-metal-active systemd target. 66815c8873SJohn Wedig * If the host CPU is in reset (e.g. OperatingSystemState is 67815c8873SJohn Wedig * Inactive), no-op cause IPMI is enabled by default. 68dd9478ddSJohn Wedig */ 69dd9478ddSJohn Wedig if (postCompleteState == state) 70dd9478ddSJohn Wedig { 71376d781cSJohn Wedig setUnitStatus(bus, action, host_instance); 72dd9478ddSJohn Wedig } 73dd9478ddSJohn Wedig }); 74dd9478ddSJohn Wedig } 75dd9478ddSJohn Wedig 76dd9478ddSJohn Wedig /* This only gets called once on startup. */ 77376d781cSJohn Wedig void checkPostCompleteStartup(sdbusplus::asio::connection& bus, 78376d781cSJohn Wedig const std::string& host_instance) 79dd9478ddSJohn Wedig { 80815c8873SJohn Wedig checkPostComplete(bus, DBUS_PROPERTY_HOST_RUNNING_VALUE, true, 81815c8873SJohn Wedig host_instance); 82dd9478ddSJohn Wedig } 83dd9478ddSJohn Wedig 84dd9478ddSJohn Wedig /* Gets called when a GPIO state change is detected. */ 85376d781cSJohn Wedig void checkPostCompleteEvent(sdbusplus::asio::connection& bus, 86376d781cSJohn Wedig const std::string& host_instance) 87dd9478ddSJohn Wedig { 88815c8873SJohn Wedig checkPostComplete(bus, DBUS_PROPERTY_HOST_IN_RESET_VALUE, false, 89815c8873SJohn Wedig host_instance); 90dd9478ddSJohn Wedig } 91dd9478ddSJohn Wedig 92376d781cSJohn Wedig int main(int argc, char** argv) 93dd9478ddSJohn Wedig { 94376d781cSJohn Wedig absl::ParseCommandLine(argc, argv); 95376d781cSJohn Wedig std::string host_label = absl::GetFlag(FLAGS_host_label); 96376d781cSJohn Wedig 97dd9478ddSJohn Wedig try 98dd9478ddSJohn Wedig { 99dd9478ddSJohn Wedig /* Setup connection to dbus. */ 100dd9478ddSJohn Wedig boost::asio::io_context io; 101dd9478ddSJohn Wedig auto conn = sdbusplus::asio::connection(io); 102dd9478ddSJohn Wedig 103dd9478ddSJohn Wedig /* check IPMI status at startup */ 104376d781cSJohn Wedig checkPostCompleteStartup(conn, host_label); 105*c9a43a30SJohn Wedig 106*c9a43a30SJohn Wedig /* Notify that the service is done starting up. */ 107*c9a43a30SJohn Wedig sd_notify(0, "READY=1"); 108*c9a43a30SJohn Wedig 109dd9478ddSJohn Wedig /* 110dd9478ddSJohn Wedig * Set up an event handler to process Post Complete GPIO state changes. 111dd9478ddSJohn Wedig */ 112dd9478ddSJohn Wedig boost::asio::steady_timer filterTimer(io); 113dd9478ddSJohn Wedig 114815c8873SJohn Wedig /* 115815c8873SJohn Wedig * Prepare object path we want to monitor, substituting in the host 116815c8873SJohn Wedig * label, if needed. 117815c8873SJohn Wedig */ 118815c8873SJohn Wedig std::string objectPath = std::format(DBUS_OBJECT_PATH, host_label); 119815c8873SJohn Wedig 120dd9478ddSJohn Wedig auto match = std::make_unique<sdbusplus::bus::match_t>( 121dd9478ddSJohn Wedig static_cast<sdbusplus::bus_t&>(conn), 122dd9478ddSJohn Wedig std::format( 123dd9478ddSJohn Wedig "type='signal',member='PropertiesChanged',path_namespace='" 124815c8873SJohn Wedig "{}',arg0namespace='{}'", 125815c8873SJohn Wedig objectPath, DBUS_INTERFACE), 126dd9478ddSJohn Wedig [&](sdbusplus::message_t& message) { 127dd9478ddSJohn Wedig if (message.is_method_error()) 128dd9478ddSJohn Wedig { 129dd9478ddSJohn Wedig lg2::error("eventHandler callback method error"); 130dd9478ddSJohn Wedig return; 131dd9478ddSJohn Wedig } 132dd9478ddSJohn Wedig 133dd9478ddSJohn Wedig /* 134dd9478ddSJohn Wedig * This implicitly cancels the timer, if it's already pending. 135dd9478ddSJohn Wedig * If there's a burst of events within a short period, we want 136dd9478ddSJohn Wedig * to handle them all at once. So, we will wait this long for no 137dd9478ddSJohn Wedig * more events to occur, before processing them. 138dd9478ddSJohn Wedig */ 1393aed6961SJohn Wedig filterTimer.expires_from_now(std::chrono::milliseconds(100)); 140dd9478ddSJohn Wedig 141c66ebc35SPatrick Williams filterTimer.async_wait( 142c66ebc35SPatrick Williams [&](const boost::system::error_code& ec) { 143dd9478ddSJohn Wedig if (ec == boost::asio::error::operation_aborted) 144dd9478ddSJohn Wedig { 145dd9478ddSJohn Wedig /* we were canceled */ 146dd9478ddSJohn Wedig return; 147dd9478ddSJohn Wedig } 148dd9478ddSJohn Wedig if (ec) 149dd9478ddSJohn Wedig { 150dd9478ddSJohn Wedig lg2::error("timer error"); 151dd9478ddSJohn Wedig return; 152dd9478ddSJohn Wedig } 153dd9478ddSJohn Wedig 154dd9478ddSJohn Wedig /* 155c66ebc35SPatrick Williams * Stop the bare metal active target if the post 156c66ebc35SPatrick Williams * complete got deasserted. 157dd9478ddSJohn Wedig */ 158376d781cSJohn Wedig checkPostCompleteEvent(conn, host_label); 159dd9478ddSJohn Wedig }); 160dd9478ddSJohn Wedig }); 161dd9478ddSJohn Wedig 162dd9478ddSJohn Wedig io.run(); 163dd9478ddSJohn Wedig return 0; 164dd9478ddSJohn Wedig } 165dd9478ddSJohn Wedig catch (const std::exception& e) 166dd9478ddSJohn Wedig { 167dd9478ddSJohn Wedig lg2::error(e.what(), "REDFISH_MESSAGE_ID", 168dd9478ddSJohn Wedig std::string("OpenBMC.1.0.ServiceException")); 169dd9478ddSJohn Wedig 170dd9478ddSJohn Wedig return 2; 171dd9478ddSJohn Wedig } 172dd9478ddSJohn Wedig return 1; 173dd9478ddSJohn Wedig } 174