xref: /openbmc/pldm/libpldmresponder/base.cpp (revision 19ea04c3)
1 #include "config.h"
2 
3 #include "base.hpp"
4 
5 #include "common/utils.hpp"
6 #include "libpldmresponder/pdr.hpp"
7 
8 #include <libpldm/base.h>
9 #include <libpldm/bios.h>
10 #include <libpldm/fru.h>
11 #include <libpldm/platform.h>
12 #include <libpldm/pldm.h>
13 
14 #include <phosphor-logging/lg2.hpp>
15 
16 #include <array>
17 #include <cstring>
18 #include <iostream>
19 #include <map>
20 #include <stdexcept>
21 #include <vector>
22 
23 #ifdef OEM_IBM
24 #include <libpldm/file_io.h>
25 #include <libpldm/host.h>
26 #endif
27 
28 PHOSPHOR_LOG2_USING;
29 
30 namespace pldm
31 {
32 using Type = uint8_t;
33 
34 namespace responder
35 {
36 using Cmd = std::vector<uint8_t>;
37 
38 static const std::map<Type, Cmd> capabilities{
39     {PLDM_BASE,
40      {PLDM_GET_TID, PLDM_GET_PLDM_VERSION, PLDM_GET_PLDM_TYPES,
41       PLDM_GET_PLDM_COMMANDS}},
42     {PLDM_PLATFORM,
43      {PLDM_GET_PDR, PLDM_SET_STATE_EFFECTER_STATES, PLDM_SET_EVENT_RECEIVER,
44       PLDM_GET_SENSOR_READING, PLDM_GET_STATE_SENSOR_READINGS,
45       PLDM_SET_NUMERIC_EFFECTER_VALUE, PLDM_GET_NUMERIC_EFFECTER_VALUE,
46       PLDM_PLATFORM_EVENT_MESSAGE}},
47     {PLDM_BIOS,
48      {PLDM_GET_DATE_TIME, PLDM_SET_DATE_TIME, PLDM_GET_BIOS_TABLE,
49       PLDM_GET_BIOS_ATTRIBUTE_CURRENT_VALUE_BY_HANDLE,
50       PLDM_SET_BIOS_ATTRIBUTE_CURRENT_VALUE, PLDM_SET_BIOS_TABLE}},
51     {PLDM_FRU,
52      {PLDM_GET_FRU_RECORD_TABLE_METADATA, PLDM_GET_FRU_RECORD_TABLE,
53       PLDM_GET_FRU_RECORD_BY_OPTION}},
54 #ifdef OEM_IBM
55     {PLDM_OEM,
56      {PLDM_HOST_GET_ALERT_STATUS, PLDM_GET_FILE_TABLE, PLDM_READ_FILE,
57       PLDM_WRITE_FILE, PLDM_READ_FILE_INTO_MEMORY, PLDM_WRITE_FILE_FROM_MEMORY,
58       PLDM_READ_FILE_BY_TYPE_INTO_MEMORY, PLDM_WRITE_FILE_BY_TYPE_FROM_MEMORY,
59       PLDM_NEW_FILE_AVAILABLE, PLDM_READ_FILE_BY_TYPE, PLDM_WRITE_FILE_BY_TYPE,
60       PLDM_FILE_ACK}},
61 #endif
62 };
63 
64 static const std::map<Type, ver32_t> versions{
65     {PLDM_BASE, {0x00, 0xf0, 0xf0, 0xf1}},
66     {PLDM_PLATFORM, {0x00, 0xf0, 0xf2, 0xf1}},
67     {PLDM_BIOS, {0x00, 0xf0, 0xf0, 0xf1}},
68     {PLDM_FRU, {0x00, 0xf0, 0xf0, 0xf1}},
69 #ifdef OEM_IBM
70     {PLDM_OEM, {0x00, 0xf0, 0xf0, 0xf1}},
71 #endif
72 };
73 
74 namespace base
75 {
76 Response Handler::getPLDMTypes(const pldm_msg* request,
77                                size_t /*payloadLength*/)
78 {
79     // DSP0240 has this as a bitfield8[N], where N = 0 to 7
80     std::array<bitfield8_t, 8> types{};
81     for (const auto& type : capabilities)
82     {
83         auto index = type.first / 8;
84         // <Type Number> = <Array Index> * 8 + <bit position>
85         auto bit = type.first - (index * 8);
86         types[index].byte |= 1 << bit;
87     }
88 
89     Response response(sizeof(pldm_msg_hdr) + PLDM_GET_TYPES_RESP_BYTES, 0);
90     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
91     auto rc = encode_get_types_resp(request->hdr.instance_id, PLDM_SUCCESS,
92                                     types.data(), responsePtr);
93     if (rc != PLDM_SUCCESS)
94     {
95         return CmdHandler::ccOnlyResponse(request, rc);
96     }
97 
98     return response;
99 }
100 
101 Response Handler::getPLDMCommands(const pldm_msg* request, size_t payloadLength)
102 {
103     ver32_t version{};
104     Type type;
105 
106     Response response(sizeof(pldm_msg_hdr) + PLDM_GET_COMMANDS_RESP_BYTES, 0);
107     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
108 
109     auto rc = decode_get_commands_req(request, payloadLength, &type, &version);
110 
111     if (rc != PLDM_SUCCESS)
112     {
113         return CmdHandler::ccOnlyResponse(request, rc);
114     }
115 
116     // DSP0240 has this as a bitfield8[N], where N = 0 to 31
117     std::array<bitfield8_t, 32> cmds{};
118     if (capabilities.find(type) == capabilities.end())
119     {
120         return CmdHandler::ccOnlyResponse(request,
121                                           PLDM_ERROR_INVALID_PLDM_TYPE);
122     }
123 
124     for (const auto& cmd : capabilities.at(type))
125     {
126         auto index = cmd / 8;
127         // <Type Number> = <Array Index> * 8 + <bit position>
128         auto bit = cmd - (index * 8);
129         cmds[index].byte |= 1 << bit;
130     }
131 
132     rc = encode_get_commands_resp(request->hdr.instance_id, PLDM_SUCCESS,
133                                   cmds.data(), responsePtr);
134     if (rc != PLDM_SUCCESS)
135     {
136         return ccOnlyResponse(request, rc);
137     }
138 
139     return response;
140 }
141 
142 Response Handler::getPLDMVersion(const pldm_msg* request, size_t payloadLength)
143 {
144     uint32_t transferHandle;
145     Type type;
146     uint8_t transferFlag;
147 
148     Response response(sizeof(pldm_msg_hdr) + PLDM_GET_VERSION_RESP_BYTES, 0);
149     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
150 
151     uint8_t rc = decode_get_version_req(request, payloadLength, &transferHandle,
152                                         &transferFlag, &type);
153 
154     if (rc != PLDM_SUCCESS)
155     {
156         return CmdHandler::ccOnlyResponse(request, rc);
157     }
158 
159     ver32_t version{};
160     auto search = versions.find(type);
161 
162     if (search == versions.end())
163     {
164         return CmdHandler::ccOnlyResponse(request,
165                                           PLDM_ERROR_INVALID_PLDM_TYPE);
166     }
167 
168     memcpy(&version, &(search->second), sizeof(version));
169     rc = encode_get_version_resp(request->hdr.instance_id, PLDM_SUCCESS, 0,
170                                  PLDM_START_AND_END, &version,
171                                  sizeof(pldm_version), responsePtr);
172     if (rc != PLDM_SUCCESS)
173     {
174         return ccOnlyResponse(request, rc);
175     }
176 
177     return response;
178 }
179 
180 void Handler::processSetEventReceiver(
181     sdeventplus::source::EventBase& /*source */)
182 {
183     survEvent.reset();
184     std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) +
185                                     PLDM_SET_EVENT_RECEIVER_REQ_BYTES);
186     auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
187     auto instanceId = requester.getInstanceId(eid);
188     uint8_t eventMessageGlobalEnable =
189         PLDM_EVENT_MESSAGE_GLOBAL_ENABLE_ASYNC_KEEP_ALIVE;
190     uint8_t transportProtocolType = PLDM_TRANSPORT_PROTOCOL_TYPE_MCTP;
191     uint8_t eventReceiverAddressInfo = pldm::responder::pdr::BmcMctpEid;
192     uint16_t heartbeatTimer = HEARTBEAT_TIMEOUT;
193 
194     auto rc = encode_set_event_receiver_req(
195         instanceId, eventMessageGlobalEnable, transportProtocolType,
196         eventReceiverAddressInfo, heartbeatTimer, request);
197     if (rc != PLDM_SUCCESS)
198     {
199         requester.markFree(eid, instanceId);
200         error("Failed to encode_set_event_receiver_req, rc = {RC}", "RC",
201               lg2::hex, rc);
202         return;
203     }
204 
205     auto processSetEventReceiverResponse = [](mctp_eid_t /*eid*/,
206                                               const pldm_msg* response,
207                                               size_t respMsgLen) {
208         if (response == nullptr || !respMsgLen)
209         {
210             error("Failed to receive response for setEventReceiver command");
211             return;
212         }
213 
214         uint8_t completionCode{};
215         auto rc = decode_set_event_receiver_resp(response, respMsgLen,
216                                                  &completionCode);
217         if (rc || completionCode)
218         {
219             error(
220                 "Failed to decode setEventReceiver command response, rc = {RC}, cc = {CC}",
221                 "RC", rc, "CC", (unsigned)completionCode);
222             pldm::utils::reportError(
223                 "xyz.openbmc_project.bmc.pldm.InternalFailure");
224         }
225     };
226     rc = handler->registerRequest(
227         eid, instanceId, PLDM_PLATFORM, PLDM_SET_EVENT_RECEIVER,
228         std::move(requestMsg), std::move(processSetEventReceiverResponse));
229 
230     if (rc != PLDM_SUCCESS)
231     {
232         error("Failed to send the setEventReceiver request");
233     }
234 
235     if (oemPlatformHandler)
236     {
237         oemPlatformHandler->countSetEventReceiver();
238         oemPlatformHandler->checkAndDisableWatchDog();
239     }
240 }
241 
242 Response Handler::getTID(const pldm_msg* request, size_t /*payloadLength*/)
243 {
244     Response response(sizeof(pldm_msg_hdr) + PLDM_GET_TID_RESP_BYTES, 0);
245     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
246     auto rc = encode_get_tid_resp(request->hdr.instance_id, PLDM_SUCCESS,
247                                   TERMINUS_ID, responsePtr);
248     if (rc != PLDM_SUCCESS)
249     {
250         return ccOnlyResponse(request, rc);
251     }
252 
253     survEvent = std::make_unique<sdeventplus::source::Defer>(
254         event, std::bind_front(&Handler::processSetEventReceiver, this));
255 
256     return response;
257 }
258 
259 } // namespace base
260 } // namespace responder
261 } // namespace pldm
262