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"] = recoverableErrors() ? "true"
179                                                                    : "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"] = std::format("{:02x}",
263                                               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"] = std::format("{:02x}",
273                                                  i_tiDataArea->numAsciiWords);
274     i_map["0x0b Num. Hex Words"] = std::format("{:02x}",
275                                                i_tiDataArea->numHexWords);
276     i_map["0x0e Length of SRC"] = std::format("{:04x}",
277                                               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"] = std::format("{:08x}",
295                                            be32toh(i_tiDataArea->asciiData0));
296     i_map["0x34 ASCII Data"] = std::format("{:08x}",
297                                            be32toh(i_tiDataArea->asciiData1));
298     i_map["0x38 ASCII Data"] = std::format("{:08x}",
299                                            be32toh(i_tiDataArea->asciiData2));
300     i_map["0x3c ASCII Data"] = std::format("{:08x}",
301                                            be32toh(i_tiDataArea->asciiData3));
302     i_map["0x40 ASCII Data"] = std::format("{:08x}",
303                                            be32toh(i_tiDataArea->asciiData4));
304     i_map["0x44 ASCII Data"] = std::format("{:08x}",
305                                            be32toh(i_tiDataArea->asciiData5));
306     i_map["0x48 ASCII Data"] = std::format("{:08x}",
307                                            be32toh(i_tiDataArea->asciiData6));
308     i_map["0x4c ASCII Data"] = std::format("{:08x}",
309                                            be32toh(i_tiDataArea->asciiData7));
310     i_map["0x50 Location"] = std::format("{:02x}", i_tiDataArea->location);
311     i_map["0x51 Code Sections"] = std::format("{:02x}",
312                                               i_tiDataArea->codeSection);
313     i_map["0x52 Additional Size"] = std::format("{:02x}",
314                                                 i_tiDataArea->additionalSize);
315     i_map["0x53 Additional Data"] = std::format("{:02x}",
316                                                 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"] = std::format("{:02x}",
329                                               i_tiDataArea->tiAreaValid);
330     i_map["0x04 Reserved"] = std::format("{:02x}", i_tiDataArea->reserved1);
331     i_map["0x05 HB_Term. Type"] = std::format("{:02x}",
332                                               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"] = std::format("{:08x}",
352                                            be32toh(i_tiDataArea->asciiData0));
353     i_map["0x34 EID"] = std::format("{:08x}",
354                                     be32toh(i_tiDataArea->asciiData1));
355 }
356 
357 } // namespace attn
358