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