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