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