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) 295 { 296 uint8_t* responseMsg = nullptr; 297 size_t responseMsgSize{}; 298 if (requestMsg.size()) 299 { 300 std::ostringstream tempStream; 301 for (int byte : requestMsg) 302 { 303 tempStream << std::setfill('0') << std::setw(2) << std::hex << byte 304 << " "; 305 } 306 std::cout << tempStream.str() << std::endl; 307 } 308 309 auto requesterRc = 310 pldm_send_recv(mctp_eid, mctp_fd, requestMsg.data(), requestMsg.size(), 311 &responseMsg, &responseMsgSize); 312 std::unique_ptr<uint8_t, decltype(std::free)*> responseMsgPtr{responseMsg, 313 std::free}; 314 if (requesterRc != PLDM_REQUESTER_SUCCESS) 315 { 316 std::cerr << "Failed to send message/receive response. RC = " 317 << requesterRc << ", errno = " << errno 318 << "for sending event to host \n"; 319 return requesterRc; 320 } 321 uint8_t completionCode{}; 322 uint8_t status{}; 323 auto responsePtr = reinterpret_cast<struct pldm_msg*>(responseMsgPtr.get()); 324 auto rc = decode_platform_event_message_resp( 325 responsePtr, responseMsgSize - sizeof(pldm_msg_hdr), &completionCode, 326 &status); 327 328 if (rc != PLDM_SUCCESS || completionCode != PLDM_SUCCESS) 329 { 330 std::cerr << "Failure in decode platform event message response, rc= " 331 << rc << " cc=" << static_cast<unsigned>(completionCode) 332 << "\n"; 333 return rc; 334 } 335 return rc; 336 } 337 338 int encodeEventMsg(uint8_t eventType, const std::vector<uint8_t>& eventDataVec, 339 std::vector<uint8_t>& requestMsg, uint8_t instanceId) 340 { 341 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data()); 342 343 auto rc = encode_platform_event_message_req( 344 instanceId, 1 /*formatVersion*/, 0 /*tId*/, eventType, 345 eventDataVec.data(), eventDataVec.size(), request, 346 eventDataVec.size() + PLDM_PLATFORM_EVENT_MESSAGE_MIN_REQ_BYTES); 347 348 return rc; 349 } 350 351 void pldm::responder::oem_ibm_platform::Handler::sendStateSensorEvent( 352 uint16_t sensorId, enum sensor_event_class_states sensorEventClass, 353 uint8_t sensorOffset, uint8_t eventState, uint8_t prevEventState) 354 { 355 std::vector<uint8_t> sensorEventDataVec{}; 356 size_t sensorEventSize = PLDM_SENSOR_EVENT_DATA_MIN_LENGTH + 1; 357 sensorEventDataVec.resize(sensorEventSize); 358 auto eventData = reinterpret_cast<struct pldm_sensor_event_data*>( 359 sensorEventDataVec.data()); 360 eventData->sensor_id = sensorId; 361 eventData->sensor_event_class_type = sensorEventClass; 362 auto eventClassStart = eventData->event_class; 363 auto eventClass = 364 reinterpret_cast<struct pldm_sensor_event_state_sensor_state*>( 365 eventClassStart); 366 eventClass->sensor_offset = sensorOffset; 367 eventClass->event_state = eventState; 368 eventClass->previous_event_state = prevEventState; 369 auto instanceId = requester.getInstanceId(mctp_eid); 370 std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) + 371 PLDM_PLATFORM_EVENT_MESSAGE_MIN_REQ_BYTES + 372 sensorEventDataVec.size()); 373 auto rc = encodeEventMsg(PLDM_SENSOR_EVENT, sensorEventDataVec, requestMsg, 374 instanceId); 375 if (rc != PLDM_SUCCESS) 376 { 377 std::cerr << "Failed to encode state sensor event, rc = " << rc 378 << std::endl; 379 return; 380 } 381 rc = sendEventToHost(requestMsg); 382 if (rc != PLDM_SUCCESS) 383 { 384 std::cerr << "Failed to send event to host: " 385 << "rc=" << rc << std::endl; 386 } 387 requester.markFree(mctp_eid, instanceId); 388 return; 389 } 390 391 void pldm::responder::oem_ibm_platform::Handler::_processEndUpdate( 392 sdeventplus::source::EventBase& /*source */) 393 { 394 assembleImageEvent.reset(); 395 int retc = assembleCodeUpdateImage(); 396 if (retc != PLDM_SUCCESS) 397 { 398 codeUpdate->setCodeUpdateProgress(false); 399 auto sensorId = codeUpdate->getFirmwareUpdateSensor(); 400 sendStateSensorEvent(sensorId, PLDM_STATE_SENSOR_STATE, 0, 401 uint8_t(CodeUpdateState::FAIL), 402 uint8_t(CodeUpdateState::START)); 403 } 404 } 405 406 void pldm::responder::oem_ibm_platform::Handler::_processStartUpdate( 407 sdeventplus::source::EventBase& /*source */) 408 { 409 codeUpdate->deleteImage(); 410 CodeUpdateState state = CodeUpdateState::START; 411 auto rc = codeUpdate->setRequestedApplyTime(); 412 if (rc != PLDM_SUCCESS) 413 { 414 std::cerr << "setRequestedApplyTime failed \n"; 415 state = CodeUpdateState::FAIL; 416 } 417 auto sensorId = codeUpdate->getFirmwareUpdateSensor(); 418 sendStateSensorEvent(sensorId, PLDM_STATE_SENSOR_STATE, 0, uint8_t(state), 419 uint8_t(CodeUpdateState::END)); 420 } 421 422 void pldm::responder::oem_ibm_platform::Handler::_processSystemReboot( 423 sdeventplus::source::EventBase& /*source */) 424 { 425 pldm::utils::PropertyValue value = 426 "xyz.openbmc_project.State.Chassis.Transition.Off"; 427 pldm::utils::DBusMapping dbusMapping{"/xyz/openbmc_project/state/chassis0", 428 "xyz.openbmc_project.State.Chassis", 429 "RequestedPowerTransition", "string"}; 430 try 431 { 432 dBusIntf->setDbusProperty(dbusMapping, value); 433 } 434 catch (const std::exception& e) 435 { 436 437 std::cerr << "Chassis State transition to Off failed," 438 << "unable to set property RequestedPowerTransition" 439 << "ERROR=" << e.what() << "\n"; 440 } 441 442 using namespace sdbusplus::bus::match::rules; 443 chassisOffMatch = std::make_unique<sdbusplus::bus::match::match>( 444 pldm::utils::DBusHandler::getBus(), 445 propertiesChanged("/xyz/openbmc_project/state/chassis0", 446 "xyz.openbmc_project.State.Chassis"), 447 [this](sdbusplus::message::message& msg) { 448 DbusChangedProps props{}; 449 std::string intf; 450 msg.read(intf, props); 451 const auto itr = props.find("CurrentPowerState"); 452 if (itr != props.end()) 453 { 454 PropertyValue value = itr->second; 455 auto propVal = std::get<std::string>(value); 456 if (propVal == 457 "xyz.openbmc_project.State.Chassis.PowerState.Off") 458 { 459 pldm::utils::DBusMapping dbusMapping{ 460 "/xyz/openbmc_project/control/host0/" 461 "power_restore_policy/one_time", 462 "xyz.openbmc_project.Control.Power.RestorePolicy", 463 "PowerRestorePolicy", "string"}; 464 value = "xyz.openbmc_project.Control.Power.RestorePolicy." 465 "Policy.AlwaysOn"; 466 try 467 { 468 dBusIntf->setDbusProperty(dbusMapping, value); 469 } 470 catch (const std::exception& e) 471 { 472 std::cerr << "Setting one-time restore policy failed," 473 << "unable to set property PowerRestorePolicy" 474 << "ERROR=" << e.what() << "\n"; 475 } 476 dbusMapping = pldm::utils::DBusMapping{ 477 "/xyz/openbmc_project/state/bmc0", 478 "xyz.openbmc_project.State.BMC", 479 "RequestedBMCTransition", "string"}; 480 value = "xyz.openbmc_project.State.BMC.Transition.Reboot"; 481 try 482 { 483 dBusIntf->setDbusProperty(dbusMapping, value); 484 } 485 catch (const std::exception& e) 486 { 487 std::cerr << "BMC state transition to reboot failed," 488 << "unable to set property " 489 "RequestedBMCTransition" 490 << "ERROR=" << e.what() << "\n"; 491 } 492 } 493 } 494 }); 495 } 496 } // namespace oem_ibm_platform 497 } // namespace responder 498 } // namespace pldm 499