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