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 '{DBUS_VALUE_SIZE}' is not equal to pv size'{PROPERTY_VALUE_SIZE}'.",
102             "DBUS_VALUE_SIZE", dBusValues.size(), "PROPERTY_VALUE_SIZE",
103             pv.size());
104         return {};
105     }
106 
107     for (auto it = dBusValues.begin(); it != dBusValues.end(); ++it, ++pos)
108     {
109         if (type == "uint8_t")
110         {
111             value = static_cast<uint8_t>(it.value());
112         }
113         else if (type == "uint16_t")
114         {
115             value = static_cast<uint16_t>(it.value());
116         }
117         else if (type == "uint32_t")
118         {
119             value = static_cast<uint32_t>(it.value());
120         }
121         else if (type == "uint64_t")
122         {
123             value = static_cast<uint64_t>(it.value());
124         }
125         else if (type == "int16_t")
126         {
127             value = static_cast<int16_t>(it.value());
128         }
129         else if (type == "int32_t")
130         {
131             value = static_cast<int32_t>(it.value());
132         }
133         else if (type == "int64_t")
134         {
135             value = static_cast<int64_t>(it.value());
136         }
137         else if (type == "bool")
138         {
139             value = static_cast<bool>(it.value());
140         }
141         else if (type == "double")
142         {
143             value = static_cast<double>(it.value());
144         }
145         else if (type == "string")
146         {
147             value = static_cast<std::string>(it.value());
148         }
149         else
150         {
151             error("Unknown D-Bus property type '{TYPE}'", "TYPE", type);
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     std::vector<StateSetId> stateSetIds{};
170 
171     while (compositeSensorCount--)
172     {
173         auto state =
174             reinterpret_cast<const state_sensor_possible_states*>(statesPtr);
175         PossibleStates possibleStates{};
176         uint8_t possibleStatesPos{};
177         auto updateStates = [&possibleStates,
178                              &possibleStatesPos](const bitfield8_t& val) {
179             for (int i = 0; i < CHAR_BIT; i++)
180             {
181                 if (val.byte & (1 << i))
182                 {
183                     possibleStates.insert(possibleStatesPos * CHAR_BIT + i);
184                 }
185             }
186             possibleStatesPos++;
187         };
188         std::for_each(&state->states[0],
189                       &state->states[state->possible_states_size],
190                       updateStates);
191 
192         sensors.emplace_back(std::move(possibleStates));
193         stateSetIds.emplace_back(state->state_set_id);
194 
195         if (compositeSensorCount)
196         {
197             statesPtr += sizeof(state_sensor_possible_states) +
198                          state->possible_states_size - 1;
199         }
200     }
201 
202     auto entityInfo =
203         std::make_tuple(static_cast<ContainerID>(pdr->container_id),
204                         static_cast<EntityType>(pdr->entity_type),
205                         static_cast<EntityInstance>(pdr->entity_instance));
206     auto sensorInfo = std::make_tuple(std::move(entityInfo), std::move(sensors),
207                                       std::move(stateSetIds));
208     return std::make_tuple(pdr->terminus_handle, pdr->sensor_id,
209                            std::move(sensorInfo));
210 }
211 
212 std::vector<FruRecordDataFormat> parseFruRecordTable(const uint8_t* fruData,
213                                                      size_t fruLen)
214 {
215     // Refer: DSP0257_1.0.0 Table 2
216     // 7: uint16_t(FRU Record Set Identifier), uint8_t(FRU Record Type),
217     // uint8_t(Number of FRU fields), uint8_t(Encoding Type for FRU fields),
218     // uint8_t(FRU Field Type), uint8_t(FRU Field Length)
219     if (fruLen < fruRecordDataFormatLength)
220     {
221         error("Invalid FRU length '{LENGTH}' while parsing FRU record table",
222               "LENGTH", fruLen);
223         return {};
224     }
225 
226     std::vector<FruRecordDataFormat> frus;
227 
228     size_t index = 0;
229     while (index < fruLen)
230     {
231         FruRecordDataFormat fru;
232 
233         auto record = reinterpret_cast<const pldm_fru_record_data_format*>(
234             fruData + index);
235         fru.fruRSI = (int)le16toh(record->record_set_id);
236         fru.fruRecType = record->record_type;
237         fru.fruNum = record->num_fru_fields;
238         fru.fruEncodeType = record->encoding_type;
239 
240         index += 5;
241 
242         std::ranges::for_each(std::views::iota(0, (int)record->num_fru_fields),
243                               [fruData, &fru, &index](int) {
244             auto tlv =
245                 reinterpret_cast<const pldm_fru_record_tlv*>(fruData + index);
246             FruTLV frutlv;
247             frutlv.fruFieldType = tlv->type;
248             frutlv.fruFieldLen = tlv->length;
249             frutlv.fruFieldValue.resize(tlv->length);
250             for (const auto& i : std::views::iota(0, (int)tlv->length))
251             {
252                 memcpy(frutlv.fruFieldValue.data() + i, tlv->value + i, 1);
253             }
254             fru.fruTLV.push_back(frutlv);
255 
256             // 2: 1byte FRU Field Type, 1byte FRU Field Length
257             index += fruFieldTypeLength + (unsigned)tlv->length;
258         });
259 
260         frus.push_back(fru);
261     }
262 
263     return frus;
264 }
265 
266 size_t getEffecterDataSize(uint8_t effecterDataSize)
267 {
268     switch (effecterDataSize)
269     {
270         case PLDM_EFFECTER_DATA_SIZE_UINT8:
271             return sizeof(uint8_t);
272         case PLDM_EFFECTER_DATA_SIZE_SINT8:
273             return sizeof(int8_t);
274         case PLDM_EFFECTER_DATA_SIZE_UINT16:
275             return sizeof(uint16_t);
276         case PLDM_EFFECTER_DATA_SIZE_SINT16:
277             return sizeof(int16_t);
278         case PLDM_EFFECTER_DATA_SIZE_UINT32:
279             return sizeof(uint32_t);
280         case PLDM_EFFECTER_DATA_SIZE_SINT32:
281             return sizeof(int32_t);
282         default:
283             return 0;
284     }
285 }
286 
287 } // namespace pdr_utils
288 } // namespace responder
289 } // namespace pldm
290