1 #include "pdr.hpp"
2 
3 #include <libpldm/fru.h>
4 #include <libpldm/platform.h>
5 
6 #include <phosphor-logging/lg2.hpp>
7 
8 #include <climits>
9 
10 PHOSPHOR_LOG2_USING;
11 
12 using namespace pldm::pdr;
13 
14 namespace pldm
15 {
16 namespace responder
17 {
18 namespace pdr_utils
19 {
20 // Refer: DSP0257_1.0.0 Table 2
21 // 7: uint16_t(FRU Record Set Identifier), uint8_t(FRU Record Type),
22 // uint8_t(Number of FRU fields), uint8_t(Encoding Type for FRU fields),
23 // uint8_t(FRU Field Type), uint8_t(FRU Field Length)
24 static constexpr uint8_t fruRecordDataFormatLength = 7;
25 
26 // // 2: 1byte FRU Field Type, 1byte FRU Field Length
27 static constexpr uint8_t fruFieldTypeLength = 2;
28 
29 pldm_pdr* Repo::getPdr() const
30 {
31     return repo;
32 }
33 
34 RecordHandle Repo::addRecord(const PdrEntry& pdrEntry)
35 {
36     uint32_t handle = pdrEntry.handle.recordHandle;
37     int rc = pldm_pdr_add_check(repo, pdrEntry.data, pdrEntry.size, false,
38                                 TERMINUS_HANDLE, &handle);
39     if (rc)
40     {
41         // pldm_pdr_add() assert()ed on failure to add PDR
42         throw std::runtime_error("Failed to add PDR");
43     }
44     return handle;
45 }
46 
47 const pldm_pdr_record* Repo::getFirstRecord(PdrEntry& pdrEntry)
48 {
49     constexpr uint32_t firstNum = 0;
50     uint8_t* pdrData = nullptr;
51     auto record = pldm_pdr_find_record(getPdr(), firstNum, &pdrData,
52                                        &pdrEntry.size,
53                                        &pdrEntry.handle.nextRecordHandle);
54     if (record)
55     {
56         pdrEntry.data = pdrData;
57     }
58 
59     return record;
60 }
61 
62 const pldm_pdr_record* Repo::getNextRecord(const pldm_pdr_record* currRecord,
63                                            PdrEntry& pdrEntry)
64 {
65     uint8_t* pdrData = nullptr;
66     auto record = pldm_pdr_get_next_record(getPdr(), currRecord, &pdrData,
67                                            &pdrEntry.size,
68                                            &pdrEntry.handle.nextRecordHandle);
69     if (record)
70     {
71         pdrEntry.data = pdrData;
72     }
73 
74     return record;
75 }
76 
77 uint32_t Repo::getRecordHandle(const pldm_pdr_record* record) const
78 {
79     return pldm_pdr_get_record_handle(getPdr(), record);
80 }
81 
82 uint32_t Repo::getRecordCount()
83 {
84     return pldm_pdr_get_record_count(getPdr());
85 }
86 
87 bool Repo::empty()
88 {
89     return !getRecordCount();
90 }
91 
92 StatestoDbusVal populateMapping(const std::string& type, const Json& dBusValues,
93                                 const PossibleValues& pv)
94 {
95     size_t pos = 0;
96     pldm::utils::PropertyValue value;
97     StatestoDbusVal valueMap;
98     if (dBusValues.size() != pv.size())
99     {
100         error(
101             "dBusValues size is not equal to pv size, dBusValues Size: {DBUS_VAL_SIZE}, pv Size: {PV_SIZE}",
102             "DBUS_VAL_SIZE", dBusValues.size(), "PV_SIZE", pv.size());
103         return {};
104     }
105 
106     for (auto it = dBusValues.begin(); it != dBusValues.end(); ++it, ++pos)
107     {
108         if (type == "uint8_t")
109         {
110             value = static_cast<uint8_t>(it.value());
111         }
112         else if (type == "uint16_t")
113         {
114             value = static_cast<uint16_t>(it.value());
115         }
116         else if (type == "uint32_t")
117         {
118             value = static_cast<uint32_t>(it.value());
119         }
120         else if (type == "uint64_t")
121         {
122             value = static_cast<uint64_t>(it.value());
123         }
124         else if (type == "int16_t")
125         {
126             value = static_cast<int16_t>(it.value());
127         }
128         else if (type == "int32_t")
129         {
130             value = static_cast<int32_t>(it.value());
131         }
132         else if (type == "int64_t")
133         {
134             value = static_cast<int64_t>(it.value());
135         }
136         else if (type == "bool")
137         {
138             value = static_cast<bool>(it.value());
139         }
140         else if (type == "double")
141         {
142             value = static_cast<double>(it.value());
143         }
144         else if (type == "string")
145         {
146             value = static_cast<std::string>(it.value());
147         }
148         else
149         {
150             error("Unknown D-Bus property type, TYPE={OTHER_TYPE}",
151                   "OTHER_TYPE", type.c_str());
152             return {};
153         }
154 
155         valueMap.emplace(pv[pos], value);
156     }
157 
158     return valueMap;
159 }
160 
161 std::tuple<TerminusHandle, SensorID, SensorInfo>
162     parseStateSensorPDR(const std::vector<uint8_t>& stateSensorPdr)
163 {
164     auto pdr =
165         reinterpret_cast<const pldm_state_sensor_pdr*>(stateSensorPdr.data());
166     CompositeSensorStates sensors{};
167     auto statesPtr = pdr->possible_states;
168     auto compositeSensorCount = pdr->composite_sensor_count;
169 
170     while (compositeSensorCount--)
171     {
172         auto state =
173             reinterpret_cast<const state_sensor_possible_states*>(statesPtr);
174         PossibleStates possibleStates{};
175         uint8_t possibleStatesPos{};
176         auto updateStates = [&possibleStates,
177                              &possibleStatesPos](const bitfield8_t& val) {
178             for (int i = 0; i < CHAR_BIT; i++)
179             {
180                 if (val.byte & (1 << i))
181                 {
182                     possibleStates.insert(possibleStatesPos * CHAR_BIT + i);
183                 }
184             }
185             possibleStatesPos++;
186         };
187         std::for_each(&state->states[0],
188                       &state->states[state->possible_states_size],
189                       updateStates);
190 
191         sensors.emplace_back(std::move(possibleStates));
192         if (compositeSensorCount)
193         {
194             statesPtr += sizeof(state_sensor_possible_states) +
195                          state->possible_states_size - 1;
196         }
197     }
198 
199     auto entityInfo =
200         std::make_tuple(static_cast<ContainerID>(pdr->container_id),
201                         static_cast<EntityType>(pdr->entity_type),
202                         static_cast<EntityInstance>(pdr->entity_instance));
203     auto sensorInfo = std::make_tuple(std::move(entityInfo),
204                                       std::move(sensors));
205     return std::make_tuple(pdr->terminus_handle, pdr->sensor_id,
206                            std::move(sensorInfo));
207 }
208 
209 std::vector<FruRecordDataFormat> parseFruRecordTable(const uint8_t* fruData,
210                                                      size_t fruLen)
211 {
212     // Refer: DSP0257_1.0.0 Table 2
213     // 7: uint16_t(FRU Record Set Identifier), uint8_t(FRU Record Type),
214     // uint8_t(Number of FRU fields), uint8_t(Encoding Type for FRU fields),
215     // uint8_t(FRU Field Type), uint8_t(FRU Field Length)
216     if (fruLen < fruRecordDataFormatLength)
217     {
218         lg2::error("Invalid fru len: {FRULEN}", "FRULEN", fruLen);
219         return {};
220     }
221 
222     std::vector<FruRecordDataFormat> frus;
223 
224     size_t index = 0;
225     while (index < fruLen)
226     {
227         FruRecordDataFormat fru;
228 
229         auto record = reinterpret_cast<const pldm_fru_record_data_format*>(
230             fruData + index);
231         fru.fruRSI = (int)le16toh(record->record_set_id);
232         fru.fruRecType = record->record_type;
233         fru.fruNum = record->num_fru_fields;
234         fru.fruEncodeType = record->encoding_type;
235 
236         index += 5;
237 
238         std::ranges::for_each(std::views::iota(0, (int)record->num_fru_fields),
239                               [fruData, &fru, &index](int) {
240             auto tlv =
241                 reinterpret_cast<const pldm_fru_record_tlv*>(fruData + index);
242             FruTLV frutlv;
243             frutlv.fruFieldType = tlv->type;
244             frutlv.fruFieldLen = tlv->length;
245             frutlv.fruFieldValue.resize(tlv->length);
246             for (const auto& i : std::views::iota(0, (int)tlv->length))
247             {
248                 memcpy(frutlv.fruFieldValue.data() + i, tlv->value + i, 1);
249             }
250             fru.fruTLV.push_back(frutlv);
251 
252             // 2: 1byte FRU Field Type, 1byte FRU Field Length
253             index += fruFieldTypeLength + (unsigned)tlv->length;
254         });
255 
256         frus.push_back(fru);
257     }
258 
259     return frus;
260 }
261 
262 size_t getEffecterDataSize(uint8_t effecterDataSize)
263 {
264     switch (effecterDataSize)
265     {
266         case PLDM_EFFECTER_DATA_SIZE_UINT8:
267             return sizeof(uint8_t);
268         case PLDM_EFFECTER_DATA_SIZE_SINT8:
269             return sizeof(int8_t);
270         case PLDM_EFFECTER_DATA_SIZE_UINT16:
271             return sizeof(uint16_t);
272         case PLDM_EFFECTER_DATA_SIZE_SINT16:
273             return sizeof(int16_t);
274         case PLDM_EFFECTER_DATA_SIZE_UINT32:
275             return sizeof(uint32_t);
276         case PLDM_EFFECTER_DATA_SIZE_SINT32:
277             return sizeof(int32_t);
278         default:
279             return 0;
280     }
281 }
282 
283 } // namespace pdr_utils
284 } // namespace responder
285 } // namespace pldm
286