1 #pragma once
2 
3 #include "common/types.hpp"
4 #include "common/utils.hpp"
5 
6 #include <libpldm/pdr.h>
7 #include <stdint.h>
8 
9 #include <nlohmann/json.hpp>
10 #include <phosphor-logging/lg2.hpp>
11 #include <xyz/openbmc_project/Common/error.hpp>
12 
13 #include <filesystem>
14 #include <fstream>
15 #include <functional>
16 #include <iostream>
17 #include <string>
18 
19 PHOSPHOR_LOG2_USING;
20 
21 using InternalFailure =
22     sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
23 
24 namespace fs = std::filesystem;
25 
26 namespace pldm
27 {
28 namespace responder
29 {
30 namespace pdr_utils
31 {
32 /** @struct Type ID associated with pdr
33  *
34  */
35 enum class TypeId
36 {
37     PLDM_EFFECTER_ID,
38     PLDM_SENSOR_ID
39 };
40 
41 struct FruTLV
42 {
43     uint8_t fruFieldType;
44     uint8_t fruFieldLen;
45     std::vector<uint8_t> fruFieldValue;
46 };
47 
48 struct FruRecordDataFormat
49 {
50     uint16_t fruRSI;
51     uint8_t fruRecType;
52     uint8_t fruNum;
53     uint8_t fruEncodeType;
54     std::vector<FruTLV> fruTLV;
55 };
56 
57 /** @struct PdrEntry
58  *  PDR entry structure that acts as a PDR record structure in the PDR
59  *  repository to handle PDR APIs.
60  */
61 struct PdrEntry
62 {
63     uint8_t* data;
64     uint32_t size;
65     union
66     {
67         uint32_t recordHandle;
68         uint32_t nextRecordHandle;
69     } handle;
70 };
71 using Type = uint8_t;
72 using Json = nlohmann::json;
73 using RecordHandle = uint32_t;
74 using State = uint8_t;
75 using PossibleValues = std::vector<uint8_t>;
76 
77 /** @brief Map of DBus property State to attribute value
78  */
79 using StatestoDbusVal = std::map<State, pldm::utils::PropertyValue>;
80 using DbusMappings = std::vector<pldm::utils::DBusMapping>;
81 using DbusValMaps = std::vector<StatestoDbusVal>;
82 using EventStates = std::array<uint8_t, 8>;
83 
84 /** @brief Parse PDR JSON file and output Json object
85  *
86  *  @param[in] path - path of PDR JSON file
87  *
88  *  @return Json - Json object
89  */
90 inline Json readJson(const std::string& path)
91 {
92     fs::path dir(path);
93     if (!fs::exists(dir) || fs::is_empty(dir))
94     {
95         throw InternalFailure();
96     }
97 
98     std::ifstream jsonFile(path);
99     if (!jsonFile.is_open())
100     {
101         error("Error opening PDR JSON file, PATH={JSON_PATH}", "JSON_PATH",
102               path);
103         return {};
104     }
105 
106     return Json::parse(jsonFile);
107 }
108 
109 /** @brief Populate the mapping between D-Bus property stateId and attribute
110  *          value for the effecter PDR enumeration attribute.
111  *
112  *  @param[in] type - type of the D-Bus property
113  *  @param[in] dBusValues - json array of D-Bus property values
114  *  @param[in] pv - Possible values for the effecter PDR enumeration attribute
115  *
116  *  @return StatestoDbusVal - Map of D-Bus property stateId to attribute value
117  */
118 StatestoDbusVal populateMapping(const std::string& type, const Json& dBusValues,
119                                 const PossibleValues& pv);
120 
121 /**
122  *  @class RepoInterface
123  *
124  *  @brief Abstract class describing the interface API to the PDR repository,
125  *         this class wraps operations used to handle the new PDR APIs.
126  */
127 class RepoInterface
128 {
129   public:
130     RepoInterface(pldm_pdr* repo) : repo(repo) {}
131 
132     virtual ~RepoInterface() = default;
133 
134     /** @brief Get an opaque pldm_pdr structure
135      *
136      *  @return pldm_pdr - pldm_pdr structure
137      */
138     virtual pldm_pdr* getPdr() const = 0;
139 
140     /** @brief Add a PDR record to a PDR repository
141      *
142      *  @param[in] pdrEntry - PDR records entry(data, size, recordHandle)
143      *
144      *  @return uint32_t - record handle assigned to PDR record
145      */
146     virtual RecordHandle addRecord(const PdrEntry& pdrEntry) = 0;
147 
148     /** @brief Get the first PDR record from a PDR repository
149      *
150      *  @param[in] pdrEntry - PDR records entry(data, size, nextRecordHandle)
151      *
152      *  @return opaque pointer acting as PDR record handle, will be NULL if
153      *          record was not found
154      */
155     virtual const pldm_pdr_record* getFirstRecord(PdrEntry& pdrEntry) = 0;
156 
157     /** @brief Get the next PDR record from a PDR repository
158      *
159      *  @param[in] currRecord - opaque pointer acting as a PDR record handle
160      *  @param[in] pdrEntry - PDR records entry(data, size, nextRecordHandle)
161      *
162      *  @return opaque pointer acting as PDR record handle, will be NULL if
163      *          record was not found
164      */
165     virtual const pldm_pdr_record*
166         getNextRecord(const pldm_pdr_record* currRecord,
167                       PdrEntry& pdrEntry) = 0;
168 
169     /** @brief Get record handle of a PDR record
170      *
171      *  @param[in] record - opaque pointer acting as a PDR record handle
172      *
173      *  @return uint32_t - record handle assigned to PDR record; 0 if record is
174      *                     not found
175      */
176     virtual uint32_t getRecordHandle(const pldm_pdr_record* record) const = 0;
177 
178     /** @brief Get number of records in a PDR repository
179      *
180      *  @return uint32_t - number of records
181      */
182     virtual uint32_t getRecordCount() = 0;
183 
184     /** @brief Determine if records are empty in a PDR repository
185      *
186      *  @return bool - true means empty and false means not empty
187      */
188     virtual bool empty() = 0;
189 
190   protected:
191     pldm_pdr* repo;
192 };
193 
194 /**
195  *  @class Repo
196  *
197  *  Wrapper class to handle the PDR APIs
198  *
199  *  This class wraps operations used to handle PDR APIs.
200  */
201 class Repo : public RepoInterface
202 {
203   public:
204     Repo(pldm_pdr* repo) : RepoInterface(repo) {}
205 
206     pldm_pdr* getPdr() const override;
207 
208     RecordHandle addRecord(const PdrEntry& pdrEntry) override;
209 
210     const pldm_pdr_record* getFirstRecord(PdrEntry& pdrEntry) override;
211 
212     const pldm_pdr_record* getNextRecord(const pldm_pdr_record* currRecord,
213                                          PdrEntry& pdrEntry) override;
214 
215     uint32_t getRecordHandle(const pldm_pdr_record* record) const override;
216 
217     uint32_t getRecordCount() override;
218 
219     bool empty() override;
220 };
221 
222 /** @brief Parse the State Sensor PDR and return the parsed sensor info which
223  *         will be used to lookup the sensor info in the PlatformEventMessage
224  *         command of sensorEvent type.
225  *
226  *  @param[in] stateSensorPdr - state sensor PDR
227  *
228  *  @return terminus handle, sensor ID and parsed sensor info
229  */
230 std::tuple<pldm::pdr::TerminusHandle, pldm::pdr::SensorID,
231            pldm::pdr::SensorInfo>
232     parseStateSensorPDR(const std::vector<uint8_t>& stateSensorPdr);
233 
234 /** @brief Parse FRU record table and return the vector of the FRU record data
235  *         format structure
236  *
237  *  @param[in] fruData - fru data
238  *  @param[in] fruLen  - fru len
239  *
240  *  @return std::vector<FruRecordDataFormat> - the vector of the FRU record data
241  *          format structure
242  */
243 std::vector<FruRecordDataFormat> parseFruRecordTable(const uint8_t* fruData,
244                                                      size_t fruLen);
245 
246 /** @brief Return the size of data type based on the effecterDataSize enum value
247  *
248  *  @param[in] effecterDataSize - Bitwidth and format of setting effecter value
249  *  @return[out] Map the effecterDataSize enum value to datatype and return the
250  *               size of dataType
251  */
252 size_t getEffecterDataSize(uint8_t effecterDataSize);
253 
254 } // namespace pdr_utils
255 } // namespace responder
256 } // namespace pldm
257