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