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