blob: 6c3f26c1984be1a8bbb4286f82301316cf76eb2d [file] [log] [blame]
Ben Tynerb797b3e2020-06-29 10:12:05 -05001#include <attn/attn_handler.hpp>
2#include <attn/attn_logging.hpp>
3#include <attn/ti_handler.hpp>
Ben Tyner9ae5ca42020-02-28 13:13:50 -06004#include <sdbusplus/bus.hpp>
Ben Tynerff17f962020-09-23 08:21:19 -05005#include <sdbusplus/exception.hpp>
Ben Tyner9ae5ca42020-02-28 13:13:50 -06006
Ben Tyner40717722020-09-23 09:43:20 -05007#include <iomanip>
8#include <iostream>
9
Ben Tyner9ae5ca42020-02-28 13:13:50 -060010namespace attn
11{
12
Ben Tyner8c5e4f42020-10-28 11:11:55 -050013/**
14 * @brief Determine if this is a HB or PHYP TI event
15 *
16 * Use the TI info data area to determine if this is either a HB or a PHYP
17 * TI event then handle the event.
18 *
19 * @param i_tiDataArea pointer to the TI infor data
20 */
Ben Tyner792f32f2020-06-02 08:50:47 -050021int tiHandler(TiDataArea* i_tiDataArea)
Ben Tyner9ae5ca42020-02-28 13:13:50 -060022{
Ben Tynere4f5dbe2020-10-19 07:19:33 -050023 int rc = RC_SUCCESS;
Ben Tyner9ae5ca42020-02-28 13:13:50 -060024
Ben Tyner8c5e4f42020-10-28 11:11:55 -050025 // check TI data area if it is available
Ben Tynere4f5dbe2020-10-19 07:19:33 -050026 if (nullptr != i_tiDataArea)
Ben Tyner792f32f2020-06-02 08:50:47 -050027 {
Ben Tyner8c5e4f42020-10-28 11:11:55 -050028 // HB v. PHYP TI logic: Only hosboot will fill in hbTerminateType
29 // and it will be non-zero. Only hostboot will fill out source and it
30 // it will be non-zero. Only PHYP will fill in srcFormat and it will
31 // be non-zero.
32 // source and only PHYP will fill in srcFormat.
33 if ((0 == i_tiDataArea->hbTerminateType) &&
34 (0 == i_tiDataArea->source) && (0 != i_tiDataArea->srcFormat))
Ben Tynere4f5dbe2020-10-19 07:19:33 -050035 {
Ben Tyner8c5e4f42020-10-28 11:11:55 -050036 handlePhypTi(i_tiDataArea);
Ben Tynere4f5dbe2020-10-19 07:19:33 -050037 }
38 else
39 {
Ben Tyner8c5e4f42020-10-28 11:11:55 -050040 handleHbTi(i_tiDataArea);
Ben Tynere4f5dbe2020-10-19 07:19:33 -050041 }
Ben Tyner8c5e4f42020-10-28 11:11:55 -050042 }
43 else
44 {
45 // TI data was not available, assume PHYP TI for now. When a host state
46 // management interface becomes availabe we may be able to make a more
47 // informed decision here.
48 handlePhypTi(i_tiDataArea);
Ben Tynere4f5dbe2020-10-19 07:19:33 -050049 }
Ben Tyner40717722020-09-23 09:43:20 -050050
Ben Tyner8c5e4f42020-10-28 11:11:55 -050051 return rc;
52}
Ben Tynere4f5dbe2020-10-19 07:19:33 -050053
Ben Tyner8c5e4f42020-10-28 11:11:55 -050054/**
55 * @brief Transition the host state
56 *
57 * We will transition the host state by starting the appropriate dbus target.
58 *
59 * @param i_target the dbus target to start
60 */
61void transitionHost(const char* i_target)
62{
63 // We will be transitioning host by starting appropriate dbus target
Ben Tynere4f5dbe2020-10-19 07:19:33 -050064 auto bus = sdbusplus::bus::new_system();
65 auto method = bus.new_method_call(
66 "org.freedesktop.systemd1", "/org/freedesktop/systemd1",
67 "org.freedesktop.systemd1.Manager", "StartUnit");
68
Ben Tyner8c5e4f42020-10-28 11:11:55 -050069 method.append(i_target); // target unit to start
70 method.append("replace"); // mode = replace conflicting queued jobs
Ben Tyner9ae5ca42020-02-28 13:13:50 -060071
Ben Tyner8c5e4f42020-10-28 11:11:55 -050072 trace<level::INFO>("transitioning host");
73 trace<level::INFO>(i_target);
74
75 bus.call_noreply(method); // start the service
76}
77
78/**
79 * @brief Handle a PHYP terminate immediate special attention
80 *
81 * The TI info data area will contain information pertaining to the TI
82 * condition. We will wither quiesce the host or initiate a MPIPL depending
83 * depending on the auto reboot configuration. We will also create a PEL which
84 * will contain the TI info data and FFDC data captured in the system journal.
85 *
86 * @param i_tiDataArea pointer to TI information filled in by hostboot
87 */
88void handlePhypTi(TiDataArea* i_tiDataArea)
89{
90 trace<level::INFO>("PHYP TI");
91
92 if (autoRebootEnabled())
93 {
94 // If autoreboot is enabled we will start diagnostic mode target
95 // which will ultimately mpipl the host.
96 transitionHost("obmc-host-diagnostic-mode@0.target");
Ben Tyner792f32f2020-06-02 08:50:47 -050097 }
Ben Tyner40717722020-09-23 09:43:20 -050098 else
99 {
Ben Tyner8c5e4f42020-10-28 11:11:55 -0500100 // If autoreboot is disabled we will quiesce the host
101 transitionHost("obmc-host-quiesce@0.target");
Ben Tyner40717722020-09-23 09:43:20 -0500102 }
Ben Tyner792f32f2020-06-02 08:50:47 -0500103
Ben Tyner8c5e4f42020-10-28 11:11:55 -0500104 // gather additional data for PEL
105 std::map<std::string, std::string> tiAdditionalData;
Ben Tynere4f5dbe2020-10-19 07:19:33 -0500106
Ben Tyner8c5e4f42020-10-28 11:11:55 -0500107 if (nullptr != i_tiDataArea)
108 {
109 parsePhypOpalTiInfo(tiAdditionalData, i_tiDataArea);
110 parseRawTiInfo(tiAdditionalData, i_tiDataArea);
111 }
112
113 eventTerminate(tiAdditionalData); // generate PEL
114}
115
116/**
117 * @brief Handle a hostboot terminate immediate special attention
118 *
119 * The TI info data area will contain information pertaining to the TI
120 * condition. The course of action to take regarding the host state will
121 * depend on the contents of the TI info data area. We will also create a
122 * PEL containing the TI info data and FFDC data captured in the system
123 * journal.
124 *
125 * @param i_tiDataArea pointer to TI information filled in by hostboot
126 */
127void handleHbTi(TiDataArea* i_tiDataArea)
128{
129 trace<level::INFO>("HB TI");
130
131 bool hbDumpRequested = true; // HB dump is common case
132 bool generatePel = true; // assume PEL will be created
133 bool terminateHost = true; // transition host state
134
135 // handle specific hostboot reason codes
136 if (nullptr != i_tiDataArea)
137 {
138 std::stringstream ss;
139 ss << std::hex << std::showbase;
140
141 switch (i_tiDataArea->hbTerminateType)
142 {
143 case TI_WITH_PLID:
144 case TI_WITH_EID:
145 ss << "TI with PLID/EID: " << be32toh(i_tiDataArea->asciiData1);
146 trace<level::INFO>(ss.str().c_str());
147 if (0 == i_tiDataArea->hbDumpFlag)
148 {
149 hbDumpRequested = false; // no HB dump requested
150 }
151 break;
152 case TI_WITH_SRC:
153 // SRC is byte 2 and 3 of 4 byte srcWord12HbWord0
154 uint16_t hbSrc = be32toh(i_tiDataArea->srcWord12HbWord0);
155
156 // trace some info
157 ss << "TI with SRC: " << (int)hbSrc;
158 trace<level::INFO>(ss.str().c_str());
159 ss.str(std::string()); // clear stream
160
161 switch (hbSrc)
162 {
163 case HB_SRC_SHUTDOWN_REQUEST:
164 trace<level::INFO>("shutdown request");
165 generatePel = false;
166 break;
167 case HB_SRC_KEY_TRANSITION:
168 trace<level::INFO>("key transition");
169 terminateHost = false;
170 break;
171 case HB_SRC_INSUFFICIENT_HW:
172 trace<level::INFO>("insufficient hardware");
173 break;
174 case HB_SRC_TPM_FAIL:
175 trace<level::INFO>("TPM fail");
176 break;
177 case HB_SRC_ROM_VERIFY:
178 trace<level::INFO>("ROM verify");
179 break;
180 case HB_SRC_EXT_MISMATCH:
181 trace<level::INFO>("EXT mismatch");
182 break;
183 case HB_SRC_ECC_UE:
184 trace<level::INFO>("ECC UE");
185 break;
186 case HB_SRC_UNSUPPORTED_MODE:
187 trace<level::INFO>("unsupported mode");
188 break;
189 case HB_SRC_UNSUPPORTED_SFCRANGE:
190 trace<level::INFO>("unsupported SFC range");
191 break;
192 case HB_SRC_PARTITION_TABLE:
193 trace<level::INFO>("partition table invalid");
194 break;
195 case HB_SRC_UNSUPPORTED_HARDWARE:
196 trace<level::INFO>("unsupported hardware");
197 break;
198 case HB_SRC_PNOR_CORRUPTION:
199 trace<level::INFO>("PNOR corruption");
200 break;
201 default:
202 trace<level::INFO>("reason: other");
203 }
204
205 break;
206 }
207 }
208
209 if (true == terminateHost)
210 {
211 // if hostboot dump is requested initiate dump
212 if (hbDumpRequested)
213 {
214 // Until HB dump support available just quiesce the host - once
215 // dump support is available the dump component will transition
216 // (ipl/halt) the host.
217 transitionHost("obmc-host-quiesce@0.target");
218 }
219 else
220 {
221 // Quiese the host - when the host is quiesced it will either
222 // "halt" or IPL depending on autoreboot setting.
223 transitionHost("obmc-host-quiesce@0.target");
224 }
225 }
226
227 // gather additional data for PEL
228 std::map<std::string, std::string> tiAdditionalData;
229
230 if (nullptr != i_tiDataArea)
231 {
232 parseHbTiInfo(tiAdditionalData, i_tiDataArea);
233 parseRawTiInfo(tiAdditionalData, i_tiDataArea);
234 }
235
236 if (true == generatePel)
237 {
238 eventTerminate(tiAdditionalData); // generate PEL
239 }
Ben Tyner9ae5ca42020-02-28 13:13:50 -0600240}
241
Ben Tyner40717722020-09-23 09:43:20 -0500242/** @brief Parse the TI info data area into map as raw 32-bit fields */
243void parseRawTiInfo(std::map<std::string, std::string>& i_map,
244 TiDataArea* i_buffer)
245{
Ben Tyner1c4b02e2020-11-09 14:00:29 -0600246 if (nullptr == i_buffer)
247 {
248 return;
249 }
Ben Tyner40717722020-09-23 09:43:20 -0500250
251 uint32_t* tiDataArea = (uint32_t*)i_buffer;
252 std::stringstream ss;
253
254 ss << std::hex << std::setfill('0');
255 ss << "raw:";
256 while (tiDataArea <= (uint32_t*)((char*)i_buffer + sizeof(TiDataArea)))
257 {
258 ss << std::setw(8) << std::endl << be32toh(*tiDataArea);
259 tiDataArea++;
260 }
261
262 std::string key, value;
263 char delim = ':';
264
265 while (std::getline(ss, key, delim))
266 {
267 std::getline(ss, value, delim);
268 i_map[key] = value;
269 }
270}
271
272/** @brief Parse the TI info data area into map as PHYP/OPAL data */
273void parsePhypOpalTiInfo(std::map<std::string, std::string>& i_map,
274 TiDataArea* i_tiDataArea)
275{
Ben Tyner1c4b02e2020-11-09 14:00:29 -0600276 if (nullptr == i_tiDataArea)
277 {
278 return;
279 }
280
Ben Tyner40717722020-09-23 09:43:20 -0500281 std::stringstream ss;
282
283 ss << std::hex << std::showbase;
284 ss << "0x00 TI Area Valid:" << (int)i_tiDataArea->tiAreaValid << ":";
285 ss << "0x01 Command:" << (int)i_tiDataArea->command << ":";
286 ss << "0x02 Num. Data Bytes:" << be16toh(i_tiDataArea->numDataBytes) << ":";
287 ss << "0x04 Reserved:" << (int)i_tiDataArea->reserved1 << ":";
288 ss << "0x06 HWDump Type:" << be16toh(i_tiDataArea->hardwareDumpType) << ":";
289 ss << "0x08 SRC Format:" << (int)i_tiDataArea->srcFormat << ":";
290 ss << "0x09 SRC Flags:" << (int)i_tiDataArea->srcFlags << ":";
291 ss << "0x0a Num. ASCII Words:" << (int)i_tiDataArea->numAsciiWords << ":";
292 ss << "0x0b Num. Hex Words:" << (int)i_tiDataArea->numHexWords << ":";
293 ss << "0x0e Length of SRC:" << be16toh(i_tiDataArea->lenSrc) << ":";
294 ss << "0x10 SRC Word 12:" << be32toh(i_tiDataArea->srcWord12HbWord0) << ":";
295 ss << "0x14 SRC Word 13:" << be32toh(i_tiDataArea->srcWord13HbWord2) << ":";
296 ss << "0x18 SRC Word 14:" << be32toh(i_tiDataArea->srcWord14HbWord3) << ":";
297 ss << "0x1c SRC Word 15:" << be32toh(i_tiDataArea->srcWord15HbWord4) << ":";
298 ss << "0x20 SRC Word 16:" << be32toh(i_tiDataArea->srcWord16HbWord5) << ":";
299 ss << "0x24 SRC Word 17:" << be32toh(i_tiDataArea->srcWord17HbWord6) << ":";
300 ss << "0x28 SRC Word 18:" << be32toh(i_tiDataArea->srcWord18HbWord7) << ":";
301 ss << "0x2c SRC Word 19:" << be32toh(i_tiDataArea->srcWord19HbWord8) << ":";
302 ss << "0x30 ASCII Data:" << be32toh(i_tiDataArea->asciiData0) << ":";
303 ss << "0x34 ASCII Data:" << be32toh(i_tiDataArea->asciiData1) << ":";
304 ss << "0x38 ASCII Data:" << be32toh(i_tiDataArea->asciiData2) << ":";
305 ss << "0x3c ASCII Data:" << be32toh(i_tiDataArea->asciiData3) << ":";
306 ss << "0x40 ASCII Data:" << be32toh(i_tiDataArea->asciiData4) << ":";
307 ss << "0x44 ASCII Data:" << be32toh(i_tiDataArea->asciiData5) << ":";
308 ss << "0x48 ASCII Data:" << be32toh(i_tiDataArea->asciiData6) << ":";
309 ss << "0x4c ASCII Data:" << be32toh(i_tiDataArea->asciiData7) << ":";
310 ss << "0x50 Location:" << (int)i_tiDataArea->location << ":";
311 ss << "0x51 Code Sections:" << (int)i_tiDataArea->codeSection << ":";
312 ss << "0x52 Additional Size:" << (int)i_tiDataArea->additionalSize << ":";
313 ss << "0x53 Additional Data:" << (int)i_tiDataArea->andData;
314
315 std::string key, value;
316 char delim = ':';
317
318 while (std::getline(ss, key, delim))
319 {
320 std::getline(ss, value, delim);
321 i_map[key] = value;
322 }
323}
324
325/** @brief Parse the TI info data area into map as hostboot data */
326void parseHbTiInfo(std::map<std::string, std::string>& i_map,
327 TiDataArea* i_tiDataArea)
328{
Ben Tyner1c4b02e2020-11-09 14:00:29 -0600329 if (nullptr == i_tiDataArea)
330 {
331 return;
332 }
333
Ben Tyner40717722020-09-23 09:43:20 -0500334 std::stringstream ss;
335
336 ss << std::hex << std::showbase;
337 ss << "0x00 TI Area Valid:" << (int)i_tiDataArea->tiAreaValid << ":";
338 ss << "0x04 Reserved:" << (int)i_tiDataArea->reserved1 << ":";
339 ss << "0x05 HB_Term. Type:" << (int)i_tiDataArea->hbTerminateType << ":";
340 ss << "0x0c HB Dump Flag:" << (int)i_tiDataArea->hbDumpFlag << ":";
341 ss << "0x0d Source:" << (int)i_tiDataArea->source << ":";
342 ss << "0x10 HB Word 0:" << be32toh(i_tiDataArea->srcWord12HbWord0) << ":";
343 ss << "0x14 HB Word 2:" << be32toh(i_tiDataArea->srcWord13HbWord2) << ":";
344 ss << "0x18 HB Word 3:" << be32toh(i_tiDataArea->srcWord14HbWord3) << ":";
345 ss << "0x1c HB Word 4:" << be32toh(i_tiDataArea->srcWord15HbWord4) << ":";
346 ss << "0x20 HB Word 5:" << be32toh(i_tiDataArea->srcWord16HbWord5) << ":";
347 ss << "0x24 HB Word 6:" << be32toh(i_tiDataArea->srcWord17HbWord6) << ":";
348 ss << "0x28 HB Word 7:" << be32toh(i_tiDataArea->srcWord18HbWord7) << ":";
349 ss << "0x2c HB Word 8:" << be32toh(i_tiDataArea->srcWord19HbWord8) << ":";
350 ss << "0x30 error_data:" << be32toh(i_tiDataArea->asciiData0) << ":";
351 ss << "0x34 EID:" << be32toh(i_tiDataArea->asciiData1);
352
353 std::string key, value;
354 char delim = ':';
355
356 while (std::getline(ss, key, delim))
357 {
358 std::getline(ss, value, delim);
359 i_map[key] = value;
360 }
361}
362
363/** @brief Read state of autoreboot propertyi via dbus */
Ben Tynerff17f962020-09-23 08:21:19 -0500364bool autoRebootEnabled()
365{
366 // Use dbus get-property interface to read the autoreboot property
367 auto bus = sdbusplus::bus::new_system();
368 auto method =
369 bus.new_method_call("xyz.openbmc_project.Settings",
370 "/xyz/openbmc_project/control/host0/auto_reboot",
371 "org.freedesktop.DBus.Properties", "Get");
Ben Tyner40717722020-09-23 09:43:20 -0500372
Ben Tynerff17f962020-09-23 08:21:19 -0500373 method.append("xyz.openbmc_project.Control.Boot.RebootPolicy",
374 "AutoReboot");
Ben Tyner40717722020-09-23 09:43:20 -0500375
Ben Tyner8c5e4f42020-10-28 11:11:55 -0500376 bool autoReboot = false; // assume autoreboot attribute not available
377
Ben Tynerff17f962020-09-23 08:21:19 -0500378 try
379 {
380 auto reply = bus.call(method);
Ben Tyner40717722020-09-23 09:43:20 -0500381
Ben Tynerff17f962020-09-23 08:21:19 -0500382 std::variant<bool> result;
383 reply.read(result);
Ben Tyner8c5e4f42020-10-28 11:11:55 -0500384 autoReboot = std::get<bool>(result);
Ben Tynerff17f962020-09-23 08:21:19 -0500385 }
386 catch (const sdbusplus::exception::SdBusError& ec)
387 {
Ben Tynerff17f962020-09-23 08:21:19 -0500388 std::string traceMessage =
389 "Error in AutoReboot Get: " + std::string(ec.what());
390 trace<level::INFO>(traceMessage.c_str());
Ben Tynerff17f962020-09-23 08:21:19 -0500391 }
Ben Tyner8c5e4f42020-10-28 11:11:55 -0500392
393 return autoReboot;
Ben Tynerff17f962020-09-23 08:21:19 -0500394}
Ben Tyner40717722020-09-23 09:43:20 -0500395
Ben Tyner9ae5ca42020-02-28 13:13:50 -0600396} // namespace attn