1 #include "oem_event_manager.hpp" 2 3 #include "requester/handler.hpp" 4 #include "requester/request.hpp" 5 6 #include <config.h> 7 #include <libpldm/pldm.h> 8 #include <libpldm/utils.h> 9 #include <systemd/sd-journal.h> 10 11 #include <phosphor-logging/lg2.hpp> 12 #include <xyz/openbmc_project/Logging/Entry/server.hpp> 13 14 #include <algorithm> 15 #include <map> 16 #include <sstream> 17 #include <string> 18 #include <unordered_map> 19 20 namespace pldm 21 { 22 namespace oem_ampere 23 { 24 namespace boot_stage = boot::stage; 25 26 constexpr const char* BIOSFWPanicRegistry = 27 "OpenBMC.0.1.BIOSFirmwarePanicReason.Warning"; 28 constexpr auto maxDIMMIdxBitNum = 24; 29 30 /* 31 An array of possible boot status of a boot stage. 32 The index maps with byte 0 of boot code. 33 */ 34 std::array<std::string, 3> bootStatMsg = {" booting", " completed", " failed"}; 35 36 /* 37 An array of possible boot status of DDR training stage. 38 The index maps with byte 0 of boot code. 39 */ 40 std::array<std::string, 3> ddrTrainingMsg = { 41 " progress started", " in-progress", " progress completed"}; 42 43 /* 44 In Ampere systems, BMC only directly communicates with MCTP/PLDM SoC 45 EPs through SMBus and PCIe. When host boots up, SMBUS interface 46 comes up first. In this interface, BMC is bus owner. 47 48 mctpd will set the EID 0x14 for S0 and 0x16 for S1 (if available). 49 pldmd will always use TID 1 for S0 and TID 2 for S1 (if available). 50 */ 51 EventToMsgMap_t tidToSocketNameMap = {{1, "SOCKET 0"}, {2, "SOCKET 1"}}; 52 53 /* 54 A map between sensor IDs and their names in string. 55 Using pldm::oem::sensor_ids 56 */ 57 EventToMsgMap_t sensorIdToStrMap = {{BOOT_OVERALL, "BOOT_OVERALL"}}; 58 59 /* 60 A map between the boot stages and logging strings. 61 Using pldm::oem::boot::stage::boot_stage 62 */ 63 EventToMsgMap_t bootStageToMsgMap = { 64 {boot_stage::SECPRO, "SECpro"}, 65 {boot_stage::MPRO, "Mpro"}, 66 {boot_stage::ATF_BL1, "ATF BL1"}, 67 {boot_stage::ATF_BL2, "ATF BL2"}, 68 {boot_stage::DDR_INITIALIZATION, "DDR initialization"}, 69 {boot_stage::DDR_TRAINING, "DDR training"}, 70 {boot_stage::S0_DDR_TRAINING_FAILURE, "DDR training failure"}, 71 {boot_stage::ATF_BL31, "ATF BL31"}, 72 {boot_stage::ATF_BL32, "ATF BL32"}, 73 {boot_stage::S1_DDR_TRAINING_FAILURE, "DDR training failure"}, 74 {boot_stage::UEFI_STATUS_CLASS_CODE_MIN, 75 "ATF BL33 (UEFI) booting status = "}}; 76 77 /* 78 A map between log level and the registry used for Redfish SEL log 79 Using pldm::oem::log_level 80 */ 81 std::unordered_map<log_level, std::string> logLevelToRedfishMsgIdMap = { 82 {log_level::BIOSFWPANIC, BIOSFWPanicRegistry}}; 83 84 std::string 85 OemEventManager::prefixMsgStrCreation(pldm_tid_t tid, uint16_t sensorId) 86 { 87 std::string description; 88 if (!tidToSocketNameMap.contains(tid)) 89 { 90 description += "TID " + std::to_string(tid) + ": "; 91 } 92 else 93 { 94 description += tidToSocketNameMap[tid] + ": "; 95 } 96 97 if (!sensorIdToStrMap.contains(sensorId)) 98 { 99 description += "Sensor ID " + std::to_string(sensorId) + ": "; 100 } 101 else 102 { 103 description += sensorIdToStrMap[sensorId] + ": "; 104 } 105 106 return description; 107 } 108 109 void OemEventManager::sendJournalRedfish(const std::string& description, 110 log_level& logLevel) 111 { 112 if (description.empty()) 113 { 114 return; 115 } 116 117 if (!logLevelToRedfishMsgIdMap.contains(logLevel)) 118 { 119 lg2::error("Invalid {LEVEL} Description {DES}", "LEVEL", logLevel, 120 "DES", description); 121 return; 122 } 123 auto redfishMsgId = logLevelToRedfishMsgIdMap[logLevel]; 124 lg2::info("MESSAGE={DES}", "DES", description, "REDFISH_MESSAGE_ID", 125 redfishMsgId, "REDFISH_MESSAGE_ARGS", description); 126 } 127 128 std::string OemEventManager::dimmIdxsToString(uint32_t dimmIdxs) 129 { 130 std::string description; 131 for (const auto bitIdx : std::views::iota(0, maxDIMMIdxBitNum)) 132 { 133 if (dimmIdxs & (static_cast<uint32_t>(1) << bitIdx)) 134 { 135 description += " #" + std::to_string(bitIdx); 136 } 137 } 138 return description; 139 } 140 141 void OemEventManager::handleBootOverallEvent( 142 pldm_tid_t /*tid*/, uint16_t /*sensorId*/, uint32_t presentReading) 143 { 144 log_level logLevel{log_level::OK}; 145 std::string description; 146 std::stringstream strStream; 147 148 uint8_t byte0 = (presentReading & 0x000000ff); 149 uint8_t byte1 = (presentReading & 0x0000ff00) >> 8; 150 uint8_t byte2 = (presentReading & 0x00ff0000) >> 16; 151 uint8_t byte3 = (presentReading & 0xff000000) >> 24; 152 /* 153 * Handle SECpro, Mpro, ATF BL1, ATF BL2, ATF BL31, 154 * ATF BL32 and DDR initialization 155 */ 156 if (bootStageToMsgMap.contains(byte3)) 157 { 158 // Boot stage adding 159 description += bootStageToMsgMap[byte3]; 160 161 switch (byte3) 162 { 163 case boot_stage::DDR_TRAINING: 164 if (byte0 >= ddrTrainingMsg.size()) 165 { 166 logLevel = log_level::BIOSFWPANIC; 167 description += " unknown status"; 168 } 169 else 170 { 171 description += ddrTrainingMsg[byte0]; 172 } 173 if (0x01 == byte0) 174 { 175 // Add complete percentage 176 description += " at " + std::to_string(byte1) + "%"; 177 } 178 break; 179 case boot_stage::S0_DDR_TRAINING_FAILURE: 180 case boot_stage::S1_DDR_TRAINING_FAILURE: 181 // ddr_training_status_msg() 182 logLevel = log_level::BIOSFWPANIC; 183 description += " at DIMMs:"; 184 // dimmIdxs = presentReading & 0x00ffffff; 185 description += dimmIdxsToString(presentReading & 0x00ffffff); 186 description += " of socket "; 187 description += 188 (boot_stage::S0_DDR_TRAINING_FAILURE == byte3) ? "0" : "1"; 189 break; 190 default: 191 if (byte0 >= bootStatMsg.size()) 192 { 193 logLevel = log_level::BIOSFWPANIC; 194 description += " unknown status"; 195 } 196 else 197 { 198 description += bootStatMsg[byte0]; 199 } 200 break; 201 } 202 203 // Sensor report action is fail 204 if (boot::status::BOOT_STATUS_FAILURE == byte2) 205 { 206 logLevel = log_level::BIOSFWPANIC; 207 } 208 } 209 else 210 { 211 if (byte3 <= boot_stage::UEFI_STATUS_CLASS_CODE_MAX) 212 { 213 description += 214 bootStageToMsgMap[boot_stage::UEFI_STATUS_CLASS_CODE_MIN]; 215 216 strStream 217 << "Segment (0x" << std::setfill('0') << std::hex 218 << std::setw(8) << static_cast<uint32_t>(presentReading) 219 << "), Status Class (0x" << std::setw(2) 220 << static_cast<uint32_t>(byte3) << "), Status SubClass (0x" 221 << std::setw(2) << static_cast<uint32_t>(byte2) 222 << "), Operation Code (0x" << std::setw(4) 223 << static_cast<uint32_t>((presentReading & 0xffff0000) >> 16) 224 << ")" << std::dec; 225 226 description += strStream.str(); 227 } 228 } 229 230 // Log to Redfish event 231 sendJournalRedfish(description, logLevel); 232 } 233 234 int OemEventManager::processNumericSensorEvent( 235 pldm_tid_t tid, uint16_t sensorId, const uint8_t* sensorData, 236 size_t sensorDataLength) 237 { 238 uint8_t eventState = 0; 239 uint8_t previousEventState = 0; 240 uint8_t sensorDataSize = 0; 241 uint32_t presentReading; 242 auto rc = decode_numeric_sensor_data( 243 sensorData, sensorDataLength, &eventState, &previousEventState, 244 &sensorDataSize, &presentReading); 245 if (rc) 246 { 247 lg2::error( 248 "Failed to decode numericSensorState event for terminus ID {TID}, error {RC} ", 249 "TID", tid, "RC", rc); 250 return rc; 251 } 252 253 switch (sensorId) 254 { 255 case BOOT_OVERALL: 256 handleBootOverallEvent(tid, sensorId, presentReading); 257 break; 258 default: 259 std::string description; 260 std::stringstream strStream; 261 log_level logLevel = log_level::OK; 262 263 description += "SENSOR_EVENT : NUMERIC_SENSOR_STATE: "; 264 description += prefixMsgStrCreation(tid, sensorId); 265 strStream << std::setfill('0') << std::hex << "eventState 0x" 266 << std::setw(2) << static_cast<uint32_t>(eventState) 267 << " previousEventState 0x" << std::setw(2) 268 << static_cast<uint32_t>(previousEventState) 269 << " sensorDataSize 0x" << std::setw(2) 270 << static_cast<uint32_t>(sensorDataSize) 271 << " presentReading 0x" << std::setw(8) 272 << static_cast<uint32_t>(presentReading) << std::dec; 273 description += strStream.str(); 274 275 sendJournalRedfish(description, logLevel); 276 break; 277 } 278 return PLDM_SUCCESS; 279 } 280 281 int OemEventManager::processStateSensorEvent(pldm_tid_t tid, uint16_t sensorId, 282 const uint8_t* sensorData, 283 size_t sensorDataLength) 284 { 285 uint8_t sensorOffset = 0; 286 uint8_t eventState = 0; 287 uint8_t previousEventState = 0; 288 289 auto rc = 290 decode_state_sensor_data(sensorData, sensorDataLength, &sensorOffset, 291 &eventState, &previousEventState); 292 if (rc) 293 { 294 lg2::error( 295 "Failed to decode stateSensorState event for terminus ID {TID}, error {RC}", 296 "TID", tid, "RC", rc); 297 return rc; 298 } 299 300 std::string description; 301 std::stringstream strStream; 302 log_level logLevel = log_level::OK; 303 304 description += "SENSOR_EVENT : STATE_SENSOR_STATE: "; 305 description += prefixMsgStrCreation(tid, sensorId); 306 strStream << std::setfill('0') << std::hex << "sensorOffset 0x" 307 << std::setw(2) << static_cast<uint32_t>(sensorOffset) 308 << "eventState 0x" << std::setw(2) 309 << static_cast<uint32_t>(eventState) << " previousEventState 0x" 310 << std::setw(2) << static_cast<uint32_t>(previousEventState) 311 << std::dec; 312 description += strStream.str(); 313 314 sendJournalRedfish(description, logLevel); 315 316 return PLDM_SUCCESS; 317 } 318 319 int OemEventManager::processSensorOpStateEvent( 320 pldm_tid_t tid, uint16_t sensorId, const uint8_t* sensorData, 321 size_t sensorDataLength) 322 { 323 uint8_t present_op_state = 0; 324 uint8_t previous_op_state = 0; 325 326 auto rc = decode_sensor_op_data(sensorData, sensorDataLength, 327 &present_op_state, &previous_op_state); 328 if (rc) 329 { 330 lg2::error( 331 "Failed to decode sensorOpState event for terminus ID {TID}, error {RC}", 332 "TID", tid, "RC", rc); 333 return rc; 334 } 335 336 std::string description; 337 std::stringstream strStream; 338 log_level logLevel = log_level::OK; 339 340 description += "SENSOR_EVENT : SENSOR_OP_STATE: "; 341 description += prefixMsgStrCreation(tid, sensorId); 342 strStream << std::setfill('0') << std::hex << "present_op_state 0x" 343 << std::setw(2) << static_cast<uint32_t>(present_op_state) 344 << "previous_op_state 0x" << std::setw(2) 345 << static_cast<uint32_t>(previous_op_state) << std::dec; 346 description += strStream.str(); 347 348 sendJournalRedfish(description, logLevel); 349 350 return PLDM_SUCCESS; 351 } 352 353 int OemEventManager::handleSensorEvent( 354 const pldm_msg* request, size_t payloadLength, uint8_t /* formatVersion */, 355 pldm_tid_t tid, size_t eventDataOffset) 356 { 357 /* This OEM event handler is only used for SoC terminus*/ 358 if (!tidToSocketNameMap.contains(tid)) 359 { 360 return PLDM_SUCCESS; 361 } 362 auto eventData = 363 reinterpret_cast<const uint8_t*>(request->payload) + eventDataOffset; 364 auto eventDataSize = payloadLength - eventDataOffset; 365 366 uint16_t sensorId = 0; 367 uint8_t sensorEventClassType = 0; 368 size_t eventClassDataOffset = 0; 369 auto rc = 370 decode_sensor_event_data(eventData, eventDataSize, &sensorId, 371 &sensorEventClassType, &eventClassDataOffset); 372 if (rc) 373 { 374 lg2::error("Failed to decode sensor event data return code {RC}.", "RC", 375 rc); 376 return rc; 377 } 378 const uint8_t* sensorData = eventData + eventClassDataOffset; 379 size_t sensorDataLength = eventDataSize - eventClassDataOffset; 380 381 switch (sensorEventClassType) 382 { 383 case PLDM_NUMERIC_SENSOR_STATE: 384 { 385 return processNumericSensorEvent(tid, sensorId, sensorData, 386 sensorDataLength); 387 } 388 case PLDM_STATE_SENSOR_STATE: 389 { 390 return processStateSensorEvent(tid, sensorId, sensorData, 391 sensorDataLength); 392 } 393 case PLDM_SENSOR_OP_STATE: 394 { 395 return processSensorOpStateEvent(tid, sensorId, sensorData, 396 sensorDataLength); 397 } 398 default: 399 std::string description; 400 std::stringstream strStream; 401 log_level logLevel = log_level::OK; 402 403 description += "SENSOR_EVENT : Unsupported Sensor Class " + 404 std::to_string(sensorEventClassType) + ": "; 405 description += prefixMsgStrCreation(tid, sensorId); 406 strStream << std::setfill('0') << std::hex 407 << std::setw(sizeof(sensorData) * 2) << "Sensor data: "; 408 409 auto dataPtr = sensorData; 410 for ([[maybe_unused]] const auto& i : 411 std::views::iota(0, (int)sensorDataLength)) 412 { 413 strStream << "0x" << static_cast<uint32_t>(*dataPtr); 414 dataPtr += sizeof(sensorData); 415 } 416 417 description += strStream.str(); 418 419 sendJournalRedfish(description, logLevel); 420 } 421 lg2::info("Unsupported class type {CLASSTYPE}", "CLASSTYPE", 422 sensorEventClassType); 423 return PLDM_ERROR; 424 } 425 426 } // namespace oem_ampere 427 } // namespace pldm 428