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
124             {
125                 rc = PLDM_PLATFORM_SET_EFFECTER_UNSUPPORTED_SENSORSTATE;
126             }
127         }
128         if (rc != PLDM_SUCCESS)
129         {
130             break;
131         }
132     }
133     return rc;
134 }
135 
136 void buildAllCodeUpdateEffecterPDR(platform::Handler* platformHandler,
137                                    uint16_t entityInstance, uint16_t stateSetID,
138                                    pdr_utils::Repo& repo)
139 {
140     size_t pdrSize = 0;
141     pdrSize = sizeof(pldm_state_effecter_pdr) +
142               sizeof(state_effecter_possible_states);
143     std::vector<uint8_t> entry{};
144     entry.resize(pdrSize);
145     pldm_state_effecter_pdr* pdr =
146         reinterpret_cast<pldm_state_effecter_pdr*>(entry.data());
147     if (!pdr)
148     {
149         std::cerr << "Failed to get record by PDR type, ERROR:"
150                   << PLDM_PLATFORM_INVALID_EFFECTER_ID << std::endl;
151     }
152     pdr->hdr.record_handle = 0;
153     pdr->hdr.version = 1;
154     pdr->hdr.type = PLDM_STATE_EFFECTER_PDR;
155     pdr->hdr.record_change_num = 0;
156     pdr->hdr.length = sizeof(pldm_state_effecter_pdr) - sizeof(pldm_pdr_hdr);
157     pdr->terminus_handle = pdr::BmcPldmTerminusHandle;
158     pdr->effecter_id = platformHandler->getNextEffecterId();
159     pdr->entity_type = PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE;
160     pdr->entity_instance = entityInstance;
161     pdr->container_id = 0;
162     pdr->effecter_semantic_id = 0;
163     pdr->effecter_init = PLDM_NO_INIT;
164     pdr->has_description_pdr = false;
165     pdr->composite_effecter_count = 1;
166 
167     auto* possibleStatesPtr = pdr->possible_states;
168     auto possibleStates =
169         reinterpret_cast<state_effecter_possible_states*>(possibleStatesPtr);
170     possibleStates->state_set_id = stateSetID;
171     possibleStates->possible_states_size = 2;
172     auto state =
173         reinterpret_cast<state_effecter_possible_states*>(possibleStates);
174     if (stateSetID == PLDM_OEM_IBM_BOOT_STATE)
175         state->states[0].byte = 6;
176     else if (stateSetID == PLDM_OEM_IBM_FIRMWARE_UPDATE_STATE)
177         state->states[0].byte = 126;
178     pldm::responder::pdr_utils::PdrEntry pdrEntry{};
179     pdrEntry.data = entry.data();
180     pdrEntry.size = pdrSize;
181     repo.addRecord(pdrEntry);
182 }
183 
184 void buildAllCodeUpdateSensorPDR(platform::Handler* platformHandler,
185                                  uint16_t entityType, uint16_t entityInstance,
186                                  uint16_t stateSetID, pdr_utils::Repo& repo)
187 {
188     size_t pdrSize = 0;
189     pdrSize =
190         sizeof(pldm_state_sensor_pdr) + sizeof(state_sensor_possible_states);
191     std::vector<uint8_t> entry{};
192     entry.resize(pdrSize);
193     pldm_state_sensor_pdr* pdr =
194         reinterpret_cast<pldm_state_sensor_pdr*>(entry.data());
195     if (!pdr)
196     {
197         std::cerr << "Failed to get record by PDR type, ERROR:"
198                   << PLDM_PLATFORM_INVALID_SENSOR_ID << std::endl;
199     }
200     pdr->hdr.record_handle = 0;
201     pdr->hdr.version = 1;
202     pdr->hdr.type = PLDM_STATE_SENSOR_PDR;
203     pdr->hdr.record_change_num = 0;
204     pdr->hdr.length = sizeof(pldm_state_sensor_pdr) - sizeof(pldm_pdr_hdr);
205     pdr->terminus_handle = pdr::BmcPldmTerminusHandle;
206     pdr->sensor_id = platformHandler->getNextSensorId();
207     pdr->entity_type = entityType;
208     pdr->entity_instance = entityInstance;
209     pdr->container_id = 0;
210     pdr->sensor_init = PLDM_NO_INIT;
211     pdr->sensor_auxiliary_names_pdr = false;
212     pdr->composite_sensor_count = 1;
213 
214     auto* possibleStatesPtr = pdr->possible_states;
215     auto possibleStates =
216         reinterpret_cast<state_sensor_possible_states*>(possibleStatesPtr);
217     possibleStates->state_set_id = stateSetID;
218     possibleStates->possible_states_size = 2;
219     auto state =
220         reinterpret_cast<state_sensor_possible_states*>(possibleStates);
221     if ((stateSetID == PLDM_OEM_IBM_BOOT_STATE) ||
222         (stateSetID == oem_ibm_platform::PLDM_OEM_IBM_VERIFICATION_STATE))
223         state->states[0].byte = 6;
224     else if (stateSetID == PLDM_OEM_IBM_FIRMWARE_UPDATE_STATE)
225         state->states[0].byte = 126;
226     pldm::responder::pdr_utils::PdrEntry pdrEntry{};
227     pdrEntry.data = entry.data();
228     pdrEntry.size = pdrSize;
229     repo.addRecord(pdrEntry);
230 }
231 
232 void pldm::responder::oem_ibm_platform::Handler::buildOEMPDR(
233     pdr_utils::Repo& repo)
234 {
235     buildAllCodeUpdateEffecterPDR(platformHandler, ENTITY_INSTANCE_0,
236                                   PLDM_OEM_IBM_BOOT_STATE, repo);
237     buildAllCodeUpdateEffecterPDR(platformHandler, ENTITY_INSTANCE_1,
238                                   PLDM_OEM_IBM_BOOT_STATE, repo);
239     buildAllCodeUpdateEffecterPDR(platformHandler, ENTITY_INSTANCE_0,
240                                   PLDM_OEM_IBM_FIRMWARE_UPDATE_STATE, repo);
241 
242     buildAllCodeUpdateSensorPDR(
243         platformHandler, PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE, ENTITY_INSTANCE_0,
244         PLDM_OEM_IBM_BOOT_STATE, repo);
245     buildAllCodeUpdateSensorPDR(
246         platformHandler, PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE, ENTITY_INSTANCE_1,
247         PLDM_OEM_IBM_BOOT_STATE, repo);
248     buildAllCodeUpdateSensorPDR(
249         platformHandler, PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE, ENTITY_INSTANCE_0,
250         PLDM_OEM_IBM_FIRMWARE_UPDATE_STATE, repo);
251     buildAllCodeUpdateSensorPDR(
252         platformHandler, PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE, ENTITY_INSTANCE_0,
253         PLDM_OEM_IBM_VERIFICATION_STATE, repo);
254     auto sensorId = findStateSensorId(
255         repo.getPdr(), 0, PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE,
256         ENTITY_INSTANCE_0, 0, PLDM_OEM_IBM_VERIFICATION_STATE);
257     codeUpdate->setMarkerLidSensor(sensorId);
258     sensorId = findStateSensorId(
259         repo.getPdr(), 0, PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE,
260         ENTITY_INSTANCE_0, 0, PLDM_OEM_IBM_FIRMWARE_UPDATE_STATE);
261     codeUpdate->setFirmwareUpdateSensor(sensorId);
262 }
263 
264 void pldm::responder::oem_ibm_platform::Handler::setPlatformHandler(
265     pldm::responder::platform::Handler* handler)
266 {
267     platformHandler = handler;
268 }
269 
270 int pldm::responder::oem_ibm_platform::Handler::sendEventToHost(
271     std::vector<uint8_t>& requestMsg)
272 {
273     uint8_t* responseMsg = nullptr;
274     size_t responseMsgSize{};
275     if (requestMsg.size())
276     {
277         std::ostringstream tempStream;
278         for (int byte : requestMsg)
279         {
280             tempStream << std::setfill('0') << std::setw(2) << std::hex << byte
281                        << " ";
282         }
283         std::cout << tempStream.str() << std::endl;
284     }
285 
286     auto requesterRc =
287         pldm_send_recv(mctp_eid, mctp_fd, requestMsg.data(), requestMsg.size(),
288                        &responseMsg, &responseMsgSize);
289     std::unique_ptr<uint8_t, decltype(std::free)*> responseMsgPtr{responseMsg,
290                                                                   std::free};
291     if (requesterRc != PLDM_REQUESTER_SUCCESS)
292     {
293         std::cerr << "Failed to send message/receive response. RC = "
294                   << requesterRc << ", errno = " << errno
295                   << "for sending event to host \n";
296         return requesterRc;
297     }
298     uint8_t completionCode{};
299     uint8_t status{};
300     auto responsePtr = reinterpret_cast<struct pldm_msg*>(responseMsgPtr.get());
301     auto rc = decode_platform_event_message_resp(
302         responsePtr, responseMsgSize - sizeof(pldm_msg_hdr), &completionCode,
303         &status);
304 
305     if (rc != PLDM_SUCCESS || completionCode != PLDM_SUCCESS)
306     {
307         std::cerr << "Failure in decode platform event message response, rc= "
308                   << rc << " cc=" << static_cast<unsigned>(completionCode)
309                   << "\n";
310         return rc;
311     }
312     return rc;
313 }
314 
315 int encodeEventMsg(uint8_t eventType, const std::vector<uint8_t>& eventDataVec,
316                    std::vector<uint8_t>& requestMsg, uint8_t instanceId)
317 {
318     auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
319 
320     auto rc = encode_platform_event_message_req(
321         instanceId, 1 /*formatVersion*/, 0 /*tId*/, eventType,
322         eventDataVec.data(), eventDataVec.size(), request,
323         eventDataVec.size() + PLDM_PLATFORM_EVENT_MESSAGE_MIN_REQ_BYTES);
324 
325     return rc;
326 }
327 
328 void pldm::responder::oem_ibm_platform::Handler::sendStateSensorEvent(
329     uint16_t sensorId, enum sensor_event_class_states sensorEventClass,
330     uint8_t sensorOffset, uint8_t eventState, uint8_t prevEventState)
331 {
332 
333     std::vector<uint8_t> sensorEventDataVec{};
334     size_t sensorEventSize = PLDM_SENSOR_EVENT_DATA_MIN_LENGTH + 1;
335     sensorEventDataVec.resize(sensorEventSize);
336     auto eventData = reinterpret_cast<struct pldm_sensor_event_data*>(
337         sensorEventDataVec.data());
338     eventData->sensor_id = sensorId;
339     eventData->sensor_event_class_type = sensorEventClass;
340     auto eventClassStart = eventData->event_class;
341     auto eventClass =
342         reinterpret_cast<struct pldm_sensor_event_state_sensor_state*>(
343             eventClassStart);
344     eventClass->sensor_offset = sensorOffset;
345     eventClass->event_state = eventState;
346     eventClass->previous_event_state = prevEventState;
347     auto instanceId = requester.getInstanceId(mctp_eid);
348     std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) +
349                                     PLDM_PLATFORM_EVENT_MESSAGE_MIN_REQ_BYTES +
350                                     sensorEventDataVec.size());
351     auto rc = encodeEventMsg(PLDM_SENSOR_EVENT, sensorEventDataVec, requestMsg,
352                              instanceId);
353     if (rc != PLDM_SUCCESS)
354     {
355         std::cerr << "Failed to encode state sensor event, rc = " << rc
356                   << std::endl;
357         return;
358     }
359     rc = sendEventToHost(requestMsg);
360     if (rc != PLDM_SUCCESS)
361     {
362         std::cerr << "Failed to send event to host: "
363                   << "rc=" << rc << std::endl;
364     }
365     requester.markFree(mctp_eid, instanceId);
366     return;
367 }
368 
369 void pldm::responder::oem_ibm_platform::Handler::_processEndUpdate(
370     sdeventplus::source::EventBase& /*source */)
371 {
372     assembleImageEvent.reset();
373     int retc = assembleCodeUpdateImage();
374     if (retc != PLDM_SUCCESS)
375     {
376         codeUpdate->setCodeUpdateProgress(false);
377         auto sensorId = codeUpdate->getFirmwareUpdateSensor();
378         sendStateSensorEvent(sensorId, PLDM_STATE_SENSOR_STATE, 0,
379                              uint8_t(CodeUpdateState::FAIL),
380                              uint8_t(CodeUpdateState::START));
381     }
382 }
383 
384 void pldm::responder::oem_ibm_platform::Handler::_processStartUpdate(
385     sdeventplus::source::EventBase& /*source */)
386 {
387     codeUpdate->deleteImage();
388     CodeUpdateState state = CodeUpdateState::START;
389     auto rc = codeUpdate->setRequestedApplyTime();
390     if (rc != PLDM_SUCCESS)
391     {
392         std::cerr << "setRequestedApplyTime failed \n";
393         state = CodeUpdateState::FAIL;
394     }
395     auto sensorId = codeUpdate->getFirmwareUpdateSensor();
396     sendStateSensorEvent(sensorId, PLDM_STATE_SENSOR_STATE, 0, uint8_t(state),
397                          uint8_t(CodeUpdateState::END));
398 }
399 
400 } // namespace oem_ibm_platform
401 } // namespace responder
402 } // namespace pldm
403