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