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