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