xref: /openbmc/pldm/libpldmresponder/base.cpp (revision 7927f90c)
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/oem/ibm/file_io.h>
22 #include <libpldm/oem/ibm/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(sdeventplus::source::EventBase&
178                                        /*source */)
179 {
180     survEvent.reset();
181     oemPlatformHandler->processSetEventReceiver();
182 }
183 
184 Response Handler::getTID(const pldm_msg* request, size_t /*payloadLength*/)
185 {
186     Response response(sizeof(pldm_msg_hdr) + PLDM_GET_TID_RESP_BYTES, 0);
187     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
188     auto rc = encode_get_tid_resp(request->hdr.instance_id, PLDM_SUCCESS,
189                                   TERMINUS_ID, responsePtr);
190     if (rc != PLDM_SUCCESS)
191     {
192         return ccOnlyResponse(request, rc);
193     }
194 
195     if (oemPlatformHandler)
196     {
197         survEvent = std::make_unique<sdeventplus::source::Defer>(
198             event, std::bind_front(&Handler::_processSetEventReceiver, this));
199     }
200 
201     return response;
202 }
203 
204 } // namespace base
205 } // namespace responder
206 } // namespace pldm
207