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(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 } 165 pdr->hdr.record_handle = 0; 166 pdr->hdr.version = 1; 167 pdr->hdr.type = PLDM_STATE_EFFECTER_PDR; 168 pdr->hdr.record_change_num = 0; 169 pdr->hdr.length = sizeof(pldm_state_effecter_pdr) - sizeof(pldm_pdr_hdr); 170 pdr->terminus_handle = pdr::BmcPldmTerminusHandle; 171 pdr->effecter_id = platformHandler->getNextEffecterId(); 172 pdr->entity_type = entityType; 173 pdr->entity_instance = entityInstance; 174 pdr->container_id = 0; 175 pdr->effecter_semantic_id = 0; 176 pdr->effecter_init = PLDM_NO_INIT; 177 pdr->has_description_pdr = false; 178 pdr->composite_effecter_count = 1; 179 180 auto* possibleStatesPtr = pdr->possible_states; 181 auto possibleStates = 182 reinterpret_cast<state_effecter_possible_states*>(possibleStatesPtr); 183 possibleStates->state_set_id = stateSetID; 184 possibleStates->possible_states_size = 2; 185 auto state = 186 reinterpret_cast<state_effecter_possible_states*>(possibleStates); 187 if (stateSetID == PLDM_OEM_IBM_BOOT_STATE) 188 state->states[0].byte = 6; 189 else if (stateSetID == PLDM_OEM_IBM_FIRMWARE_UPDATE_STATE) 190 state->states[0].byte = 126; 191 else if (stateSetID == PLDM_OEM_IBM_SYSTEM_POWER_STATE) 192 state->states[0].byte = 2; 193 pldm::responder::pdr_utils::PdrEntry pdrEntry{}; 194 pdrEntry.data = entry.data(); 195 pdrEntry.size = pdrSize; 196 repo.addRecord(pdrEntry); 197 } 198 199 void buildAllCodeUpdateSensorPDR(platform::Handler* platformHandler, 200 uint16_t entityType, uint16_t entityInstance, 201 uint16_t stateSetID, pdr_utils::Repo& repo) 202 { 203 size_t pdrSize = 0; 204 pdrSize = 205 sizeof(pldm_state_sensor_pdr) + sizeof(state_sensor_possible_states); 206 std::vector<uint8_t> entry{}; 207 entry.resize(pdrSize); 208 pldm_state_sensor_pdr* pdr = 209 reinterpret_cast<pldm_state_sensor_pdr*>(entry.data()); 210 if (!pdr) 211 { 212 std::cerr << "Failed to get record by PDR type, ERROR:" 213 << PLDM_PLATFORM_INVALID_SENSOR_ID << std::endl; 214 } 215 pdr->hdr.record_handle = 0; 216 pdr->hdr.version = 1; 217 pdr->hdr.type = PLDM_STATE_SENSOR_PDR; 218 pdr->hdr.record_change_num = 0; 219 pdr->hdr.length = sizeof(pldm_state_sensor_pdr) - sizeof(pldm_pdr_hdr); 220 pdr->terminus_handle = pdr::BmcPldmTerminusHandle; 221 pdr->sensor_id = platformHandler->getNextSensorId(); 222 pdr->entity_type = entityType; 223 pdr->entity_instance = entityInstance; 224 pdr->container_id = 0; 225 pdr->sensor_init = PLDM_NO_INIT; 226 pdr->sensor_auxiliary_names_pdr = false; 227 pdr->composite_sensor_count = 1; 228 229 auto* possibleStatesPtr = pdr->possible_states; 230 auto possibleStates = 231 reinterpret_cast<state_sensor_possible_states*>(possibleStatesPtr); 232 possibleStates->state_set_id = stateSetID; 233 possibleStates->possible_states_size = 2; 234 auto state = 235 reinterpret_cast<state_sensor_possible_states*>(possibleStates); 236 if ((stateSetID == PLDM_OEM_IBM_BOOT_STATE) || 237 (stateSetID == oem_ibm_platform::PLDM_OEM_IBM_VERIFICATION_STATE)) 238 state->states[0].byte = 6; 239 else if (stateSetID == PLDM_OEM_IBM_FIRMWARE_UPDATE_STATE) 240 state->states[0].byte = 126; 241 pldm::responder::pdr_utils::PdrEntry pdrEntry{}; 242 pdrEntry.data = entry.data(); 243 pdrEntry.size = pdrSize; 244 repo.addRecord(pdrEntry); 245 } 246 247 void pldm::responder::oem_ibm_platform::Handler::buildOEMPDR( 248 pdr_utils::Repo& repo) 249 { 250 buildAllCodeUpdateEffecterPDR( 251 platformHandler, PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE, ENTITY_INSTANCE_0, 252 PLDM_OEM_IBM_BOOT_STATE, repo); 253 buildAllCodeUpdateEffecterPDR( 254 platformHandler, PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE, ENTITY_INSTANCE_1, 255 PLDM_OEM_IBM_BOOT_STATE, repo); 256 buildAllCodeUpdateEffecterPDR( 257 platformHandler, PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE, ENTITY_INSTANCE_0, 258 PLDM_OEM_IBM_FIRMWARE_UPDATE_STATE, repo); 259 buildAllCodeUpdateEffecterPDR(platformHandler, PLDM_ENTITY_SYSTEM_CHASSIS, 260 ENTITY_INSTANCE_0, 261 PLDM_OEM_IBM_SYSTEM_POWER_STATE, repo); 262 263 buildAllCodeUpdateSensorPDR( 264 platformHandler, PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE, ENTITY_INSTANCE_0, 265 PLDM_OEM_IBM_BOOT_STATE, repo); 266 buildAllCodeUpdateSensorPDR( 267 platformHandler, PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE, ENTITY_INSTANCE_1, 268 PLDM_OEM_IBM_BOOT_STATE, repo); 269 buildAllCodeUpdateSensorPDR( 270 platformHandler, PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE, ENTITY_INSTANCE_0, 271 PLDM_OEM_IBM_FIRMWARE_UPDATE_STATE, repo); 272 buildAllCodeUpdateSensorPDR( 273 platformHandler, PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE, ENTITY_INSTANCE_0, 274 PLDM_OEM_IBM_VERIFICATION_STATE, repo); 275 auto sensorId = findStateSensorId( 276 repo.getPdr(), 0, PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE, 277 ENTITY_INSTANCE_0, 0, PLDM_OEM_IBM_VERIFICATION_STATE); 278 codeUpdate->setMarkerLidSensor(sensorId); 279 sensorId = findStateSensorId( 280 repo.getPdr(), 0, PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE, 281 ENTITY_INSTANCE_0, 0, PLDM_OEM_IBM_FIRMWARE_UPDATE_STATE); 282 codeUpdate->setFirmwareUpdateSensor(sensorId); 283 } 284 285 void pldm::responder::oem_ibm_platform::Handler::setPlatformHandler( 286 pldm::responder::platform::Handler* handler) 287 { 288 platformHandler = handler; 289 } 290 291 int pldm::responder::oem_ibm_platform::Handler::sendEventToHost( 292 std::vector<uint8_t>& requestMsg) 293 { 294 uint8_t* responseMsg = nullptr; 295 size_t responseMsgSize{}; 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 307 auto requesterRc = 308 pldm_send_recv(mctp_eid, mctp_fd, requestMsg.data(), requestMsg.size(), 309 &responseMsg, &responseMsgSize); 310 std::unique_ptr<uint8_t, decltype(std::free)*> responseMsgPtr{responseMsg, 311 std::free}; 312 if (requesterRc != PLDM_REQUESTER_SUCCESS) 313 { 314 std::cerr << "Failed to send message/receive response. RC = " 315 << requesterRc << ", errno = " << errno 316 << "for sending event to host \n"; 317 return requesterRc; 318 } 319 uint8_t completionCode{}; 320 uint8_t status{}; 321 auto responsePtr = reinterpret_cast<struct pldm_msg*>(responseMsgPtr.get()); 322 auto rc = decode_platform_event_message_resp( 323 responsePtr, responseMsgSize - sizeof(pldm_msg_hdr), &completionCode, 324 &status); 325 326 if (rc != PLDM_SUCCESS || completionCode != PLDM_SUCCESS) 327 { 328 std::cerr << "Failure in decode platform event message response, rc= " 329 << rc << " cc=" << static_cast<unsigned>(completionCode) 330 << "\n"; 331 return rc; 332 } 333 return rc; 334 } 335 336 int encodeEventMsg(uint8_t eventType, const std::vector<uint8_t>& eventDataVec, 337 std::vector<uint8_t>& requestMsg, uint8_t instanceId) 338 { 339 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data()); 340 341 auto rc = encode_platform_event_message_req( 342 instanceId, 1 /*formatVersion*/, 0 /*tId*/, eventType, 343 eventDataVec.data(), eventDataVec.size(), request, 344 eventDataVec.size() + PLDM_PLATFORM_EVENT_MESSAGE_MIN_REQ_BYTES); 345 346 return rc; 347 } 348 349 void pldm::responder::oem_ibm_platform::Handler::sendStateSensorEvent( 350 uint16_t sensorId, enum sensor_event_class_states sensorEventClass, 351 uint8_t sensorOffset, uint8_t eventState, uint8_t prevEventState) 352 { 353 std::vector<uint8_t> sensorEventDataVec{}; 354 size_t sensorEventSize = PLDM_SENSOR_EVENT_DATA_MIN_LENGTH + 1; 355 sensorEventDataVec.resize(sensorEventSize); 356 auto eventData = reinterpret_cast<struct pldm_sensor_event_data*>( 357 sensorEventDataVec.data()); 358 eventData->sensor_id = sensorId; 359 eventData->sensor_event_class_type = sensorEventClass; 360 auto eventClassStart = eventData->event_class; 361 auto eventClass = 362 reinterpret_cast<struct pldm_sensor_event_state_sensor_state*>( 363 eventClassStart); 364 eventClass->sensor_offset = sensorOffset; 365 eventClass->event_state = eventState; 366 eventClass->previous_event_state = prevEventState; 367 auto instanceId = requester.getInstanceId(mctp_eid); 368 std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) + 369 PLDM_PLATFORM_EVENT_MESSAGE_MIN_REQ_BYTES + 370 sensorEventDataVec.size()); 371 auto rc = encodeEventMsg(PLDM_SENSOR_EVENT, sensorEventDataVec, requestMsg, 372 instanceId); 373 if (rc != PLDM_SUCCESS) 374 { 375 std::cerr << "Failed to encode state sensor event, rc = " << rc 376 << std::endl; 377 return; 378 } 379 rc = sendEventToHost(requestMsg); 380 if (rc != PLDM_SUCCESS) 381 { 382 std::cerr << "Failed to send event to host: " 383 << "rc=" << rc << std::endl; 384 } 385 requester.markFree(mctp_eid, instanceId); 386 return; 387 } 388 389 void pldm::responder::oem_ibm_platform::Handler::_processEndUpdate( 390 sdeventplus::source::EventBase& /*source */) 391 { 392 assembleImageEvent.reset(); 393 int retc = assembleCodeUpdateImage(); 394 if (retc != PLDM_SUCCESS) 395 { 396 codeUpdate->setCodeUpdateProgress(false); 397 auto sensorId = codeUpdate->getFirmwareUpdateSensor(); 398 sendStateSensorEvent(sensorId, PLDM_STATE_SENSOR_STATE, 0, 399 uint8_t(CodeUpdateState::FAIL), 400 uint8_t(CodeUpdateState::START)); 401 } 402 } 403 404 void pldm::responder::oem_ibm_platform::Handler::_processStartUpdate( 405 sdeventplus::source::EventBase& /*source */) 406 { 407 codeUpdate->deleteImage(); 408 CodeUpdateState state = CodeUpdateState::START; 409 auto rc = codeUpdate->setRequestedApplyTime(); 410 if (rc != PLDM_SUCCESS) 411 { 412 std::cerr << "setRequestedApplyTime failed \n"; 413 state = CodeUpdateState::FAIL; 414 } 415 auto sensorId = codeUpdate->getFirmwareUpdateSensor(); 416 sendStateSensorEvent(sensorId, PLDM_STATE_SENSOR_STATE, 0, uint8_t(state), 417 uint8_t(CodeUpdateState::END)); 418 } 419 420 void pldm::responder::oem_ibm_platform::Handler::_processSystemReboot( 421 sdeventplus::source::EventBase& /*source */) 422 { 423 pldm::utils::PropertyValue value = 424 "xyz.openbmc_project.State.Chassis.Transition.Off"; 425 pldm::utils::DBusMapping dbusMapping{"/xyz/openbmc_project/state/chassis0", 426 "xyz.openbmc_project.State.Chassis", 427 "RequestedPowerTransition", "string"}; 428 try 429 { 430 dBusIntf->setDbusProperty(dbusMapping, value); 431 } 432 catch (const std::exception& e) 433 { 434 435 std::cerr << "Chassis State transition to Off failed," 436 << "unable to set property RequestedPowerTransition" 437 << "ERROR=" << e.what() << "\n"; 438 } 439 440 using namespace sdbusplus::bus::match::rules; 441 chassisOffMatch = std::make_unique<sdbusplus::bus::match::match>( 442 pldm::utils::DBusHandler::getBus(), 443 propertiesChanged("/xyz/openbmc_project/state/chassis0", 444 "xyz.openbmc_project.State.Chassis"), 445 [this](sdbusplus::message::message& msg) { 446 DbusChangedProps props{}; 447 std::string intf; 448 msg.read(intf, props); 449 const auto itr = props.find("CurrentPowerState"); 450 if (itr != props.end()) 451 { 452 PropertyValue value = itr->second; 453 auto propVal = std::get<std::string>(value); 454 if (propVal == 455 "xyz.openbmc_project.State.Chassis.PowerState.Off") 456 { 457 pldm::utils::DBusMapping dbusMapping{ 458 "/xyz/openbmc_project/control/host0/" 459 "power_restore_policy/one_time", 460 "xyz.openbmc_project.Control.Power.RestorePolicy", 461 "PowerRestorePolicy", "string"}; 462 value = "xyz.openbmc_project.Control.Power.RestorePolicy." 463 "Policy.AlwaysOn"; 464 try 465 { 466 dBusIntf->setDbusProperty(dbusMapping, value); 467 } 468 catch (const std::exception& e) 469 { 470 std::cerr << "Setting one-time restore policy failed," 471 << "unable to set property PowerRestorePolicy" 472 << "ERROR=" << e.what() << "\n"; 473 } 474 dbusMapping = pldm::utils::DBusMapping{ 475 "/xyz/openbmc_project/state/bmc0", 476 "xyz.openbmc_project.State.BMC", 477 "RequestedBMCTransition", "string"}; 478 value = "xyz.openbmc_project.State.BMC.Transition.Reboot"; 479 try 480 { 481 dBusIntf->setDbusProperty(dbusMapping, value); 482 } 483 catch (const std::exception& e) 484 { 485 std::cerr << "BMC state transition to reboot failed," 486 << "unable to set property " 487 "RequestedBMCTransition" 488 << "ERROR=" << e.what() << "\n"; 489 } 490 } 491 } 492 }); 493 } 494 } // namespace oem_ibm_platform 495 } // namespace responder 496 } // namespace pldm 497