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