1 #pragma once 2 3 #include "config.h" 4 5 #include "settings.hpp" 6 #include "xyz/openbmc_project/State/Host/server.hpp" 7 8 #include <cereal/access.hpp> 9 #include <cereal/cereal.hpp> 10 #include <phosphor-logging/lg2.hpp> 11 #include <sdbusplus/bus.hpp> 12 #include <xyz/openbmc_project/Control/Boot/RebootAttempts/server.hpp> 13 #include <xyz/openbmc_project/State/Boot/Progress/server.hpp> 14 #include <xyz/openbmc_project/State/OperatingSystem/Status/server.hpp> 15 16 #include <filesystem> 17 #include <functional> 18 #include <string> 19 20 namespace phosphor 21 { 22 namespace state 23 { 24 namespace manager 25 { 26 27 using HostInherit = sdbusplus::server::object::object< 28 sdbusplus::xyz::openbmc_project::State::server::Host, 29 sdbusplus::xyz::openbmc_project::State::Boot::server::Progress, 30 sdbusplus::xyz::openbmc_project::Control::Boot::server::RebootAttempts, 31 sdbusplus::xyz::openbmc_project::State::OperatingSystem::server::Status>; 32 33 PHOSPHOR_LOG2_USING; 34 35 namespace sdbusRule = sdbusplus::bus::match::rules; 36 namespace fs = std::filesystem; 37 38 /** @class Host 39 * @brief OpenBMC host state management implementation. 40 * @details A concrete implementation for xyz.openbmc_project.State.Host 41 * DBus API. 42 */ 43 class Host : public HostInherit 44 { 45 public: 46 /** @brief Constructs Host State Manager 47 * 48 * @note This constructor passes 'true' to the base class in order to 49 * defer dbus object registration until we can run 50 * determineInitialState() and set our properties 51 * 52 * @param[in] bus - The Dbus bus object 53 * @param[in] objPath - The Dbus object path 54 * @param[in] id - The Host id 55 */ 56 Host(sdbusplus::bus::bus& bus, const char* objPath, size_t id) : 57 HostInherit(bus, objPath, true), bus(bus), 58 systemdSignalJobRemoved( 59 bus, 60 sdbusRule::type::signal() + sdbusRule::member("JobRemoved") + 61 sdbusRule::path("/org/freedesktop/systemd1") + 62 sdbusRule::interface("org.freedesktop.systemd1.Manager"), 63 std::bind(std::mem_fn(&Host::sysStateChangeJobRemoved), this, 64 std::placeholders::_1)), 65 systemdSignalJobNew( 66 bus, 67 sdbusRule::type::signal() + sdbusRule::member("JobNew") + 68 sdbusRule::path("/org/freedesktop/systemd1") + 69 sdbusRule::interface("org.freedesktop.systemd1.Manager"), 70 std::bind(std::mem_fn(&Host::sysStateChangeJobNew), this, 71 std::placeholders::_1)), 72 settings(bus, id), id(id) 73 { 74 // Enable systemd signals 75 subscribeToSystemdSignals(); 76 77 // create map of target name base on host id 78 createSystemdTargetMaps(); 79 80 // Will throw exception on fail 81 determineInitialState(); 82 83 attemptsLeft(BOOT_COUNT_MAX_ALLOWED); 84 85 // We deferred this until we could get our property correct 86 this->emit_object_added(); 87 } 88 89 /** @brief Set value of HostTransition */ 90 Transition requestedHostTransition(Transition value) override; 91 92 /** @brief Set Value for boot progress */ 93 ProgressStages bootProgress(ProgressStages value) override; 94 95 /** @brief Set Value for Operating System Status */ 96 OSStatus operatingSystemState(OSStatus value) override; 97 98 /** @brief Set value of CurrentHostState */ 99 HostState currentHostState(HostState value) override; 100 101 /** 102 * @brief Set host reboot count to default 103 * 104 * OpenBMC software controls the number of allowed reboot attempts so 105 * any external set request of this property will be overridden by 106 * this function and set to the default. 107 * 108 * The only code responsible for decrementing the boot count resides 109 * within this process and that will use the sub class interface 110 * directly 111 * 112 * @param[in] value - Reboot count value, will be ignored 113 * 114 * @return Default number of reboot attempts left 115 */ 116 uint32_t attemptsLeft(uint32_t value) override 117 { 118 // value is ignored in this implementation 119 (void)(value); 120 debug("External request to reset reboot count"); 121 return (sdbusplus::xyz::openbmc_project::Control::Boot::server:: 122 RebootAttempts::attemptsLeft(BOOT_COUNT_MAX_ALLOWED)); 123 } 124 125 private: 126 /** 127 * @brief subscribe to the systemd signals 128 * 129 * This object needs to capture when it's systemd targets complete 130 * so it can keep it's state updated 131 * 132 **/ 133 void subscribeToSystemdSignals(); 134 135 /** 136 * @brief Determine initial host state and set internally 137 * 138 * @return Will throw exceptions on failure 139 **/ 140 void determineInitialState(); 141 142 /** 143 * create systemd target instance names and mapping table 144 **/ 145 void createSystemdTargetMaps(); 146 147 /** @brief Execute the transition request 148 * 149 * This function assumes the state has been validated and the host 150 * is in an appropriate state for the transition to be started. 151 * 152 * @param[in] tranReq - Transition requested 153 */ 154 void executeTransition(Transition tranReq); 155 156 /** 157 * @brief Determine if target is active 158 * 159 * This function determines if the target is active and 160 * helps prevent misleading log recorded states. 161 * 162 * @param[in] target - Target string to check on 163 * 164 * @return boolean corresponding to state active 165 **/ 166 bool stateActive(const std::string& target); 167 168 /** 169 * @brief Determine if auto reboot flag is set 170 * 171 * @return boolean corresponding to current auto_reboot setting 172 **/ 173 bool isAutoReboot(); 174 175 /** @brief Check if systemd state change is relevant to this object 176 * 177 * Instance specific interface to handle the detected systemd state 178 * change 179 * 180 * @param[in] msg - Data associated with subscribed signal 181 * 182 */ 183 void sysStateChangeJobRemoved(sdbusplus::message::message& msg); 184 185 /** @brief Check if JobNew systemd signal is relevant to this object 186 * 187 * In certain instances phosphor-state-manager needs to monitor for the 188 * entry into a systemd target. This function will be used for these cases. 189 * 190 * Instance specific interface to handle the detected systemd state 191 * change 192 * 193 * @param[in] msg - Data associated with subscribed signal 194 * 195 */ 196 void sysStateChangeJobNew(sdbusplus::message::message& msg); 197 198 /** @brief Decrement reboot count 199 * 200 * This is used internally to this application to decrement the boot 201 * count on each boot attempt. The host will use the external 202 * attemptsLeft() interface to reset the count when a boot is successful 203 * 204 * @return number of reboot count attempts left 205 */ 206 uint32_t decrementRebootCount(); 207 208 // Allow cereal class access to allow these next two function to be 209 // private 210 friend class cereal::access; 211 212 /** @brief Function required by Cereal to perform serialization. 213 * 214 * @tparam Archive - Cereal archive type (binary in our case). 215 * @param[in] archive - reference to Cereal archive. 216 * @param[in] version - Class version that enables handling 217 * a serialized data across code levels 218 */ 219 template <class Archive> 220 void save(Archive& archive, const std::uint32_t version) const 221 { 222 // version is not used currently 223 (void)(version); 224 archive(convertForMessage(sdbusplus::xyz::openbmc_project::State:: 225 server::Host::requestedHostTransition()), 226 convertForMessage(sdbusplus::xyz::openbmc_project::State::Boot:: 227 server::Progress::bootProgress()), 228 convertForMessage( 229 sdbusplus::xyz::openbmc_project::State::OperatingSystem:: 230 server::Status::operatingSystemState())); 231 } 232 233 /** @brief Function required by Cereal to perform deserialization. 234 * 235 * @tparam Archive - Cereal archive type (binary in our case). 236 * @param[in] archive - reference to Cereal archive. 237 * @param[in] version - Class version that enables handling 238 * a serialized data across code levels 239 */ 240 template <class Archive> 241 void load(Archive& archive, const std::uint32_t version) 242 { 243 // version is not used currently 244 (void)(version); 245 std::string reqTranState; 246 std::string bootProgress; 247 std::string osState; 248 archive(reqTranState, bootProgress, osState); 249 auto reqTran = Host::convertTransitionFromString(reqTranState); 250 // When restoring, set the requested state with persistent value 251 // but don't call the override which would execute it 252 sdbusplus::xyz::openbmc_project::State::server::Host:: 253 requestedHostTransition(reqTran); 254 sdbusplus::xyz::openbmc_project::State::Boot::server::Progress:: 255 bootProgress(Host::convertProgressStagesFromString(bootProgress)); 256 sdbusplus::xyz::openbmc_project::State::OperatingSystem::server:: 257 Status::operatingSystemState( 258 Host::convertOSStatusFromString(osState)); 259 } 260 261 /** @brief Serialize and persist requested host state 262 * 263 * @param[in] dir - pathname of file where the serialized host state will 264 * be placed. 265 * 266 * @return fs::path - pathname of persisted requested host state. 267 */ 268 fs::path serialize(const fs::path& dir = fs::path(HOST_STATE_PERSIST_PATH)); 269 270 /** @brief Deserialze a persisted requested host state. 271 * 272 * @param[in] path - pathname of persisted host state file 273 * 274 * @return bool - true if the deserialization was successful, false 275 * otherwise. 276 */ 277 bool deserialize(const fs::path& path); 278 279 /** 280 * @brief Get target name of a HostState 281 * 282 * @param[in] state - The state of the host 283 * 284 * @return string - systemd target name of the state 285 */ 286 const std::string& getTarget(HostState state); 287 288 /** 289 * @brief Get target name of a TransitionRequest 290 * 291 * @param[in] tranReq - Transition requested 292 * 293 * @return string - systemd target name of Requested transition 294 */ 295 const std::string& getTarget(Transition tranReq); 296 297 /** @brief Persistent sdbusplus DBus bus connection. */ 298 sdbusplus::bus::bus& bus; 299 300 /** @brief Used to subscribe to dbus systemd JobRemoved signal **/ 301 sdbusplus::bus::match_t systemdSignalJobRemoved; 302 303 /** @brief Used to subscribe to dbus systemd JobNew signal **/ 304 sdbusplus::bus::match_t systemdSignalJobNew; 305 306 // Settings host objects of interest 307 settings::HostObjects settings; 308 309 /** @brief Host id. **/ 310 const size_t id = 0; 311 312 /** @brief HostState to systemd target mapping table. **/ 313 std::map<HostState, std::string> stateTargetTable; 314 315 /** @brief Requested Transition to systemd target mapping table. **/ 316 std::map<Transition, std::string> transitionTargetTable; 317 }; 318 319 } // namespace manager 320 } // namespace state 321 } // namespace phosphor 322