#include #include #include #include namespace util { namespace dbus { //------------------------------------------------------------------------------ constexpr auto objectMapperService = "xyz.openbmc_project.ObjectMapper"; constexpr auto objectMapperPath = "/xyz/openbmc_project/object_mapper"; constexpr auto objectMapperInterface = "xyz.openbmc_project.ObjectMapper"; constexpr uint8_t terminusIdZero = 0; /** @brief Find the path and service that implements the given interface */ int find(const std::string& i_interface, std::string& o_path, std::string& o_service) { int rc = 1; // assume not success auto bus = sdbusplus::bus::new_default(); try { constexpr auto function = "GetSubTree"; auto method = bus.new_method_call(objectMapperService, objectMapperPath, objectMapperInterface, function); // Search the entire dbus tree for the specified interface method.append(std::string{"/"}, 0, std::vector{i_interface}); auto reply = bus.call(method); DBusSubTree response; reply.read(response); if (!response.empty()) { // Response is a map of object paths to a map of service, interfaces auto object = *(response.begin()); o_path = object.first; // return path o_service = object.second.begin()->first; // return service rc = 0; // success } } catch (const sdbusplus::exception::SdBusError& e) { trace::err("util::dbus::find exception"); std::string traceMsg = std::string(e.what()); trace::err(traceMsg.c_str()); } return rc; } /** @brief Find the service that implements the given object and interface */ int findService(const std::string& i_interface, const std::string& i_path, std::string& o_service) { int rc = 1; // assume not success auto bus = sdbusplus::bus::new_default(); try { constexpr auto function = "GetObject"; auto method = bus.new_method_call(objectMapperService, objectMapperPath, objectMapperInterface, function); // Find services that implement the object path, constrain the search // to the given interface. method.append(i_path, std::vector{i_interface}); auto reply = bus.call(method); // response is a map of service names to their interfaces std::map response; reply.read(response); if (!response.empty()) { // return the service o_service = response.begin()->first; rc = 0; // success } } catch (const sdbusplus::exception::SdBusError& e) { trace::err("util::dbus::map exception"); std::string traceMsg = std::string(e.what()); trace::err(traceMsg.c_str()); } return rc; } /** @brief Read a property from a dbus object interface */ int getProperty(const std::string& i_interface, const std::string& i_path, const std::string& i_service, const std::string& i_property, DBusValue& o_response) { int rc = 1; // assume not success auto bus = sdbusplus::bus::new_default(); try { constexpr auto interface = "org.freedesktop.DBus.Properties"; constexpr auto function = "Get"; // calling the get property method auto method = bus.new_method_call(i_service.c_str(), i_path.c_str(), interface, function); method.append(i_interface, i_property); auto reply = bus.call(method); // returning the property value reply.read(o_response); rc = 0; // success } catch (const sdbusplus::exception::SdBusError& e) { trace::err("util::dbus::getProperty exception"); std::string traceMsg = std::string(e.what()); trace::err(traceMsg.c_str()); } return rc; } /** @brief Get the IBM compatible names defined for this system */ std::vector systemNames() { std::vector names; constexpr auto interface = "xyz.openbmc_project.Configuration.IBMCompatibleSystem"; DBusService service; DBusPath path; // find a dbus object and path that implements the interface if (0 == find(interface, path, service)) { DBusValue value; // compatible system names are implemented as a property constexpr auto property = "Names"; if (0 == getProperty(interface, path, service, property, value)) { // return value is a variant, names are in the vector names = std::get>(value); } } return names; } /** @brief Transition the host state */ void transitionHost(const HostState i_hostState) { try { // We will be transitioning host by starting appropriate dbus target std::string target = "obmc-host-quiesce@0.target"; // quiesce is default // crash (mpipl) mode state requested if (HostState::Crash == i_hostState) { target = "obmc-host-crash@0.target"; } // If the system is powering off for any reason (ex. we hit a PHYP TI // in the graceful power off path), then we want to call the immediate // power off target if (hostRunningState() == HostRunningState::Stopping) { trace::inf("system is powering off so no dump will be requested"); target = "obmc-chassis-hard-poweroff@0.target"; } auto bus = sdbusplus::bus::new_system(); auto method = bus.new_method_call( "org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "StartUnit"); method.append(target); // target unit to start method.append("replace"); // mode = replace conflicting queued jobs bus.call_noreply(method); // start the service } catch (const sdbusplus::exception::SdBusError& e) { trace::err("util::dbus::transitionHost exception"); std::string traceMsg = std::string(e.what()); trace::err(traceMsg.c_str()); } } /** @brief Read state of autoRebootEnabled property via dbus */ bool autoRebootEnabled() { // Assume true in case autoRebootEnbabled property is not available bool autoReboot = true; constexpr auto interface = "xyz.openbmc_project.Control.Boot.RebootPolicy"; DBusService service; // will find this DBusPath path; // will find this // find a dbus object and path that implements the interface if (0 == find(interface, path, service)) { DBusValue value; // autoreboot policy is implemented as a property constexpr auto property = "AutoReboot"; if (0 == getProperty(interface, path, service, property, value)) { // return value is a variant, autoreboot policy is boolean autoReboot = std::get(value); } } return autoReboot; } /** @brief Get the running state of the host */ HostRunningState hostRunningState() { // assume not able to get host running state HostRunningState host = HostRunningState::Unknown; constexpr auto interface = "xyz.openbmc_project.State.Boot.Progress"; DBusService service; DBusPath path; // find a dbus object and path that implements the interface if (0 == find(interface, path, service)) { DBusValue value; // boot progress is implemented as a property constexpr auto property = "BootProgress"; if (0 == getProperty(interface, path, service, property, value)) { // return value is a variant, progress is in the vector of strings std::string bootProgress(std::get(value)); // convert boot progress to host state using BootProgress = sdbusplus::xyz::openbmc_project::State::Boot:: server::Progress::ProgressStages; BootProgress stage = sdbusplus::xyz::openbmc_project::State::Boot:: server::Progress::convertProgressStagesFromString(bootProgress); if ((stage == BootProgress::SystemInitComplete) || (stage == BootProgress::OSRunning)) { host = HostRunningState::Started; } else { host = HostRunningState::NotStarted; } } } // See if host in process of powering off when we get NotStarted if (host == HostRunningState::NotStarted) { constexpr auto hostStateInterface = "xyz.openbmc_project.State.Host"; if (0 == find(hostStateInterface, path, service)) { DBusValue value; // current host state is implemented as a property constexpr auto stateProperty = "CurrentHostState"; if (0 == getProperty(hostStateInterface, path, service, stateProperty, value)) { // return value is a variant, host state is in the vector of // strings std::string hostState(std::get(value)); if (hostState == "xyz.openbmc_project.State.Host.HostState." "TransitioningToOff") { host = HostRunningState::Stopping; } } } } return host; } /** @brief Read state of dumpPolicyEnabled property via dbus */ bool dumpPolicyEnabled() { // Assume true In case dumpPolicyEnabled property is not available bool dumpPolicyEnabled = true; constexpr auto interface = "xyz.openbmc_project.Object.Enable"; constexpr auto path = "/xyz/openbmc_project/dump/system_dump_policy"; DBusService service; // will find this // find a dbus object and path that implements the interface if (0 == findService(interface, path, service)) { DBusValue value; // autoreboot policy is implemented as a property constexpr auto property = "Enabled"; if (0 == getProperty(interface, path, service, property, value)) { // return value is a variant, dump policy enabled is a boolean dumpPolicyEnabled = std::get(value); } } return dumpPolicyEnabled; } /** @brief Create a PEL */ uint32_t createPel(const std::string& i_message, const std::string& i_severity, std::map& io_additional, const std::vector& i_ffdc) { // CreatePELWithFFDCFiles returns plid int plid = 0; // Sdbus call specifics constexpr auto interface = "org.open_power.Logging.PEL"; constexpr auto path = "/xyz/openbmc_project/logging"; // we need to find the service implementing the interface util::dbus::DBusService service; if (0 == findService(interface, path, service)) { try { constexpr auto function = "CreatePELWithFFDCFiles"; // The "Create" method requires manually adding the process ID. io_additional["_PID"] = std::to_string(getpid()); // create dbus method auto bus = sdbusplus::bus::new_system(); sdbusplus::message_t method = bus.new_method_call(service.c_str(), path, interface, function); // append additional dbus call paramaters method.append(i_message, i_severity, io_additional, i_ffdc); // using system dbus auto response = bus.call(method); // reply will be tuple containing bmc log id, platform log id std::tuple reply = {0, 0}; // parse dbus response into reply response.read(reply); plid = std::get<1>(reply); // platform log id is tuple "second" } catch (const sdbusplus::exception::SdBusError& e) { trace::err("createPel exception"); trace::err(e.what()); } } return plid; // platform log id or 0 } MachineType getMachineType() { // default to Rainier 2S4U MachineType machineType = MachineType::Rainier_2S4U; // The return value of the dbus operation is a vector of 4 uint8_ts std::vector ids; constexpr auto interface = "com.ibm.ipzvpd.VSBP"; DBusService service; DBusPath path; if (0 == find(interface, path, service)) { DBusValue value; // Machine ID is given from the "IM" keyword constexpr auto property = "IM"; if (0 == getProperty(interface, path, service, property, value)) { // return value is a variant, ID value is a vector of 4 uint8_ts ids = std::get>(value); // Convert the returned ID value to a hex string to determine // machine type. The hex values corresponding to the machine type // are defined in /openbmc/openpower-vpd-parser/const.hpp // RAINIER_2S4U == 0x50001000 // RAINIER_2S2U == 0x50001001 // RAINIER_1S4U == 0x50001002 // RAINIER_1S2U == 0x50001003 // EVEREST == 0x50003000 // BONNELL == 0x50004000 try { // Format the vector into a single hex string to compare to. std::string hexId = std::format("0x{:02x}{:02x}{:02x}{:02x}", ids.at(0), ids.at(1), ids.at(2), ids.at(3)); std::map typeMap = { {"0x50001000", MachineType::Rainier_2S4U}, {"0x50001001", MachineType::Rainier_2S2U}, {"0x50001002", MachineType::Rainier_1S4U}, {"0x50001003", MachineType::Rainier_1S2U}, {"0x50003000", MachineType::Everest}, {"0x50004000", MachineType::Bonnell}, }; machineType = typeMap.at(hexId); } catch (const std::out_of_range& e) { trace::err("Out of range exception caught from returned " "machine ID."); for (const auto& id : ids) { trace::err("Returned Machine ID value: 0x%x", id); } throw; } } } else { throw std::invalid_argument( "Unable to find dbus service to get machine type."); } return machineType; } /** @brief Get list of state effecter PDRs */ bool getStateEffecterPdrs(std::vector>& pdrList, uint16_t stateSetId) { constexpr auto service = "xyz.openbmc_project.PLDM"; constexpr auto path = "/xyz/openbmc_project/pldm"; constexpr auto interface = "xyz.openbmc_project.PLDM.PDR"; constexpr auto function = "FindStateEffecterPDR"; constexpr uint16_t PLDM_ENTITY_PROC = 135; try { // create dbus method auto bus = sdbusplus::bus::new_default(); sdbusplus::message_t method = bus.new_method_call(service, path, interface, function); // append additional method data method.append(terminusIdZero, PLDM_ENTITY_PROC, stateSetId); // request PDRs auto reply = bus.call(method); reply.read(pdrList); } catch (const sdbusplus::exception_t& e) { trace::err("failed to find state effecter PDRs"); trace::err(e.what()); return false; } return true; } /** @brief Get list of state sensor PDRs */ bool getStateSensorPdrs(std::vector>& pdrList, uint16_t stateSetId) { constexpr auto service = "xyz.openbmc_project.PLDM"; constexpr auto path = "/xyz/openbmc_project/pldm"; constexpr auto interface = "xyz.openbmc_project.PLDM.PDR"; constexpr auto function = "FindStateSensorPDR"; constexpr uint16_t PLDM_ENTITY_PROC = 135; try { // create dbus method auto bus = sdbusplus::bus::new_default(); sdbusplus::message_t method = bus.new_method_call(service, path, interface, function); // append additional method data method.append(terminusIdZero, PLDM_ENTITY_PROC, stateSetId); // request PDRs auto reply = bus.call(method); reply.read(pdrList); } catch (const sdbusplus::exception_t& e) { trace::err("failed to find state sensor PDRs"); trace::err(e.what()); return false; } return true; } /** @brief Get MCTP instance associated with endpoint */ bool getMctpInstance(uint8_t& mctpInstance, uint8_t Eid) { constexpr auto service = "xyz.openbmc_project.PLDM"; constexpr auto path = "/xyz/openbmc_project/pldm"; constexpr auto interface = "xyz.openbmc_project.PLDM.Requester"; constexpr auto function = "GetInstanceId"; try { // create dbus method auto bus = sdbusplus::bus::new_default(); sdbusplus::message_t method = bus.new_method_call(service, path, interface, function); // append endpoint ID method.append(Eid); // request MCTP instance ID auto reply = bus.call(method); reply.read(mctpInstance); } catch (const sdbusplus::exception_t& e) { trace::err("get MCTP instance exception"); trace::err(e.what()); return false; } return true; } /** @brief Determine if power fault was detected */ bool powerFault() { // power fault based on pgood property int32_t pgood = 0; // assume fault or unknown constexpr auto interface = "org.openbmc.control.Power"; DBusService service; DBusPath path; // find a dbus service and object path that implements the interface if (0 == find(interface, path, service)) { DBusValue value; // chassis pgood is implemented as a property constexpr auto property = "pgood"; if (0 == getProperty(interface, path, service, property, value)) { // return value is a variant, int32 == 1 for pgood OK pgood = std::get(value); } } return pgood != 1 ? true : false; // if not pgood then power fault } } // namespace dbus } // namespace util