1 #include <attn/attn_common.hpp>
2 #include <attn/attn_dbus.hpp>
3 #include <attn/attn_dump.hpp>
4 #include <attn/attn_logging.hpp>
5 #include <attn/pel/pel_common.hpp>
6 #include <attn/ti_handler.hpp>
7 #include <sdbusplus/bus.hpp>
8 #include <sdbusplus/exception.hpp>
9 #include <util/dbus.hpp>
10 #include <util/trace.hpp>
11
12 #include <format>
13 #include <iomanip>
14 #include <iostream>
15
16 namespace attn
17 {
18
19 /**
20 * @brief Determine if this is a HB or PHYP TI event
21 *
22 * Use the TI info data area to determine if this is either a HB or a PHYP
23 * TI event then handle the event.
24 *
25 * @param i_tiDataArea pointer to the TI info data
26 */
tiHandler(TiDataArea * i_tiDataArea)27 int tiHandler(TiDataArea* i_tiDataArea)
28 {
29 int rc = RC_SUCCESS;
30
31 // capture some additional data for logs/traces
32 addHbStatusRegs();
33
34 // check TI data area if it is available
35 if (nullptr != i_tiDataArea)
36 {
37 // HB v. PHYP TI logic: Only hosboot will fill in hbTerminateType
38 // and it will be non-zero. Only hostboot will fill out source and
39 // it it will be non-zero. Only PHYP will fill in srcFormat and it
40 // will be non-zero.
41 if ((0 == i_tiDataArea->hbTerminateType) &&
42 (0 == i_tiDataArea->source) && (0 != i_tiDataArea->srcFormat))
43 {
44 handlePhypTi(i_tiDataArea);
45 }
46 else
47 {
48 handleHbTi(i_tiDataArea);
49 }
50 }
51 else
52 {
53 // TI data was not available This should not happen since we provide
54 // a default TI info in the case where get TI info was not successful.
55 eventAttentionFail((int)AttnSection::tiHandler | ATTN_INFO_NULL);
56 rc = RC_NOT_HANDLED;
57 }
58
59 return rc;
60 }
61
62 /**
63 * @brief Handle a PHYP terminate immediate special attention
64 *
65 * The TI info data area will contain information pertaining to the TI
66 * condition. We will wither quiesce the host or initiate a MPIPL depending
67 * depending on the auto reboot configuration. We will also create a PEL which
68 * will contain the TI info data and FFDC data captured in the system journal.
69 *
70 * @param i_tiDataArea pointer to TI information filled in by hostboot
71 */
handlePhypTi(TiDataArea * i_tiDataArea)72 void handlePhypTi(TiDataArea* i_tiDataArea)
73 {
74 trace::inf("PHYP TI");
75
76 // gather additional data for PEL
77 std::map<std::string, std::string> tiAdditionalData;
78
79 // make note of recoverable errors present
80 tiAdditionalData["recoverables"] = recoverableErrors() ? "true" : "false";
81
82 if (nullptr != i_tiDataArea)
83 {
84 parsePhypOpalTiInfo(tiAdditionalData, i_tiDataArea);
85
86 tiAdditionalData["Subsystem"] =
87 std::to_string(static_cast<uint8_t>(pel::SubsystemID::hypervisor));
88
89 // Copy all ascii src chars to additional data
90 char srcChar[33]; // 32 ascii chars + null term
91 memcpy(srcChar, &(i_tiDataArea->asciiData0), 32);
92 srcChar[32] = 0;
93 tiAdditionalData["SrcAscii"] = std::string{srcChar};
94
95 // TI event
96 eventTerminate(tiAdditionalData, (char*)i_tiDataArea);
97 }
98 else
99 {
100 // TI data was not available This should not happen since we provide
101 // a default TI info in the case where get TI info was not successful.
102 eventAttentionFail((int)AttnSection::handlePhypTi | ATTN_INFO_NULL);
103 }
104
105 // We are finished creating the event log entries so transition host to
106 // the required state.
107 if (true == util::dbus::dumpPolicyEnabled())
108 {
109 // MPIPL is considered a "dump" so we will qualify this transition with
110 // the dumpPolicyEnabled property. MPIPL is triggered by by starting
111 // the host "crash" target.
112 util::dbus::transitionHost(util::dbus::HostState::Crash);
113 }
114 else
115 {
116 // If dumpPolicyEnabled property is disabled we will quiesce the host
117 util::dbus::transitionHost(util::dbus::HostState::Quiesce);
118 }
119 }
120
121 /**
122 * @brief Handle a hostboot terminate immediate with SRC provided
123 *
124 * The TI info will contain the log ID of the event log that has already been
125 * submitted by hostboot. In this case the attention handler does not need to
126 * create a PEL. A hostboot dump may be requested and the host will be
127 * transitioned.
128 *
129 * @param i_tiDataArea pointer to TI information filled in by hostboot
130 */
handleHbTiWithEid(TiDataArea * i_tiDataArea)131 void handleHbTiWithEid(TiDataArea* i_tiDataArea)
132 {
133 trace::inf("HB TI with PLID/EID");
134
135 if (nullptr != i_tiDataArea)
136 {
137 // Trace relevant TI data.
138 trace::inf("TI data HB Flags = 0x%02x", i_tiDataArea->hbFlags);
139 trace::inf("TI data HB Word 0 = 0x%08x",
140 be32toh(i_tiDataArea->srcWord12HbWord0));
141 trace::inf("TI data HB Word 2 = 0x%08x",
142 be32toh(i_tiDataArea->srcWord13HbWord2));
143 trace::inf("TI data HB Word 3 = 0x%08x",
144 be32toh(i_tiDataArea->srcWord14HbWord3));
145 trace::inf("TI data HB Word 4 = 0x%08x",
146 be32toh(i_tiDataArea->srcWord15HbWord4));
147 trace::inf("TI data HB Word 5 = 0x%08x",
148 be32toh(i_tiDataArea->srcWord16HbWord5));
149 trace::inf("TI data HB Word 6 = 0x%08x",
150 be32toh(i_tiDataArea->srcWord17HbWord6));
151 trace::inf("TI data HB Word 7 = 0x%08x",
152 be32toh(i_tiDataArea->srcWord18HbWord7));
153 trace::inf("TI data HB Word 8 = 0x%08x",
154 be32toh(i_tiDataArea->srcWord19HbWord8));
155 trace::inf("TI data Error Data = 0x%08x",
156 be32toh(i_tiDataArea->asciiData0));
157 trace::inf("TI data EID = 0x%08x", be32toh(i_tiDataArea->asciiData1));
158
159 // see if HB dump is requested
160 if (i_tiDataArea->hbFlags & hbDumpFlag)
161 {
162 // retrieve log ID from TI info data
163 uint32_t logId = be32toh(i_tiDataArea->asciiData1);
164 requestDump(logId, DumpParameters{0, DumpType::Hostboot});
165 }
166 }
167
168 util::dbus::transitionHost(util::dbus::HostState::Quiesce);
169 }
170
171 /**
172 * @brief Handle a hostboot terminate immediate with SRC provided
173 *
174 * The TI info will contain the reason code and additional data necessary
175 * to create a PEL on behalf of hostboot. A hostboot dump may be created
176 * (after generating the PEL) and the host may be transitioned depending
177 * on the reason code.
178 *
179 * @param i_tiDataArea pointer to TI information filled in by hostboot
180 */
handleHbTiWithSrc(TiDataArea * i_tiDataArea)181 void handleHbTiWithSrc(TiDataArea* i_tiDataArea)
182 {
183 trace::inf("HB TI with SRC");
184
185 // handle specific hostboot reason codes
186 if (nullptr != i_tiDataArea)
187 {
188 // Reason code is byte 2 and 3 of 4 byte srcWord12HbWord0
189 uint16_t reasonCode = be32toh(i_tiDataArea->srcWord12HbWord0);
190
191 trace::inf("reason code %04x", reasonCode);
192
193 // for clean shutdown (reason code 050B) no PEL and no dump
194 if (reasonCode != HB_SRC_SHUTDOWN_REQUEST)
195 {
196 // gather additional data for PEL
197 std::map<std::string, std::string> tiAdditionalData;
198
199 // make note of recoverable errors present
200 tiAdditionalData["recoverables"] =
201 recoverableErrors() ? "true" : "false";
202
203 parseHbTiInfo(tiAdditionalData, i_tiDataArea);
204
205 tiAdditionalData["Subsystem"] = std::to_string(
206 static_cast<uint8_t>(pel::SubsystemID::hostboot));
207
208 // Translate hex src value to ascii. This results in an 8
209 // character SRC (hostboot SRC is 32 bits)
210 tiAdditionalData["SrcAscii"] =
211 std::format("{:08X}", be32toh(i_tiDataArea->srcWord12HbWord0));
212
213 // dump flag is only valid for TI with EID (not TI with SRC)
214 trace::inf("Ignoring TI info dump flag for HB TI with SRC");
215 tiAdditionalData["Dump"] = "true";
216
217 // TI with SRC will honor hbNotVisibleFlag
218 if (i_tiDataArea->hbFlags & hbNotVisibleFlag)
219 {
220 tiAdditionalData["hidden"] = "true";
221 }
222
223 // Generate event log
224 eventTerminate(tiAdditionalData, (char*)i_tiDataArea);
225 }
226
227 if (HB_SRC_KEY_TRANSITION != reasonCode)
228 {
229 util::dbus::transitionHost(util::dbus::HostState::Quiesce);
230 }
231 }
232 else
233 {
234 // TI data was not available, this should not happen
235 eventAttentionFail((int)AttnSection::handleHbTi | ATTN_INFO_NULL);
236 }
237 }
238
239 /**
240 * @brief Handle a hostboot terminate immediate special attention
241 *
242 * The TI info data area will contain information pertaining to the TI
243 * condition. The course of action to take regarding the host state will
244 * depend on the contents of the TI info data area. We will also create a
245 * PEL containing the TI info data and FFDC data captured in the system
246 * journal.
247 *
248 * @param i_tiDataArea pointer to TI information filled in by hostboot
249 */
handleHbTi(TiDataArea * i_tiDataArea)250 void handleHbTi(TiDataArea* i_tiDataArea)
251 {
252 trace::inf("HB TI");
253
254 // handle specific hostboot reason codes
255 if (nullptr != i_tiDataArea)
256 {
257 uint8_t terminateType = i_tiDataArea->hbTerminateType;
258
259 if (TI_WITH_SRC == terminateType)
260 {
261 handleHbTiWithSrc(i_tiDataArea);
262 }
263 else
264 {
265 handleHbTiWithEid(i_tiDataArea);
266 }
267 }
268 else
269 {
270 // TI data was not available, this should not happen
271 eventAttentionFail((int)AttnSection::handleHbTi | ATTN_INFO_NULL);
272 }
273 }
274
275 /** @brief Parse the TI info data area into map as PHYP/OPAL data */
parsePhypOpalTiInfo(std::map<std::string,std::string> & i_map,TiDataArea * i_tiDataArea)276 void parsePhypOpalTiInfo(std::map<std::string, std::string>& i_map,
277 TiDataArea* i_tiDataArea)
278 {
279 if (nullptr == i_tiDataArea)
280 {
281 return;
282 }
283
284 i_map["0x00 TI Area Valid"] =
285 std::format("{:02x}", i_tiDataArea->tiAreaValid);
286 i_map["0x01 Command"] = std::format("{:02x}", i_tiDataArea->command);
287 i_map["0x02 Num. Data Bytes"] =
288 std::format("{:04x}", be16toh(i_tiDataArea->numDataBytes));
289 i_map["0x04 Reserved"] = std::format("{:02x}", i_tiDataArea->reserved1);
290 i_map["0x06 HWDump Type"] =
291 std::format("{:04x}", be16toh(i_tiDataArea->hardwareDumpType));
292 i_map["0x08 SRC Format"] = std::format("{:02x}", i_tiDataArea->srcFormat);
293 i_map["0x09 SRC Flags"] = std::format("{:02x}", i_tiDataArea->srcFlags);
294 i_map["0x0a Num. ASCII Words"] =
295 std::format("{:02x}", i_tiDataArea->numAsciiWords);
296 i_map["0x0b Num. Hex Words"] =
297 std::format("{:02x}", i_tiDataArea->numHexWords);
298 i_map["0x0e Length of SRC"] =
299 std::format("{:04x}", be16toh(i_tiDataArea->lenSrc));
300 i_map["0x10 SRC Word 12"] =
301 std::format("{:08x}", be32toh(i_tiDataArea->srcWord12HbWord0));
302 i_map["0x14 SRC Word 13"] =
303 std::format("{:08x}", be32toh(i_tiDataArea->srcWord13HbWord2));
304 i_map["0x18 SRC Word 14"] =
305 std::format("{:08x}", be32toh(i_tiDataArea->srcWord14HbWord3));
306 i_map["0x1c SRC Word 15"] =
307 std::format("{:08x}", be32toh(i_tiDataArea->srcWord15HbWord4));
308 i_map["0x20 SRC Word 16"] =
309 std::format("{:08x}", be32toh(i_tiDataArea->srcWord16HbWord5));
310 i_map["0x24 SRC Word 17"] =
311 std::format("{:08x}", be32toh(i_tiDataArea->srcWord17HbWord6));
312 i_map["0x28 SRC Word 18"] =
313 std::format("{:08x}", be32toh(i_tiDataArea->srcWord18HbWord7));
314 i_map["0x2c SRC Word 19"] =
315 std::format("{:08x}", be32toh(i_tiDataArea->srcWord19HbWord8));
316 i_map["0x30 ASCII Data"] =
317 std::format("{:08x}", be32toh(i_tiDataArea->asciiData0));
318 i_map["0x34 ASCII Data"] =
319 std::format("{:08x}", be32toh(i_tiDataArea->asciiData1));
320 i_map["0x38 ASCII Data"] =
321 std::format("{:08x}", be32toh(i_tiDataArea->asciiData2));
322 i_map["0x3c ASCII Data"] =
323 std::format("{:08x}", be32toh(i_tiDataArea->asciiData3));
324 i_map["0x40 ASCII Data"] =
325 std::format("{:08x}", be32toh(i_tiDataArea->asciiData4));
326 i_map["0x44 ASCII Data"] =
327 std::format("{:08x}", be32toh(i_tiDataArea->asciiData5));
328 i_map["0x48 ASCII Data"] =
329 std::format("{:08x}", be32toh(i_tiDataArea->asciiData6));
330 i_map["0x4c ASCII Data"] =
331 std::format("{:08x}", be32toh(i_tiDataArea->asciiData7));
332 i_map["0x50 Location"] = std::format("{:02x}", i_tiDataArea->location);
333 i_map["0x51 Code Sections"] =
334 std::format("{:02x}", i_tiDataArea->codeSection);
335 i_map["0x52 Additional Size"] =
336 std::format("{:02x}", i_tiDataArea->additionalSize);
337 i_map["0x53 Additional Data"] =
338 std::format("{:02x}", i_tiDataArea->andData);
339 }
340
341 /** @brief Parse the TI info data area into map as hostboot data */
parseHbTiInfo(std::map<std::string,std::string> & i_map,TiDataArea * i_tiDataArea)342 void parseHbTiInfo(std::map<std::string, std::string>& i_map,
343 TiDataArea* i_tiDataArea)
344 {
345 if (nullptr == i_tiDataArea)
346 {
347 return;
348 }
349
350 i_map["0x00 TI Area Valid"] =
351 std::format("{:02x}", i_tiDataArea->tiAreaValid);
352 i_map["0x04 Reserved"] = std::format("{:02x}", i_tiDataArea->reserved1);
353 i_map["0x05 HB_Term. Type"] =
354 std::format("{:02x}", i_tiDataArea->hbTerminateType);
355 i_map["0x0c HB Flags"] = std::format("{:02x}", i_tiDataArea->hbFlags);
356 i_map["0x0d Source"] = std::format("{:02x}", i_tiDataArea->source);
357 i_map["0x10 HB Word 0"] =
358 std::format("{:08x}", be32toh(i_tiDataArea->srcWord12HbWord0));
359 i_map["0x14 HB Word 2"] =
360 std::format("{:08x}", be32toh(i_tiDataArea->srcWord13HbWord2));
361 i_map["0x18 HB Word 3"] =
362 std::format("{:08x}", be32toh(i_tiDataArea->srcWord14HbWord3));
363 i_map["0x1c HB Word 4"] =
364 std::format("{:08x}", be32toh(i_tiDataArea->srcWord15HbWord4));
365 i_map["0x20 HB Word 5"] =
366 std::format("{:08x}", be32toh(i_tiDataArea->srcWord16HbWord5));
367 i_map["0x24 HB Word 6"] =
368 std::format("{:08x}", be32toh(i_tiDataArea->srcWord17HbWord6));
369 i_map["0x28 HB Word 7"] =
370 std::format("{:08x}", be32toh(i_tiDataArea->srcWord18HbWord7));
371 i_map["0x2c HB Word 8"] =
372 std::format("{:08x}", be32toh(i_tiDataArea->srcWord19HbWord8));
373 i_map["0x30 error_data"] =
374 std::format("{:08x}", be32toh(i_tiDataArea->asciiData0));
375 i_map["0x34 EID"] =
376 std::format("{:08x}", be32toh(i_tiDataArea->asciiData1));
377 }
378
379 } // namespace attn
380