xref: /openbmc/pldm/oem/ibm/libpldmresponder/oem_ibm_handler.hpp (revision 505542588031c26ce7918ad4d35aacf6bc3b80b9)
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