xref: /openbmc/pldm/libpldmresponder/base.cpp (revision 33705fda)
1 #include "libpldm/base.h"
2 
3 #include "base.hpp"
4 #include "registration.hpp"
5 
6 #include <array>
7 #include <cstring>
8 #include <map>
9 #include <stdexcept>
10 #include <vector>
11 
12 namespace pldm
13 {
14 namespace responder
15 {
16 
17 using Cmd = std::vector<uint8_t>;
18 
19 static const std::map<Type, Cmd> capabilities{
20     {PLDM_BASE, {PLDM_GET_PLDM_TYPES, PLDM_GET_PLDM_COMMANDS}}};
21 
22 static const std::map<Type, ver32_t> versions{
23     {PLDM_BASE, {0xF1, 0xF0, 0xF0, 0x00}},
24     {PLDM_PLATFORM, {0xF1, 0xF1, 0xF1, 0x00}},
25     {PLDM_BIOS, {0xF1, 0xF0, 0xF0, 0x00}},
26 };
27 
28 namespace base
29 {
30 
31 void registerHandlers()
32 {
33     registerHandler(PLDM_BASE, PLDM_GET_PLDM_TYPES, std::move(getPLDMTypes));
34     registerHandler(PLDM_BASE, PLDM_GET_PLDM_COMMANDS,
35                     std::move(getPLDMCommands));
36     registerHandler(PLDM_BASE, PLDM_GET_PLDM_VERSION,
37                     std::move(getPLDMVersion));
38 }
39 
40 } // namespace base
41 
42 Response getPLDMTypes(const pldm_msg* request, size_t payloadLength)
43 {
44     // DSP0240 has this as a bitfield8[N], where N = 0 to 7
45     std::array<bitfield8_t, 8> types{};
46     for (const auto& type : capabilities)
47     {
48         auto index = type.first / 8;
49         // <Type Number> = <Array Index> * 8 + <bit position>
50         auto bit = type.first - (index * 8);
51         types[index].byte |= 1 << bit;
52     }
53 
54     Response response(sizeof(pldm_msg_hdr) + PLDM_GET_TYPES_RESP_BYTES, 0);
55     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
56     encode_get_types_resp(request->hdr.instance_id, PLDM_SUCCESS, types.data(),
57                           responsePtr);
58 
59     return response;
60 }
61 
62 Response getPLDMCommands(const pldm_msg* request, size_t payloadLength)
63 {
64     ver32_t version{};
65     Type type;
66 
67     Response response(sizeof(pldm_msg_hdr) + PLDM_GET_COMMANDS_RESP_BYTES, 0);
68     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
69 
70     auto rc = decode_get_commands_req(request->payload, payloadLength, &type,
71                                       &version);
72 
73     if (rc != PLDM_SUCCESS)
74     {
75         encode_get_commands_resp(request->hdr.instance_id, rc, nullptr,
76                                  responsePtr);
77         return response;
78     }
79 
80     // DSP0240 has this as a bitfield8[N], where N = 0 to 31
81     std::array<bitfield8_t, 32> cmds{};
82     if (capabilities.find(type) == capabilities.end())
83     {
84         encode_get_commands_resp(request->hdr.instance_id,
85                                  PLDM_ERROR_INVALID_PLDM_TYPE, nullptr,
86                                  responsePtr);
87         return response;
88     }
89 
90     for (const auto& cmd : capabilities.at(type))
91     {
92         auto index = cmd / 8;
93         // <Type Number> = <Array Index> * 8 + <bit position>
94         auto bit = cmd - (index * 8);
95         cmds[index].byte |= 1 << bit;
96     }
97 
98     encode_get_commands_resp(request->hdr.instance_id, PLDM_SUCCESS,
99                              cmds.data(), responsePtr);
100 
101     return response;
102 }
103 
104 Response getPLDMVersion(const pldm_msg* request, size_t payloadLength)
105 {
106     uint32_t transferHandle;
107     Type type;
108     uint8_t transferFlag;
109 
110     Response response(sizeof(pldm_msg_hdr) + PLDM_GET_VERSION_RESP_BYTES, 0);
111     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
112 
113     uint8_t rc = decode_get_version_req(request->payload, payloadLength,
114                                         &transferHandle, &transferFlag, &type);
115 
116     if (rc != PLDM_SUCCESS)
117     {
118         encode_get_version_resp(request->hdr.instance_id, rc, 0, 0, nullptr, 4,
119                                 responsePtr);
120         return response;
121     }
122 
123     ver32_t version{};
124     auto search = versions.find(type);
125 
126     if (search == versions.end())
127     {
128         encode_get_version_resp(request->hdr.instance_id,
129                                 PLDM_ERROR_INVALID_PLDM_TYPE, 0, 0, nullptr, 4,
130                                 responsePtr);
131         return response;
132     }
133 
134     memcpy(&version, &(search->second), sizeof(version));
135     encode_get_version_resp(request->hdr.instance_id, PLDM_SUCCESS, 0,
136                             PLDM_START_AND_END, &version, sizeof(pldm_version),
137                             responsePtr);
138 
139     return response;
140 }
141 
142 } // namespace responder
143 } // namespace pldm
144