1 #include "oem_ibm_handler.hpp" 2 3 #include "libpldm/entity.h" 4 #include "libpldm/requester/pldm.h" 5 6 #include "file_io_type_lid.hpp" 7 #include "libpldmresponder/file_io.hpp" 8 #include "libpldmresponder/pdr_utils.hpp" 9 namespace pldm 10 { 11 namespace responder 12 { 13 namespace oem_ibm_platform 14 { 15 16 int pldm::responder::oem_ibm_platform::Handler:: 17 getOemStateSensorReadingsHandler( 18 EntityType entityType, EntityInstance entityInstance, 19 StateSetId stateSetId, CompositeCount compSensorCnt, 20 std::vector<get_sensor_state_field>& stateField) 21 { 22 int rc = PLDM_SUCCESS; 23 stateField.clear(); 24 25 for (size_t i = 0; i < compSensorCnt; i++) 26 { 27 uint8_t sensorOpState{}; 28 if (entityType == PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE && 29 stateSetId == PLDM_OEM_IBM_BOOT_STATE) 30 { 31 sensorOpState = fetchBootSide(entityInstance, codeUpdate); 32 } 33 else 34 { 35 rc = PLDM_PLATFORM_INVALID_STATE_VALUE; 36 break; 37 } 38 stateField.push_back({PLDM_SENSOR_ENABLED, PLDM_SENSOR_UNKNOWN, 39 PLDM_SENSOR_UNKNOWN, sensorOpState}); 40 } 41 return rc; 42 } 43 44 int pldm::responder::oem_ibm_platform::Handler:: 45 oemSetStateEffecterStatesHandler( 46 uint16_t entityType, uint16_t entityInstance, uint16_t stateSetId, 47 uint8_t compEffecterCnt, 48 std::vector<set_effecter_state_field>& stateField, 49 uint16_t /*effecterId*/) 50 { 51 int rc = PLDM_SUCCESS; 52 53 for (uint8_t currState = 0; currState < compEffecterCnt; ++currState) 54 { 55 if (stateField[currState].set_request == PLDM_REQUEST_SET) 56 { 57 if (entityType == PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE && 58 stateSetId == PLDM_OEM_IBM_BOOT_STATE) 59 { 60 rc = setBootSide(entityInstance, currState, stateField, 61 codeUpdate); 62 } 63 else if (entityType == PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE && 64 stateSetId == PLDM_OEM_IBM_FIRMWARE_UPDATE_STATE) 65 { 66 if (stateField[currState].effecter_state == 67 uint8_t(CodeUpdateState::START)) 68 { 69 codeUpdate->setCodeUpdateProgress(true); 70 startUpdateEvent = 71 std::make_unique<sdeventplus::source::Defer>( 72 event, 73 std::bind(std::mem_fn(&oem_ibm_platform::Handler:: 74 _processStartUpdate), 75 this, std::placeholders::_1)); 76 } 77 else if (stateField[currState].effecter_state == 78 uint8_t(CodeUpdateState::END)) 79 { 80 rc = PLDM_SUCCESS; 81 assembleImageEvent = std::make_unique< 82 sdeventplus::source::Defer>( 83 event, 84 std::bind( 85 std::mem_fn( 86 &oem_ibm_platform::Handler::_processEndUpdate), 87 this, std::placeholders::_1)); 88 89 // sendCodeUpdateEvent(effecterId, END, START); 90 } 91 else if (stateField[currState].effecter_state == 92 uint8_t(CodeUpdateState::ABORT)) 93 { 94 codeUpdate->setCodeUpdateProgress(false); 95 codeUpdate->clearDirPath(LID_STAGING_DIR); 96 auto sensorId = codeUpdate->getFirmwareUpdateSensor(); 97 sendStateSensorEvent(sensorId, PLDM_STATE_SENSOR_STATE, 0, 98 uint8_t(CodeUpdateState::ABORT), 99 uint8_t(CodeUpdateState::START)); 100 // sendCodeUpdateEvent(effecterId, ABORT, END); 101 } 102 else if (stateField[currState].effecter_state == 103 uint8_t(CodeUpdateState::ACCEPT)) 104 { 105 auto sensorId = codeUpdate->getFirmwareUpdateSensor(); 106 sendStateSensorEvent(sensorId, PLDM_STATE_SENSOR_STATE, 0, 107 uint8_t(CodeUpdateState::ACCEPT), 108 uint8_t(CodeUpdateState::END)); 109 // TODO Set new Dbus property provided by code update app 110 // sendCodeUpdateEvent(effecterId, ACCEPT, END); 111 } 112 else if (stateField[currState].effecter_state == 113 uint8_t(CodeUpdateState::REJECT)) 114 { 115 auto sensorId = codeUpdate->getFirmwareUpdateSensor(); 116 sendStateSensorEvent(sensorId, PLDM_STATE_SENSOR_STATE, 0, 117 uint8_t(CodeUpdateState::REJECT), 118 uint8_t(CodeUpdateState::END)); 119 // TODO Set new Dbus property provided by code update app 120 // sendCodeUpdateEvent(effecterId, REJECT, END); 121 } 122 } 123 else if (entityType == PLDM_ENTITY_SYSTEM_CHASSIS && 124 stateSetId == PLDM_OEM_IBM_SYSTEM_POWER_STATE) 125 { 126 if (stateField[currState].effecter_state == POWER_CYCLE_HARD) 127 { 128 systemRebootEvent = 129 std::make_unique<sdeventplus::source::Defer>( 130 event, 131 std::bind(std::mem_fn(&oem_ibm_platform::Handler:: 132 _processSystemReboot), 133 this, std::placeholders::_1)); 134 } 135 } 136 else 137 { 138 rc = PLDM_PLATFORM_SET_EFFECTER_UNSUPPORTED_SENSORSTATE; 139 } 140 } 141 if (rc != PLDM_SUCCESS) 142 { 143 break; 144 } 145 } 146 return rc; 147 } 148 149 void buildAllCodeUpdateEffecterPDR(oem_ibm_platform::Handler* platformHandler, 150 uint16_t entityType, uint16_t entityInstance, 151 uint16_t stateSetID, pdr_utils::Repo& repo) 152 { 153 size_t pdrSize = 0; 154 pdrSize = sizeof(pldm_state_effecter_pdr) + 155 sizeof(state_effecter_possible_states); 156 std::vector<uint8_t> entry{}; 157 entry.resize(pdrSize); 158 pldm_state_effecter_pdr* pdr = 159 reinterpret_cast<pldm_state_effecter_pdr*>(entry.data()); 160 if (!pdr) 161 { 162 std::cerr << "Failed to get record by PDR type, ERROR:" 163 << PLDM_PLATFORM_INVALID_EFFECTER_ID << std::endl; 164 return; 165 } 166 pdr->hdr.record_handle = 0; 167 pdr->hdr.version = 1; 168 pdr->hdr.type = PLDM_STATE_EFFECTER_PDR; 169 pdr->hdr.record_change_num = 0; 170 pdr->hdr.length = sizeof(pldm_state_effecter_pdr) - sizeof(pldm_pdr_hdr); 171 pdr->terminus_handle = pdr::BmcPldmTerminusHandle; 172 pdr->effecter_id = platformHandler->getNextEffecterId(); 173 pdr->entity_type = entityType; 174 pdr->entity_instance = entityInstance; 175 pdr->container_id = 0; 176 pdr->effecter_semantic_id = 0; 177 pdr->effecter_init = PLDM_NO_INIT; 178 pdr->has_description_pdr = false; 179 pdr->composite_effecter_count = 1; 180 181 auto* possibleStatesPtr = pdr->possible_states; 182 auto possibleStates = 183 reinterpret_cast<state_effecter_possible_states*>(possibleStatesPtr); 184 possibleStates->state_set_id = stateSetID; 185 possibleStates->possible_states_size = 2; 186 auto state = 187 reinterpret_cast<state_effecter_possible_states*>(possibleStates); 188 if (stateSetID == PLDM_OEM_IBM_BOOT_STATE) 189 state->states[0].byte = 6; 190 else if (stateSetID == PLDM_OEM_IBM_FIRMWARE_UPDATE_STATE) 191 state->states[0].byte = 126; 192 else if (stateSetID == PLDM_OEM_IBM_SYSTEM_POWER_STATE) 193 state->states[0].byte = 2; 194 pldm::responder::pdr_utils::PdrEntry pdrEntry{}; 195 pdrEntry.data = entry.data(); 196 pdrEntry.size = pdrSize; 197 repo.addRecord(pdrEntry); 198 } 199 200 void buildAllCodeUpdateSensorPDR(oem_ibm_platform::Handler* platformHandler, 201 uint16_t entityType, uint16_t entityInstance, 202 uint16_t stateSetID, pdr_utils::Repo& repo) 203 { 204 size_t pdrSize = 0; 205 pdrSize = 206 sizeof(pldm_state_sensor_pdr) + sizeof(state_sensor_possible_states); 207 std::vector<uint8_t> entry{}; 208 entry.resize(pdrSize); 209 pldm_state_sensor_pdr* pdr = 210 reinterpret_cast<pldm_state_sensor_pdr*>(entry.data()); 211 if (!pdr) 212 { 213 std::cerr << "Failed to get record by PDR type, ERROR:" 214 << PLDM_PLATFORM_INVALID_SENSOR_ID << std::endl; 215 return; 216 } 217 pdr->hdr.record_handle = 0; 218 pdr->hdr.version = 1; 219 pdr->hdr.type = PLDM_STATE_SENSOR_PDR; 220 pdr->hdr.record_change_num = 0; 221 pdr->hdr.length = sizeof(pldm_state_sensor_pdr) - sizeof(pldm_pdr_hdr); 222 pdr->terminus_handle = pdr::BmcPldmTerminusHandle; 223 pdr->sensor_id = platformHandler->getNextSensorId(); 224 pdr->entity_type = entityType; 225 pdr->entity_instance = entityInstance; 226 pdr->container_id = 0; 227 pdr->sensor_init = PLDM_NO_INIT; 228 pdr->sensor_auxiliary_names_pdr = false; 229 pdr->composite_sensor_count = 1; 230 231 auto* possibleStatesPtr = pdr->possible_states; 232 auto possibleStates = 233 reinterpret_cast<state_sensor_possible_states*>(possibleStatesPtr); 234 possibleStates->state_set_id = stateSetID; 235 possibleStates->possible_states_size = 2; 236 auto state = 237 reinterpret_cast<state_sensor_possible_states*>(possibleStates); 238 if ((stateSetID == PLDM_OEM_IBM_BOOT_STATE) || 239 (stateSetID == oem_ibm_platform::PLDM_OEM_IBM_VERIFICATION_STATE)) 240 state->states[0].byte = 6; 241 else if (stateSetID == PLDM_OEM_IBM_FIRMWARE_UPDATE_STATE) 242 state->states[0].byte = 126; 243 pldm::responder::pdr_utils::PdrEntry pdrEntry{}; 244 pdrEntry.data = entry.data(); 245 pdrEntry.size = pdrSize; 246 repo.addRecord(pdrEntry); 247 } 248 249 void pldm::responder::oem_ibm_platform::Handler::buildOEMPDR( 250 pdr_utils::Repo& repo) 251 { 252 buildAllCodeUpdateEffecterPDR(this, PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE, 253 ENTITY_INSTANCE_0, PLDM_OEM_IBM_BOOT_STATE, 254 repo); 255 buildAllCodeUpdateEffecterPDR(this, PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE, 256 ENTITY_INSTANCE_1, PLDM_OEM_IBM_BOOT_STATE, 257 repo); 258 buildAllCodeUpdateEffecterPDR(this, PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE, 259 ENTITY_INSTANCE_0, 260 PLDM_OEM_IBM_FIRMWARE_UPDATE_STATE, repo); 261 buildAllCodeUpdateEffecterPDR(this, PLDM_ENTITY_SYSTEM_CHASSIS, 262 ENTITY_INSTANCE_0, 263 PLDM_OEM_IBM_SYSTEM_POWER_STATE, repo); 264 265 buildAllCodeUpdateSensorPDR(this, PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE, 266 ENTITY_INSTANCE_0, PLDM_OEM_IBM_BOOT_STATE, 267 repo); 268 buildAllCodeUpdateSensorPDR(this, PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE, 269 ENTITY_INSTANCE_1, PLDM_OEM_IBM_BOOT_STATE, 270 repo); 271 buildAllCodeUpdateSensorPDR(this, PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE, 272 ENTITY_INSTANCE_0, 273 PLDM_OEM_IBM_FIRMWARE_UPDATE_STATE, repo); 274 buildAllCodeUpdateSensorPDR(this, PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE, 275 ENTITY_INSTANCE_0, 276 PLDM_OEM_IBM_VERIFICATION_STATE, repo); 277 auto sensorId = findStateSensorId( 278 repo.getPdr(), 0, PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE, 279 ENTITY_INSTANCE_0, 0, PLDM_OEM_IBM_VERIFICATION_STATE); 280 codeUpdate->setMarkerLidSensor(sensorId); 281 sensorId = findStateSensorId( 282 repo.getPdr(), 0, PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE, 283 ENTITY_INSTANCE_0, 0, PLDM_OEM_IBM_FIRMWARE_UPDATE_STATE); 284 codeUpdate->setFirmwareUpdateSensor(sensorId); 285 } 286 287 void pldm::responder::oem_ibm_platform::Handler::setPlatformHandler( 288 pldm::responder::platform::Handler* handler) 289 { 290 platformHandler = handler; 291 } 292 293 int pldm::responder::oem_ibm_platform::Handler::sendEventToHost( 294 std::vector<uint8_t>& requestMsg, uint8_t instanceId) 295 { 296 if (requestMsg.size()) 297 { 298 std::ostringstream tempStream; 299 for (int byte : requestMsg) 300 { 301 tempStream << std::setfill('0') << std::setw(2) << std::hex << byte 302 << " "; 303 } 304 std::cout << tempStream.str() << std::endl; 305 } 306 auto oemPlatformEventMessageResponseHandler = 307 [](mctp_eid_t /*eid*/, const pldm_msg* response, size_t respMsgLen) { 308 uint8_t completionCode{}; 309 uint8_t status{}; 310 auto rc = decode_platform_event_message_resp( 311 response, respMsgLen, &completionCode, &status); 312 if (rc || completionCode) 313 { 314 std::cerr << "Failed to decode_platform_event_message_resp: " 315 << " for code update event rc=" << rc 316 << ", cc=" << static_cast<unsigned>(completionCode) 317 << std::endl; 318 } 319 }; 320 auto rc = handler->registerRequest( 321 mctp_eid, instanceId, PLDM_PLATFORM, PLDM_PLATFORM_EVENT_MESSAGE, 322 std::move(requestMsg), 323 std::move(oemPlatformEventMessageResponseHandler)); 324 if (rc) 325 { 326 std::cerr << "Failed to send BIOS attribute change event message \n"; 327 } 328 329 return rc; 330 } 331 332 int encodeEventMsg(uint8_t eventType, const std::vector<uint8_t>& eventDataVec, 333 std::vector<uint8_t>& requestMsg, uint8_t instanceId) 334 { 335 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data()); 336 337 auto rc = encode_platform_event_message_req( 338 instanceId, 1 /*formatVersion*/, 0 /*tId*/, eventType, 339 eventDataVec.data(), eventDataVec.size(), request, 340 eventDataVec.size() + PLDM_PLATFORM_EVENT_MESSAGE_MIN_REQ_BYTES); 341 342 return rc; 343 } 344 345 void pldm::responder::oem_ibm_platform::Handler::sendStateSensorEvent( 346 uint16_t sensorId, enum sensor_event_class_states sensorEventClass, 347 uint8_t sensorOffset, uint8_t eventState, uint8_t prevEventState) 348 { 349 std::vector<uint8_t> sensorEventDataVec{}; 350 size_t sensorEventSize = PLDM_SENSOR_EVENT_DATA_MIN_LENGTH + 1; 351 sensorEventDataVec.resize(sensorEventSize); 352 auto eventData = reinterpret_cast<struct pldm_sensor_event_data*>( 353 sensorEventDataVec.data()); 354 eventData->sensor_id = sensorId; 355 eventData->sensor_event_class_type = sensorEventClass; 356 auto eventClassStart = eventData->event_class; 357 auto eventClass = 358 reinterpret_cast<struct pldm_sensor_event_state_sensor_state*>( 359 eventClassStart); 360 eventClass->sensor_offset = sensorOffset; 361 eventClass->event_state = eventState; 362 eventClass->previous_event_state = prevEventState; 363 auto instanceId = requester.getInstanceId(mctp_eid); 364 std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) + 365 PLDM_PLATFORM_EVENT_MESSAGE_MIN_REQ_BYTES + 366 sensorEventDataVec.size()); 367 auto rc = encodeEventMsg(PLDM_SENSOR_EVENT, sensorEventDataVec, requestMsg, 368 instanceId); 369 if (rc != PLDM_SUCCESS) 370 { 371 std::cerr << "Failed to encode state sensor event, rc = " << rc 372 << std::endl; 373 requester.markFree(mctp_eid, instanceId); 374 return; 375 } 376 rc = sendEventToHost(requestMsg, instanceId); 377 if (rc != PLDM_SUCCESS) 378 { 379 std::cerr << "Failed to send event to host: " 380 << "rc=" << rc << std::endl; 381 } 382 return; 383 } 384 385 void pldm::responder::oem_ibm_platform::Handler::_processEndUpdate( 386 sdeventplus::source::EventBase& /*source */) 387 { 388 assembleImageEvent.reset(); 389 int retc = assembleCodeUpdateImage(); 390 if (retc != PLDM_SUCCESS) 391 { 392 codeUpdate->setCodeUpdateProgress(false); 393 auto sensorId = codeUpdate->getFirmwareUpdateSensor(); 394 sendStateSensorEvent(sensorId, PLDM_STATE_SENSOR_STATE, 0, 395 uint8_t(CodeUpdateState::FAIL), 396 uint8_t(CodeUpdateState::START)); 397 } 398 } 399 400 void pldm::responder::oem_ibm_platform::Handler::_processStartUpdate( 401 sdeventplus::source::EventBase& /*source */) 402 { 403 codeUpdate->deleteImage(); 404 CodeUpdateState state = CodeUpdateState::START; 405 auto rc = codeUpdate->setRequestedApplyTime(); 406 if (rc != PLDM_SUCCESS) 407 { 408 std::cerr << "setRequestedApplyTime failed \n"; 409 state = CodeUpdateState::FAIL; 410 } 411 auto sensorId = codeUpdate->getFirmwareUpdateSensor(); 412 sendStateSensorEvent(sensorId, PLDM_STATE_SENSOR_STATE, 0, uint8_t(state), 413 uint8_t(CodeUpdateState::END)); 414 } 415 416 void pldm::responder::oem_ibm_platform::Handler::_processSystemReboot( 417 sdeventplus::source::EventBase& /*source */) 418 { 419 pldm::utils::PropertyValue value = 420 "xyz.openbmc_project.State.Chassis.Transition.Off"; 421 pldm::utils::DBusMapping dbusMapping{"/xyz/openbmc_project/state/chassis0", 422 "xyz.openbmc_project.State.Chassis", 423 "RequestedPowerTransition", "string"}; 424 try 425 { 426 dBusIntf->setDbusProperty(dbusMapping, value); 427 } 428 catch (const std::exception& e) 429 { 430 431 std::cerr << "Chassis State transition to Off failed," 432 << "unable to set property RequestedPowerTransition" 433 << "ERROR=" << e.what() << "\n"; 434 } 435 436 using namespace sdbusplus::bus::match::rules; 437 chassisOffMatch = std::make_unique<sdbusplus::bus::match::match>( 438 pldm::utils::DBusHandler::getBus(), 439 propertiesChanged("/xyz/openbmc_project/state/chassis0", 440 "xyz.openbmc_project.State.Chassis"), 441 [this](sdbusplus::message::message& msg) { 442 DbusChangedProps props{}; 443 std::string intf; 444 msg.read(intf, props); 445 const auto itr = props.find("CurrentPowerState"); 446 if (itr != props.end()) 447 { 448 PropertyValue value = itr->second; 449 auto propVal = std::get<std::string>(value); 450 if (propVal == 451 "xyz.openbmc_project.State.Chassis.PowerState.Off") 452 { 453 pldm::utils::DBusMapping dbusMapping{ 454 "/xyz/openbmc_project/control/host0/" 455 "power_restore_policy/one_time", 456 "xyz.openbmc_project.Control.Power.RestorePolicy", 457 "PowerRestorePolicy", "string"}; 458 value = "xyz.openbmc_project.Control.Power.RestorePolicy." 459 "Policy.AlwaysOn"; 460 try 461 { 462 dBusIntf->setDbusProperty(dbusMapping, value); 463 } 464 catch (const std::exception& e) 465 { 466 std::cerr << "Setting one-time restore policy failed," 467 << "unable to set property PowerRestorePolicy" 468 << "ERROR=" << e.what() << "\n"; 469 } 470 dbusMapping = pldm::utils::DBusMapping{ 471 "/xyz/openbmc_project/state/bmc0", 472 "xyz.openbmc_project.State.BMC", 473 "RequestedBMCTransition", "string"}; 474 value = "xyz.openbmc_project.State.BMC.Transition.Reboot"; 475 try 476 { 477 dBusIntf->setDbusProperty(dbusMapping, value); 478 } 479 catch (const std::exception& e) 480 { 481 std::cerr << "BMC state transition to reboot failed," 482 << "unable to set property " 483 "RequestedBMCTransition" 484 << "ERROR=" << e.what() << "\n"; 485 } 486 } 487 } 488 }); 489 } 490 } // namespace oem_ibm_platform 491 } // namespace responder 492 } // namespace pldm 493