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 // see if HB dump is requested
138 if (i_tiDataArea->hbFlags & hbDumpFlag)
139 {
140 // retrieve log ID from TI info data
141 uint32_t logId = be32toh(i_tiDataArea->asciiData1);
142 requestDump(logId, DumpParameters{0, DumpType::Hostboot});
143 }
144 }
145
146 util::dbus::transitionHost(util::dbus::HostState::Quiesce);
147 }
148
149 /**
150 * @brief Handle a hostboot terminate immediate with SRC provided
151 *
152 * The TI info will contain the reason code and additional data necessary
153 * to create a PEL on behalf of hostboot. A hostboot dump may be created
154 * (after generating the PEL) and the host may be transitioned depending
155 * on the reason code.
156 *
157 * @param i_tiDataArea pointer to TI information filled in by hostboot
158 */
handleHbTiWithSrc(TiDataArea * i_tiDataArea)159 void handleHbTiWithSrc(TiDataArea* i_tiDataArea)
160 {
161 trace::inf("HB TI with SRC");
162
163 // handle specific hostboot reason codes
164 if (nullptr != i_tiDataArea)
165 {
166 // Reason code is byte 2 and 3 of 4 byte srcWord12HbWord0
167 uint16_t reasonCode = be32toh(i_tiDataArea->srcWord12HbWord0);
168
169 trace::inf("reason code %04x", reasonCode);
170
171 // for clean shutdown (reason code 050B) no PEL and no dump
172 if (reasonCode != HB_SRC_SHUTDOWN_REQUEST)
173 {
174 // gather additional data for PEL
175 std::map<std::string, std::string> tiAdditionalData;
176
177 // make note of recoverable errors present
178 tiAdditionalData["recoverables"] =
179 recoverableErrors() ? "true" : "false";
180
181 parseHbTiInfo(tiAdditionalData, i_tiDataArea);
182
183 tiAdditionalData["Subsystem"] = std::to_string(
184 static_cast<uint8_t>(pel::SubsystemID::hostboot));
185
186 // Translate hex src value to ascii. This results in an 8
187 // character SRC (hostboot SRC is 32 bits)
188 tiAdditionalData["SrcAscii"] =
189 std::format("{:08X}", be32toh(i_tiDataArea->srcWord12HbWord0));
190
191 // dump flag is only valid for TI with EID (not TI with SRC)
192 trace::inf("Ignoring TI info dump flag for HB TI with SRC");
193 tiAdditionalData["Dump"] = "true";
194
195 // TI with SRC will honor hbNotVisibleFlag
196 if (i_tiDataArea->hbFlags & hbNotVisibleFlag)
197 {
198 tiAdditionalData["hidden"] = "true";
199 }
200
201 // Generate event log
202 eventTerminate(tiAdditionalData, (char*)i_tiDataArea);
203 }
204
205 if (HB_SRC_KEY_TRANSITION != reasonCode)
206 {
207 util::dbus::transitionHost(util::dbus::HostState::Quiesce);
208 }
209 }
210 else
211 {
212 // TI data was not available, this should not happen
213 eventAttentionFail((int)AttnSection::handleHbTi | ATTN_INFO_NULL);
214 }
215 }
216
217 /**
218 * @brief Handle a hostboot terminate immediate special attention
219 *
220 * The TI info data area will contain information pertaining to the TI
221 * condition. The course of action to take regarding the host state will
222 * depend on the contents of the TI info data area. We will also create a
223 * PEL containing the TI info data and FFDC data captured in the system
224 * journal.
225 *
226 * @param i_tiDataArea pointer to TI information filled in by hostboot
227 */
handleHbTi(TiDataArea * i_tiDataArea)228 void handleHbTi(TiDataArea* i_tiDataArea)
229 {
230 trace::inf("HB TI");
231
232 // handle specific hostboot reason codes
233 if (nullptr != i_tiDataArea)
234 {
235 uint8_t terminateType = i_tiDataArea->hbTerminateType;
236
237 if (TI_WITH_SRC == terminateType)
238 {
239 handleHbTiWithSrc(i_tiDataArea);
240 }
241 else
242 {
243 handleHbTiWithEid(i_tiDataArea);
244 }
245 }
246 else
247 {
248 // TI data was not available, this should not happen
249 eventAttentionFail((int)AttnSection::handleHbTi | ATTN_INFO_NULL);
250 }
251 }
252
253 /** @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)254 void parsePhypOpalTiInfo(std::map<std::string, std::string>& i_map,
255 TiDataArea* i_tiDataArea)
256 {
257 if (nullptr == i_tiDataArea)
258 {
259 return;
260 }
261
262 i_map["0x00 TI Area Valid"] =
263 std::format("{:02x}", i_tiDataArea->tiAreaValid);
264 i_map["0x01 Command"] = std::format("{:02x}", i_tiDataArea->command);
265 i_map["0x02 Num. Data Bytes"] =
266 std::format("{:04x}", be16toh(i_tiDataArea->numDataBytes));
267 i_map["0x04 Reserved"] = std::format("{:02x}", i_tiDataArea->reserved1);
268 i_map["0x06 HWDump Type"] =
269 std::format("{:04x}", be16toh(i_tiDataArea->hardwareDumpType));
270 i_map["0x08 SRC Format"] = std::format("{:02x}", i_tiDataArea->srcFormat);
271 i_map["0x09 SRC Flags"] = std::format("{:02x}", i_tiDataArea->srcFlags);
272 i_map["0x0a Num. ASCII Words"] =
273 std::format("{:02x}", i_tiDataArea->numAsciiWords);
274 i_map["0x0b Num. Hex Words"] =
275 std::format("{:02x}", i_tiDataArea->numHexWords);
276 i_map["0x0e Length of SRC"] =
277 std::format("{:04x}", be16toh(i_tiDataArea->lenSrc));
278 i_map["0x10 SRC Word 12"] =
279 std::format("{:08x}", be32toh(i_tiDataArea->srcWord12HbWord0));
280 i_map["0x14 SRC Word 13"] =
281 std::format("{:08x}", be32toh(i_tiDataArea->srcWord13HbWord2));
282 i_map["0x18 SRC Word 14"] =
283 std::format("{:08x}", be32toh(i_tiDataArea->srcWord14HbWord3));
284 i_map["0x1c SRC Word 15"] =
285 std::format("{:08x}", be32toh(i_tiDataArea->srcWord15HbWord4));
286 i_map["0x20 SRC Word 16"] =
287 std::format("{:08x}", be32toh(i_tiDataArea->srcWord16HbWord5));
288 i_map["0x24 SRC Word 17"] =
289 std::format("{:08x}", be32toh(i_tiDataArea->srcWord17HbWord6));
290 i_map["0x28 SRC Word 18"] =
291 std::format("{:08x}", be32toh(i_tiDataArea->srcWord18HbWord7));
292 i_map["0x2c SRC Word 19"] =
293 std::format("{:08x}", be32toh(i_tiDataArea->srcWord19HbWord8));
294 i_map["0x30 ASCII Data"] =
295 std::format("{:08x}", be32toh(i_tiDataArea->asciiData0));
296 i_map["0x34 ASCII Data"] =
297 std::format("{:08x}", be32toh(i_tiDataArea->asciiData1));
298 i_map["0x38 ASCII Data"] =
299 std::format("{:08x}", be32toh(i_tiDataArea->asciiData2));
300 i_map["0x3c ASCII Data"] =
301 std::format("{:08x}", be32toh(i_tiDataArea->asciiData3));
302 i_map["0x40 ASCII Data"] =
303 std::format("{:08x}", be32toh(i_tiDataArea->asciiData4));
304 i_map["0x44 ASCII Data"] =
305 std::format("{:08x}", be32toh(i_tiDataArea->asciiData5));
306 i_map["0x48 ASCII Data"] =
307 std::format("{:08x}", be32toh(i_tiDataArea->asciiData6));
308 i_map["0x4c ASCII Data"] =
309 std::format("{:08x}", be32toh(i_tiDataArea->asciiData7));
310 i_map["0x50 Location"] = std::format("{:02x}", i_tiDataArea->location);
311 i_map["0x51 Code Sections"] =
312 std::format("{:02x}", i_tiDataArea->codeSection);
313 i_map["0x52 Additional Size"] =
314 std::format("{:02x}", i_tiDataArea->additionalSize);
315 i_map["0x53 Additional Data"] =
316 std::format("{:02x}", i_tiDataArea->andData);
317 }
318
319 /** @brief Parse the TI info data area into map as hostboot data */
parseHbTiInfo(std::map<std::string,std::string> & i_map,TiDataArea * i_tiDataArea)320 void parseHbTiInfo(std::map<std::string, std::string>& i_map,
321 TiDataArea* i_tiDataArea)
322 {
323 if (nullptr == i_tiDataArea)
324 {
325 return;
326 }
327
328 i_map["0x00 TI Area Valid"] =
329 std::format("{:02x}", i_tiDataArea->tiAreaValid);
330 i_map["0x04 Reserved"] = std::format("{:02x}", i_tiDataArea->reserved1);
331 i_map["0x05 HB_Term. Type"] =
332 std::format("{:02x}", i_tiDataArea->hbTerminateType);
333 i_map["0x0c HB Flags"] = std::format("{:02x}", i_tiDataArea->hbFlags);
334 i_map["0x0d Source"] = std::format("{:02x}", i_tiDataArea->source);
335 i_map["0x10 HB Word 0"] =
336 std::format("{:08x}", be32toh(i_tiDataArea->srcWord12HbWord0));
337 i_map["0x14 HB Word 2"] =
338 std::format("{:08x}", be32toh(i_tiDataArea->srcWord13HbWord2));
339 i_map["0x18 HB Word 3"] =
340 std::format("{:08x}", be32toh(i_tiDataArea->srcWord14HbWord3));
341 i_map["0x1c HB Word 4"] =
342 std::format("{:08x}", be32toh(i_tiDataArea->srcWord15HbWord4));
343 i_map["0x20 HB Word 5"] =
344 std::format("{:08x}", be32toh(i_tiDataArea->srcWord16HbWord5));
345 i_map["0x24 HB Word 6"] =
346 std::format("{:08x}", be32toh(i_tiDataArea->srcWord17HbWord6));
347 i_map["0x28 HB Word 7"] =
348 std::format("{:08x}", be32toh(i_tiDataArea->srcWord18HbWord7));
349 i_map["0x2c HB Word 8"] =
350 std::format("{:08x}", be32toh(i_tiDataArea->srcWord19HbWord8));
351 i_map["0x30 error_data"] =
352 std::format("{:08x}", be32toh(i_tiDataArea->asciiData0));
353 i_map["0x34 EID"] =
354 std::format("{:08x}", be32toh(i_tiDataArea->asciiData1));
355 }
356
357 } // namespace attn
358