xref: /openbmc/pldm/libpldmresponder/base.cpp (revision f666db13)
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(0, PLDM_SUCCESS, types.data(), responsePtr);
57 
58     return response;
59 }
60 
61 Response getPLDMCommands(const pldm_msg* request, size_t payloadLength)
62 {
63     ver32_t version{};
64     Type type;
65 
66     Response response(sizeof(pldm_msg_hdr) + PLDM_GET_COMMANDS_RESP_BYTES, 0);
67     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
68 
69     auto rc = decode_get_commands_req(request->payload, payloadLength, &type,
70                                       &version);
71 
72     if (rc != PLDM_SUCCESS)
73     {
74         encode_get_commands_resp(0, rc, nullptr, responsePtr);
75         return response;
76     }
77 
78     // DSP0240 has this as a bitfield8[N], where N = 0 to 31
79     std::array<bitfield8_t, 32> cmds{};
80     if (capabilities.find(type) == capabilities.end())
81     {
82         encode_get_commands_resp(0, PLDM_ERROR_INVALID_PLDM_TYPE, nullptr,
83                                  responsePtr);
84         return response;
85     }
86 
87     for (const auto& cmd : capabilities.at(type))
88     {
89         auto index = cmd / 8;
90         // <Type Number> = <Array Index> * 8 + <bit position>
91         auto bit = cmd - (index * 8);
92         cmds[index].byte |= 1 << bit;
93     }
94 
95     encode_get_commands_resp(0, PLDM_SUCCESS, cmds.data(), responsePtr);
96 
97     return response;
98 }
99 
100 Response getPLDMVersion(const pldm_msg* request, size_t payloadLength)
101 {
102     uint32_t transferHandle;
103     Type type;
104     uint8_t transferFlag;
105 
106     Response response(sizeof(pldm_msg_hdr) + PLDM_GET_VERSION_RESP_BYTES, 0);
107     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
108 
109     uint8_t rc = decode_get_version_req(request->payload, payloadLength,
110                                         &transferHandle, &transferFlag, &type);
111 
112     if (rc != PLDM_SUCCESS)
113     {
114         encode_get_version_resp(0, rc, 0, 0, nullptr, 4, responsePtr);
115         return response;
116     }
117 
118     ver32_t version{};
119     auto search = versions.find(type);
120 
121     if (search == versions.end())
122     {
123         encode_get_version_resp(0, PLDM_ERROR_INVALID_PLDM_TYPE, 0, 0, nullptr,
124                                 4, responsePtr);
125         return response;
126     }
127 
128     memcpy(&version, &(search->second), sizeof(version));
129     encode_get_version_resp(0, PLDM_SUCCESS, 0, PLDM_START_AND_END, &version,
130                             sizeof(pldm_version), responsePtr);
131 
132     return response;
133 }
134 
135 } // namespace responder
136 } // namespace pldm
137