| Charles Hsu | dbd77b9 | 2020-10-29 11:20:34 +0800 | [diff] [blame] | 1 | /* | 
 | 2 | // Copyright (c) 2018 Intel Corporation | 
 | 3 | // | 
 | 4 | // Licensed under the Apache License, Version 2.0 (the "License"); | 
 | 5 | // you may not use this file except in compliance with the License. | 
 | 6 | // You may obtain a copy of the License at | 
 | 7 | // | 
 | 8 | //      http://www.apache.org/licenses/LICENSE-2.0 | 
 | 9 | // | 
 | 10 | // Unless required by applicable law or agreed to in writing, software | 
 | 11 | // distributed under the License is distributed on an "AS IS" BASIS, | 
 | 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 | 13 | // See the License for the specific language governing permissions and | 
 | 14 | // limitations under the License. | 
 | 15 | */ | 
 | 16 |  | 
 | 17 | #pragma once | 
 | 18 | #include <sel_logger.hpp> | 
 | 19 | #include <sensorutils.hpp> | 
 | 20 |  | 
| Willy Tu | f0243dc | 2021-08-03 22:49:14 -0700 | [diff] [blame] | 21 | #include <string> | 
| Charles Hsu | dbd77b9 | 2020-10-29 11:20:34 +0800 | [diff] [blame] | 22 | #include <string_view> | 
 | 23 | #include <variant> | 
 | 24 |  | 
 | 25 | enum class watchdogEventOffsets : uint8_t | 
 | 26 | { | 
 | 27 |     noAction = 0x00, | 
 | 28 |     hardReset = 0x01, | 
 | 29 |     powerDown = 0x02, | 
 | 30 |     powerCycle = 0x03, | 
 | 31 | }; | 
 | 32 |  | 
 | 33 | enum class watchdogTimerUseOffsets : uint8_t | 
 | 34 | { | 
 | 35 |     reserved = 0x00, | 
 | 36 |     BIOSFRB2 = 0x01, | 
 | 37 |     BIOSPOST = 0x02, | 
 | 38 |     OSLoad = 0x03, | 
 | 39 |     SMSOS = 0x04, | 
 | 40 |     OEM = 0x05, | 
 | 41 |     unspecified = 0x0f, | 
 | 42 | }; | 
 | 43 |  | 
 | 44 | enum class watchdogInterruptTypeOffsets : uint8_t | 
 | 45 | { | 
 | 46 |     none = 0x00, | 
 | 47 |     SMI = 0x01, | 
 | 48 |     NMI = 0x02, | 
 | 49 |     messageInterrupt = 0x03, | 
 | 50 |     unspecified = 0x0f, | 
 | 51 | }; | 
 | 52 |  | 
 | 53 | static constexpr const uint8_t wdtNologBit = (1 << 7); | 
 | 54 | static constexpr int interruptTypeBits = 4; | 
 | 55 |  | 
| Willy Tu | f0243dc | 2021-08-03 22:49:14 -0700 | [diff] [blame] | 56 | inline static void sendWatchdogEventLog( | 
 | 57 |     std::shared_ptr<sdbusplus::asio::connection> conn, | 
| Patrick Williams | ccef227 | 2022-07-22 19:26:54 -0500 | [diff] [blame] | 58 |     sdbusplus::message_t& msg, bool assert, | 
| Willy Tu | f0243dc | 2021-08-03 22:49:14 -0700 | [diff] [blame] | 59 |     std::optional<std::string_view> expireAction = std::nullopt) | 
| Charles Hsu | dbd77b9 | 2020-10-29 11:20:34 +0800 | [diff] [blame] | 60 | { | 
| Willy Tu | f0243dc | 2021-08-03 22:49:14 -0700 | [diff] [blame] | 61 |     // SEL event data is three bytes where 0xFF means unspecified | 
 | 62 |     std::vector<uint8_t> eventData(selEvtDataMaxSize, 0xFF); | 
| Charles Hsu | dbd77b9 | 2020-10-29 11:20:34 +0800 | [diff] [blame] | 63 |  | 
| Patrick Williams | ccef227 | 2022-07-22 19:26:54 -0500 | [diff] [blame] | 64 |     sdbusplus::message_t getWatchdogStatus = | 
| Willy Tu | f0243dc | 2021-08-03 22:49:14 -0700 | [diff] [blame] | 65 |         conn->new_method_call(msg.get_sender(), msg.get_path(), | 
 | 66 |                               "org.freedesktop.DBus.Properties", "GetAll"); | 
 | 67 |     getWatchdogStatus.append("xyz.openbmc_project.State.Watchdog"); | 
 | 68 |     boost::container::flat_map<std::string, | 
 | 69 |                                std::variant<std::string, uint64_t, bool>> | 
 | 70 |         watchdogStatus; | 
| Charles Hsu | dbd77b9 | 2020-10-29 11:20:34 +0800 | [diff] [blame] | 71 |  | 
| Willy Tu | f0243dc | 2021-08-03 22:49:14 -0700 | [diff] [blame] | 72 |     try | 
 | 73 |     { | 
| Patrick Williams | ccef227 | 2022-07-22 19:26:54 -0500 | [diff] [blame] | 74 |         sdbusplus::message_t getWatchdogStatusResp = | 
| Willy Tu | f0243dc | 2021-08-03 22:49:14 -0700 | [diff] [blame] | 75 |             conn->call(getWatchdogStatus); | 
 | 76 |         getWatchdogStatusResp.read(watchdogStatus); | 
 | 77 |     } | 
| Patrick Williams | 3f4cd97 | 2021-10-06 12:42:50 -0500 | [diff] [blame] | 78 |     catch (const sdbusplus::exception_t&) | 
| Willy Tu | f0243dc | 2021-08-03 22:49:14 -0700 | [diff] [blame] | 79 |     { | 
 | 80 |         std::cerr << "error getting watchdog status from " << msg.get_path() | 
 | 81 |                   << "\n"; | 
 | 82 |         return; | 
 | 83 |     } | 
| Charles Hsu | dbd77b9 | 2020-10-29 11:20:34 +0800 | [diff] [blame] | 84 |  | 
| Willy Tu | f0243dc | 2021-08-03 22:49:14 -0700 | [diff] [blame] | 85 |     if (!expireAction) | 
 | 86 |     { | 
| Charles Hsu | dbd77b9 | 2020-10-29 11:20:34 +0800 | [diff] [blame] | 87 |         auto getExpireAction = watchdogStatus.find("ExpireAction"); | 
| Charles Hsu | dbd77b9 | 2020-10-29 11:20:34 +0800 | [diff] [blame] | 88 |         if (getExpireAction != watchdogStatus.end()) | 
 | 89 |         { | 
 | 90 |             expireAction = std::get<std::string>(getExpireAction->second); | 
| Willy Tu | f0243dc | 2021-08-03 22:49:14 -0700 | [diff] [blame] | 91 |             expireAction->remove_prefix(std::min( | 
 | 92 |                 expireAction->find_last_of(".") + 1, expireAction->size())); | 
| Charles Hsu | dbd77b9 | 2020-10-29 11:20:34 +0800 | [diff] [blame] | 93 |         } | 
| Willy Tu | f0243dc | 2021-08-03 22:49:14 -0700 | [diff] [blame] | 94 |     } | 
| Charles Hsu | dbd77b9 | 2020-10-29 11:20:34 +0800 | [diff] [blame] | 95 |  | 
| Willy Tu | f0243dc | 2021-08-03 22:49:14 -0700 | [diff] [blame] | 96 |     if (*expireAction == "HardReset") | 
 | 97 |     { | 
 | 98 |         eventData[0] = static_cast<uint8_t>(watchdogEventOffsets::hardReset); | 
 | 99 |     } | 
 | 100 |     else if (*expireAction == "PowerOff") | 
 | 101 |     { | 
 | 102 |         eventData[0] = static_cast<uint8_t>(watchdogEventOffsets::powerDown); | 
 | 103 |     } | 
 | 104 |     else if (*expireAction == "PowerCycle") | 
 | 105 |     { | 
 | 106 |         eventData[0] = static_cast<uint8_t>(watchdogEventOffsets::powerCycle); | 
 | 107 |     } | 
 | 108 |     else if (*expireAction == "None") | 
 | 109 |     { | 
 | 110 |         eventData[0] = static_cast<uint8_t>(watchdogEventOffsets::noAction); | 
 | 111 |     } | 
| Charles Hsu | dbd77b9 | 2020-10-29 11:20:34 +0800 | [diff] [blame] | 112 |  | 
| Willy Tu | f0243dc | 2021-08-03 22:49:14 -0700 | [diff] [blame] | 113 |     auto getPreTimeoutInterrupt = watchdogStatus.find("PreTimeoutInterrupt"); | 
 | 114 |     std::string_view preTimeoutInterrupt; | 
 | 115 |     if (getPreTimeoutInterrupt != watchdogStatus.end()) | 
 | 116 |     { | 
 | 117 |         preTimeoutInterrupt = | 
 | 118 |             std::get<std::string>(getPreTimeoutInterrupt->second); | 
 | 119 |         preTimeoutInterrupt.remove_prefix( | 
 | 120 |             std::min(preTimeoutInterrupt.find_last_of(".") + 1, | 
 | 121 |                      preTimeoutInterrupt.size())); | 
 | 122 |     } | 
 | 123 |     if (preTimeoutInterrupt == "None") | 
 | 124 |     { | 
 | 125 |         eventData[1] &= | 
 | 126 |             (static_cast<uint8_t>(watchdogInterruptTypeOffsets::none) | 
 | 127 |              << interruptTypeBits); | 
 | 128 |     } | 
 | 129 |     else if (preTimeoutInterrupt == "SMI") | 
 | 130 |     { | 
 | 131 |         eventData[1] &= (static_cast<uint8_t>(watchdogInterruptTypeOffsets::SMI) | 
 | 132 |                          << interruptTypeBits); | 
 | 133 |     } | 
 | 134 |     else if (preTimeoutInterrupt == "NMI") | 
 | 135 |     { | 
 | 136 |         eventData[1] &= (static_cast<uint8_t>(watchdogInterruptTypeOffsets::NMI) | 
 | 137 |                          << interruptTypeBits); | 
 | 138 |     } | 
 | 139 |     else if (preTimeoutInterrupt == "MI") | 
 | 140 |     { | 
 | 141 |         eventData[1] &= (static_cast<uint8_t>( | 
 | 142 |                              watchdogInterruptTypeOffsets::messageInterrupt) | 
 | 143 |                          << interruptTypeBits); | 
 | 144 |     } | 
| Charles Hsu | dbd77b9 | 2020-10-29 11:20:34 +0800 | [diff] [blame] | 145 |  | 
| Willy Tu | f0243dc | 2021-08-03 22:49:14 -0700 | [diff] [blame] | 146 |     auto getCurrentTimerUse = watchdogStatus.find("CurrentTimerUse"); | 
 | 147 |     std::string_view currentTimerUse; | 
 | 148 |     if (getCurrentTimerUse != watchdogStatus.end()) | 
 | 149 |     { | 
 | 150 |         currentTimerUse = std::get<std::string>(getCurrentTimerUse->second); | 
 | 151 |         currentTimerUse.remove_prefix(std::min( | 
 | 152 |             currentTimerUse.find_last_of(".") + 1, currentTimerUse.size())); | 
 | 153 |     } | 
 | 154 |     if (currentTimerUse == "BIOSFRB2") | 
 | 155 |     { | 
 | 156 |         eventData[1] |= static_cast<uint8_t>(watchdogTimerUseOffsets::BIOSFRB2); | 
 | 157 |     } | 
 | 158 |     else if (currentTimerUse == "BIOSPOST") | 
 | 159 |     { | 
 | 160 |         eventData[1] |= static_cast<uint8_t>(watchdogTimerUseOffsets::BIOSPOST); | 
 | 161 |     } | 
 | 162 |     else if (currentTimerUse == "OSLoad") | 
 | 163 |     { | 
 | 164 |         eventData[1] |= static_cast<uint8_t>(watchdogTimerUseOffsets::OSLoad); | 
 | 165 |     } | 
 | 166 |     else if (currentTimerUse == "SMSOS") | 
 | 167 |     { | 
 | 168 |         eventData[1] |= static_cast<uint8_t>(watchdogTimerUseOffsets::SMSOS); | 
 | 169 |     } | 
 | 170 |     else if (currentTimerUse == "OEM") | 
 | 171 |     { | 
 | 172 |         eventData[1] |= static_cast<uint8_t>(watchdogTimerUseOffsets::OEM); | 
 | 173 |     } | 
 | 174 |     else | 
 | 175 |     { | 
 | 176 |         eventData[1] |= | 
 | 177 |             static_cast<uint8_t>(watchdogTimerUseOffsets::unspecified); | 
 | 178 |     } | 
| Charles Hsu | dbd77b9 | 2020-10-29 11:20:34 +0800 | [diff] [blame] | 179 |  | 
| Willy Tu | f0243dc | 2021-08-03 22:49:14 -0700 | [diff] [blame] | 180 |     auto getWatchdogInterval = watchdogStatus.find("Interval"); | 
 | 181 |     uint64_t watchdogInterval = 0; | 
 | 182 |     if (getWatchdogInterval != watchdogStatus.end()) | 
 | 183 |     { | 
 | 184 |         watchdogInterval = std::get<uint64_t>(getWatchdogInterval->second); | 
 | 185 |     } | 
| Charles Hsu | dbd77b9 | 2020-10-29 11:20:34 +0800 | [diff] [blame] | 186 |  | 
| Willy Tu | f0243dc | 2021-08-03 22:49:14 -0700 | [diff] [blame] | 187 |     // get watchdog status properties | 
 | 188 |     static bool wdt_nolog; | 
| Patrick Williams | ccef227 | 2022-07-22 19:26:54 -0500 | [diff] [blame] | 189 |     sdbusplus::bus_t bus = sdbusplus::bus::new_default(); | 
| Willy Tu | f0243dc | 2021-08-03 22:49:14 -0700 | [diff] [blame] | 190 |     uint8_t netFn = 0x06; | 
 | 191 |     uint8_t lun = 0x00; | 
 | 192 |     uint8_t cmd = 0x25; | 
 | 193 |     std::vector<uint8_t> commandData; | 
 | 194 |     std::map<std::string, std::variant<int>> options; | 
| Charles Hsu | dbd77b9 | 2020-10-29 11:20:34 +0800 | [diff] [blame] | 195 |  | 
| Willy Tu | f0243dc | 2021-08-03 22:49:14 -0700 | [diff] [blame] | 196 |     auto ipmiCall = bus.new_method_call( | 
 | 197 |         "xyz.openbmc_project.Ipmi.Host", "/xyz/openbmc_project/Ipmi", | 
 | 198 |         "xyz.openbmc_project.Ipmi.Server", "execute"); | 
 | 199 |     ipmiCall.append(netFn, lun, cmd, commandData, options); | 
 | 200 |     std::tuple<uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>> rsp; | 
 | 201 |     auto ipmiReply = bus.call(ipmiCall); | 
 | 202 |     ipmiReply.read(rsp); | 
 | 203 |     auto& [rnetFn, rlun, rcmd, cc, responseData] = rsp; | 
| Charles Hsu | dbd77b9 | 2020-10-29 11:20:34 +0800 | [diff] [blame] | 204 |  | 
| Willy Tu | f0243dc | 2021-08-03 22:49:14 -0700 | [diff] [blame] | 205 |     std::string direction; | 
 | 206 |     std::string eventMessageArgs; | 
 | 207 |     if (assert) | 
 | 208 |     { | 
 | 209 |         direction = " enable "; | 
 | 210 |         eventMessageArgs = "Enabled"; | 
 | 211 |         wdt_nolog = responseData[0] & wdtNologBit; | 
 | 212 |     } | 
 | 213 |     else | 
 | 214 |     { | 
 | 215 |         direction = " disable "; | 
 | 216 |         eventMessageArgs = "Disabled"; | 
 | 217 |     } | 
| Charles Hsu | dbd77b9 | 2020-10-29 11:20:34 +0800 | [diff] [blame] | 218 |  | 
| Willy Tu | f0243dc | 2021-08-03 22:49:14 -0700 | [diff] [blame] | 219 |     // Set Watchdog Timer byte1[7]-1b=don't log | 
 | 220 |     if (!wdt_nolog) | 
 | 221 |     { | 
 | 222 |         // Construct a human-readable message of this event for the log | 
 | 223 |         std::string journalMsg( | 
 | 224 |             std::string(currentTimerUse) + std::string(direction) + | 
 | 225 |             "watchdog countdown " + std::to_string(watchdogInterval / 1000) + | 
 | 226 |             " seconds " + std::string(*expireAction) + " action"); | 
| Charles Hsu | dbd77b9 | 2020-10-29 11:20:34 +0800 | [diff] [blame] | 227 |  | 
| Willy Tu | f0243dc | 2021-08-03 22:49:14 -0700 | [diff] [blame] | 228 |         std::string redfishMessageID = "OpenBMC.0.1.IPMIWatchdog"; | 
 | 229 |  | 
| Konstantin Aladyshev | 6f5342d | 2023-04-19 09:23:11 +0000 | [diff] [blame] | 230 |         selAddSystemRecord( | 
 | 231 |             conn, journalMsg, std::string(msg.get_path()), eventData, assert, | 
 | 232 |             selBMCGenID, "REDFISH_MESSAGE_ID=%s", redfishMessageID.c_str(), | 
 | 233 |             "REDFISH_MESSAGE_ARGS=%s", eventMessageArgs.c_str(), NULL); | 
| Willy Tu | f0243dc | 2021-08-03 22:49:14 -0700 | [diff] [blame] | 234 |     } | 
 | 235 | } | 
 | 236 |  | 
| Patrick Williams | ccef227 | 2022-07-22 19:26:54 -0500 | [diff] [blame] | 237 | inline static sdbusplus::bus::match_t | 
| Willy Tu | f0243dc | 2021-08-03 22:49:14 -0700 | [diff] [blame] | 238 |     startWatchdogEventMonitor(std::shared_ptr<sdbusplus::asio::connection> conn) | 
 | 239 | { | 
| Patrick Williams | ccef227 | 2022-07-22 19:26:54 -0500 | [diff] [blame] | 240 |     auto watchdogEventMatcherCallback = [conn](sdbusplus::message_t& msg) { | 
 | 241 |         std::string expiredAction; | 
 | 242 |         msg.read(expiredAction); | 
| Willy Tu | f0243dc | 2021-08-03 22:49:14 -0700 | [diff] [blame] | 243 |  | 
| Patrick Williams | ccef227 | 2022-07-22 19:26:54 -0500 | [diff] [blame] | 244 |         std::string_view action = expiredAction; | 
 | 245 |         action.remove_prefix( | 
 | 246 |             std::min(action.find_last_of(".") + 1, action.size())); | 
| Willy Tu | f0243dc | 2021-08-03 22:49:14 -0700 | [diff] [blame] | 247 |  | 
| Patrick Williams | ccef227 | 2022-07-22 19:26:54 -0500 | [diff] [blame] | 248 |         sendWatchdogEventLog(conn, msg, true, action); | 
 | 249 |     }; | 
| Willy Tu | f0243dc | 2021-08-03 22:49:14 -0700 | [diff] [blame] | 250 |  | 
| Patrick Williams | ccef227 | 2022-07-22 19:26:54 -0500 | [diff] [blame] | 251 |     sdbusplus::bus::match_t watchdogEventMatcher( | 
 | 252 |         static_cast<sdbusplus::bus_t&>(*conn), | 
| Willy Tu | f0243dc | 2021-08-03 22:49:14 -0700 | [diff] [blame] | 253 |         "type='signal',interface='xyz.openbmc_project.Watchdog'," | 
 | 254 |         "member='Timeout'", | 
| Charles Hsu | dbd77b9 | 2020-10-29 11:20:34 +0800 | [diff] [blame] | 255 |         std::move(watchdogEventMatcherCallback)); | 
| Willy Tu | f0243dc | 2021-08-03 22:49:14 -0700 | [diff] [blame] | 256 |  | 
| Charles Hsu | dbd77b9 | 2020-10-29 11:20:34 +0800 | [diff] [blame] | 257 |     return watchdogEventMatcher; | 
 | 258 | } |