xref: /openbmc/pldm/libpldmresponder/base.cpp (revision 579a34a3)
1 #include "libpldm/base.h"
2 
3 #include "libpldm/bios.h"
4 #include "libpldm/fru.h"
5 #include "libpldm/platform.h"
6 
7 #include "base.hpp"
8 
9 #include <array>
10 #include <cstring>
11 #include <map>
12 #include <stdexcept>
13 #include <vector>
14 
15 #ifdef OEM_IBM
16 #include "libpldm/file_io.h"
17 #include "libpldm/host.h"
18 #endif
19 
20 namespace pldm
21 {
22 
23 using Type = uint8_t;
24 
25 namespace responder
26 {
27 
28 using Cmd = std::vector<uint8_t>;
29 
30 static const std::map<Type, Cmd> capabilities{
31     {PLDM_BASE,
32      {PLDM_GET_TID, PLDM_GET_PLDM_VERSION, PLDM_GET_PLDM_TYPES,
33       PLDM_GET_PLDM_COMMANDS}},
34     {PLDM_PLATFORM, {PLDM_GET_PDR, PLDM_SET_STATE_EFFECTER_STATES}},
35     {PLDM_BIOS,
36      {PLDM_GET_DATE_TIME, PLDM_SET_DATE_TIME, PLDM_GET_BIOS_TABLE,
37       PLDM_GET_BIOS_ATTRIBUTE_CURRENT_VALUE_BY_HANDLE,
38       PLDM_SET_BIOS_ATTRIBUTE_CURRENT_VALUE}},
39     {PLDM_FRU, {PLDM_GET_FRU_RECORD_TABLE_METADATA, PLDM_GET_FRU_RECORD_TABLE}},
40 #ifdef OEM_IBM
41     {PLDM_OEM,
42      {PLDM_HOST_GET_ALERT_STATUS, PLDM_GET_FILE_TABLE, PLDM_READ_FILE,
43       PLDM_WRITE_FILE, PLDM_READ_FILE_INTO_MEMORY, PLDM_WRITE_FILE_FROM_MEMORY,
44       PLDM_READ_FILE_BY_TYPE_INTO_MEMORY, PLDM_WRITE_FILE_BY_TYPE_FROM_MEMORY,
45       PLDM_NEW_FILE_AVAILABLE, PLDM_READ_FILE_BY_TYPE, PLDM_WRITE_FILE_BY_TYPE,
46       PLDM_FILE_ACK}},
47 #endif
48 };
49 
50 static const std::map<Type, ver32_t> versions{
51     {PLDM_BASE, {0xF1, 0xF0, 0xF0, 0x00}},
52     {PLDM_PLATFORM, {0xF1, 0xF2, 0xF0, 0x00}},
53     {PLDM_BIOS, {0xF1, 0xF0, 0xF0, 0x00}},
54     {PLDM_FRU, {0xF1, 0xF0, 0xF0, 0x00}},
55 #ifdef OEM_IBM
56     {PLDM_OEM, {0xF1, 0xF0, 0xF0, 0x00}},
57 #endif
58 };
59 
60 namespace base
61 {
62 
63 Response Handler::getPLDMTypes(const pldm_msg* request,
64                                size_t /*payloadLength*/)
65 {
66     // DSP0240 has this as a bitfield8[N], where N = 0 to 7
67     std::array<bitfield8_t, 8> types{};
68     for (const auto& type : capabilities)
69     {
70         auto index = type.first / 8;
71         // <Type Number> = <Array Index> * 8 + <bit position>
72         auto bit = type.first - (index * 8);
73         types[index].byte |= 1 << bit;
74     }
75 
76     Response response(sizeof(pldm_msg_hdr) + PLDM_GET_TYPES_RESP_BYTES, 0);
77     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
78     auto rc = encode_get_types_resp(request->hdr.instance_id, PLDM_SUCCESS,
79                                     types.data(), responsePtr);
80     if (rc != PLDM_SUCCESS)
81     {
82         return CmdHandler::ccOnlyResponse(request, rc);
83     }
84 
85     return response;
86 }
87 
88 Response Handler::getPLDMCommands(const pldm_msg* request, size_t payloadLength)
89 {
90     ver32_t version{};
91     Type type;
92 
93     Response response(sizeof(pldm_msg_hdr) + PLDM_GET_COMMANDS_RESP_BYTES, 0);
94     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
95 
96     auto rc = decode_get_commands_req(request, payloadLength, &type, &version);
97 
98     if (rc != PLDM_SUCCESS)
99     {
100         return CmdHandler::ccOnlyResponse(request, rc);
101     }
102 
103     // DSP0240 has this as a bitfield8[N], where N = 0 to 31
104     std::array<bitfield8_t, 32> cmds{};
105     if (capabilities.find(type) == capabilities.end())
106     {
107         return CmdHandler::ccOnlyResponse(request,
108                                           PLDM_ERROR_INVALID_PLDM_TYPE);
109     }
110 
111     for (const auto& cmd : capabilities.at(type))
112     {
113         auto index = cmd / 8;
114         // <Type Number> = <Array Index> * 8 + <bit position>
115         auto bit = cmd - (index * 8);
116         cmds[index].byte |= 1 << bit;
117     }
118 
119     rc = encode_get_commands_resp(request->hdr.instance_id, PLDM_SUCCESS,
120                                   cmds.data(), responsePtr);
121     if (rc != PLDM_SUCCESS)
122     {
123         return ccOnlyResponse(request, rc);
124     }
125 
126     return response;
127 }
128 
129 Response Handler::getPLDMVersion(const pldm_msg* request, size_t payloadLength)
130 {
131     uint32_t transferHandle;
132     Type type;
133     uint8_t transferFlag;
134 
135     Response response(sizeof(pldm_msg_hdr) + PLDM_GET_VERSION_RESP_BYTES, 0);
136     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
137 
138     uint8_t rc = decode_get_version_req(request, payloadLength, &transferHandle,
139                                         &transferFlag, &type);
140 
141     if (rc != PLDM_SUCCESS)
142     {
143         return CmdHandler::ccOnlyResponse(request, rc);
144     }
145 
146     ver32_t version{};
147     auto search = versions.find(type);
148 
149     if (search == versions.end())
150     {
151         return CmdHandler::ccOnlyResponse(request,
152                                           PLDM_ERROR_INVALID_PLDM_TYPE);
153     }
154 
155     memcpy(&version, &(search->second), sizeof(version));
156     rc = encode_get_version_resp(request->hdr.instance_id, PLDM_SUCCESS, 0,
157                                  PLDM_START_AND_END, &version,
158                                  sizeof(pldm_version), responsePtr);
159     if (rc != PLDM_SUCCESS)
160     {
161         return ccOnlyResponse(request, rc);
162     }
163 
164     return response;
165 }
166 
167 Response Handler::getTID(const pldm_msg* request, size_t /*payloadLength*/)
168 {
169     // assigned 1 to the bmc as the PLDM terminus
170     uint8_t tid = 1;
171 
172     Response response(sizeof(pldm_msg_hdr) + PLDM_GET_TID_RESP_BYTES, 0);
173     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
174     auto rc = encode_get_tid_resp(request->hdr.instance_id, PLDM_SUCCESS, tid,
175                                   responsePtr);
176     if (rc != PLDM_SUCCESS)
177     {
178         return ccOnlyResponse(request, rc);
179     }
180 
181     return response;
182 }
183 
184 } // namespace base
185 } // namespace responder
186 } // namespace pldm
187