blob: 57ba24eee4f3ea801828da313b559241cedd89f7 [file] [log] [blame]
Charles Hsudbd77b92020-10-29 11:20:34 +08001/*
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
Lei YU9916d412025-02-06 11:51:18 +000018#include <boost/container/flat_map.hpp>
19#include <sdbusplus/bus/match.hpp>
Charles Hsudbd77b92020-10-29 11:20:34 +080020#include <sel_logger.hpp>
21#include <sensorutils.hpp>
22
Willy Tuf0243dc2021-08-03 22:49:14 -070023#include <string>
Charles Hsudbd77b92020-10-29 11:20:34 +080024#include <string_view>
25#include <variant>
26
27enum class watchdogEventOffsets : uint8_t
28{
29 noAction = 0x00,
30 hardReset = 0x01,
31 powerDown = 0x02,
32 powerCycle = 0x03,
33};
34
35enum class watchdogTimerUseOffsets : uint8_t
36{
37 reserved = 0x00,
38 BIOSFRB2 = 0x01,
39 BIOSPOST = 0x02,
40 OSLoad = 0x03,
41 SMSOS = 0x04,
42 OEM = 0x05,
43 unspecified = 0x0f,
44};
45
46enum class watchdogInterruptTypeOffsets : uint8_t
47{
48 none = 0x00,
49 SMI = 0x01,
50 NMI = 0x02,
51 messageInterrupt = 0x03,
52 unspecified = 0x0f,
53};
54
55static constexpr const uint8_t wdtNologBit = (1 << 7);
56static constexpr int interruptTypeBits = 4;
57
Willy Tuf0243dc2021-08-03 22:49:14 -070058inline static void sendWatchdogEventLog(
59 std::shared_ptr<sdbusplus::asio::connection> conn,
Patrick Williamsccef2272022-07-22 19:26:54 -050060 sdbusplus::message_t& msg, bool assert,
Willy Tuf0243dc2021-08-03 22:49:14 -070061 std::optional<std::string_view> expireAction = std::nullopt)
Charles Hsudbd77b92020-10-29 11:20:34 +080062{
Willy Tuf0243dc2021-08-03 22:49:14 -070063 // SEL event data is three bytes where 0xFF means unspecified
64 std::vector<uint8_t> eventData(selEvtDataMaxSize, 0xFF);
Charles Hsudbd77b92020-10-29 11:20:34 +080065
Patrick Williamsccef2272022-07-22 19:26:54 -050066 sdbusplus::message_t getWatchdogStatus =
Willy Tuf0243dc2021-08-03 22:49:14 -070067 conn->new_method_call(msg.get_sender(), msg.get_path(),
68 "org.freedesktop.DBus.Properties", "GetAll");
69 getWatchdogStatus.append("xyz.openbmc_project.State.Watchdog");
70 boost::container::flat_map<std::string,
71 std::variant<std::string, uint64_t, bool>>
72 watchdogStatus;
Charles Hsudbd77b92020-10-29 11:20:34 +080073
Willy Tuf0243dc2021-08-03 22:49:14 -070074 try
75 {
Patrick Williamsccef2272022-07-22 19:26:54 -050076 sdbusplus::message_t getWatchdogStatusResp =
Willy Tuf0243dc2021-08-03 22:49:14 -070077 conn->call(getWatchdogStatus);
78 getWatchdogStatusResp.read(watchdogStatus);
79 }
Patrick Williams3f4cd972021-10-06 12:42:50 -050080 catch (const sdbusplus::exception_t&)
Willy Tuf0243dc2021-08-03 22:49:14 -070081 {
82 std::cerr << "error getting watchdog status from " << msg.get_path()
83 << "\n";
84 return;
85 }
Charles Hsudbd77b92020-10-29 11:20:34 +080086
Willy Tuf0243dc2021-08-03 22:49:14 -070087 if (!expireAction)
88 {
Lei YU9916d412025-02-06 11:51:18 +000089 expireAction = "";
Charles Hsudbd77b92020-10-29 11:20:34 +080090 auto getExpireAction = watchdogStatus.find("ExpireAction");
Charles Hsudbd77b92020-10-29 11:20:34 +080091 if (getExpireAction != watchdogStatus.end())
92 {
93 expireAction = std::get<std::string>(getExpireAction->second);
Willy Tuf0243dc2021-08-03 22:49:14 -070094 expireAction->remove_prefix(std::min(
95 expireAction->find_last_of(".") + 1, expireAction->size()));
Charles Hsudbd77b92020-10-29 11:20:34 +080096 }
Willy Tuf0243dc2021-08-03 22:49:14 -070097 }
Charles Hsudbd77b92020-10-29 11:20:34 +080098
Willy Tuf0243dc2021-08-03 22:49:14 -070099 if (*expireAction == "HardReset")
100 {
101 eventData[0] = static_cast<uint8_t>(watchdogEventOffsets::hardReset);
102 }
103 else if (*expireAction == "PowerOff")
104 {
105 eventData[0] = static_cast<uint8_t>(watchdogEventOffsets::powerDown);
106 }
107 else if (*expireAction == "PowerCycle")
108 {
109 eventData[0] = static_cast<uint8_t>(watchdogEventOffsets::powerCycle);
110 }
111 else if (*expireAction == "None")
112 {
113 eventData[0] = static_cast<uint8_t>(watchdogEventOffsets::noAction);
114 }
Charles Hsudbd77b92020-10-29 11:20:34 +0800115
Willy Tuf0243dc2021-08-03 22:49:14 -0700116 auto getPreTimeoutInterrupt = watchdogStatus.find("PreTimeoutInterrupt");
117 std::string_view preTimeoutInterrupt;
118 if (getPreTimeoutInterrupt != watchdogStatus.end())
119 {
120 preTimeoutInterrupt =
121 std::get<std::string>(getPreTimeoutInterrupt->second);
122 preTimeoutInterrupt.remove_prefix(
123 std::min(preTimeoutInterrupt.find_last_of(".") + 1,
124 preTimeoutInterrupt.size()));
125 }
126 if (preTimeoutInterrupt == "None")
127 {
128 eventData[1] &=
129 (static_cast<uint8_t>(watchdogInterruptTypeOffsets::none)
130 << interruptTypeBits);
131 }
132 else if (preTimeoutInterrupt == "SMI")
133 {
134 eventData[1] &= (static_cast<uint8_t>(watchdogInterruptTypeOffsets::SMI)
135 << interruptTypeBits);
136 }
137 else if (preTimeoutInterrupt == "NMI")
138 {
139 eventData[1] &= (static_cast<uint8_t>(watchdogInterruptTypeOffsets::NMI)
140 << interruptTypeBits);
141 }
142 else if (preTimeoutInterrupt == "MI")
143 {
144 eventData[1] &= (static_cast<uint8_t>(
145 watchdogInterruptTypeOffsets::messageInterrupt)
146 << interruptTypeBits);
147 }
Charles Hsudbd77b92020-10-29 11:20:34 +0800148
Willy Tuf0243dc2021-08-03 22:49:14 -0700149 auto getCurrentTimerUse = watchdogStatus.find("CurrentTimerUse");
150 std::string_view currentTimerUse;
151 if (getCurrentTimerUse != watchdogStatus.end())
152 {
153 currentTimerUse = std::get<std::string>(getCurrentTimerUse->second);
154 currentTimerUse.remove_prefix(std::min(
155 currentTimerUse.find_last_of(".") + 1, currentTimerUse.size()));
156 }
157 if (currentTimerUse == "BIOSFRB2")
158 {
159 eventData[1] |= static_cast<uint8_t>(watchdogTimerUseOffsets::BIOSFRB2);
160 }
161 else if (currentTimerUse == "BIOSPOST")
162 {
163 eventData[1] |= static_cast<uint8_t>(watchdogTimerUseOffsets::BIOSPOST);
164 }
165 else if (currentTimerUse == "OSLoad")
166 {
167 eventData[1] |= static_cast<uint8_t>(watchdogTimerUseOffsets::OSLoad);
168 }
169 else if (currentTimerUse == "SMSOS")
170 {
171 eventData[1] |= static_cast<uint8_t>(watchdogTimerUseOffsets::SMSOS);
172 }
173 else if (currentTimerUse == "OEM")
174 {
175 eventData[1] |= static_cast<uint8_t>(watchdogTimerUseOffsets::OEM);
176 }
177 else
178 {
179 eventData[1] |=
180 static_cast<uint8_t>(watchdogTimerUseOffsets::unspecified);
181 }
Charles Hsudbd77b92020-10-29 11:20:34 +0800182
Willy Tuf0243dc2021-08-03 22:49:14 -0700183 auto getWatchdogInterval = watchdogStatus.find("Interval");
184 uint64_t watchdogInterval = 0;
185 if (getWatchdogInterval != watchdogStatus.end())
186 {
187 watchdogInterval = std::get<uint64_t>(getWatchdogInterval->second);
188 }
Charles Hsudbd77b92020-10-29 11:20:34 +0800189
Willy Tuf0243dc2021-08-03 22:49:14 -0700190 // get watchdog status properties
191 static bool wdt_nolog;
Patrick Williamsccef2272022-07-22 19:26:54 -0500192 sdbusplus::bus_t bus = sdbusplus::bus::new_default();
Willy Tuf0243dc2021-08-03 22:49:14 -0700193 uint8_t netFn = 0x06;
194 uint8_t lun = 0x00;
195 uint8_t cmd = 0x25;
196 std::vector<uint8_t> commandData;
197 std::map<std::string, std::variant<int>> options;
Charles Hsudbd77b92020-10-29 11:20:34 +0800198
Willy Tuf0243dc2021-08-03 22:49:14 -0700199 auto ipmiCall = bus.new_method_call(
200 "xyz.openbmc_project.Ipmi.Host", "/xyz/openbmc_project/Ipmi",
201 "xyz.openbmc_project.Ipmi.Server", "execute");
202 ipmiCall.append(netFn, lun, cmd, commandData, options);
203 std::tuple<uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>> rsp;
204 auto ipmiReply = bus.call(ipmiCall);
205 ipmiReply.read(rsp);
206 auto& [rnetFn, rlun, rcmd, cc, responseData] = rsp;
Charles Hsudbd77b92020-10-29 11:20:34 +0800207
Willy Tuf0243dc2021-08-03 22:49:14 -0700208 std::string direction;
209 std::string eventMessageArgs;
210 if (assert)
211 {
212 direction = " enable ";
213 eventMessageArgs = "Enabled";
214 wdt_nolog = responseData[0] & wdtNologBit;
215 }
216 else
217 {
218 direction = " disable ";
219 eventMessageArgs = "Disabled";
220 }
Charles Hsudbd77b92020-10-29 11:20:34 +0800221
Willy Tuf0243dc2021-08-03 22:49:14 -0700222 // Set Watchdog Timer byte1[7]-1b=don't log
223 if (!wdt_nolog)
224 {
225 // Construct a human-readable message of this event for the log
226 std::string journalMsg(
227 std::string(currentTimerUse) + std::string(direction) +
228 "watchdog countdown " + std::to_string(watchdogInterval / 1000) +
229 " seconds " + std::string(*expireAction) + " action");
Charles Hsudbd77b92020-10-29 11:20:34 +0800230
Willy Tuf0243dc2021-08-03 22:49:14 -0700231 std::string redfishMessageID = "OpenBMC.0.1.IPMIWatchdog";
232
Konstantin Aladyshev6f5342d2023-04-19 09:23:11 +0000233 selAddSystemRecord(
234 conn, journalMsg, std::string(msg.get_path()), eventData, assert,
235 selBMCGenID, "REDFISH_MESSAGE_ID=%s", redfishMessageID.c_str(),
236 "REDFISH_MESSAGE_ARGS=%s", eventMessageArgs.c_str(), NULL);
Willy Tuf0243dc2021-08-03 22:49:14 -0700237 }
238}
239
Patrick Williamsa58ea682025-02-01 08:22:21 -0500240inline static sdbusplus::bus::match_t startWatchdogEventMonitor(
241 std::shared_ptr<sdbusplus::asio::connection> conn)
Willy Tuf0243dc2021-08-03 22:49:14 -0700242{
Patrick Williamsccef2272022-07-22 19:26:54 -0500243 auto watchdogEventMatcherCallback = [conn](sdbusplus::message_t& msg) {
244 std::string expiredAction;
245 msg.read(expiredAction);
Willy Tuf0243dc2021-08-03 22:49:14 -0700246
Patrick Williamsccef2272022-07-22 19:26:54 -0500247 std::string_view action = expiredAction;
248 action.remove_prefix(
249 std::min(action.find_last_of(".") + 1, action.size()));
Willy Tuf0243dc2021-08-03 22:49:14 -0700250
Patrick Williamsccef2272022-07-22 19:26:54 -0500251 sendWatchdogEventLog(conn, msg, true, action);
252 };
Willy Tuf0243dc2021-08-03 22:49:14 -0700253
Patrick Williamsccef2272022-07-22 19:26:54 -0500254 sdbusplus::bus::match_t watchdogEventMatcher(
255 static_cast<sdbusplus::bus_t&>(*conn),
Willy Tuf0243dc2021-08-03 22:49:14 -0700256 "type='signal',interface='xyz.openbmc_project.Watchdog',"
257 "member='Timeout'",
Charles Hsudbd77b92020-10-29 11:20:34 +0800258 std::move(watchdogEventMatcherCallback));
Willy Tuf0243dc2021-08-03 22:49:14 -0700259
Charles Hsudbd77b92020-10-29 11:20:34 +0800260 return watchdogEventMatcher;
261}