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, uint8_t instanceId)
295 {
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     auto oemPlatformEventMessageResponseHandler =
307         [](mctp_eid_t /*eid*/, const pldm_msg* response, size_t respMsgLen) {
308             uint8_t completionCode{};
309             uint8_t status{};
310             auto rc = decode_platform_event_message_resp(
311                 response, respMsgLen, &completionCode, &status);
312             if (rc || completionCode)
313             {
314                 std::cerr << "Failed to decode_platform_event_message_resp: "
315                           << " for code update event rc=" << rc
316                           << ", cc=" << static_cast<unsigned>(completionCode)
317                           << std::endl;
318             }
319         };
320     auto rc = handler->registerRequest(
321         mctp_eid, instanceId, PLDM_PLATFORM, PLDM_PLATFORM_EVENT_MESSAGE,
322         std::move(requestMsg),
323         std::move(oemPlatformEventMessageResponseHandler));
324     if (rc)
325     {
326         std::cerr << "Failed to send BIOS attribute change event message \n";
327     }
328 
329     return rc;
330 }
331 
332 int encodeEventMsg(uint8_t eventType, const std::vector<uint8_t>& eventDataVec,
333                    std::vector<uint8_t>& requestMsg, uint8_t instanceId)
334 {
335     auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
336 
337     auto rc = encode_platform_event_message_req(
338         instanceId, 1 /*formatVersion*/, 0 /*tId*/, eventType,
339         eventDataVec.data(), eventDataVec.size(), request,
340         eventDataVec.size() + PLDM_PLATFORM_EVENT_MESSAGE_MIN_REQ_BYTES);
341 
342     return rc;
343 }
344 
345 void pldm::responder::oem_ibm_platform::Handler::sendStateSensorEvent(
346     uint16_t sensorId, enum sensor_event_class_states sensorEventClass,
347     uint8_t sensorOffset, uint8_t eventState, uint8_t prevEventState)
348 {
349     std::vector<uint8_t> sensorEventDataVec{};
350     size_t sensorEventSize = PLDM_SENSOR_EVENT_DATA_MIN_LENGTH + 1;
351     sensorEventDataVec.resize(sensorEventSize);
352     auto eventData = reinterpret_cast<struct pldm_sensor_event_data*>(
353         sensorEventDataVec.data());
354     eventData->sensor_id = sensorId;
355     eventData->sensor_event_class_type = sensorEventClass;
356     auto eventClassStart = eventData->event_class;
357     auto eventClass =
358         reinterpret_cast<struct pldm_sensor_event_state_sensor_state*>(
359             eventClassStart);
360     eventClass->sensor_offset = sensorOffset;
361     eventClass->event_state = eventState;
362     eventClass->previous_event_state = prevEventState;
363     auto instanceId = requester.getInstanceId(mctp_eid);
364     std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) +
365                                     PLDM_PLATFORM_EVENT_MESSAGE_MIN_REQ_BYTES +
366                                     sensorEventDataVec.size());
367     auto rc = encodeEventMsg(PLDM_SENSOR_EVENT, sensorEventDataVec, requestMsg,
368                              instanceId);
369     if (rc != PLDM_SUCCESS)
370     {
371         std::cerr << "Failed to encode state sensor event, rc = " << rc
372                   << std::endl;
373         requester.markFree(mctp_eid, instanceId);
374         return;
375     }
376     rc = sendEventToHost(requestMsg, instanceId);
377     if (rc != PLDM_SUCCESS)
378     {
379         std::cerr << "Failed to send event to host: "
380                   << "rc=" << rc << std::endl;
381     }
382     return;
383 }
384 
385 void pldm::responder::oem_ibm_platform::Handler::_processEndUpdate(
386     sdeventplus::source::EventBase& /*source */)
387 {
388     assembleImageEvent.reset();
389     int retc = assembleCodeUpdateImage();
390     if (retc != PLDM_SUCCESS)
391     {
392         codeUpdate->setCodeUpdateProgress(false);
393         auto sensorId = codeUpdate->getFirmwareUpdateSensor();
394         sendStateSensorEvent(sensorId, PLDM_STATE_SENSOR_STATE, 0,
395                              uint8_t(CodeUpdateState::FAIL),
396                              uint8_t(CodeUpdateState::START));
397     }
398 }
399 
400 void pldm::responder::oem_ibm_platform::Handler::_processStartUpdate(
401     sdeventplus::source::EventBase& /*source */)
402 {
403     codeUpdate->deleteImage();
404     CodeUpdateState state = CodeUpdateState::START;
405     auto rc = codeUpdate->setRequestedApplyTime();
406     if (rc != PLDM_SUCCESS)
407     {
408         std::cerr << "setRequestedApplyTime failed \n";
409         state = CodeUpdateState::FAIL;
410     }
411     auto sensorId = codeUpdate->getFirmwareUpdateSensor();
412     sendStateSensorEvent(sensorId, PLDM_STATE_SENSOR_STATE, 0, uint8_t(state),
413                          uint8_t(CodeUpdateState::END));
414 }
415 
416 void pldm::responder::oem_ibm_platform::Handler::_processSystemReboot(
417     sdeventplus::source::EventBase& /*source */)
418 {
419     pldm::utils::PropertyValue value =
420         "xyz.openbmc_project.State.Chassis.Transition.Off";
421     pldm::utils::DBusMapping dbusMapping{"/xyz/openbmc_project/state/chassis0",
422                                          "xyz.openbmc_project.State.Chassis",
423                                          "RequestedPowerTransition", "string"};
424     try
425     {
426         dBusIntf->setDbusProperty(dbusMapping, value);
427     }
428     catch (const std::exception& e)
429     {
430 
431         std::cerr << "Chassis State transition to Off failed,"
432                   << "unable to set property RequestedPowerTransition"
433                   << "ERROR=" << e.what() << "\n";
434     }
435 
436     using namespace sdbusplus::bus::match::rules;
437     chassisOffMatch = std::make_unique<sdbusplus::bus::match::match>(
438         pldm::utils::DBusHandler::getBus(),
439         propertiesChanged("/xyz/openbmc_project/state/chassis0",
440                           "xyz.openbmc_project.State.Chassis"),
441         [this](sdbusplus::message::message& msg) {
442             DbusChangedProps props{};
443             std::string intf;
444             msg.read(intf, props);
445             const auto itr = props.find("CurrentPowerState");
446             if (itr != props.end())
447             {
448                 PropertyValue value = itr->second;
449                 auto propVal = std::get<std::string>(value);
450                 if (propVal ==
451                     "xyz.openbmc_project.State.Chassis.PowerState.Off")
452                 {
453                     pldm::utils::DBusMapping dbusMapping{
454                         "/xyz/openbmc_project/control/host0/"
455                         "power_restore_policy/one_time",
456                         "xyz.openbmc_project.Control.Power.RestorePolicy",
457                         "PowerRestorePolicy", "string"};
458                     value = "xyz.openbmc_project.Control.Power.RestorePolicy."
459                             "Policy.AlwaysOn";
460                     try
461                     {
462                         dBusIntf->setDbusProperty(dbusMapping, value);
463                     }
464                     catch (const std::exception& e)
465                     {
466                         std::cerr << "Setting one-time restore policy failed,"
467                                   << "unable to set property PowerRestorePolicy"
468                                   << "ERROR=" << e.what() << "\n";
469                     }
470                     dbusMapping = pldm::utils::DBusMapping{
471                         "/xyz/openbmc_project/state/bmc0",
472                         "xyz.openbmc_project.State.BMC",
473                         "RequestedBMCTransition", "string"};
474                     value = "xyz.openbmc_project.State.BMC.Transition.Reboot";
475                     try
476                     {
477                         dBusIntf->setDbusProperty(dbusMapping, value);
478                     }
479                     catch (const std::exception& e)
480                     {
481                         std::cerr << "BMC state transition to reboot failed,"
482                                   << "unable to set property "
483                                      "RequestedBMCTransition"
484                                   << "ERROR=" << e.what() << "\n";
485                     }
486                 }
487             }
488         });
489 }
490 } // namespace oem_ibm_platform
491 } // namespace responder
492 } // namespace pldm
493