blob: 9752fca5173ab3bafe122fea7aa6ff1c472c1f00 [file] [log] [blame]
Ben Tynerbcf65a82020-12-01 08:46:36 -06001#include <attn/attn_common.hpp>
Ben Tynerb797b3e2020-06-29 10:12:05 -05002#include <attn/attn_handler.hpp>
3#include <attn/attn_logging.hpp>
Ben Tynerf5210bb2021-01-05 12:58:10 -06004#include <attn/pel/pel_common.hpp>
Ben Tynerb797b3e2020-06-29 10:12:05 -05005#include <attn/ti_handler.hpp>
Ben Tyner9ae5ca42020-02-28 13:13:50 -06006#include <sdbusplus/bus.hpp>
Ben Tynerff17f962020-09-23 08:21:19 -05007#include <sdbusplus/exception.hpp>
Ben Tyner9ae5ca42020-02-28 13:13:50 -06008
Ben Tyner40717722020-09-23 09:43:20 -05009#include <iomanip>
10#include <iostream>
11
Ben Tyner9ae5ca42020-02-28 13:13:50 -060012namespace attn
13{
14
Ben Tyner8c5e4f42020-10-28 11:11:55 -050015/**
16 * @brief Determine if this is a HB or PHYP TI event
17 *
18 * Use the TI info data area to determine if this is either a HB or a PHYP
19 * TI event then handle the event.
20 *
Ben Tynerf5210bb2021-01-05 12:58:10 -060021 * @param i_tiDataArea pointer to the TI info data
Ben Tyner8c5e4f42020-10-28 11:11:55 -050022 */
Ben Tyner792f32f2020-06-02 08:50:47 -050023int tiHandler(TiDataArea* i_tiDataArea)
Ben Tyner9ae5ca42020-02-28 13:13:50 -060024{
Ben Tynere4f5dbe2020-10-19 07:19:33 -050025 int rc = RC_SUCCESS;
Ben Tyner9ae5ca42020-02-28 13:13:50 -060026
Ben Tyner8c5e4f42020-10-28 11:11:55 -050027 // check TI data area if it is available
Ben Tynere4f5dbe2020-10-19 07:19:33 -050028 if (nullptr != i_tiDataArea)
Ben Tyner792f32f2020-06-02 08:50:47 -050029 {
Ben Tyner8c5e4f42020-10-28 11:11:55 -050030 // HB v. PHYP TI logic: Only hosboot will fill in hbTerminateType
Ben Tyner8882c322021-02-05 12:13:21 -060031 // and it will be non-zero. Only hostboot will fill out source and
32 // it it will be non-zero. Only PHYP will fill in srcFormat and it
33 // will be non-zero.
Ben Tyner8c5e4f42020-10-28 11:11:55 -050034 if ((0 == i_tiDataArea->hbTerminateType) &&
35 (0 == i_tiDataArea->source) && (0 != i_tiDataArea->srcFormat))
Ben Tynere4f5dbe2020-10-19 07:19:33 -050036 {
Ben Tyner8c5e4f42020-10-28 11:11:55 -050037 handlePhypTi(i_tiDataArea);
Ben Tynere4f5dbe2020-10-19 07:19:33 -050038 }
39 else
40 {
Ben Tyner8c5e4f42020-10-28 11:11:55 -050041 handleHbTi(i_tiDataArea);
Ben Tynere4f5dbe2020-10-19 07:19:33 -050042 }
Ben Tyner8c5e4f42020-10-28 11:11:55 -050043 }
44 else
45 {
Ben Tyner29651ef2021-02-08 10:51:03 -060046 // TI data was not available This should not happen since we provide
47 // a default TI info in the case where get TI info was not successful.
48 eventAttentionFail(ATTN_INFO_NULL);
49 rc = RC_NOT_HANDLED;
Ben Tynere4f5dbe2020-10-19 07:19:33 -050050 }
Ben Tyner40717722020-09-23 09:43:20 -050051
Ben Tyner8c5e4f42020-10-28 11:11:55 -050052 return rc;
53}
Ben Tynere4f5dbe2020-10-19 07:19:33 -050054
Ben Tyner8c5e4f42020-10-28 11:11:55 -050055/**
Ben Tyner8c5e4f42020-10-28 11:11:55 -050056 * @brief Handle a PHYP terminate immediate special attention
57 *
58 * The TI info data area will contain information pertaining to the TI
59 * condition. We will wither quiesce the host or initiate a MPIPL depending
60 * depending on the auto reboot configuration. We will also create a PEL which
61 * will contain the TI info data and FFDC data captured in the system journal.
62 *
63 * @param i_tiDataArea pointer to TI information filled in by hostboot
64 */
65void handlePhypTi(TiDataArea* i_tiDataArea)
66{
67 trace<level::INFO>("PHYP TI");
68
69 if (autoRebootEnabled())
70 {
Ben Tynerfe2757b2021-01-14 13:17:50 -060071 // If autoreboot is enabled we will start crash (mpipl) mode target
72 transitionHost(HostState::Crash);
Ben Tyner792f32f2020-06-02 08:50:47 -050073 }
Ben Tyner40717722020-09-23 09:43:20 -050074 else
75 {
Ben Tyner8c5e4f42020-10-28 11:11:55 -050076 // If autoreboot is disabled we will quiesce the host
Ben Tynerbcf65a82020-12-01 08:46:36 -060077 transitionHost(HostState::Quiesce);
Ben Tyner40717722020-09-23 09:43:20 -050078 }
Ben Tyner792f32f2020-06-02 08:50:47 -050079
Ben Tyner8c5e4f42020-10-28 11:11:55 -050080 // gather additional data for PEL
81 std::map<std::string, std::string> tiAdditionalData;
Ben Tynere4f5dbe2020-10-19 07:19:33 -050082
Ben Tyner8c5e4f42020-10-28 11:11:55 -050083 if (nullptr != i_tiDataArea)
84 {
85 parsePhypOpalTiInfo(tiAdditionalData, i_tiDataArea);
Ben Tyner29651ef2021-02-08 10:51:03 -060086
87 tiAdditionalData["Subsystem"] =
88 std::to_string(static_cast<uint8_t>(pel::SubsystemID::hypervisor));
89
Ben Tyner9d4f91c2021-02-09 08:27:58 -060090 // 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;
Ben Tyner29651ef2021-02-08 10:51:03 -060094 tiAdditionalData["SrcAscii"] = std::string{srcChar};
95
96 // TI event
97 eventTerminate(tiAdditionalData, (char*)i_tiDataArea);
Ben Tyner8c5e4f42020-10-28 11:11:55 -050098 }
Ben Tyner29651ef2021-02-08 10:51:03 -060099 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(ATTN_INFO_NULL);
104 }
Ben Tyner8c5e4f42020-10-28 11:11:55 -0500105}
106
107/**
108 * @brief Handle a hostboot terminate immediate special attention
109 *
110 * The TI info data area will contain information pertaining to the TI
111 * condition. The course of action to take regarding the host state will
112 * depend on the contents of the TI info data area. We will also create a
113 * PEL containing the TI info data and FFDC data captured in the system
114 * journal.
115 *
116 * @param i_tiDataArea pointer to TI information filled in by hostboot
117 */
118void handleHbTi(TiDataArea* i_tiDataArea)
119{
120 trace<level::INFO>("HB TI");
121
122 bool hbDumpRequested = true; // HB dump is common case
123 bool generatePel = true; // assume PEL will be created
124 bool terminateHost = true; // transition host state
125
126 // handle specific hostboot reason codes
127 if (nullptr != i_tiDataArea)
128 {
Ben Tyner8882c322021-02-05 12:13:21 -0600129 std::stringstream ss; // stream object for tracing
130 std::string strobj; // string object for tracing
Ben Tyner8c5e4f42020-10-28 11:11:55 -0500131
132 switch (i_tiDataArea->hbTerminateType)
133 {
134 case TI_WITH_PLID:
135 case TI_WITH_EID:
Ben Tyner8882c322021-02-05 12:13:21 -0600136
137 // trace this value
138 ss.str(std::string()); // empty the stream
139 ss.clear(); // clear the stream
140 ss << "TI with PLID/EID: " << std::hex << std::showbase
141 << std::setw(8) << std::setfill('0')
142 << be32toh(i_tiDataArea->asciiData1);
143 strobj = ss.str();
144 trace<level::INFO>(strobj.c_str());
145
146 // see if HB dump is requested
Ben Tyner8c5e4f42020-10-28 11:11:55 -0500147 if (0 == i_tiDataArea->hbDumpFlag)
148 {
149 hbDumpRequested = false; // no HB dump requested
150 }
151 break;
152 case TI_WITH_SRC:
Ben Tyner8882c322021-02-05 12:13:21 -0600153 // Reason code is byte 2 and 3 of 4 byte srcWord12HbWord0
154 uint16_t reasonCode = be32toh(i_tiDataArea->srcWord12HbWord0);
Ben Tyner8c5e4f42020-10-28 11:11:55 -0500155
Ben Tyner8882c322021-02-05 12:13:21 -0600156 // trace this value
157 ss.str(std::string()); // empty the stream
158 ss.clear(); // clear the stream
159 ss << "TI with SRC: " << std::hex << std::showbase
160 << std::setw(4) << std::setfill('0') << (int)reasonCode;
161 strobj = ss.str();
162 trace<level::INFO>(strobj.c_str());
Ben Tyner8c5e4f42020-10-28 11:11:55 -0500163
Ben Tyner8882c322021-02-05 12:13:21 -0600164 switch (reasonCode)
Ben Tyner8c5e4f42020-10-28 11:11:55 -0500165 {
166 case HB_SRC_SHUTDOWN_REQUEST:
167 trace<level::INFO>("shutdown request");
Ben Tyner8882c322021-02-05 12:13:21 -0600168 generatePel = false;
169 hbDumpRequested = false;
Ben Tyner8c5e4f42020-10-28 11:11:55 -0500170 break;
171 case HB_SRC_KEY_TRANSITION:
Ben Tyner8882c322021-02-05 12:13:21 -0600172 // Note: Should never see this so lets leave
173 // hbDumpRequested == true so we can figure out why
174 // we are here.
Ben Tyner8c5e4f42020-10-28 11:11:55 -0500175 trace<level::INFO>("key transition");
176 terminateHost = false;
177 break;
178 case HB_SRC_INSUFFICIENT_HW:
179 trace<level::INFO>("insufficient hardware");
180 break;
181 case HB_SRC_TPM_FAIL:
182 trace<level::INFO>("TPM fail");
183 break;
184 case HB_SRC_ROM_VERIFY:
185 trace<level::INFO>("ROM verify");
186 break;
187 case HB_SRC_EXT_MISMATCH:
188 trace<level::INFO>("EXT mismatch");
189 break;
190 case HB_SRC_ECC_UE:
191 trace<level::INFO>("ECC UE");
192 break;
193 case HB_SRC_UNSUPPORTED_MODE:
194 trace<level::INFO>("unsupported mode");
195 break;
196 case HB_SRC_UNSUPPORTED_SFCRANGE:
197 trace<level::INFO>("unsupported SFC range");
198 break;
199 case HB_SRC_PARTITION_TABLE:
200 trace<level::INFO>("partition table invalid");
201 break;
202 case HB_SRC_UNSUPPORTED_HARDWARE:
203 trace<level::INFO>("unsupported hardware");
204 break;
205 case HB_SRC_PNOR_CORRUPTION:
206 trace<level::INFO>("PNOR corruption");
207 break;
208 default:
209 trace<level::INFO>("reason: other");
210 }
211
212 break;
213 }
214 }
215
216 if (true == terminateHost)
217 {
218 // if hostboot dump is requested initiate dump
219 if (hbDumpRequested)
220 {
221 // Until HB dump support available just quiesce the host - once
222 // dump support is available the dump component will transition
223 // (ipl/halt) the host.
Ben Tynerbcf65a82020-12-01 08:46:36 -0600224 transitionHost(HostState::Quiesce);
Ben Tyner8c5e4f42020-10-28 11:11:55 -0500225 }
226 else
227 {
228 // Quiese the host - when the host is quiesced it will either
229 // "halt" or IPL depending on autoreboot setting.
Ben Tynerbcf65a82020-12-01 08:46:36 -0600230 transitionHost(HostState::Quiesce);
Ben Tyner8c5e4f42020-10-28 11:11:55 -0500231 }
232 }
233
234 // gather additional data for PEL
235 std::map<std::string, std::string> tiAdditionalData;
236
237 if (nullptr != i_tiDataArea)
238 {
239 parseHbTiInfo(tiAdditionalData, i_tiDataArea);
Ben Tyner29651ef2021-02-08 10:51:03 -0600240
241 if (true == generatePel)
242 {
243 tiAdditionalData["Subsystem"] = std::to_string(
244 static_cast<uint8_t>(pel::SubsystemID::hostboot));
245
Ben Tyner9d4f91c2021-02-09 08:27:58 -0600246 // Translate hex src value to ascii. This results in an 8 character
247 // SRC (hostboot SRC is 32 bits)
248 std::stringstream src;
249 src << std::setw(8) << std::setfill('0') << std::hex
250 << be32toh(i_tiDataArea->srcWord12HbWord0);
251 tiAdditionalData["SrcAscii"] = src.str();
Ben Tyner29651ef2021-02-08 10:51:03 -0600252
253 eventTerminate(tiAdditionalData, (char*)i_tiDataArea);
254 }
Ben Tyner8c5e4f42020-10-28 11:11:55 -0500255 }
Ben Tyner29651ef2021-02-08 10:51:03 -0600256 else
Ben Tyner8c5e4f42020-10-28 11:11:55 -0500257 {
Ben Tyner29651ef2021-02-08 10:51:03 -0600258 // TI data was not available This should not happen since we provide
259 // a default TI info in the case where get TI info was not successful.
260 eventAttentionFail(ATTN_INFO_NULL);
Ben Tyner40717722020-09-23 09:43:20 -0500261 }
262}
263
264/** @brief Parse the TI info data area into map as PHYP/OPAL data */
265void parsePhypOpalTiInfo(std::map<std::string, std::string>& i_map,
266 TiDataArea* i_tiDataArea)
267{
Ben Tyner1c4b02e2020-11-09 14:00:29 -0600268 if (nullptr == i_tiDataArea)
269 {
270 return;
271 }
272
Ben Tyner40717722020-09-23 09:43:20 -0500273 std::stringstream ss;
274
275 ss << std::hex << std::showbase;
276 ss << "0x00 TI Area Valid:" << (int)i_tiDataArea->tiAreaValid << ":";
277 ss << "0x01 Command:" << (int)i_tiDataArea->command << ":";
278 ss << "0x02 Num. Data Bytes:" << be16toh(i_tiDataArea->numDataBytes) << ":";
279 ss << "0x04 Reserved:" << (int)i_tiDataArea->reserved1 << ":";
280 ss << "0x06 HWDump Type:" << be16toh(i_tiDataArea->hardwareDumpType) << ":";
281 ss << "0x08 SRC Format:" << (int)i_tiDataArea->srcFormat << ":";
282 ss << "0x09 SRC Flags:" << (int)i_tiDataArea->srcFlags << ":";
283 ss << "0x0a Num. ASCII Words:" << (int)i_tiDataArea->numAsciiWords << ":";
284 ss << "0x0b Num. Hex Words:" << (int)i_tiDataArea->numHexWords << ":";
285 ss << "0x0e Length of SRC:" << be16toh(i_tiDataArea->lenSrc) << ":";
286 ss << "0x10 SRC Word 12:" << be32toh(i_tiDataArea->srcWord12HbWord0) << ":";
287 ss << "0x14 SRC Word 13:" << be32toh(i_tiDataArea->srcWord13HbWord2) << ":";
288 ss << "0x18 SRC Word 14:" << be32toh(i_tiDataArea->srcWord14HbWord3) << ":";
289 ss << "0x1c SRC Word 15:" << be32toh(i_tiDataArea->srcWord15HbWord4) << ":";
290 ss << "0x20 SRC Word 16:" << be32toh(i_tiDataArea->srcWord16HbWord5) << ":";
291 ss << "0x24 SRC Word 17:" << be32toh(i_tiDataArea->srcWord17HbWord6) << ":";
292 ss << "0x28 SRC Word 18:" << be32toh(i_tiDataArea->srcWord18HbWord7) << ":";
293 ss << "0x2c SRC Word 19:" << be32toh(i_tiDataArea->srcWord19HbWord8) << ":";
294 ss << "0x30 ASCII Data:" << be32toh(i_tiDataArea->asciiData0) << ":";
295 ss << "0x34 ASCII Data:" << be32toh(i_tiDataArea->asciiData1) << ":";
296 ss << "0x38 ASCII Data:" << be32toh(i_tiDataArea->asciiData2) << ":";
297 ss << "0x3c ASCII Data:" << be32toh(i_tiDataArea->asciiData3) << ":";
298 ss << "0x40 ASCII Data:" << be32toh(i_tiDataArea->asciiData4) << ":";
299 ss << "0x44 ASCII Data:" << be32toh(i_tiDataArea->asciiData5) << ":";
300 ss << "0x48 ASCII Data:" << be32toh(i_tiDataArea->asciiData6) << ":";
301 ss << "0x4c ASCII Data:" << be32toh(i_tiDataArea->asciiData7) << ":";
302 ss << "0x50 Location:" << (int)i_tiDataArea->location << ":";
303 ss << "0x51 Code Sections:" << (int)i_tiDataArea->codeSection << ":";
304 ss << "0x52 Additional Size:" << (int)i_tiDataArea->additionalSize << ":";
305 ss << "0x53 Additional Data:" << (int)i_tiDataArea->andData;
306
307 std::string key, value;
308 char delim = ':';
309
310 while (std::getline(ss, key, delim))
311 {
312 std::getline(ss, value, delim);
313 i_map[key] = value;
314 }
315}
316
317/** @brief Parse the TI info data area into map as hostboot data */
318void parseHbTiInfo(std::map<std::string, std::string>& i_map,
319 TiDataArea* i_tiDataArea)
320{
Ben Tyner1c4b02e2020-11-09 14:00:29 -0600321 if (nullptr == i_tiDataArea)
322 {
323 return;
324 }
325
Ben Tyner40717722020-09-23 09:43:20 -0500326 std::stringstream ss;
327
328 ss << std::hex << std::showbase;
329 ss << "0x00 TI Area Valid:" << (int)i_tiDataArea->tiAreaValid << ":";
330 ss << "0x04 Reserved:" << (int)i_tiDataArea->reserved1 << ":";
331 ss << "0x05 HB_Term. Type:" << (int)i_tiDataArea->hbTerminateType << ":";
332 ss << "0x0c HB Dump Flag:" << (int)i_tiDataArea->hbDumpFlag << ":";
333 ss << "0x0d Source:" << (int)i_tiDataArea->source << ":";
334 ss << "0x10 HB Word 0:" << be32toh(i_tiDataArea->srcWord12HbWord0) << ":";
335 ss << "0x14 HB Word 2:" << be32toh(i_tiDataArea->srcWord13HbWord2) << ":";
336 ss << "0x18 HB Word 3:" << be32toh(i_tiDataArea->srcWord14HbWord3) << ":";
337 ss << "0x1c HB Word 4:" << be32toh(i_tiDataArea->srcWord15HbWord4) << ":";
338 ss << "0x20 HB Word 5:" << be32toh(i_tiDataArea->srcWord16HbWord5) << ":";
339 ss << "0x24 HB Word 6:" << be32toh(i_tiDataArea->srcWord17HbWord6) << ":";
340 ss << "0x28 HB Word 7:" << be32toh(i_tiDataArea->srcWord18HbWord7) << ":";
341 ss << "0x2c HB Word 8:" << be32toh(i_tiDataArea->srcWord19HbWord8) << ":";
342 ss << "0x30 error_data:" << be32toh(i_tiDataArea->asciiData0) << ":";
343 ss << "0x34 EID:" << be32toh(i_tiDataArea->asciiData1);
344
345 std::string key, value;
346 char delim = ':';
347
348 while (std::getline(ss, key, delim))
349 {
350 std::getline(ss, value, delim);
351 i_map[key] = value;
352 }
353}
354
355/** @brief Read state of autoreboot propertyi via dbus */
Ben Tynerff17f962020-09-23 08:21:19 -0500356bool autoRebootEnabled()
357{
358 // Use dbus get-property interface to read the autoreboot property
359 auto bus = sdbusplus::bus::new_system();
360 auto method =
361 bus.new_method_call("xyz.openbmc_project.Settings",
362 "/xyz/openbmc_project/control/host0/auto_reboot",
363 "org.freedesktop.DBus.Properties", "Get");
Ben Tyner40717722020-09-23 09:43:20 -0500364
Ben Tynerff17f962020-09-23 08:21:19 -0500365 method.append("xyz.openbmc_project.Control.Boot.RebootPolicy",
366 "AutoReboot");
Ben Tyner40717722020-09-23 09:43:20 -0500367
Ben Tyner8c5e4f42020-10-28 11:11:55 -0500368 bool autoReboot = false; // assume autoreboot attribute not available
369
Ben Tynerff17f962020-09-23 08:21:19 -0500370 try
371 {
372 auto reply = bus.call(method);
Ben Tyner40717722020-09-23 09:43:20 -0500373
Ben Tynerff17f962020-09-23 08:21:19 -0500374 std::variant<bool> result;
375 reply.read(result);
Ben Tyner8c5e4f42020-10-28 11:11:55 -0500376 autoReboot = std::get<bool>(result);
Ben Tynerff17f962020-09-23 08:21:19 -0500377 }
378 catch (const sdbusplus::exception::SdBusError& ec)
379 {
Ben Tynerff17f962020-09-23 08:21:19 -0500380 std::string traceMessage =
381 "Error in AutoReboot Get: " + std::string(ec.what());
382 trace<level::INFO>(traceMessage.c_str());
Ben Tynerff17f962020-09-23 08:21:19 -0500383 }
Ben Tyner8c5e4f42020-10-28 11:11:55 -0500384
385 return autoReboot;
Ben Tynerff17f962020-09-23 08:21:19 -0500386}
Ben Tyner40717722020-09-23 09:43:20 -0500387
Ben Tyner9ae5ca42020-02-28 13:13:50 -0600388} // namespace attn