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