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