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