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(oem_ibm_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         return;
165     }
166     pdr->hdr.record_handle = 0;
167     pdr->hdr.version = 1;
168     pdr->hdr.type = PLDM_STATE_EFFECTER_PDR;
169     pdr->hdr.record_change_num = 0;
170     pdr->hdr.length = sizeof(pldm_state_effecter_pdr) - sizeof(pldm_pdr_hdr);
171     pdr->terminus_handle = pdr::BmcPldmTerminusHandle;
172     pdr->effecter_id = platformHandler->getNextEffecterId();
173     pdr->entity_type = entityType;
174     pdr->entity_instance = entityInstance;
175     pdr->container_id = 0;
176     pdr->effecter_semantic_id = 0;
177     pdr->effecter_init = PLDM_NO_INIT;
178     pdr->has_description_pdr = false;
179     pdr->composite_effecter_count = 1;
180 
181     auto* possibleStatesPtr = pdr->possible_states;
182     auto possibleStates =
183         reinterpret_cast<state_effecter_possible_states*>(possibleStatesPtr);
184     possibleStates->state_set_id = stateSetID;
185     possibleStates->possible_states_size = 2;
186     auto state =
187         reinterpret_cast<state_effecter_possible_states*>(possibleStates);
188     if (stateSetID == PLDM_OEM_IBM_BOOT_STATE)
189         state->states[0].byte = 6;
190     else if (stateSetID == PLDM_OEM_IBM_FIRMWARE_UPDATE_STATE)
191         state->states[0].byte = 126;
192     else if (stateSetID == PLDM_OEM_IBM_SYSTEM_POWER_STATE)
193         state->states[0].byte = 2;
194     pldm::responder::pdr_utils::PdrEntry pdrEntry{};
195     pdrEntry.data = entry.data();
196     pdrEntry.size = pdrSize;
197     repo.addRecord(pdrEntry);
198 }
199 
200 void buildAllCodeUpdateSensorPDR(oem_ibm_platform::Handler* platformHandler,
201                                  uint16_t entityType, uint16_t entityInstance,
202                                  uint16_t stateSetID, pdr_utils::Repo& repo)
203 {
204     size_t pdrSize = 0;
205     pdrSize =
206         sizeof(pldm_state_sensor_pdr) + sizeof(state_sensor_possible_states);
207     std::vector<uint8_t> entry{};
208     entry.resize(pdrSize);
209     pldm_state_sensor_pdr* pdr =
210         reinterpret_cast<pldm_state_sensor_pdr*>(entry.data());
211     if (!pdr)
212     {
213         std::cerr << "Failed to get record by PDR type, ERROR:"
214                   << PLDM_PLATFORM_INVALID_SENSOR_ID << std::endl;
215         return;
216     }
217     pdr->hdr.record_handle = 0;
218     pdr->hdr.version = 1;
219     pdr->hdr.type = PLDM_STATE_SENSOR_PDR;
220     pdr->hdr.record_change_num = 0;
221     pdr->hdr.length = sizeof(pldm_state_sensor_pdr) - sizeof(pldm_pdr_hdr);
222     pdr->terminus_handle = pdr::BmcPldmTerminusHandle;
223     pdr->sensor_id = platformHandler->getNextSensorId();
224     pdr->entity_type = entityType;
225     pdr->entity_instance = entityInstance;
226     pdr->container_id = 0;
227     pdr->sensor_init = PLDM_NO_INIT;
228     pdr->sensor_auxiliary_names_pdr = false;
229     pdr->composite_sensor_count = 1;
230 
231     auto* possibleStatesPtr = pdr->possible_states;
232     auto possibleStates =
233         reinterpret_cast<state_sensor_possible_states*>(possibleStatesPtr);
234     possibleStates->state_set_id = stateSetID;
235     possibleStates->possible_states_size = 2;
236     auto state =
237         reinterpret_cast<state_sensor_possible_states*>(possibleStates);
238     if ((stateSetID == PLDM_OEM_IBM_BOOT_STATE) ||
239         (stateSetID == oem_ibm_platform::PLDM_OEM_IBM_VERIFICATION_STATE))
240         state->states[0].byte = 6;
241     else if (stateSetID == PLDM_OEM_IBM_FIRMWARE_UPDATE_STATE)
242         state->states[0].byte = 126;
243     pldm::responder::pdr_utils::PdrEntry pdrEntry{};
244     pdrEntry.data = entry.data();
245     pdrEntry.size = pdrSize;
246     repo.addRecord(pdrEntry);
247 }
248 
249 void pldm::responder::oem_ibm_platform::Handler::buildOEMPDR(
250     pdr_utils::Repo& repo)
251 {
252     buildAllCodeUpdateEffecterPDR(this, PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE,
253                                   ENTITY_INSTANCE_0, PLDM_OEM_IBM_BOOT_STATE,
254                                   repo);
255     buildAllCodeUpdateEffecterPDR(this, PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE,
256                                   ENTITY_INSTANCE_1, PLDM_OEM_IBM_BOOT_STATE,
257                                   repo);
258     buildAllCodeUpdateEffecterPDR(this, PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE,
259                                   ENTITY_INSTANCE_0,
260                                   PLDM_OEM_IBM_FIRMWARE_UPDATE_STATE, repo);
261     buildAllCodeUpdateEffecterPDR(this, PLDM_ENTITY_SYSTEM_CHASSIS,
262                                   ENTITY_INSTANCE_0,
263                                   PLDM_OEM_IBM_SYSTEM_POWER_STATE, repo);
264 
265     buildAllCodeUpdateSensorPDR(this, PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE,
266                                 ENTITY_INSTANCE_0, PLDM_OEM_IBM_BOOT_STATE,
267                                 repo);
268     buildAllCodeUpdateSensorPDR(this, PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE,
269                                 ENTITY_INSTANCE_1, PLDM_OEM_IBM_BOOT_STATE,
270                                 repo);
271     buildAllCodeUpdateSensorPDR(this, PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE,
272                                 ENTITY_INSTANCE_0,
273                                 PLDM_OEM_IBM_FIRMWARE_UPDATE_STATE, repo);
274     buildAllCodeUpdateSensorPDR(this, PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE,
275                                 ENTITY_INSTANCE_0,
276                                 PLDM_OEM_IBM_VERIFICATION_STATE, repo);
277     auto sensorId = findStateSensorId(
278         repo.getPdr(), 0, PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE,
279         ENTITY_INSTANCE_0, 0, PLDM_OEM_IBM_VERIFICATION_STATE);
280     codeUpdate->setMarkerLidSensor(sensorId);
281     sensorId = findStateSensorId(
282         repo.getPdr(), 0, PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE,
283         ENTITY_INSTANCE_0, 0, PLDM_OEM_IBM_FIRMWARE_UPDATE_STATE);
284     codeUpdate->setFirmwareUpdateSensor(sensorId);
285 }
286 
287 void pldm::responder::oem_ibm_platform::Handler::setPlatformHandler(
288     pldm::responder::platform::Handler* handler)
289 {
290     platformHandler = handler;
291 }
292 
293 int pldm::responder::oem_ibm_platform::Handler::sendEventToHost(
294     std::vector<uint8_t>& requestMsg)
295 {
296     uint8_t* responseMsg = nullptr;
297     size_t responseMsgSize{};
298     if (requestMsg.size())
299     {
300         std::ostringstream tempStream;
301         for (int byte : requestMsg)
302         {
303             tempStream << std::setfill('0') << std::setw(2) << std::hex << byte
304                        << " ";
305         }
306         std::cout << tempStream.str() << std::endl;
307     }
308 
309     auto requesterRc =
310         pldm_send_recv(mctp_eid, mctp_fd, requestMsg.data(), requestMsg.size(),
311                        &responseMsg, &responseMsgSize);
312     std::unique_ptr<uint8_t, decltype(std::free)*> responseMsgPtr{responseMsg,
313                                                                   std::free};
314     if (requesterRc != PLDM_REQUESTER_SUCCESS)
315     {
316         std::cerr << "Failed to send message/receive response. RC = "
317                   << requesterRc << ", errno = " << errno
318                   << "for sending event to host \n";
319         return requesterRc;
320     }
321     uint8_t completionCode{};
322     uint8_t status{};
323     auto responsePtr = reinterpret_cast<struct pldm_msg*>(responseMsgPtr.get());
324     auto rc = decode_platform_event_message_resp(
325         responsePtr, responseMsgSize - sizeof(pldm_msg_hdr), &completionCode,
326         &status);
327 
328     if (rc != PLDM_SUCCESS || completionCode != PLDM_SUCCESS)
329     {
330         std::cerr << "Failure in decode platform event message response, rc= "
331                   << rc << " cc=" << static_cast<unsigned>(completionCode)
332                   << "\n";
333         return rc;
334     }
335     return rc;
336 }
337 
338 int encodeEventMsg(uint8_t eventType, const std::vector<uint8_t>& eventDataVec,
339                    std::vector<uint8_t>& requestMsg, uint8_t instanceId)
340 {
341     auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
342 
343     auto rc = encode_platform_event_message_req(
344         instanceId, 1 /*formatVersion*/, 0 /*tId*/, eventType,
345         eventDataVec.data(), eventDataVec.size(), request,
346         eventDataVec.size() + PLDM_PLATFORM_EVENT_MESSAGE_MIN_REQ_BYTES);
347 
348     return rc;
349 }
350 
351 void pldm::responder::oem_ibm_platform::Handler::sendStateSensorEvent(
352     uint16_t sensorId, enum sensor_event_class_states sensorEventClass,
353     uint8_t sensorOffset, uint8_t eventState, uint8_t prevEventState)
354 {
355     std::vector<uint8_t> sensorEventDataVec{};
356     size_t sensorEventSize = PLDM_SENSOR_EVENT_DATA_MIN_LENGTH + 1;
357     sensorEventDataVec.resize(sensorEventSize);
358     auto eventData = reinterpret_cast<struct pldm_sensor_event_data*>(
359         sensorEventDataVec.data());
360     eventData->sensor_id = sensorId;
361     eventData->sensor_event_class_type = sensorEventClass;
362     auto eventClassStart = eventData->event_class;
363     auto eventClass =
364         reinterpret_cast<struct pldm_sensor_event_state_sensor_state*>(
365             eventClassStart);
366     eventClass->sensor_offset = sensorOffset;
367     eventClass->event_state = eventState;
368     eventClass->previous_event_state = prevEventState;
369     auto instanceId = requester.getInstanceId(mctp_eid);
370     std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) +
371                                     PLDM_PLATFORM_EVENT_MESSAGE_MIN_REQ_BYTES +
372                                     sensorEventDataVec.size());
373     auto rc = encodeEventMsg(PLDM_SENSOR_EVENT, sensorEventDataVec, requestMsg,
374                              instanceId);
375     if (rc != PLDM_SUCCESS)
376     {
377         std::cerr << "Failed to encode state sensor event, rc = " << rc
378                   << std::endl;
379         return;
380     }
381     rc = sendEventToHost(requestMsg);
382     if (rc != PLDM_SUCCESS)
383     {
384         std::cerr << "Failed to send event to host: "
385                   << "rc=" << rc << std::endl;
386     }
387     requester.markFree(mctp_eid, instanceId);
388     return;
389 }
390 
391 void pldm::responder::oem_ibm_platform::Handler::_processEndUpdate(
392     sdeventplus::source::EventBase& /*source */)
393 {
394     assembleImageEvent.reset();
395     int retc = assembleCodeUpdateImage();
396     if (retc != PLDM_SUCCESS)
397     {
398         codeUpdate->setCodeUpdateProgress(false);
399         auto sensorId = codeUpdate->getFirmwareUpdateSensor();
400         sendStateSensorEvent(sensorId, PLDM_STATE_SENSOR_STATE, 0,
401                              uint8_t(CodeUpdateState::FAIL),
402                              uint8_t(CodeUpdateState::START));
403     }
404 }
405 
406 void pldm::responder::oem_ibm_platform::Handler::_processStartUpdate(
407     sdeventplus::source::EventBase& /*source */)
408 {
409     codeUpdate->deleteImage();
410     CodeUpdateState state = CodeUpdateState::START;
411     auto rc = codeUpdate->setRequestedApplyTime();
412     if (rc != PLDM_SUCCESS)
413     {
414         std::cerr << "setRequestedApplyTime failed \n";
415         state = CodeUpdateState::FAIL;
416     }
417     auto sensorId = codeUpdate->getFirmwareUpdateSensor();
418     sendStateSensorEvent(sensorId, PLDM_STATE_SENSOR_STATE, 0, uint8_t(state),
419                          uint8_t(CodeUpdateState::END));
420 }
421 
422 void pldm::responder::oem_ibm_platform::Handler::_processSystemReboot(
423     sdeventplus::source::EventBase& /*source */)
424 {
425     pldm::utils::PropertyValue value =
426         "xyz.openbmc_project.State.Chassis.Transition.Off";
427     pldm::utils::DBusMapping dbusMapping{"/xyz/openbmc_project/state/chassis0",
428                                          "xyz.openbmc_project.State.Chassis",
429                                          "RequestedPowerTransition", "string"};
430     try
431     {
432         dBusIntf->setDbusProperty(dbusMapping, value);
433     }
434     catch (const std::exception& e)
435     {
436 
437         std::cerr << "Chassis State transition to Off failed,"
438                   << "unable to set property RequestedPowerTransition"
439                   << "ERROR=" << e.what() << "\n";
440     }
441 
442     using namespace sdbusplus::bus::match::rules;
443     chassisOffMatch = std::make_unique<sdbusplus::bus::match::match>(
444         pldm::utils::DBusHandler::getBus(),
445         propertiesChanged("/xyz/openbmc_project/state/chassis0",
446                           "xyz.openbmc_project.State.Chassis"),
447         [this](sdbusplus::message::message& msg) {
448             DbusChangedProps props{};
449             std::string intf;
450             msg.read(intf, props);
451             const auto itr = props.find("CurrentPowerState");
452             if (itr != props.end())
453             {
454                 PropertyValue value = itr->second;
455                 auto propVal = std::get<std::string>(value);
456                 if (propVal ==
457                     "xyz.openbmc_project.State.Chassis.PowerState.Off")
458                 {
459                     pldm::utils::DBusMapping dbusMapping{
460                         "/xyz/openbmc_project/control/host0/"
461                         "power_restore_policy/one_time",
462                         "xyz.openbmc_project.Control.Power.RestorePolicy",
463                         "PowerRestorePolicy", "string"};
464                     value = "xyz.openbmc_project.Control.Power.RestorePolicy."
465                             "Policy.AlwaysOn";
466                     try
467                     {
468                         dBusIntf->setDbusProperty(dbusMapping, value);
469                     }
470                     catch (const std::exception& e)
471                     {
472                         std::cerr << "Setting one-time restore policy failed,"
473                                   << "unable to set property PowerRestorePolicy"
474                                   << "ERROR=" << e.what() << "\n";
475                     }
476                     dbusMapping = pldm::utils::DBusMapping{
477                         "/xyz/openbmc_project/state/bmc0",
478                         "xyz.openbmc_project.State.BMC",
479                         "RequestedBMCTransition", "string"};
480                     value = "xyz.openbmc_project.State.BMC.Transition.Reboot";
481                     try
482                     {
483                         dBusIntf->setDbusProperty(dbusMapping, value);
484                     }
485                     catch (const std::exception& e)
486                     {
487                         std::cerr << "BMC state transition to reboot failed,"
488                                   << "unable to set property "
489                                      "RequestedBMCTransition"
490                                   << "ERROR=" << e.what() << "\n";
491                     }
492                 }
493             }
494         });
495 }
496 } // namespace oem_ibm_platform
497 } // namespace responder
498 } // namespace pldm
499