1 #pragma once 2 3 #include "config.h" 4 5 #include "settings.hpp" 6 #include "utils.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/Host/server.hpp> 15 #include <xyz/openbmc_project/State/OperatingSystem/Status/server.hpp> 16 17 #include <filesystem> 18 #include <string> 19 20 namespace phosphor 21 { 22 namespace state 23 { 24 namespace manager 25 { 26 27 using HostInherit = sdbusplus::server::object_t< 28 sdbusplus::server::xyz::openbmc_project::state::Host, 29 sdbusplus::server::xyz::openbmc_project::state::boot::Progress, 30 sdbusplus::server::xyz::openbmc_project::control::boot::RebootAttempts, 31 sdbusplus::server::xyz::openbmc_project::state::operating_system::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 */ Host(sdbusplus::bus_t & bus,const char * objPath,size_t id)56 Host(sdbusplus::bus_t& bus, const char* objPath, size_t id) : 57 HostInherit(bus, objPath, HostInherit::action::defer_emit), 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 [this](sdbusplus::message_t& m) { sysStateChangeJobRemoved(m); }), 64 systemdSignalJobNew( 65 bus, 66 sdbusRule::type::signal() + sdbusRule::member("JobNew") + 67 sdbusRule::path("/org/freedesktop/systemd1") + 68 sdbusRule::interface("org.freedesktop.systemd1.Manager"), __anon553c66d80202(sdbusplus::message_t& m) 69 [this](sdbusplus::message_t& m) { sysStateChangeJobNew(m); }), 70 settings(bus, id), id(id) 71 { 72 // Enable systemd signals 73 utils::subscribeToSystemdSignals(bus); 74 75 // create map of target name base on host id 76 createSystemdTargetMaps(); 77 78 // Will throw exception on fail 79 determineInitialState(); 80 81 // Setup supported transitions against this host object 82 setupSupportedTransitions(); 83 84 // Sets auto-reboot attempts to max-allowed 85 attemptsLeft(sdbusplus::server::xyz::openbmc_project::control::boot:: 86 RebootAttempts::retryAttempts()); 87 88 // We deferred this until we could get our property correct 89 this->emit_object_added(); 90 } 91 92 /** @brief Set value of HostTransition */ 93 Transition requestedHostTransition(Transition value) override; 94 95 /** @brief Set Value for boot progress */ 96 ProgressStages bootProgress(ProgressStages value) override; 97 98 /** @brief Set Value for Operating System Status */ 99 OSStatus operatingSystemState(OSStatus value) override; 100 101 /** @brief Set value of CurrentHostState */ 102 HostState currentHostState(HostState value) override; 103 104 /** 105 * @brief Set value for allowable auto-reboot count 106 * 107 * This override is responsible for ensuring that when external users 108 * set the number of automatic retry attempts that the number of 109 * automatic reboot attempts left will update accordingly. 110 * 111 * @param[in] value - desired Reboot count value 112 * 113 * @return number of reboot attempts allowed. 114 */ retryAttempts(uint32_t value)115 uint32_t retryAttempts(uint32_t value) override 116 { 117 if (sdbusplus::server::xyz::openbmc_project::control::boot:: 118 RebootAttempts::attemptsLeft() != value) 119 { 120 info("Automatic reboot retry attempts set to: {VALUE} ", "VALUE", 121 value); 122 sdbusplus::server::xyz::openbmc_project::control::boot:: 123 RebootAttempts::attemptsLeft(value); 124 } 125 126 return (sdbusplus::server::xyz::openbmc_project::control::boot:: 127 RebootAttempts::retryAttempts(value)); 128 } 129 130 /** 131 * @brief Set host reboot count to default 132 * 133 * OpenBMC software controls the number of allowed reboot attempts so 134 * any external set request of this property will be overridden by 135 * this function and set to the number of the allowed auto-reboot 136 * retry attempts found on the system. 137 * 138 * The only code responsible for decrementing the boot count resides 139 * within this process and that will use the sub class interface 140 * directly 141 * 142 * @param[in] value - Reboot count value 143 * 144 * @return number of reboot attempts left(allowed by retry attempts 145 * property) 146 */ attemptsLeft(uint32_t value)147 uint32_t attemptsLeft(uint32_t value) override 148 { 149 debug("External request to reset reboot count"); 150 auto retryAttempts = sdbusplus::xyz::openbmc_project::Control::Boot:: 151 server::RebootAttempts::retryAttempts(); 152 return ( 153 sdbusplus::server::xyz::openbmc_project::control::boot:: 154 RebootAttempts::attemptsLeft(std::min(value, retryAttempts))); 155 } 156 157 private: 158 /** 159 * @brief Determine initial host state and set internally 160 * 161 * @return Will throw exceptions on failure 162 **/ 163 void determineInitialState(); 164 165 /** 166 * @brief Configure supported transitions for system 167 * 168 * @return Will throw exceptions on failure 169 **/ 170 void setupSupportedTransitions(); 171 172 /** 173 * create systemd target instance names and mapping table 174 **/ 175 void createSystemdTargetMaps(); 176 177 /** @brief Execute the transition request 178 * 179 * This function assumes the state has been validated and the host 180 * is in an appropriate state for the transition to be started. 181 * 182 * @param[in] tranReq - Transition requested 183 */ 184 void executeTransition(Transition tranReq); 185 186 /** 187 * @brief Determine if target is active 188 * 189 * This function determines if the target is active and 190 * helps prevent misleading log recorded states. 191 * 192 * @param[in] target - Target string to check on 193 * 194 * @return boolean corresponding to state active 195 **/ 196 bool stateActive(const std::string& target); 197 198 /** 199 * @brief Determine if auto reboot flag is set 200 * 201 * @return boolean corresponding to current auto_reboot setting 202 **/ 203 bool isAutoReboot(); 204 205 /** @brief Check if systemd state change is relevant to this object 206 * 207 * Instance specific interface to handle the detected systemd state 208 * change 209 * 210 * @param[in] msg - Data associated with subscribed signal 211 * 212 */ 213 void sysStateChangeJobRemoved(sdbusplus::message_t& msg); 214 215 /** @brief Check if JobNew systemd signal is relevant to this object 216 * 217 * In certain instances phosphor-state-manager needs to monitor for the 218 * entry into a systemd target. This function will be used for these cases. 219 * 220 * Instance specific interface to handle the detected systemd state 221 * change 222 * 223 * @param[in] msg - Data associated with subscribed signal 224 * 225 */ 226 void sysStateChangeJobNew(sdbusplus::message_t& msg); 227 228 /** @brief Decrement reboot count 229 * 230 * This is used internally to this application to decrement the boot 231 * count on each boot attempt. The host will use the external 232 * attemptsLeft() interface to reset the count when a boot is successful 233 * 234 * @return number of reboot count attempts left 235 */ 236 uint32_t decrementRebootCount(); 237 238 // Allow cereal class access to allow these next two function to be 239 // private 240 friend class cereal::access; 241 242 /** @brief Function required by Cereal to perform serialization. 243 * 244 * @tparam Archive - Cereal archive type (binary in our case). 245 * @param[in] archive - reference to Cereal archive. 246 * @param[in] version - Class version that enables handling 247 * a serialized data across code levels 248 */ 249 template <class Archive> save(Archive & archive,const std::uint32_t version) const250 void save(Archive& archive, const std::uint32_t version) const 251 { 252 // version is not used currently 253 (void)(version); 254 archive(sdbusplus::server::xyz::openbmc_project::control::boot:: 255 RebootAttempts::retryAttempts(), 256 convertForMessage(sdbusplus::xyz::openbmc_project::State:: 257 server::Host::requestedHostTransition()), 258 convertForMessage(sdbusplus::xyz::openbmc_project::State::Boot:: 259 server::Progress::bootProgress()), 260 convertForMessage( 261 sdbusplus::xyz::openbmc_project::State::OperatingSystem:: 262 server::Status::operatingSystemState())); 263 } 264 265 /** @brief Function required by Cereal to perform deserialization. 266 * 267 * @tparam Archive - Cereal archive type (binary in our case). 268 * @param[in] archive - reference to Cereal archive. 269 * @param[in] version - Class version that enables handling 270 * a serialized data across code levels 271 */ 272 template <class Archive> load(Archive & archive,const std::uint32_t version)273 void load(Archive& archive, const std::uint32_t version) 274 { 275 std::string reqTranState; 276 std::string bootProgress; 277 std::string osState; 278 // Older cereal archive without RetryAttempt may be implemented 279 // just set to (BOOT_COUNT_MAX_ALLOWED) 280 uint32_t retryAttempts = BOOT_COUNT_MAX_ALLOWED; 281 switch (version) 282 { 283 case 2: 284 archive(retryAttempts); 285 [[fallthrough]]; 286 case 1: 287 archive(reqTranState, bootProgress, osState); 288 break; 289 } 290 auto reqTran = Host::convertTransitionFromString(reqTranState); 291 // When restoring, set the requested state with persistent value 292 // but don't call the override which would execute it 293 sdbusplus::server::xyz::openbmc_project::state::Host:: 294 requestedHostTransition(reqTran); 295 sdbusplus::server::xyz::openbmc_project::state::boot::Progress:: 296 bootProgress(Host::convertProgressStagesFromString(bootProgress)); 297 sdbusplus::server::xyz::openbmc_project::state::operating_system:: 298 Status::operatingSystemState( 299 Host::convertOSStatusFromString(osState)); 300 sdbusplus::server::xyz::openbmc_project::control::boot::RebootAttempts:: 301 retryAttempts(retryAttempts); 302 } 303 304 /** @brief Serialize and persist requested host state 305 * 306 * @return fs::path - pathname of persisted requested host state. 307 */ 308 fs::path serialize(); 309 310 /** @brief Deserialize a persisted requested host state. 311 * 312 * @return bool - true if the deserialization was successful, false 313 * otherwise. 314 */ 315 bool deserialize(); 316 317 /** 318 * @brief Get target name of a HostState 319 * 320 * @param[in] state - The state of the host 321 * 322 * @return string - systemd target name of the state 323 */ 324 const std::string& getTarget(HostState state); 325 326 /** 327 * @brief Get target name of a TransitionRequest 328 * 329 * @param[in] tranReq - Transition requested 330 * 331 * @return string - systemd target name of Requested transition 332 */ 333 const std::string& getTarget(Transition tranReq); 334 335 /** @brief Persistent sdbusplus DBus bus connection. */ 336 sdbusplus::bus_t& bus; 337 338 /** @brief Used to subscribe to dbus systemd JobRemoved signal **/ 339 sdbusplus::bus::match_t systemdSignalJobRemoved; 340 341 /** @brief Used to subscribe to dbus systemd JobNew signal **/ 342 sdbusplus::bus::match_t systemdSignalJobNew; 343 344 // Settings host objects of interest 345 settings::HostObjects settings; 346 347 /** @brief Host id. **/ 348 const size_t id = 0; 349 350 /** @brief HostState to systemd target mapping table. **/ 351 std::map<HostState, std::string> stateTargetTable; 352 353 /** @brief Requested Transition to systemd target mapping table. **/ 354 std::map<Transition, std::string> transitionTargetTable; 355 356 /** @brief Target called when a host crash occurs **/ 357 std::string hostCrashTarget; 358 }; 359 360 } // namespace manager 361 } // namespace state 362 } // namespace phosphor 363