1 #include "oem_ibm_handler.hpp"
2 
3 #include "libpldm/entity.h"
4 #include "libpldm/requester/pldm.h"
5 
6 #include "file_io_type_lid.hpp"
7 #include "libpldmresponder/file_io.hpp"
8 #include "libpldmresponder/pdr_utils.hpp"
9 namespace pldm
10 {
11 namespace responder
12 {
13 namespace oem_ibm_platform
14 {
15 
16 int pldm::responder::oem_ibm_platform::Handler::
17     getOemStateSensorReadingsHandler(
18         EntityType entityType, EntityInstance entityInstance,
19         StateSetId stateSetId, CompositeCount compSensorCnt,
20         std::vector<get_sensor_state_field>& stateField)
21 {
22     int rc = PLDM_SUCCESS;
23     stateField.clear();
24 
25     for (size_t i = 0; i < compSensorCnt; i++)
26     {
27         uint8_t sensorOpState{};
28         if (entityType == PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE &&
29             stateSetId == PLDM_OEM_IBM_BOOT_STATE)
30         {
31             sensorOpState = fetchBootSide(entityInstance, codeUpdate);
32         }
33         else
34         {
35             rc = PLDM_PLATFORM_INVALID_STATE_VALUE;
36             break;
37         }
38         stateField.push_back({PLDM_SENSOR_ENABLED, PLDM_SENSOR_UNKNOWN,
39                               PLDM_SENSOR_UNKNOWN, sensorOpState});
40     }
41     return rc;
42 }
43 
44 int pldm::responder::oem_ibm_platform::Handler::
45     oemSetStateEffecterStatesHandler(
46         uint16_t entityType, uint16_t entityInstance, uint16_t stateSetId,
47         uint8_t compEffecterCnt,
48         std::vector<set_effecter_state_field>& stateField,
49         uint16_t /*effecterId*/)
50 {
51     int rc = PLDM_SUCCESS;
52 
53     for (uint8_t currState = 0; currState < compEffecterCnt; ++currState)
54     {
55         if (stateField[currState].set_request == PLDM_REQUEST_SET)
56         {
57             if (entityType == PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE &&
58                 stateSetId == PLDM_OEM_IBM_BOOT_STATE)
59             {
60                 rc = setBootSide(entityInstance, currState, stateField,
61                                  codeUpdate);
62             }
63             else if (entityType == PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE &&
64                      stateSetId == PLDM_OEM_IBM_FIRMWARE_UPDATE_STATE)
65             {
66                 if (stateField[currState].effecter_state ==
67                     uint8_t(CodeUpdateState::START))
68                 {
69                     codeUpdate->setCodeUpdateProgress(true);
70                     startUpdateEvent =
71                         std::make_unique<sdeventplus::source::Defer>(
72                             event,
73                             std::bind(std::mem_fn(&oem_ibm_platform::Handler::
74                                                       _processStartUpdate),
75                                       this, std::placeholders::_1));
76                 }
77                 else if (stateField[currState].effecter_state ==
78                          uint8_t(CodeUpdateState::END))
79                 {
80                     rc = PLDM_SUCCESS;
81                     assembleImageEvent = std::make_unique<
82                         sdeventplus::source::Defer>(
83                         event,
84                         std::bind(
85                             std::mem_fn(
86                                 &oem_ibm_platform::Handler::_processEndUpdate),
87                             this, std::placeholders::_1));
88 
89                     // sendCodeUpdateEvent(effecterId, END, START);
90                 }
91                 else if (stateField[currState].effecter_state ==
92                          uint8_t(CodeUpdateState::ABORT))
93                 {
94                     codeUpdate->setCodeUpdateProgress(false);
95                     codeUpdate->clearDirPath(LID_STAGING_DIR);
96                     auto sensorId = codeUpdate->getFirmwareUpdateSensor();
97                     sendStateSensorEvent(sensorId, PLDM_STATE_SENSOR_STATE, 0,
98                                          uint8_t(CodeUpdateState::ABORT),
99                                          uint8_t(CodeUpdateState::START));
100                     // sendCodeUpdateEvent(effecterId, ABORT, END);
101                 }
102                 else if (stateField[currState].effecter_state ==
103                          uint8_t(CodeUpdateState::ACCEPT))
104                 {
105                     auto sensorId = codeUpdate->getFirmwareUpdateSensor();
106                     sendStateSensorEvent(sensorId, PLDM_STATE_SENSOR_STATE, 0,
107                                          uint8_t(CodeUpdateState::ACCEPT),
108                                          uint8_t(CodeUpdateState::END));
109                     // TODO Set new Dbus property provided by code update app
110                     // sendCodeUpdateEvent(effecterId, ACCEPT, END);
111                 }
112                 else if (stateField[currState].effecter_state ==
113                          uint8_t(CodeUpdateState::REJECT))
114                 {
115                     auto sensorId = codeUpdate->getFirmwareUpdateSensor();
116                     sendStateSensorEvent(sensorId, PLDM_STATE_SENSOR_STATE, 0,
117                                          uint8_t(CodeUpdateState::REJECT),
118                                          uint8_t(CodeUpdateState::END));
119                     // TODO Set new Dbus property provided by code update app
120                     // sendCodeUpdateEvent(effecterId, REJECT, END);
121                 }
122             }
123             else if (entityType == PLDM_ENTITY_SYSTEM_CHASSIS &&
124                      stateSetId == PLDM_OEM_IBM_SYSTEM_POWER_STATE)
125             {
126                 if (stateField[currState].effecter_state == POWER_CYCLE_HARD)
127                 {
128                     systemRebootEvent =
129                         std::make_unique<sdeventplus::source::Defer>(
130                             event,
131                             std::bind(std::mem_fn(&oem_ibm_platform::Handler::
132                                                       _processSystemReboot),
133                                       this, std::placeholders::_1));
134                 }
135             }
136             else
137             {
138                 rc = PLDM_PLATFORM_SET_EFFECTER_UNSUPPORTED_SENSORSTATE;
139             }
140         }
141         if (rc != PLDM_SUCCESS)
142         {
143             break;
144         }
145     }
146     return rc;
147 }
148 
149 void buildAllCodeUpdateEffecterPDR(platform::Handler* platformHandler,
150                                    uint16_t entityType, uint16_t entityInstance,
151                                    uint16_t stateSetID, pdr_utils::Repo& repo)
152 {
153     size_t pdrSize = 0;
154     pdrSize = sizeof(pldm_state_effecter_pdr) +
155               sizeof(state_effecter_possible_states);
156     std::vector<uint8_t> entry{};
157     entry.resize(pdrSize);
158     pldm_state_effecter_pdr* pdr =
159         reinterpret_cast<pldm_state_effecter_pdr*>(entry.data());
160     if (!pdr)
161     {
162         std::cerr << "Failed to get record by PDR type, ERROR:"
163                   << PLDM_PLATFORM_INVALID_EFFECTER_ID << std::endl;
164     }
165     pdr->hdr.record_handle = 0;
166     pdr->hdr.version = 1;
167     pdr->hdr.type = PLDM_STATE_EFFECTER_PDR;
168     pdr->hdr.record_change_num = 0;
169     pdr->hdr.length = sizeof(pldm_state_effecter_pdr) - sizeof(pldm_pdr_hdr);
170     pdr->terminus_handle = pdr::BmcPldmTerminusHandle;
171     pdr->effecter_id = platformHandler->getNextEffecterId();
172     pdr->entity_type = entityType;
173     pdr->entity_instance = entityInstance;
174     pdr->container_id = 0;
175     pdr->effecter_semantic_id = 0;
176     pdr->effecter_init = PLDM_NO_INIT;
177     pdr->has_description_pdr = false;
178     pdr->composite_effecter_count = 1;
179 
180     auto* possibleStatesPtr = pdr->possible_states;
181     auto possibleStates =
182         reinterpret_cast<state_effecter_possible_states*>(possibleStatesPtr);
183     possibleStates->state_set_id = stateSetID;
184     possibleStates->possible_states_size = 2;
185     auto state =
186         reinterpret_cast<state_effecter_possible_states*>(possibleStates);
187     if (stateSetID == PLDM_OEM_IBM_BOOT_STATE)
188         state->states[0].byte = 6;
189     else if (stateSetID == PLDM_OEM_IBM_FIRMWARE_UPDATE_STATE)
190         state->states[0].byte = 126;
191     else if (stateSetID == PLDM_OEM_IBM_SYSTEM_POWER_STATE)
192         state->states[0].byte = 2;
193     pldm::responder::pdr_utils::PdrEntry pdrEntry{};
194     pdrEntry.data = entry.data();
195     pdrEntry.size = pdrSize;
196     repo.addRecord(pdrEntry);
197 }
198 
199 void buildAllCodeUpdateSensorPDR(platform::Handler* platformHandler,
200                                  uint16_t entityType, uint16_t entityInstance,
201                                  uint16_t stateSetID, pdr_utils::Repo& repo)
202 {
203     size_t pdrSize = 0;
204     pdrSize =
205         sizeof(pldm_state_sensor_pdr) + sizeof(state_sensor_possible_states);
206     std::vector<uint8_t> entry{};
207     entry.resize(pdrSize);
208     pldm_state_sensor_pdr* pdr =
209         reinterpret_cast<pldm_state_sensor_pdr*>(entry.data());
210     if (!pdr)
211     {
212         std::cerr << "Failed to get record by PDR type, ERROR:"
213                   << PLDM_PLATFORM_INVALID_SENSOR_ID << std::endl;
214     }
215     pdr->hdr.record_handle = 0;
216     pdr->hdr.version = 1;
217     pdr->hdr.type = PLDM_STATE_SENSOR_PDR;
218     pdr->hdr.record_change_num = 0;
219     pdr->hdr.length = sizeof(pldm_state_sensor_pdr) - sizeof(pldm_pdr_hdr);
220     pdr->terminus_handle = pdr::BmcPldmTerminusHandle;
221     pdr->sensor_id = platformHandler->getNextSensorId();
222     pdr->entity_type = entityType;
223     pdr->entity_instance = entityInstance;
224     pdr->container_id = 0;
225     pdr->sensor_init = PLDM_NO_INIT;
226     pdr->sensor_auxiliary_names_pdr = false;
227     pdr->composite_sensor_count = 1;
228 
229     auto* possibleStatesPtr = pdr->possible_states;
230     auto possibleStates =
231         reinterpret_cast<state_sensor_possible_states*>(possibleStatesPtr);
232     possibleStates->state_set_id = stateSetID;
233     possibleStates->possible_states_size = 2;
234     auto state =
235         reinterpret_cast<state_sensor_possible_states*>(possibleStates);
236     if ((stateSetID == PLDM_OEM_IBM_BOOT_STATE) ||
237         (stateSetID == oem_ibm_platform::PLDM_OEM_IBM_VERIFICATION_STATE))
238         state->states[0].byte = 6;
239     else if (stateSetID == PLDM_OEM_IBM_FIRMWARE_UPDATE_STATE)
240         state->states[0].byte = 126;
241     pldm::responder::pdr_utils::PdrEntry pdrEntry{};
242     pdrEntry.data = entry.data();
243     pdrEntry.size = pdrSize;
244     repo.addRecord(pdrEntry);
245 }
246 
247 void pldm::responder::oem_ibm_platform::Handler::buildOEMPDR(
248     pdr_utils::Repo& repo)
249 {
250     buildAllCodeUpdateEffecterPDR(
251         platformHandler, PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE, ENTITY_INSTANCE_0,
252         PLDM_OEM_IBM_BOOT_STATE, repo);
253     buildAllCodeUpdateEffecterPDR(
254         platformHandler, PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE, ENTITY_INSTANCE_1,
255         PLDM_OEM_IBM_BOOT_STATE, repo);
256     buildAllCodeUpdateEffecterPDR(
257         platformHandler, PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE, ENTITY_INSTANCE_0,
258         PLDM_OEM_IBM_FIRMWARE_UPDATE_STATE, repo);
259     buildAllCodeUpdateEffecterPDR(platformHandler, PLDM_ENTITY_SYSTEM_CHASSIS,
260                                   ENTITY_INSTANCE_0,
261                                   PLDM_OEM_IBM_SYSTEM_POWER_STATE, repo);
262 
263     buildAllCodeUpdateSensorPDR(
264         platformHandler, PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE, ENTITY_INSTANCE_0,
265         PLDM_OEM_IBM_BOOT_STATE, repo);
266     buildAllCodeUpdateSensorPDR(
267         platformHandler, PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE, ENTITY_INSTANCE_1,
268         PLDM_OEM_IBM_BOOT_STATE, repo);
269     buildAllCodeUpdateSensorPDR(
270         platformHandler, PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE, ENTITY_INSTANCE_0,
271         PLDM_OEM_IBM_FIRMWARE_UPDATE_STATE, repo);
272     buildAllCodeUpdateSensorPDR(
273         platformHandler, PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE, ENTITY_INSTANCE_0,
274         PLDM_OEM_IBM_VERIFICATION_STATE, repo);
275     auto sensorId = findStateSensorId(
276         repo.getPdr(), 0, PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE,
277         ENTITY_INSTANCE_0, 0, PLDM_OEM_IBM_VERIFICATION_STATE);
278     codeUpdate->setMarkerLidSensor(sensorId);
279     sensorId = findStateSensorId(
280         repo.getPdr(), 0, PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE,
281         ENTITY_INSTANCE_0, 0, PLDM_OEM_IBM_FIRMWARE_UPDATE_STATE);
282     codeUpdate->setFirmwareUpdateSensor(sensorId);
283 }
284 
285 void pldm::responder::oem_ibm_platform::Handler::setPlatformHandler(
286     pldm::responder::platform::Handler* handler)
287 {
288     platformHandler = handler;
289 }
290 
291 int pldm::responder::oem_ibm_platform::Handler::sendEventToHost(
292     std::vector<uint8_t>& requestMsg)
293 {
294     uint8_t* responseMsg = nullptr;
295     size_t responseMsgSize{};
296     if (requestMsg.size())
297     {
298         std::ostringstream tempStream;
299         for (int byte : requestMsg)
300         {
301             tempStream << std::setfill('0') << std::setw(2) << std::hex << byte
302                        << " ";
303         }
304         std::cout << tempStream.str() << std::endl;
305     }
306 
307     auto requesterRc =
308         pldm_send_recv(mctp_eid, mctp_fd, requestMsg.data(), requestMsg.size(),
309                        &responseMsg, &responseMsgSize);
310     std::unique_ptr<uint8_t, decltype(std::free)*> responseMsgPtr{responseMsg,
311                                                                   std::free};
312     if (requesterRc != PLDM_REQUESTER_SUCCESS)
313     {
314         std::cerr << "Failed to send message/receive response. RC = "
315                   << requesterRc << ", errno = " << errno
316                   << "for sending event to host \n";
317         return requesterRc;
318     }
319     uint8_t completionCode{};
320     uint8_t status{};
321     auto responsePtr = reinterpret_cast<struct pldm_msg*>(responseMsgPtr.get());
322     auto rc = decode_platform_event_message_resp(
323         responsePtr, responseMsgSize - sizeof(pldm_msg_hdr), &completionCode,
324         &status);
325 
326     if (rc != PLDM_SUCCESS || completionCode != PLDM_SUCCESS)
327     {
328         std::cerr << "Failure in decode platform event message response, rc= "
329                   << rc << " cc=" << static_cast<unsigned>(completionCode)
330                   << "\n";
331         return rc;
332     }
333     return rc;
334 }
335 
336 int encodeEventMsg(uint8_t eventType, const std::vector<uint8_t>& eventDataVec,
337                    std::vector<uint8_t>& requestMsg, uint8_t instanceId)
338 {
339     auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
340 
341     auto rc = encode_platform_event_message_req(
342         instanceId, 1 /*formatVersion*/, 0 /*tId*/, eventType,
343         eventDataVec.data(), eventDataVec.size(), request,
344         eventDataVec.size() + PLDM_PLATFORM_EVENT_MESSAGE_MIN_REQ_BYTES);
345 
346     return rc;
347 }
348 
349 void pldm::responder::oem_ibm_platform::Handler::sendStateSensorEvent(
350     uint16_t sensorId, enum sensor_event_class_states sensorEventClass,
351     uint8_t sensorOffset, uint8_t eventState, uint8_t prevEventState)
352 {
353     std::vector<uint8_t> sensorEventDataVec{};
354     size_t sensorEventSize = PLDM_SENSOR_EVENT_DATA_MIN_LENGTH + 1;
355     sensorEventDataVec.resize(sensorEventSize);
356     auto eventData = reinterpret_cast<struct pldm_sensor_event_data*>(
357         sensorEventDataVec.data());
358     eventData->sensor_id = sensorId;
359     eventData->sensor_event_class_type = sensorEventClass;
360     auto eventClassStart = eventData->event_class;
361     auto eventClass =
362         reinterpret_cast<struct pldm_sensor_event_state_sensor_state*>(
363             eventClassStart);
364     eventClass->sensor_offset = sensorOffset;
365     eventClass->event_state = eventState;
366     eventClass->previous_event_state = prevEventState;
367     auto instanceId = requester.getInstanceId(mctp_eid);
368     std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) +
369                                     PLDM_PLATFORM_EVENT_MESSAGE_MIN_REQ_BYTES +
370                                     sensorEventDataVec.size());
371     auto rc = encodeEventMsg(PLDM_SENSOR_EVENT, sensorEventDataVec, requestMsg,
372                              instanceId);
373     if (rc != PLDM_SUCCESS)
374     {
375         std::cerr << "Failed to encode state sensor event, rc = " << rc
376                   << std::endl;
377         return;
378     }
379     rc = sendEventToHost(requestMsg);
380     if (rc != PLDM_SUCCESS)
381     {
382         std::cerr << "Failed to send event to host: "
383                   << "rc=" << rc << std::endl;
384     }
385     requester.markFree(mctp_eid, instanceId);
386     return;
387 }
388 
389 void pldm::responder::oem_ibm_platform::Handler::_processEndUpdate(
390     sdeventplus::source::EventBase& /*source */)
391 {
392     assembleImageEvent.reset();
393     int retc = assembleCodeUpdateImage();
394     if (retc != PLDM_SUCCESS)
395     {
396         codeUpdate->setCodeUpdateProgress(false);
397         auto sensorId = codeUpdate->getFirmwareUpdateSensor();
398         sendStateSensorEvent(sensorId, PLDM_STATE_SENSOR_STATE, 0,
399                              uint8_t(CodeUpdateState::FAIL),
400                              uint8_t(CodeUpdateState::START));
401     }
402 }
403 
404 void pldm::responder::oem_ibm_platform::Handler::_processStartUpdate(
405     sdeventplus::source::EventBase& /*source */)
406 {
407     codeUpdate->deleteImage();
408     CodeUpdateState state = CodeUpdateState::START;
409     auto rc = codeUpdate->setRequestedApplyTime();
410     if (rc != PLDM_SUCCESS)
411     {
412         std::cerr << "setRequestedApplyTime failed \n";
413         state = CodeUpdateState::FAIL;
414     }
415     auto sensorId = codeUpdate->getFirmwareUpdateSensor();
416     sendStateSensorEvent(sensorId, PLDM_STATE_SENSOR_STATE, 0, uint8_t(state),
417                          uint8_t(CodeUpdateState::END));
418 }
419 
420 void pldm::responder::oem_ibm_platform::Handler::_processSystemReboot(
421     sdeventplus::source::EventBase& /*source */)
422 {
423     pldm::utils::PropertyValue value =
424         "xyz.openbmc_project.State.Chassis.Transition.Off";
425     pldm::utils::DBusMapping dbusMapping{"/xyz/openbmc_project/state/chassis0",
426                                          "xyz.openbmc_project.State.Chassis",
427                                          "RequestedPowerTransition", "string"};
428     try
429     {
430         dBusIntf->setDbusProperty(dbusMapping, value);
431     }
432     catch (const std::exception& e)
433     {
434 
435         std::cerr << "Chassis State transition to Off failed,"
436                   << "unable to set property RequestedPowerTransition"
437                   << "ERROR=" << e.what() << "\n";
438     }
439 
440     using namespace sdbusplus::bus::match::rules;
441     chassisOffMatch = std::make_unique<sdbusplus::bus::match::match>(
442         pldm::utils::DBusHandler::getBus(),
443         propertiesChanged("/xyz/openbmc_project/state/chassis0",
444                           "xyz.openbmc_project.State.Chassis"),
445         [this](sdbusplus::message::message& msg) {
446             DbusChangedProps props{};
447             std::string intf;
448             msg.read(intf, props);
449             const auto itr = props.find("CurrentPowerState");
450             if (itr != props.end())
451             {
452                 PropertyValue value = itr->second;
453                 auto propVal = std::get<std::string>(value);
454                 if (propVal ==
455                     "xyz.openbmc_project.State.Chassis.PowerState.Off")
456                 {
457                     pldm::utils::DBusMapping dbusMapping{
458                         "/xyz/openbmc_project/control/host0/"
459                         "power_restore_policy/one_time",
460                         "xyz.openbmc_project.Control.Power.RestorePolicy",
461                         "PowerRestorePolicy", "string"};
462                     value = "xyz.openbmc_project.Control.Power.RestorePolicy."
463                             "Policy.AlwaysOn";
464                     try
465                     {
466                         dBusIntf->setDbusProperty(dbusMapping, value);
467                     }
468                     catch (const std::exception& e)
469                     {
470                         std::cerr << "Setting one-time restore policy failed,"
471                                   << "unable to set property PowerRestorePolicy"
472                                   << "ERROR=" << e.what() << "\n";
473                     }
474                     dbusMapping = pldm::utils::DBusMapping{
475                         "/xyz/openbmc_project/state/bmc0",
476                         "xyz.openbmc_project.State.BMC",
477                         "RequestedBMCTransition", "string"};
478                     value = "xyz.openbmc_project.State.BMC.Transition.Reboot";
479                     try
480                     {
481                         dBusIntf->setDbusProperty(dbusMapping, value);
482                     }
483                     catch (const std::exception& e)
484                     {
485                         std::cerr << "BMC state transition to reboot failed,"
486                                   << "unable to set property "
487                                      "RequestedBMCTransition"
488                                   << "ERROR=" << e.what() << "\n";
489                     }
490                 }
491             }
492         });
493 }
494 } // namespace oem_ibm_platform
495 } // namespace responder
496 } // namespace pldm
497