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