xref: /openbmc/pldm/libpldmresponder/pdr.hpp (revision c6e8fb50)
1*c6e8fb50SDeepak Kodihalli #pragma once
2*c6e8fb50SDeepak Kodihalli 
3*c6e8fb50SDeepak Kodihalli #include "effecters.hpp"
4*c6e8fb50SDeepak Kodihalli 
5*c6e8fb50SDeepak Kodihalli #include <stdint.h>
6*c6e8fb50SDeepak Kodihalli 
7*c6e8fb50SDeepak Kodihalli #include <filesystem>
8*c6e8fb50SDeepak Kodihalli #include <fstream>
9*c6e8fb50SDeepak Kodihalli #include <functional>
10*c6e8fb50SDeepak Kodihalli #include <map>
11*c6e8fb50SDeepak Kodihalli #include <nlohmann/json.hpp>
12*c6e8fb50SDeepak Kodihalli #include <phosphor-logging/elog-errors.hpp>
13*c6e8fb50SDeepak Kodihalli #include <phosphor-logging/log.hpp>
14*c6e8fb50SDeepak Kodihalli #include <string>
15*c6e8fb50SDeepak Kodihalli #include <vector>
16*c6e8fb50SDeepak Kodihalli #include <xyz/openbmc_project/Common/error.hpp>
17*c6e8fb50SDeepak Kodihalli 
18*c6e8fb50SDeepak Kodihalli #include "libpldm/platform.h"
19*c6e8fb50SDeepak Kodihalli 
20*c6e8fb50SDeepak Kodihalli using namespace phosphor::logging;
21*c6e8fb50SDeepak Kodihalli using InternalFailure =
22*c6e8fb50SDeepak Kodihalli     sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
23*c6e8fb50SDeepak Kodihalli namespace fs = std::filesystem;
24*c6e8fb50SDeepak Kodihalli 
25*c6e8fb50SDeepak Kodihalli namespace pldm
26*c6e8fb50SDeepak Kodihalli {
27*c6e8fb50SDeepak Kodihalli 
28*c6e8fb50SDeepak Kodihalli namespace responder
29*c6e8fb50SDeepak Kodihalli {
30*c6e8fb50SDeepak Kodihalli 
31*c6e8fb50SDeepak Kodihalli namespace pdr
32*c6e8fb50SDeepak Kodihalli {
33*c6e8fb50SDeepak Kodihalli 
34*c6e8fb50SDeepak Kodihalli using Type = uint8_t;
35*c6e8fb50SDeepak Kodihalli using Json = nlohmann::json;
36*c6e8fb50SDeepak Kodihalli using RecordHandle = uint32_t;
37*c6e8fb50SDeepak Kodihalli using Entry = std::vector<uint8_t>;
38*c6e8fb50SDeepak Kodihalli using Pdr = std::vector<Entry>;
39*c6e8fb50SDeepak Kodihalli 
40*c6e8fb50SDeepak Kodihalli /** @class Repo
41*c6e8fb50SDeepak Kodihalli  *
42*c6e8fb50SDeepak Kodihalli  *  @brief Abstract class describing the interface API to the PDR repository
43*c6e8fb50SDeepak Kodihalli  *
44*c6e8fb50SDeepak Kodihalli  *  Concrete implementations of this must handle storing and addressing the
45*c6e8fb50SDeepak Kodihalli  *  PDR entries by a "record handle", which can be indices, offsets, etc.
46*c6e8fb50SDeepak Kodihalli  */
47*c6e8fb50SDeepak Kodihalli class Repo
48*c6e8fb50SDeepak Kodihalli {
49*c6e8fb50SDeepak Kodihalli   public:
50*c6e8fb50SDeepak Kodihalli     /** @brief Add a new entry to the PDR
51*c6e8fb50SDeepak Kodihalli      *
52*c6e8fb50SDeepak Kodihalli      *  @param[in] entry - new PDR entry
53*c6e8fb50SDeepak Kodihalli      */
54*c6e8fb50SDeepak Kodihalli     virtual void add(Entry&& entry) = 0;
55*c6e8fb50SDeepak Kodihalli 
56*c6e8fb50SDeepak Kodihalli     /** @brief Access PDR entry at inout record handle
57*c6e8fb50SDeepak Kodihalli      *
58*c6e8fb50SDeepak Kodihalli      *  @param[in] handle - record handle
59*c6e8fb50SDeepak Kodihalli      *
60*c6e8fb50SDeepak Kodihalli      *  @return Entry - PDR entry
61*c6e8fb50SDeepak Kodihalli      */
62*c6e8fb50SDeepak Kodihalli     virtual Entry at(RecordHandle handle) const = 0;
63*c6e8fb50SDeepak Kodihalli 
64*c6e8fb50SDeepak Kodihalli     /** @brief Get next available record handle for assignment
65*c6e8fb50SDeepak Kodihalli      *
66*c6e8fb50SDeepak Kodihalli      *  @return RecordHandle - PDR record handle
67*c6e8fb50SDeepak Kodihalli      */
68*c6e8fb50SDeepak Kodihalli     virtual RecordHandle getNextRecordHandle() const = 0;
69*c6e8fb50SDeepak Kodihalli 
70*c6e8fb50SDeepak Kodihalli     /** @brief Get record handle immediately suceeding the input record
71*c6e8fb50SDeepak Kodihalli      *         handle
72*c6e8fb50SDeepak Kodihalli      *
73*c6e8fb50SDeepak Kodihalli      *  @param[in] current - input record handle
74*c6e8fb50SDeepak Kodihalli      *
75*c6e8fb50SDeepak Kodihalli      *  @return RecordHandle - PDR record handle
76*c6e8fb50SDeepak Kodihalli      */
77*c6e8fb50SDeepak Kodihalli     virtual RecordHandle getNextRecordHandle(RecordHandle current) const = 0;
78*c6e8fb50SDeepak Kodihalli 
79*c6e8fb50SDeepak Kodihalli     /** @brief Get number of entries in the PDR
80*c6e8fb50SDeepak Kodihalli      *
81*c6e8fb50SDeepak Kodihalli      *  @return size_t - number of entries
82*c6e8fb50SDeepak Kodihalli      */
83*c6e8fb50SDeepak Kodihalli     virtual size_t numEntries() const = 0;
84*c6e8fb50SDeepak Kodihalli 
85*c6e8fb50SDeepak Kodihalli     /** @brief Check if PDR is empty
86*c6e8fb50SDeepak Kodihalli      *
87*c6e8fb50SDeepak Kodihalli      *  @return bool - true if PDR is empty, false otherwise
88*c6e8fb50SDeepak Kodihalli      */
89*c6e8fb50SDeepak Kodihalli     virtual bool empty() const = 0;
90*c6e8fb50SDeepak Kodihalli 
91*c6e8fb50SDeepak Kodihalli     /** @brief Empty the PDR
92*c6e8fb50SDeepak Kodihalli      */
93*c6e8fb50SDeepak Kodihalli     virtual void makeEmpty() = 0;
94*c6e8fb50SDeepak Kodihalli };
95*c6e8fb50SDeepak Kodihalli 
96*c6e8fb50SDeepak Kodihalli namespace internal
97*c6e8fb50SDeepak Kodihalli {
98*c6e8fb50SDeepak Kodihalli 
99*c6e8fb50SDeepak Kodihalli /** @brief Parse PDR JSON file and output Json object
100*c6e8fb50SDeepak Kodihalli  *
101*c6e8fb50SDeepak Kodihalli  *  @param[in] path - path of PDR JSON file
102*c6e8fb50SDeepak Kodihalli  *
103*c6e8fb50SDeepak Kodihalli  *  @return Json - Json object
104*c6e8fb50SDeepak Kodihalli  */
105*c6e8fb50SDeepak Kodihalli inline Json readJson(const std::string& path)
106*c6e8fb50SDeepak Kodihalli {
107*c6e8fb50SDeepak Kodihalli     std::ifstream jsonFile(path);
108*c6e8fb50SDeepak Kodihalli     if (!jsonFile.is_open())
109*c6e8fb50SDeepak Kodihalli     {
110*c6e8fb50SDeepak Kodihalli         log<level::INFO>("Error opening PDR JSON file",
111*c6e8fb50SDeepak Kodihalli                          entry("PATH=%s", path.c_str()));
112*c6e8fb50SDeepak Kodihalli         return {};
113*c6e8fb50SDeepak Kodihalli     }
114*c6e8fb50SDeepak Kodihalli 
115*c6e8fb50SDeepak Kodihalli     return Json::parse(jsonFile);
116*c6e8fb50SDeepak Kodihalli }
117*c6e8fb50SDeepak Kodihalli 
118*c6e8fb50SDeepak Kodihalli /** @class IndexedRepo
119*c6e8fb50SDeepak Kodihalli  *
120*c6e8fb50SDeepak Kodihalli  *  @brief Inherits and implements Repo
121*c6e8fb50SDeepak Kodihalli  *
122*c6e8fb50SDeepak Kodihalli  *  Stores the PDR as a vector of entries, and addresses PDR entries based on an
123*c6e8fb50SDeepak Kodihalli  *  incrementing record handle, starting at 1.
124*c6e8fb50SDeepak Kodihalli  */
125*c6e8fb50SDeepak Kodihalli class IndexedRepo : public Repo
126*c6e8fb50SDeepak Kodihalli {
127*c6e8fb50SDeepak Kodihalli   public:
128*c6e8fb50SDeepak Kodihalli     void add(Entry&& entry)
129*c6e8fb50SDeepak Kodihalli     {
130*c6e8fb50SDeepak Kodihalli         repo.emplace_back(std::move(entry));
131*c6e8fb50SDeepak Kodihalli     }
132*c6e8fb50SDeepak Kodihalli 
133*c6e8fb50SDeepak Kodihalli     Entry at(RecordHandle handle) const
134*c6e8fb50SDeepak Kodihalli     {
135*c6e8fb50SDeepak Kodihalli         if (!handle)
136*c6e8fb50SDeepak Kodihalli         {
137*c6e8fb50SDeepak Kodihalli             handle = 1;
138*c6e8fb50SDeepak Kodihalli         }
139*c6e8fb50SDeepak Kodihalli         return repo.at(handle - 1);
140*c6e8fb50SDeepak Kodihalli     }
141*c6e8fb50SDeepak Kodihalli 
142*c6e8fb50SDeepak Kodihalli     RecordHandle getNextRecordHandle() const
143*c6e8fb50SDeepak Kodihalli     {
144*c6e8fb50SDeepak Kodihalli         return repo.size() + 1;
145*c6e8fb50SDeepak Kodihalli     }
146*c6e8fb50SDeepak Kodihalli 
147*c6e8fb50SDeepak Kodihalli     RecordHandle getNextRecordHandle(RecordHandle current) const
148*c6e8fb50SDeepak Kodihalli     {
149*c6e8fb50SDeepak Kodihalli         if (current >= repo.size())
150*c6e8fb50SDeepak Kodihalli         {
151*c6e8fb50SDeepak Kodihalli             return 0;
152*c6e8fb50SDeepak Kodihalli         }
153*c6e8fb50SDeepak Kodihalli         if (!current)
154*c6e8fb50SDeepak Kodihalli         {
155*c6e8fb50SDeepak Kodihalli             current = 1;
156*c6e8fb50SDeepak Kodihalli         }
157*c6e8fb50SDeepak Kodihalli         return current + 1;
158*c6e8fb50SDeepak Kodihalli     }
159*c6e8fb50SDeepak Kodihalli 
160*c6e8fb50SDeepak Kodihalli     size_t numEntries() const
161*c6e8fb50SDeepak Kodihalli     {
162*c6e8fb50SDeepak Kodihalli         return repo.size();
163*c6e8fb50SDeepak Kodihalli     }
164*c6e8fb50SDeepak Kodihalli 
165*c6e8fb50SDeepak Kodihalli     bool empty() const
166*c6e8fb50SDeepak Kodihalli     {
167*c6e8fb50SDeepak Kodihalli         return repo.empty();
168*c6e8fb50SDeepak Kodihalli     }
169*c6e8fb50SDeepak Kodihalli 
170*c6e8fb50SDeepak Kodihalli     void makeEmpty()
171*c6e8fb50SDeepak Kodihalli     {
172*c6e8fb50SDeepak Kodihalli         repo.clear();
173*c6e8fb50SDeepak Kodihalli     }
174*c6e8fb50SDeepak Kodihalli 
175*c6e8fb50SDeepak Kodihalli   private:
176*c6e8fb50SDeepak Kodihalli     Pdr repo{};
177*c6e8fb50SDeepak Kodihalli };
178*c6e8fb50SDeepak Kodihalli 
179*c6e8fb50SDeepak Kodihalli /** @brief Parse PDR JSONs and build PDR repository
180*c6e8fb50SDeepak Kodihalli  *
181*c6e8fb50SDeepak Kodihalli  *  @param[in] dir - directory housing platform specific PDR JSON files
182*c6e8fb50SDeepak Kodihalli  *  @tparam[in] repo - instance of concrete implementation of Repo
183*c6e8fb50SDeepak Kodihalli  */
184*c6e8fb50SDeepak Kodihalli template <typename T>
185*c6e8fb50SDeepak Kodihalli void generate(const std::string& dir, T& repo)
186*c6e8fb50SDeepak Kodihalli {
187*c6e8fb50SDeepak Kodihalli     using namespace internal;
188*c6e8fb50SDeepak Kodihalli     // A map of PDR type to a lambda that handles creation of that PDR type.
189*c6e8fb50SDeepak Kodihalli     // The lambda essentially would parse the platform specific PDR JSONs to
190*c6e8fb50SDeepak Kodihalli     // generate the PDR structures. This function iterates through the map to
191*c6e8fb50SDeepak Kodihalli     // invoke all lambdas, so that all PDR types can be created.
192*c6e8fb50SDeepak Kodihalli     std::map<Type, std::function<void(const Json& json, T& repo)>> generators =
193*c6e8fb50SDeepak Kodihalli         {{PLDM_STATE_EFFECTER_PDR, [](const auto& json, T& repo) {
194*c6e8fb50SDeepak Kodihalli               static const std::vector<Json> emptyList{};
195*c6e8fb50SDeepak Kodihalli               static const Json empty{};
196*c6e8fb50SDeepak Kodihalli               auto entries = json.value("entries", emptyList);
197*c6e8fb50SDeepak Kodihalli               for (const auto& e : entries)
198*c6e8fb50SDeepak Kodihalli               {
199*c6e8fb50SDeepak Kodihalli                   size_t pdrSize = 0;
200*c6e8fb50SDeepak Kodihalli                   auto effecters = e.value("effecters", emptyList);
201*c6e8fb50SDeepak Kodihalli                   static const Json empty{};
202*c6e8fb50SDeepak Kodihalli                   for (const auto& effecter : effecters)
203*c6e8fb50SDeepak Kodihalli                   {
204*c6e8fb50SDeepak Kodihalli                       auto set = effecter.value("set", empty);
205*c6e8fb50SDeepak Kodihalli                       auto statesSize = set.value("size", 0);
206*c6e8fb50SDeepak Kodihalli                       if (!statesSize)
207*c6e8fb50SDeepak Kodihalli                       {
208*c6e8fb50SDeepak Kodihalli                           log<level::ERR>(
209*c6e8fb50SDeepak Kodihalli                               "Malformed PDR JSON - no state set info",
210*c6e8fb50SDeepak Kodihalli                               entry("TYPE=%d", PLDM_STATE_EFFECTER_PDR));
211*c6e8fb50SDeepak Kodihalli                           elog<InternalFailure>();
212*c6e8fb50SDeepak Kodihalli                       }
213*c6e8fb50SDeepak Kodihalli                       pdrSize += sizeof(state_effecter_possible_states) -
214*c6e8fb50SDeepak Kodihalli                                  sizeof(bitfield8_t) +
215*c6e8fb50SDeepak Kodihalli                                  (sizeof(bitfield8_t) * statesSize);
216*c6e8fb50SDeepak Kodihalli                   }
217*c6e8fb50SDeepak Kodihalli                   pdrSize += sizeof(pldm_state_effecter_pdr) - sizeof(uint8_t);
218*c6e8fb50SDeepak Kodihalli 
219*c6e8fb50SDeepak Kodihalli                   Entry pdrEntry{};
220*c6e8fb50SDeepak Kodihalli                   pdrEntry.resize(pdrSize);
221*c6e8fb50SDeepak Kodihalli 
222*c6e8fb50SDeepak Kodihalli                   pldm_state_effecter_pdr* pdr =
223*c6e8fb50SDeepak Kodihalli                       reinterpret_cast<pldm_state_effecter_pdr*>(
224*c6e8fb50SDeepak Kodihalli                           pdrEntry.data());
225*c6e8fb50SDeepak Kodihalli                   pdr->hdr.record_handle = repo.getNextRecordHandle();
226*c6e8fb50SDeepak Kodihalli                   pdr->hdr.version = 1;
227*c6e8fb50SDeepak Kodihalli                   pdr->hdr.type = PLDM_STATE_EFFECTER_PDR;
228*c6e8fb50SDeepak Kodihalli                   pdr->hdr.record_change_num = 0;
229*c6e8fb50SDeepak Kodihalli                   pdr->hdr.length = pdrSize - sizeof(pldm_pdr_hdr);
230*c6e8fb50SDeepak Kodihalli 
231*c6e8fb50SDeepak Kodihalli                   pdr->terminus_handle = 0;
232*c6e8fb50SDeepak Kodihalli                   pdr->effecter_id = effecter::nextId();
233*c6e8fb50SDeepak Kodihalli                   pdr->entity_type = e.value("type", 0);
234*c6e8fb50SDeepak Kodihalli                   pdr->entity_instance = e.value("instance", 0);
235*c6e8fb50SDeepak Kodihalli                   pdr->container_id = e.value("container", 0);
236*c6e8fb50SDeepak Kodihalli                   pdr->effecter_semantic_id = 0;
237*c6e8fb50SDeepak Kodihalli                   pdr->effecter_init = PLDM_NO_INIT;
238*c6e8fb50SDeepak Kodihalli                   pdr->has_description_pdr = false;
239*c6e8fb50SDeepak Kodihalli                   pdr->composite_effecter_count = effecters.size();
240*c6e8fb50SDeepak Kodihalli 
241*c6e8fb50SDeepak Kodihalli                   uint8_t* start = pdrEntry.data() +
242*c6e8fb50SDeepak Kodihalli                                    sizeof(pldm_state_effecter_pdr) -
243*c6e8fb50SDeepak Kodihalli                                    sizeof(uint8_t);
244*c6e8fb50SDeepak Kodihalli                   for (const auto& effecter : effecters)
245*c6e8fb50SDeepak Kodihalli                   {
246*c6e8fb50SDeepak Kodihalli                       auto set = effecter.value("set", empty);
247*c6e8fb50SDeepak Kodihalli                       state_effecter_possible_states* possibleStates =
248*c6e8fb50SDeepak Kodihalli                           reinterpret_cast<state_effecter_possible_states*>(
249*c6e8fb50SDeepak Kodihalli                               start);
250*c6e8fb50SDeepak Kodihalli                       possibleStates->state_set_id = set.value("id", 0);
251*c6e8fb50SDeepak Kodihalli                       possibleStates->possible_states_size =
252*c6e8fb50SDeepak Kodihalli                           set.value("size", 0);
253*c6e8fb50SDeepak Kodihalli 
254*c6e8fb50SDeepak Kodihalli                       start += sizeof(possibleStates->state_set_id) +
255*c6e8fb50SDeepak Kodihalli                                sizeof(possibleStates->possible_states_size);
256*c6e8fb50SDeepak Kodihalli                       static const std::vector<uint8_t> emptyStates{};
257*c6e8fb50SDeepak Kodihalli                       auto states = set.value("states", emptyStates);
258*c6e8fb50SDeepak Kodihalli                       for (const auto& state : states)
259*c6e8fb50SDeepak Kodihalli                       {
260*c6e8fb50SDeepak Kodihalli                           auto index = state / 8;
261*c6e8fb50SDeepak Kodihalli                           auto bit = state - (index * 8);
262*c6e8fb50SDeepak Kodihalli                           bitfield8_t* bf =
263*c6e8fb50SDeepak Kodihalli                               reinterpret_cast<bitfield8_t*>(start + index);
264*c6e8fb50SDeepak Kodihalli                           bf->byte |= 1 << bit;
265*c6e8fb50SDeepak Kodihalli                       }
266*c6e8fb50SDeepak Kodihalli                       start += possibleStates->possible_states_size;
267*c6e8fb50SDeepak Kodihalli                   }
268*c6e8fb50SDeepak Kodihalli                   repo.add(std::move(pdrEntry));
269*c6e8fb50SDeepak Kodihalli               }
270*c6e8fb50SDeepak Kodihalli           }}};
271*c6e8fb50SDeepak Kodihalli 
272*c6e8fb50SDeepak Kodihalli     auto eraseLen = strlen(".json");
273*c6e8fb50SDeepak Kodihalli     Type pdrType{};
274*c6e8fb50SDeepak Kodihalli     for (const auto& dirEntry : fs::directory_iterator(dir))
275*c6e8fb50SDeepak Kodihalli     {
276*c6e8fb50SDeepak Kodihalli         try
277*c6e8fb50SDeepak Kodihalli         {
278*c6e8fb50SDeepak Kodihalli             auto json = readJson(dirEntry.path().string());
279*c6e8fb50SDeepak Kodihalli             if (!json.empty())
280*c6e8fb50SDeepak Kodihalli             {
281*c6e8fb50SDeepak Kodihalli                 auto fileName = dirEntry.path().filename().string();
282*c6e8fb50SDeepak Kodihalli                 fileName.erase(fileName.end() - eraseLen);
283*c6e8fb50SDeepak Kodihalli                 pdrType = stoi(fileName);
284*c6e8fb50SDeepak Kodihalli                 generators.at(pdrType)(json, repo);
285*c6e8fb50SDeepak Kodihalli             }
286*c6e8fb50SDeepak Kodihalli         }
287*c6e8fb50SDeepak Kodihalli         catch (const InternalFailure& e)
288*c6e8fb50SDeepak Kodihalli         {
289*c6e8fb50SDeepak Kodihalli         }
290*c6e8fb50SDeepak Kodihalli         catch (const std::exception& e)
291*c6e8fb50SDeepak Kodihalli         {
292*c6e8fb50SDeepak Kodihalli             log<level::ERR>("Failed parsing PDR JSON file",
293*c6e8fb50SDeepak Kodihalli                             entry("TYPE=%d", pdrType),
294*c6e8fb50SDeepak Kodihalli                             entry("ERROR=%s", e.what()));
295*c6e8fb50SDeepak Kodihalli             report<InternalFailure>();
296*c6e8fb50SDeepak Kodihalli         }
297*c6e8fb50SDeepak Kodihalli     }
298*c6e8fb50SDeepak Kodihalli }
299*c6e8fb50SDeepak Kodihalli 
300*c6e8fb50SDeepak Kodihalli } // namespace internal
301*c6e8fb50SDeepak Kodihalli 
302*c6e8fb50SDeepak Kodihalli /** @brief Build (if not built already) and retrieve PDR
303*c6e8fb50SDeepak Kodihalli  *
304*c6e8fb50SDeepak Kodihalli  *  @param[in] dir - directory housing platform specific PDR JSON files
305*c6e8fb50SDeepak Kodihalli  *
306*c6e8fb50SDeepak Kodihalli  *  @return Repo& - Reference to instance of pdr::Repo
307*c6e8fb50SDeepak Kodihalli  */
308*c6e8fb50SDeepak Kodihalli Repo& get(const std::string& dir);
309*c6e8fb50SDeepak Kodihalli 
310*c6e8fb50SDeepak Kodihalli } // namespace pdr
311*c6e8fb50SDeepak Kodihalli } // namespace responder
312*c6e8fb50SDeepak Kodihalli } // namespace pldm
313