1 #pragma once
2 
3 #include "utils.hpp"
4 #include "xyz/openbmc_project/State/BMC/server.hpp"
5 
6 #include <linux/watchdog.h>
7 #include <sys/sysinfo.h>
8 
9 #include <sdbusplus/bus.hpp>
10 
11 #include <cassert>
12 #include <chrono>
13 
14 namespace phosphor
15 {
16 namespace state
17 {
18 namespace manager
19 {
20 
21 using BMCInherit = sdbusplus::server::object_t<
22     sdbusplus::server::xyz::openbmc_project::state::BMC>;
23 namespace sdbusRule = sdbusplus::bus::match::rules;
24 
25 /** @class BMC
26  *  @brief OpenBMC BMC state management implementation.
27  *  @details A concrete implementation for xyz.openbmc_project.State.BMC
28  *  DBus API.
29  */
30 class BMC : public BMCInherit
31 {
32   public:
33     /** @brief Constructs BMC State Manager
34      *
35      * @param[in] bus       - The Dbus bus object
36      * @param[in] busName   - The Dbus name to own
37      * @param[in] objPath   - The Dbus object path
38      */
39     BMC(sdbusplus::bus_t& bus, const char* objPath) :
40         BMCInherit(bus, objPath, BMCInherit::action::defer_emit), bus(bus),
41         stateSignal(std::make_unique<decltype(stateSignal)::element_type>(
42             bus,
43             sdbusRule::type::signal() + sdbusRule::member("JobRemoved") +
44                 sdbusRule::path("/org/freedesktop/systemd1") +
45                 sdbusRule::interface("org.freedesktop.systemd1.Manager"),
46             [this](sdbusplus::message_t& m) { bmcStateChange(m); })),
47 
48         timeSyncSignal(std::make_unique<decltype(timeSyncSignal)::element_type>(
49             bus,
50             sdbusRule::propertiesChanged(
51                 "/org/freedesktop/systemd1/unit/time_2dsync_2etarget",
52                 "org.freedesktop.systemd1.Unit"),
53             [this](sdbusplus::message_t& m) {
54         std::string interface;
55         std::unordered_map<std::string, std::variant<std::string>>
56             propertyChanged;
57         m.read(interface, propertyChanged);
58 
59         for (const auto& [key, value] : propertyChanged)
60         {
61             if (key == "ActiveState" &&
62                 std::holds_alternative<std::string>(value) &&
63                 std::get<std::string>(value) == "active")
64             {
65                 updateLastRebootTime();
66                 timeSyncSignal.reset();
67             }
68         }
69             }))
70     {
71         utils::subscribeToSystemdSignals(bus);
72         discoverInitialState();
73         discoverLastRebootCause();
74         updateLastRebootTime();
75 
76         this->emit_object_added();
77     };
78 
79     /** @brief Set value of BMCTransition **/
80     Transition requestedBMCTransition(Transition value) override;
81 
82     /** @brief Set value of CurrentBMCState **/
83     BMCState currentBMCState(BMCState value) override;
84 
85     /** @brief Returns the last time the BMC was rebooted
86      *
87      *  @details Uses uptime information to determine when
88      *           the BMC was last rebooted.
89      *
90      *  @return uint64_t - Epoch time, in milliseconds, of the
91      *                     last reboot.
92      */
93     uint64_t lastRebootTime() const override;
94 
95     /** @brief Set value of LastRebootCause **/
96     RebootCause lastRebootCause(RebootCause value) override;
97 
98   private:
99     /**
100      * @brief Retrieve input systemd unit state
101      **/
102     std::string getUnitState(const std::string& unitToCheck);
103     /**
104      * @brief discover the state of the bmc
105      **/
106     void discoverInitialState();
107 
108     /** @brief Execute the transition request
109      *
110      *  @param[in] tranReq   - Transition requested
111      */
112     void executeTransition(Transition tranReq);
113 
114     /** @brief Callback function on bmc state change
115      *
116      * Check if the state is relevant to the BMC and if so, update
117      * corresponding BMC object's state
118      *
119      * @param[in]  msg       - Data associated with subscribed signal
120      *
121      */
122     int bmcStateChange(sdbusplus::message_t& msg);
123 
124     /** @brief Persistent sdbusplus DBus bus connection. **/
125     sdbusplus::bus_t& bus;
126 
127     /** @brief Used to subscribe to dbus system state changes **/
128     std::unique_ptr<sdbusplus::bus::match_t> stateSignal;
129 
130     /** @brief Used to subscribe to timesync **/
131     std::unique_ptr<sdbusplus::bus::match_t> timeSyncSignal;
132 
133     /**
134      * @brief discover the last reboot cause of the bmc
135      **/
136     void discoverLastRebootCause();
137 
138     /**
139      * @brief update the last reboot time of the bmc
140      **/
141     void updateLastRebootTime();
142 
143     /**
144      * @brief the lastRebootTime calcuated at startup.
145      **/
146     uint64_t rebootTime;
147 };
148 
149 } // namespace manager
150 } // namespace state
151 } // namespace phosphor
152