1 #pragma once 2 3 #include "collect_slot_vpd.hpp" 4 #include "common/utils.hpp" 5 #include "file_table.hpp" 6 #include "inband_code_update.hpp" 7 #include "libpldmresponder/bios_config.hpp" 8 #include "libpldmresponder/oem_handler.hpp" 9 #include "libpldmresponder/pdr_utils.hpp" 10 #include "libpldmresponder/platform.hpp" 11 #include "requester/handler.hpp" 12 13 #include <libpldm/entity.h> 14 #include <libpldm/oem/ibm/state_set.h> 15 #include <libpldm/platform.h> 16 #include <libpldm/state_set.h> 17 18 #include <sdbusplus/bus/match.hpp> 19 #include <sdeventplus/event.hpp> 20 #include <sdeventplus/utility/timer.hpp> 21 #include <xyz/openbmc_project/State/Host/client.hpp> 22 23 typedef ibm_oem_pldm_state_set_firmware_update_state_values CodeUpdateState; 24 25 using HostState = sdbusplus::common::xyz::openbmc_project::state::Host; 26 27 namespace pldm 28 { 29 namespace responder 30 { 31 using ObjectPath = std::string; 32 using AssociatedEntityMap = std::map<ObjectPath, pldm_entity>; 33 using namespace pldm::bios; 34 using namespace pldm::utils; 35 36 namespace oem_ibm_platform 37 { 38 constexpr uint16_t ENTITY_INSTANCE_0 = 0; 39 constexpr uint16_t ENTITY_INSTANCE_1 = 1; 40 41 constexpr uint32_t BMC_PDR_START_RANGE = 0x00000000; 42 constexpr uint32_t BMC_PDR_END_RANGE = 0x00FFFFFF; 43 constexpr uint32_t HOST_PDR_START_RANGE = 0x01000000; 44 constexpr uint32_t HOST_PDR_END_RANGE = 0x01FFFFFF; 45 46 const pldm::pdr::TerminusID HYPERVISOR_TID = 208; 47 48 static constexpr uint8_t HEARTBEAT_TIMEOUT_DELTA = 10; 49 50 enum SetEventReceiverCount 51 { 52 SET_EVENT_RECEIVER_SENT = 0x2, 53 }; 54 55 class Handler : public oem_platform::Handler 56 { 57 public: Handler(const pldm::utils::DBusHandler * dBusIntf,pldm::responder::CodeUpdate * codeUpdate,pldm::responder::SlotHandler * slotHandler,int mctp_fd,uint8_t mctp_eid,pldm::InstanceIdDb & instanceIdDb,sdeventplus::Event & event,pldm::requester::Handler<pldm::requester::Request> * handler)58 Handler(const pldm::utils::DBusHandler* dBusIntf, 59 pldm::responder::CodeUpdate* codeUpdate, 60 pldm::responder::SlotHandler* slotHandler, int mctp_fd, 61 uint8_t mctp_eid, pldm::InstanceIdDb& instanceIdDb, 62 sdeventplus::Event& event, 63 pldm::requester::Handler<pldm::requester::Request>* handler) : 64 oem_platform::Handler(dBusIntf), codeUpdate(codeUpdate), 65 slotHandler(slotHandler), platformHandler(nullptr), mctp_fd(mctp_fd), 66 mctp_eid(mctp_eid), instanceIdDb(instanceIdDb), event(event), 67 handler(handler), 68 timer(event, std::bind(std::mem_fn(&Handler::setSurvTimer), this, 69 HYPERVISOR_TID, false)), 70 hostTransitioningToOff(true) 71 { 72 codeUpdate->setVersions(); 73 setEventReceiverCnt = 0; 74 75 using namespace sdbusplus::bus::match::rules; 76 hostOffMatch = std::make_unique<sdbusplus::bus::match_t>( 77 pldm::utils::DBusHandler::getBus(), 78 propertiesChanged("/xyz/openbmc_project/state/host0", 79 HostState::interface), 80 [this](sdbusplus::message_t& msg) { 81 pldm::utils::DbusChangedProps props{}; 82 std::string intf; 83 msg.read(intf, props); 84 const auto itr = 85 props.find(HostState::property_names::current_host_state); 86 if (itr != props.end()) 87 { 88 pldm::utils::PropertyValue value = itr->second; 89 auto propVal = std::get<std::string>(value); 90 if (propVal == 91 "xyz.openbmc_project.State.Host.HostState.Off") 92 { 93 hostOff = true; 94 setEventReceiverCnt = 0; 95 disableWatchDogTimer(); 96 startStopTimer(false); 97 pldm::filetable::clearFileTable(); 98 } 99 else if (propVal == 100 "xyz.openbmc_project.State.Host.HostState.Running") 101 { 102 hostOff = false; 103 hostTransitioningToOff = false; 104 } 105 else if ( 106 propVal == 107 "xyz.openbmc_project.State.Host.HostState.TransitioningToOff") 108 { 109 hostTransitioningToOff = true; 110 } 111 } 112 }); 113 114 powerStateOffMatch = std::make_unique<sdbusplus::bus::match_t>( 115 pldm::utils::DBusHandler::getBus(), 116 propertiesChanged("/xyz/openbmc_project/state/chassis0", 117 "xyz.openbmc_project.State.Chassis"), 118 [this](sdbusplus::message_t& msg) { 119 pldm::utils::DbusChangedProps props{}; 120 std::string intf; 121 msg.read(intf, props); 122 const auto itr = props.find("CurrentPowerState"); 123 if (itr != props.end()) 124 { 125 pldm::utils::PropertyValue value = itr->second; 126 auto propVal = std::get<std::string>(value); 127 if (propVal == 128 "xyz.openbmc_project.State.Chassis.PowerState.Off") 129 { 130 handleBootTypesAtChassisOff(); 131 static constexpr auto searchpath = 132 "/xyz/openbmc_project/inventory/system/chassis/motherboard"; 133 int depth = 0; 134 std::vector<std::string> powerInterface = { 135 "xyz.openbmc_project.State.Decorator.PowerState"}; 136 pldm::utils::GetSubTreeResponse response = 137 pldm::utils::DBusHandler().getSubtree( 138 searchpath, depth, powerInterface); 139 for (const auto& [objPath, serviceMap] : response) 140 { 141 pldm::utils::DBusMapping dbusMapping{ 142 objPath, 143 "xyz.openbmc_project.State.Decorator.PowerState", 144 "PowerState", "string"}; 145 value = 146 "xyz.openbmc_project.State.Decorator.PowerState.State.Off"; 147 try 148 { 149 pldm::utils::DBusHandler().setDbusProperty( 150 dbusMapping, value); 151 } 152 catch (const std::exception& e) 153 { 154 error( 155 "Unable to set the slot power state to Off error - {ERROR}", 156 "ERROR", e); 157 } 158 } 159 } 160 } 161 }); 162 163 updateBIOSMatch = std::make_unique<sdbusplus::bus::match_t>( 164 pldm::utils::DBusHandler::getBus(), 165 propertiesChanged("/xyz/openbmc_project/bios_config/manager", 166 "xyz.openbmc_project.BIOSConfig.Manager"), 167 [codeUpdate](sdbusplus::message_t& msg) { 168 constexpr auto propertyName = "PendingAttributes"; 169 using Value = 170 std::variant<std::string, PendingAttributes, BaseBIOSTable>; 171 using Properties = std::map<pldm::utils::DbusProp, Value>; 172 Properties props{}; 173 std::string intf; 174 msg.read(intf, props); 175 auto valPropMap = props.find(propertyName); 176 if (valPropMap == props.end()) 177 { 178 return; 179 } 180 181 PendingAttributes pendingAttributes = 182 std::get<PendingAttributes>(valPropMap->second); 183 for (auto it : pendingAttributes) 184 { 185 if (it.first == "fw_boot_side") 186 { 187 auto& [attributeType, attributevalue] = it.second; 188 std::string nextBootSideAttr = 189 std::get<std::string>(attributevalue); 190 std::string nextBootSide = 191 (nextBootSideAttr == "Perm" ? Pside : Tside); 192 codeUpdate->setNextBootSide(nextBootSide); 193 } 194 } 195 }); 196 197 platformSAIMatch = std::make_unique<sdbusplus::bus::match_t>( 198 pldm::utils::DBusHandler::getBus(), 199 propertiesChanged( 200 "/xyz/openbmc_project/led/groups/partition_system_attention_indicator", 201 "xyz.openbmc_project.Led.Group"), 202 [this](sdbusplus::message_t& msg) { 203 pldm::utils::DbusChangedProps props{}; 204 std::string intf; 205 msg.read(intf, props); 206 const auto itr = props.find("Asserted"); 207 if (itr != props.end()) 208 { 209 processSAIUpdate(); 210 } 211 }); 212 213 partitionSAIMatch = std::make_unique<sdbusplus::bus::match_t>( 214 pldm::utils::DBusHandler::getBus(), 215 propertiesChanged( 216 "/xyz/openbmc_project/led/groups/platform_system_attention_indicator", 217 "xyz.openbmc_project.Led.Group"), 218 [this](sdbusplus::message_t& msg) { 219 pldm::utils::DbusChangedProps props{}; 220 std::string intf; 221 msg.read(intf, props); 222 const auto itr = props.find("Asserted"); 223 if (itr != props.end()) 224 { 225 processSAIUpdate(); 226 } 227 }); 228 } 229 230 int getOemStateSensorReadingsHandler( 231 pldm::pdr::EntityType entityType, 232 pldm::pdr::EntityInstance entityInstance, 233 pldm::pdr::ContainerID containerId, pldm::pdr::StateSetId stateSetId, 234 pldm::pdr::CompositeCount compSensorCnt, uint16_t sensorId, 235 std::vector<get_sensor_state_field>& stateField); 236 237 int oemSetStateEffecterStatesHandler( 238 uint16_t entityType, uint16_t entityInstance, uint16_t stateSetId, 239 uint8_t compEffecterCnt, 240 std::vector<set_effecter_state_field>& stateField, uint16_t effecterId); 241 242 /** @brief Method to set the platform handler in the 243 * oem_ibm_handler class 244 * @param[in] handler - pointer to PLDM platform handler 245 */ 246 void setPlatformHandler(pldm::responder::platform::Handler* handler); 247 248 /** @brief Method to fetch the effecter ID of the code update PDRs 249 * 250 * @return platformHandler->getNextEffecterId() - returns the 251 * effecter ID from the platform handler 252 */ getNextEffecterId()253 virtual uint16_t getNextEffecterId() 254 { 255 return platformHandler->getNextEffecterId(); 256 } 257 258 /** @brief Method to fetch the sensor ID of the code update PDRs 259 * 260 * @return platformHandler->getNextSensorId() - returns the 261 * Sensor ID from the platform handler 262 */ getNextSensorId()263 virtual uint16_t getNextSensorId() 264 { 265 return platformHandler->getNextSensorId(); 266 } 267 268 /** @brief Get std::map associated with the entity 269 * key: object path 270 * value: pldm_entity 271 * 272 * @return std::map<ObjectPath, pldm_entity> 273 */ getAssociateEntityMap()274 virtual const AssociatedEntityMap& getAssociateEntityMap() 275 { 276 return platformHandler->getAssociateEntityMap(); 277 } 278 279 /** @brief Method to Generate the OEM PDRs 280 * 281 * @param[in] repo - instance of concrete implementation of Repo 282 */ 283 void buildOEMPDR(pdr_utils::Repo& repo); 284 285 /** @brief Method to send code update event to host 286 * @param[in] sensorId - sendor ID 287 * @param[in] sensorEventClass - event class of sensor 288 * @param[in] sensorOffset - sensor offset 289 * @param[in] eventState - new code update event state 290 * @param[in] prevEventState - previous code update event state 291 * @return none 292 */ 293 void sendStateSensorEvent(uint16_t sensorId, 294 enum sensor_event_class_states sensorEventClass, 295 uint8_t sensorOffset, uint8_t eventState, 296 uint8_t prevEventState); 297 298 /** @brief Method to send encoded request msg of code update event to host 299 * @param[in] requestMsg - encoded request msg 300 * @param[in] instanceId - instance id of the message 301 * @return PLDM status code 302 */ 303 int sendEventToHost(std::vector<uint8_t>& requestMsg, uint8_t instanceId); 304 305 /** @brief _processEndUpdate processes the actual work that needs 306 * to be carried out after EndUpdate effecter is set. This is done async 307 * after sending response for EndUpdate set effecter 308 * @param[in] source - sdeventplus event source 309 */ 310 void _processEndUpdate(sdeventplus::source::EventBase& source); 311 312 /** @brief _processStartUpdate processes the actual work that needs 313 * to be carried out after StartUpdate effecter is set. This is done async 314 * after sending response for StartUpdate set effecter 315 * @param[in] source - sdeventplus event source 316 */ 317 void _processStartUpdate(sdeventplus::source::EventBase& source); 318 319 /** @brief _processSystemReboot processes the actual work that needs to be 320 * carried out after the System Power State effecter is set to reboot 321 * the system 322 * @param[in] source - sdeventplus event source 323 */ 324 void _processSystemReboot(sdeventplus::source::EventBase& source); 325 326 /*keeps track how many times setEventReceiver is sent */ countSetEventReceiver()327 void countSetEventReceiver() 328 { 329 setEventReceiverCnt++; 330 } 331 332 /* disables watchdog if running and Host is up */ 333 void checkAndDisableWatchDog(); 334 335 /** @brief To check if the watchdog app is running 336 * 337 * @return the running status of watchdog app 338 */ 339 bool watchDogRunning(); 340 341 /** @brief Method to reset the Watchdog timer on receiving platform Event 342 * Message for heartbeat elapsed time from Hostboot 343 */ 344 void resetWatchDogTimer(); 345 346 /** @brief To disable to the watchdog timer on host poweron completion*/ 347 void disableWatchDogTimer(); 348 349 /** @brief to check the BMC state*/ 350 int checkBMCState(); 351 352 /** @brief update the dbus object paths */ 353 void updateOemDbusPaths(std::string& dbusPath); 354 355 /** @brief Method to fetch the last BMC record from the PDR repo 356 * 357 * @param[in] repo - pointer to BMC's primary PDR repo 358 * 359 * @return the last BMC record from the repo 360 */ 361 const pldm_pdr_record* fetchLastBMCRecord(const pldm_pdr* repo); 362 363 /** @brief Method to check if the record handle passed is in remote PDR 364 * record handle range 365 * 366 * @param[in] record_handle - record handle of the PDR 367 * 368 * @return true if record handle passed is in host PDR record handle range 369 */ 370 bool checkRecordHandleInRange(const uint32_t& record_handle); 371 372 /** *brief Method to call the setEventReceiver command*/ 373 void processSetEventReceiver(); 374 375 /** @brief Method to call the setEventReceiver through the platform 376 * handler 377 */ setEventReceiver()378 virtual void setEventReceiver() 379 { 380 platformHandler->setEventReceiver(); 381 } 382 383 /** @brief Method to Enable/Disable timer to see if remote terminus sends 384 * the surveillance ping and logs informational error if remote terminus 385 * fails to send the surveillance pings 386 * 387 * @param[in] tid - TID of the remote terminus 388 * @param[in] value - true or false, to indicate if the timer is 389 * running or not 390 */ 391 void setSurvTimer(uint8_t tid, bool value); 392 393 /** @brief To handle the boot types bios attributes at power on*/ 394 void handleBootTypesAtPowerOn(); 395 396 /** @brief To handle the boot types bios attributes at shutdown*/ 397 void handleBootTypesAtChassisOff(); 398 399 /** @brief To set the boot types bios attributes based on the RestartCause 400 * of host 401 * 402 * @param[in] RestartCause - Host restart cause 403 */ 404 void setBootTypesBiosAttr(const std::string& restartCause); 405 406 /** @brief To turn off Real SAI effecter*/ 407 void turnOffRealSAIEffecter(); 408 409 /** @brief Fetch Real SAI status based on the partition SAI and platform SAI 410 * sensor states. Real SAI is turned on if any of the partition or platform 411 * SAI turned on else Real SAI is turned off 412 * @return Real SAI sensor state PLDM_SENSOR_WARNING/PLDM_SENSOR_NORMAL 413 */ 414 uint8_t fetchRealSAIStatus(); 415 416 /** @brief Method to process virtual platform/partition SAI update*/ 417 void processSAIUpdate(); 418 419 ~Handler() = default; 420 421 pldm::responder::CodeUpdate* codeUpdate; //!< pointer to CodeUpdate object 422 423 pldm::responder::SlotHandler* 424 slotHandler; //!< pointer to SlotHandler object 425 426 pldm::responder::platform::Handler* 427 platformHandler; //!< pointer to PLDM platform handler 428 429 /** @brief fd of MCTP communications socket */ 430 int mctp_fd; 431 432 /** @brief MCTP EID of host firmware */ 433 uint8_t mctp_eid; 434 435 /** @brief reference to an InstanceIdDb object, used to obtain a PLDM 436 * instance id. */ 437 pldm::InstanceIdDb& instanceIdDb; 438 /** @brief sdeventplus event source */ 439 std::unique_ptr<sdeventplus::source::Defer> assembleImageEvent; 440 std::unique_ptr<sdeventplus::source::Defer> startUpdateEvent; 441 std::unique_ptr<sdeventplus::source::Defer> systemRebootEvent; 442 443 /** @brief Effecterid to dbus object path map 444 */ 445 std::unordered_map<uint16_t, std::string> effecterIdToDbusMap; 446 447 /** @brief reference of main event loop of pldmd, primarily used to schedule 448 * work 449 */ 450 sdeventplus::Event& event; 451 452 private: 453 /** @brief Method to reset or stop the surveillance timer 454 * 455 * @param[in] value - true or false, to indicate if the timer 456 * should be reset or turned off 457 */ 458 void startStopTimer(bool value); 459 460 /** @brief D-Bus property changed signal match for CurrentPowerState*/ 461 std::unique_ptr<sdbusplus::bus::match_t> chassisOffMatch; 462 463 /** @brief PLDM request handler */ 464 pldm::requester::Handler<pldm::requester::Request>* handler; 465 466 /** @brief D-Bus property changed signal match */ 467 std::unique_ptr<sdbusplus::bus::match_t> updateBIOSMatch; 468 469 /** @brief D-Bus property changed signal match */ 470 std::unique_ptr<sdbusplus::bus::match_t> hostOffMatch; 471 472 /** @brief D-Bus property changed signal match */ 473 std::unique_ptr<sdbusplus::bus::match_t> powerStateOffMatch; 474 475 /** @brief Timer used for monitoring surveillance pings from host */ 476 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic> timer; 477 478 /** @brief D-Bus Interface added signal match for virtual platform SAI */ 479 std::unique_ptr<sdbusplus::bus::match_t> platformSAIMatch; 480 481 /** @brief D-Bus Interface added signal match for virtual partition SAI */ 482 std::unique_ptr<sdbusplus::bus::match_t> partitionSAIMatch; 483 484 /** @brief Real SAI sensor id*/ 485 uint16_t realSAISensorId; 486 487 bool hostOff = true; 488 489 bool hostTransitioningToOff; 490 491 int setEventReceiverCnt = 0; 492 }; 493 494 /** @brief Method to encode code update event msg 495 * @param[in] eventType - type of event 496 * @param[in] eventDataVec - vector of event data to be sent to host 497 * @param[in/out] requestMsg - request msg to be encoded 498 * @param[in] instanceId - instance ID 499 * @return PLDM status code 500 */ 501 int encodeEventMsg(uint8_t eventType, const std::vector<uint8_t>& eventDataVec, 502 std::vector<uint8_t>& requestMsg, uint8_t instanceId); 503 504 } // namespace oem_ibm_platform 505 506 namespace oem_ibm_bios 507 { 508 /** @brief The file where bootside data will be saved */ 509 constexpr auto bootSideDirPath = "/var/lib/pldm/bootSide"; 510 511 class Handler : public oem_bios::Handler 512 { 513 public: Handler()514 Handler() {} 515 processOEMBaseBiosTable(const BaseBIOSTable & biosTable)516 void processOEMBaseBiosTable(const BaseBIOSTable& biosTable) 517 { 518 for (const auto& [attrName, biostabObj] : biosTable) 519 { 520 // The additional check to see if /var/lib/pldm/bootSide file exists 521 // is added to make sure we are doing the fw_boot_side setting after 522 // the base bios table is initialised. 523 if ((attrName == "fw_boot_side") && fs::exists(bootSideDirPath)) 524 { 525 PendingAttributesList biosAttrList; 526 527 std::string nextBootSide = 528 std::get<std::string>(std::get<5>(biostabObj)); 529 530 std::string currNextBootSide; 531 auto attributeValue = 532 getBiosAttrValue<std::string>("fw_boot_side"); 533 534 if (attributeValue.has_value()) 535 { 536 currNextBootSide = attributeValue.value(); 537 } 538 else 539 { 540 info( 541 "Boot side is not initialized yet, so setting default value"); 542 currNextBootSide = "Temp"; 543 } 544 545 if (currNextBootSide != nextBootSide) 546 { 547 biosAttrList.emplace_back(std::make_pair( 548 attrName, 549 std::make_tuple(EnumAttribute, nextBootSide))); 550 setBiosAttr(biosAttrList); 551 } 552 } 553 } 554 } 555 }; 556 557 } // namespace oem_ibm_bios 558 559 } // namespace responder 560 561 } // namespace pldm 562