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 
10 using namespace pldm::pdr;
11 using namespace pldm::utils;
12 
13 namespace pldm
14 {
15 namespace responder
16 {
17 namespace oem_ibm_platform
18 {
19 
20 int pldm::responder::oem_ibm_platform::Handler::
21     getOemStateSensorReadingsHandler(
22         EntityType entityType, EntityInstance entityInstance,
23         StateSetId stateSetId, CompositeCount compSensorCnt,
24         std::vector<get_sensor_state_field>& stateField)
25 {
26     int rc = PLDM_SUCCESS;
27     stateField.clear();
28 
29     for (size_t i = 0; i < compSensorCnt; i++)
30     {
31         uint8_t sensorOpState{};
32         if (entityType == PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE &&
33             stateSetId == PLDM_OEM_IBM_BOOT_STATE)
34         {
35             sensorOpState = fetchBootSide(entityInstance, codeUpdate);
36         }
37         else
38         {
39             rc = PLDM_PLATFORM_INVALID_STATE_VALUE;
40             break;
41         }
42         stateField.push_back({PLDM_SENSOR_ENABLED, PLDM_SENSOR_UNKNOWN,
43                               PLDM_SENSOR_UNKNOWN, sensorOpState});
44     }
45     return rc;
46 }
47 
48 int pldm::responder::oem_ibm_platform::Handler::
49     oemSetStateEffecterStatesHandler(
50         uint16_t entityType, uint16_t entityInstance, uint16_t stateSetId,
51         uint8_t compEffecterCnt,
52         std::vector<set_effecter_state_field>& stateField,
53         uint16_t /*effecterId*/)
54 {
55     int rc = PLDM_SUCCESS;
56 
57     for (uint8_t currState = 0; currState < compEffecterCnt; ++currState)
58     {
59         if (stateField[currState].set_request == PLDM_REQUEST_SET)
60         {
61             if (entityType == PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE &&
62                 stateSetId == PLDM_OEM_IBM_BOOT_STATE)
63             {
64                 rc = setBootSide(entityInstance, currState, stateField,
65                                  codeUpdate);
66             }
67             else if (entityType == PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE &&
68                      stateSetId == PLDM_OEM_IBM_FIRMWARE_UPDATE_STATE)
69             {
70                 if (stateField[currState].effecter_state ==
71                     uint8_t(CodeUpdateState::START))
72                 {
73                     codeUpdate->setCodeUpdateProgress(true);
74                     startUpdateEvent =
75                         std::make_unique<sdeventplus::source::Defer>(
76                             event,
77                             std::bind(std::mem_fn(&oem_ibm_platform::Handler::
78                                                       _processStartUpdate),
79                                       this, std::placeholders::_1));
80                 }
81                 else if (stateField[currState].effecter_state ==
82                          uint8_t(CodeUpdateState::END))
83                 {
84                     rc = PLDM_SUCCESS;
85                     assembleImageEvent = std::make_unique<
86                         sdeventplus::source::Defer>(
87                         event,
88                         std::bind(
89                             std::mem_fn(
90                                 &oem_ibm_platform::Handler::_processEndUpdate),
91                             this, std::placeholders::_1));
92 
93                     // sendCodeUpdateEvent(effecterId, END, START);
94                 }
95                 else if (stateField[currState].effecter_state ==
96                          uint8_t(CodeUpdateState::ABORT))
97                 {
98                     codeUpdate->setCodeUpdateProgress(false);
99                     codeUpdate->clearDirPath(LID_STAGING_DIR);
100                     auto sensorId = codeUpdate->getFirmwareUpdateSensor();
101                     sendStateSensorEvent(sensorId, PLDM_STATE_SENSOR_STATE, 0,
102                                          uint8_t(CodeUpdateState::ABORT),
103                                          uint8_t(CodeUpdateState::START));
104                     // sendCodeUpdateEvent(effecterId, ABORT, END);
105                 }
106                 else if (stateField[currState].effecter_state ==
107                          uint8_t(CodeUpdateState::ACCEPT))
108                 {
109                     auto sensorId = codeUpdate->getFirmwareUpdateSensor();
110                     sendStateSensorEvent(sensorId, PLDM_STATE_SENSOR_STATE, 0,
111                                          uint8_t(CodeUpdateState::ACCEPT),
112                                          uint8_t(CodeUpdateState::END));
113                     // TODO Set new Dbus property provided by code update app
114                     // sendCodeUpdateEvent(effecterId, ACCEPT, END);
115                 }
116                 else if (stateField[currState].effecter_state ==
117                          uint8_t(CodeUpdateState::REJECT))
118                 {
119                     auto sensorId = codeUpdate->getFirmwareUpdateSensor();
120                     sendStateSensorEvent(sensorId, PLDM_STATE_SENSOR_STATE, 0,
121                                          uint8_t(CodeUpdateState::REJECT),
122                                          uint8_t(CodeUpdateState::END));
123                     // TODO Set new Dbus property provided by code update app
124                     // sendCodeUpdateEvent(effecterId, REJECT, END);
125                 }
126             }
127             else if (entityType == PLDM_ENTITY_SYSTEM_CHASSIS &&
128                      stateSetId == PLDM_OEM_IBM_SYSTEM_POWER_STATE)
129             {
130                 if (stateField[currState].effecter_state == POWER_CYCLE_HARD)
131                 {
132                     systemRebootEvent =
133                         std::make_unique<sdeventplus::source::Defer>(
134                             event,
135                             std::bind(std::mem_fn(&oem_ibm_platform::Handler::
136                                                       _processSystemReboot),
137                                       this, std::placeholders::_1));
138                 }
139             }
140             else
141             {
142                 rc = PLDM_PLATFORM_SET_EFFECTER_UNSUPPORTED_SENSORSTATE;
143             }
144         }
145         if (rc != PLDM_SUCCESS)
146         {
147             break;
148         }
149     }
150     return rc;
151 }
152 
153 void buildAllCodeUpdateEffecterPDR(oem_ibm_platform::Handler* platformHandler,
154                                    uint16_t entityType, uint16_t entityInstance,
155                                    uint16_t stateSetID, pdr_utils::Repo& repo)
156 {
157     size_t pdrSize = 0;
158     pdrSize = sizeof(pldm_state_effecter_pdr) +
159               sizeof(state_effecter_possible_states);
160     std::vector<uint8_t> entry{};
161     entry.resize(pdrSize);
162     pldm_state_effecter_pdr* pdr =
163         reinterpret_cast<pldm_state_effecter_pdr*>(entry.data());
164     if (!pdr)
165     {
166         std::cerr << "Failed to get record by PDR type, ERROR:"
167                   << PLDM_PLATFORM_INVALID_EFFECTER_ID << std::endl;
168         return;
169     }
170     pdr->hdr.record_handle = 0;
171     pdr->hdr.version = 1;
172     pdr->hdr.type = PLDM_STATE_EFFECTER_PDR;
173     pdr->hdr.record_change_num = 0;
174     pdr->hdr.length = sizeof(pldm_state_effecter_pdr) - sizeof(pldm_pdr_hdr);
175     pdr->terminus_handle = pdr::BmcPldmTerminusHandle;
176     pdr->effecter_id = platformHandler->getNextEffecterId();
177     pdr->entity_type = entityType;
178     pdr->entity_instance = entityInstance;
179     pdr->container_id = 0;
180     pdr->effecter_semantic_id = 0;
181     pdr->effecter_init = PLDM_NO_INIT;
182     pdr->has_description_pdr = false;
183     pdr->composite_effecter_count = 1;
184 
185     auto* possibleStatesPtr = pdr->possible_states;
186     auto possibleStates =
187         reinterpret_cast<state_effecter_possible_states*>(possibleStatesPtr);
188     possibleStates->state_set_id = stateSetID;
189     possibleStates->possible_states_size = 2;
190     auto state =
191         reinterpret_cast<state_effecter_possible_states*>(possibleStates);
192     if (stateSetID == PLDM_OEM_IBM_BOOT_STATE)
193         state->states[0].byte = 6;
194     else if (stateSetID == PLDM_OEM_IBM_FIRMWARE_UPDATE_STATE)
195         state->states[0].byte = 126;
196     else if (stateSetID == PLDM_OEM_IBM_SYSTEM_POWER_STATE)
197         state->states[0].byte = 2;
198     pldm::responder::pdr_utils::PdrEntry pdrEntry{};
199     pdrEntry.data = entry.data();
200     pdrEntry.size = pdrSize;
201     repo.addRecord(pdrEntry);
202 }
203 
204 void buildAllCodeUpdateSensorPDR(oem_ibm_platform::Handler* platformHandler,
205                                  uint16_t entityType, uint16_t entityInstance,
206                                  uint16_t stateSetID, pdr_utils::Repo& repo)
207 {
208     size_t pdrSize = 0;
209     pdrSize =
210         sizeof(pldm_state_sensor_pdr) + sizeof(state_sensor_possible_states);
211     std::vector<uint8_t> entry{};
212     entry.resize(pdrSize);
213     pldm_state_sensor_pdr* pdr =
214         reinterpret_cast<pldm_state_sensor_pdr*>(entry.data());
215     if (!pdr)
216     {
217         std::cerr << "Failed to get record by PDR type, ERROR:"
218                   << PLDM_PLATFORM_INVALID_SENSOR_ID << std::endl;
219         return;
220     }
221     pdr->hdr.record_handle = 0;
222     pdr->hdr.version = 1;
223     pdr->hdr.type = PLDM_STATE_SENSOR_PDR;
224     pdr->hdr.record_change_num = 0;
225     pdr->hdr.length = sizeof(pldm_state_sensor_pdr) - sizeof(pldm_pdr_hdr);
226     pdr->terminus_handle = pdr::BmcPldmTerminusHandle;
227     pdr->sensor_id = platformHandler->getNextSensorId();
228     pdr->entity_type = entityType;
229     pdr->entity_instance = entityInstance;
230     pdr->container_id = 0;
231     pdr->sensor_init = PLDM_NO_INIT;
232     pdr->sensor_auxiliary_names_pdr = false;
233     pdr->composite_sensor_count = 1;
234 
235     auto* possibleStatesPtr = pdr->possible_states;
236     auto possibleStates =
237         reinterpret_cast<state_sensor_possible_states*>(possibleStatesPtr);
238     possibleStates->state_set_id = stateSetID;
239     possibleStates->possible_states_size = 2;
240     auto state =
241         reinterpret_cast<state_sensor_possible_states*>(possibleStates);
242     if ((stateSetID == PLDM_OEM_IBM_BOOT_STATE) ||
243         (stateSetID == oem_ibm_platform::PLDM_OEM_IBM_VERIFICATION_STATE))
244         state->states[0].byte = 6;
245     else if (stateSetID == PLDM_OEM_IBM_FIRMWARE_UPDATE_STATE)
246         state->states[0].byte = 126;
247     pldm::responder::pdr_utils::PdrEntry pdrEntry{};
248     pdrEntry.data = entry.data();
249     pdrEntry.size = pdrSize;
250     repo.addRecord(pdrEntry);
251 }
252 
253 void pldm::responder::oem_ibm_platform::Handler::buildOEMPDR(
254     pdr_utils::Repo& repo)
255 {
256     buildAllCodeUpdateEffecterPDR(this, PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE,
257                                   ENTITY_INSTANCE_0, PLDM_OEM_IBM_BOOT_STATE,
258                                   repo);
259     buildAllCodeUpdateEffecterPDR(this, PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE,
260                                   ENTITY_INSTANCE_1, PLDM_OEM_IBM_BOOT_STATE,
261                                   repo);
262     buildAllCodeUpdateEffecterPDR(this, PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE,
263                                   ENTITY_INSTANCE_0,
264                                   PLDM_OEM_IBM_FIRMWARE_UPDATE_STATE, repo);
265     buildAllCodeUpdateEffecterPDR(this, PLDM_ENTITY_SYSTEM_CHASSIS,
266                                   ENTITY_INSTANCE_0,
267                                   PLDM_OEM_IBM_SYSTEM_POWER_STATE, repo);
268 
269     buildAllCodeUpdateSensorPDR(this, PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE,
270                                 ENTITY_INSTANCE_0, PLDM_OEM_IBM_BOOT_STATE,
271                                 repo);
272     buildAllCodeUpdateSensorPDR(this, PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE,
273                                 ENTITY_INSTANCE_1, PLDM_OEM_IBM_BOOT_STATE,
274                                 repo);
275     buildAllCodeUpdateSensorPDR(this, PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE,
276                                 ENTITY_INSTANCE_0,
277                                 PLDM_OEM_IBM_FIRMWARE_UPDATE_STATE, repo);
278     buildAllCodeUpdateSensorPDR(this, PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE,
279                                 ENTITY_INSTANCE_0,
280                                 PLDM_OEM_IBM_VERIFICATION_STATE, repo);
281     auto sensorId = findStateSensorId(
282         repo.getPdr(), 0, PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE,
283         ENTITY_INSTANCE_0, 0, PLDM_OEM_IBM_VERIFICATION_STATE);
284     codeUpdate->setMarkerLidSensor(sensorId);
285     sensorId = findStateSensorId(
286         repo.getPdr(), 0, PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE,
287         ENTITY_INSTANCE_0, 0, PLDM_OEM_IBM_FIRMWARE_UPDATE_STATE);
288     codeUpdate->setFirmwareUpdateSensor(sensorId);
289 }
290 
291 void pldm::responder::oem_ibm_platform::Handler::setPlatformHandler(
292     pldm::responder::platform::Handler* handler)
293 {
294     platformHandler = handler;
295 }
296 
297 int pldm::responder::oem_ibm_platform::Handler::sendEventToHost(
298     std::vector<uint8_t>& requestMsg, uint8_t instanceId)
299 {
300     if (requestMsg.size())
301     {
302         std::ostringstream tempStream;
303         for (int byte : requestMsg)
304         {
305             tempStream << std::setfill('0') << std::setw(2) << std::hex << byte
306                        << " ";
307         }
308         std::cout << tempStream.str() << std::endl;
309     }
310     auto oemPlatformEventMessageResponseHandler =
311         [](mctp_eid_t /*eid*/, const pldm_msg* response, size_t respMsgLen) {
312             uint8_t completionCode{};
313             uint8_t status{};
314             auto rc = decode_platform_event_message_resp(
315                 response, respMsgLen, &completionCode, &status);
316             if (rc || completionCode)
317             {
318                 std::cerr << "Failed to decode_platform_event_message_resp: "
319                           << " for code update event rc=" << rc
320                           << ", cc=" << static_cast<unsigned>(completionCode)
321                           << std::endl;
322             }
323         };
324     auto rc = handler->registerRequest(
325         mctp_eid, instanceId, PLDM_PLATFORM, PLDM_PLATFORM_EVENT_MESSAGE,
326         std::move(requestMsg),
327         std::move(oemPlatformEventMessageResponseHandler));
328     if (rc)
329     {
330         std::cerr << "Failed to send BIOS attribute change event message \n";
331     }
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         requester.markFree(mctp_eid, instanceId);
378         return;
379     }
380     rc = sendEventToHost(requestMsg, instanceId);
381     if (rc != PLDM_SUCCESS)
382     {
383         std::cerr << "Failed to send event to host: "
384                   << "rc=" << rc << std::endl;
385     }
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