1 #include <attn/attn_common.hpp> 2 #include <attn/attn_handler.hpp> 3 #include <attn/attn_logging.hpp> 4 #include <attn/pel/pel_common.hpp> 5 #include <attn/ti_handler.hpp> 6 #include <sdbusplus/bus.hpp> 7 #include <sdbusplus/exception.hpp> 8 9 #include <iomanip> 10 #include <iostream> 11 12 namespace attn 13 { 14 15 /** 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 * 21 * @param i_tiDataArea pointer to the TI info data 22 */ 23 int tiHandler(TiDataArea* i_tiDataArea) 24 { 25 int rc = RC_SUCCESS; 26 27 // check TI data area if it is available 28 if (nullptr != i_tiDataArea) 29 { 30 // HB v. PHYP TI logic: Only hosboot will fill in hbTerminateType 31 // 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. 34 if ((0 == i_tiDataArea->hbTerminateType) && 35 (0 == i_tiDataArea->source) && (0 != i_tiDataArea->srcFormat)) 36 { 37 handlePhypTi(i_tiDataArea); 38 } 39 else 40 { 41 handleHbTi(i_tiDataArea); 42 } 43 } 44 else 45 { 46 // 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; 50 } 51 52 return rc; 53 } 54 55 /** 56 * @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 */ 65 void handlePhypTi(TiDataArea* i_tiDataArea) 66 { 67 trace<level::INFO>("PHYP TI"); 68 69 if (autoRebootEnabled()) 70 { 71 // If autoreboot is enabled we will start crash (mpipl) mode target 72 transitionHost(HostState::Crash); 73 } 74 else 75 { 76 // If autoreboot is disabled we will quiesce the host 77 transitionHost(HostState::Quiesce); 78 } 79 80 // gather additional data for PEL 81 std::map<std::string, std::string> tiAdditionalData; 82 83 if (nullptr != i_tiDataArea) 84 { 85 parsePhypOpalTiInfo(tiAdditionalData, i_tiDataArea); 86 87 tiAdditionalData["Subsystem"] = 88 std::to_string(static_cast<uint8_t>(pel::SubsystemID::hypervisor)); 89 90 // 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; 94 tiAdditionalData["SrcAscii"] = std::string{srcChar}; 95 96 // TI event 97 eventTerminate(tiAdditionalData, (char*)i_tiDataArea); 98 } 99 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 } 105 } 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 */ 118 void 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 { 129 std::stringstream ss; // stream object for tracing 130 std::string strobj; // string object for tracing 131 132 switch (i_tiDataArea->hbTerminateType) 133 { 134 case TI_WITH_PLID: 135 case TI_WITH_EID: 136 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 147 if (0 == i_tiDataArea->hbDumpFlag) 148 { 149 hbDumpRequested = false; // no HB dump requested 150 } 151 break; 152 case TI_WITH_SRC: 153 // Reason code is byte 2 and 3 of 4 byte srcWord12HbWord0 154 uint16_t reasonCode = be32toh(i_tiDataArea->srcWord12HbWord0); 155 156 // 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()); 163 164 switch (reasonCode) 165 { 166 case HB_SRC_SHUTDOWN_REQUEST: 167 trace<level::INFO>("shutdown request"); 168 generatePel = false; 169 hbDumpRequested = false; 170 break; 171 case HB_SRC_KEY_TRANSITION: 172 // Note: Should never see this so lets leave 173 // hbDumpRequested == true so we can figure out why 174 // we are here. 175 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. 224 transitionHost(HostState::Quiesce); 225 } 226 else 227 { 228 // Quiese the host - when the host is quiesced it will either 229 // "halt" or IPL depending on autoreboot setting. 230 transitionHost(HostState::Quiesce); 231 } 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); 240 241 if (true == generatePel) 242 { 243 tiAdditionalData["Subsystem"] = std::to_string( 244 static_cast<uint8_t>(pel::SubsystemID::hostboot)); 245 246 // 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(); 252 253 eventTerminate(tiAdditionalData, (char*)i_tiDataArea); 254 } 255 } 256 else 257 { 258 // 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); 261 } 262 } 263 264 /** @brief Parse the TI info data area into map as PHYP/OPAL data */ 265 void parsePhypOpalTiInfo(std::map<std::string, std::string>& i_map, 266 TiDataArea* i_tiDataArea) 267 { 268 if (nullptr == i_tiDataArea) 269 { 270 return; 271 } 272 273 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 */ 318 void parseHbTiInfo(std::map<std::string, std::string>& i_map, 319 TiDataArea* i_tiDataArea) 320 { 321 if (nullptr == i_tiDataArea) 322 { 323 return; 324 } 325 326 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 */ 356 bool 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"); 364 365 method.append("xyz.openbmc_project.Control.Boot.RebootPolicy", 366 "AutoReboot"); 367 368 bool autoReboot = false; // assume autoreboot attribute not available 369 370 try 371 { 372 auto reply = bus.call(method); 373 374 std::variant<bool> result; 375 reply.read(result); 376 autoReboot = std::get<bool>(result); 377 } 378 catch (const sdbusplus::exception::SdBusError& e) 379 { 380 trace<level::INFO>("autoRebootEnbabled exception"); 381 std::string traceMsg = std::string(e.what(), maxTraceLen); 382 trace<level::ERROR>(traceMsg.c_str()); 383 } 384 385 return autoReboot; 386 } 387 388 } // namespace attn 389