1 #pragma once
2 
3 #include "utils.hpp"
4 
5 #include <stdint.h>
6 
7 #include <filesystem>
8 #include <fstream>
9 #include <functional>
10 #include <iostream>
11 #include <nlohmann/json.hpp>
12 #include <string>
13 #include <xyz/openbmc_project/Common/error.hpp>
14 
15 #include "libpldm/pdr.h"
16 
17 using InternalFailure =
18     sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
19 
20 namespace fs = std::filesystem;
21 
22 namespace pldm
23 {
24 
25 namespace responder
26 {
27 
28 namespace pdr_utils
29 {
30 
31 /** @struct PdrEntry
32  *  PDR entry structure that acts as a PDR record structure in the PDR
33  *  repository to handle PDR APIs.
34  */
35 struct PdrEntry
36 {
37     uint8_t* data;
38     uint32_t size;
39     union
40     {
41         uint32_t recordHandle;
42         uint32_t nextRecordHandle;
43     } handle;
44 };
45 using Type = uint8_t;
46 using Json = nlohmann::json;
47 using RecordHandle = uint32_t;
48 using State = uint8_t;
49 using PossibleValues = std::vector<uint8_t>;
50 
51 /** @brief Map of DBus property State to attribute value
52  */
53 using StatestoDbusVal = std::map<State, pldm::utils::PropertyValue>;
54 using DbusMappings = std::vector<pldm::utils::DBusMapping>;
55 using DbusValMaps = std::vector<StatestoDbusVal>;
56 
57 /** @brief Parse PDR JSON file and output Json object
58  *
59  *  @param[in] path - path of PDR JSON file
60  *
61  *  @return Json - Json object
62  */
63 inline Json readJson(const std::string& path)
64 {
65     fs::path dir(path);
66     if (!fs::exists(dir) || fs::is_empty(dir))
67     {
68         throw InternalFailure();
69     }
70 
71     std::ifstream jsonFile(path);
72     if (!jsonFile.is_open())
73     {
74         std::cerr << "Error opening PDR JSON file, PATH=" << path << "\n";
75         return {};
76     }
77 
78     return Json::parse(jsonFile);
79 }
80 
81 /** @brief Populate the mapping between D-Bus property stateId and attribute
82  *          value for the effecter PDR enumeration attribute.
83  *
84  *  @param[in] type - type of the D-Bus property
85  *  @param[in] dBusValues - json array of D-Bus property values
86  *  @param[in] pv - Possible values for the effecter PDR enumeration attribute
87  *
88  *  @return StatestoDbusVal - Map of D-Bus property stateId to attribute value
89  */
90 StatestoDbusVal populateMapping(const std::string& type, const Json& dBusValues,
91                                 const PossibleValues& pv);
92 
93 /**
94  *  @class RepoInterface
95  *
96  *  @brief Abstract class describing the interface API to the PDR repository,
97  *         this class wraps operations used to handle the new PDR APIs.
98  */
99 class RepoInterface
100 {
101   public:
102     RepoInterface(pldm_pdr* repo) : repo(repo)
103     {
104     }
105 
106     virtual ~RepoInterface() = default;
107 
108     /** @brief Get an opaque pldm_pdr structure
109      *
110      *  @return pldm_pdr - pldm_pdr structure
111      */
112     virtual pldm_pdr* getPdr() const = 0;
113 
114     /** @brief Add a PDR record to a PDR repository
115      *
116      *  @param[in] pdrEntry - PDR records entry(data, size, recordHandle)
117      *
118      *  @return uint32_t - record handle assigned to PDR record
119      */
120     virtual RecordHandle addRecord(const PdrEntry& pdrEntry) = 0;
121 
122     /** @brief Get the first PDR record from a PDR repository
123      *
124      *  @param[in] pdrEntry - PDR records entry(data, size, nextRecordHandle)
125      *
126      *  @return opaque pointer acting as PDR record handle, will be NULL if
127      *          record was not found
128      */
129     virtual const pldm_pdr_record* getFirstRecord(PdrEntry& pdrEntry) = 0;
130 
131     /** @brief Get the next PDR record from a PDR repository
132      *
133      *  @param[in] currRecord - opaque pointer acting as a PDR record handle
134      *  @param[in] pdrEntry - PDR records entry(data, size, nextRecordHandle)
135      *
136      *  @return opaque pointer acting as PDR record handle, will be NULL if
137      *          record was not found
138      */
139     virtual const pldm_pdr_record*
140         getNextRecord(const pldm_pdr_record* currRecord,
141                       PdrEntry& pdrEntry) = 0;
142 
143     /** @brief Get record handle of a PDR record
144      *
145      *  @param[in] record - opaque pointer acting as a PDR record handle
146      *
147      *  @return uint32_t - record handle assigned to PDR record; 0 if record is
148      *                     not found
149      */
150     virtual uint32_t getRecordHandle(const pldm_pdr_record* record) const = 0;
151 
152     /** @brief Get number of records in a PDR repository
153      *
154      *  @return uint32_t - number of records
155      */
156     virtual uint32_t getRecordCount() = 0;
157 
158     /** @brief Determine if records are empty in a PDR repository
159      *
160      *  @return bool - true means empty and false means not empty
161      */
162     virtual bool empty() = 0;
163 
164   protected:
165     pldm_pdr* repo;
166 };
167 
168 /**
169  *  @class Repo
170  *
171  *  Wrapper class to handle the PDR APIs
172  *
173  *  This class wraps operations used to handle PDR APIs.
174  */
175 class Repo : public RepoInterface
176 {
177   public:
178     Repo(pldm_pdr* repo) : RepoInterface(repo)
179     {
180     }
181 
182     pldm_pdr* getPdr() const override;
183 
184     RecordHandle addRecord(const PdrEntry& pdrEntry) override;
185 
186     const pldm_pdr_record* getFirstRecord(PdrEntry& pdrEntry) override;
187 
188     const pldm_pdr_record* getNextRecord(const pldm_pdr_record* currRecord,
189                                          PdrEntry& pdrEntry) override;
190 
191     uint32_t getRecordHandle(const pldm_pdr_record* record) const override;
192 
193     uint32_t getRecordCount() override;
194 
195     bool empty() override;
196 };
197 
198 } // namespace pdr_utils
199 } // namespace responder
200 } // namespace pldm
201