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     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         lg2::error("Invalid fru len: {FRULEN}", "FRULEN", fruLen);
222         return {};
223     }
224 
225     std::vector<FruRecordDataFormat> frus;
226 
227     size_t index = 0;
228     while (index < fruLen)
229     {
230         FruRecordDataFormat fru;
231 
232         auto record = reinterpret_cast<const pldm_fru_record_data_format*>(
233             fruData + index);
234         fru.fruRSI = (int)le16toh(record->record_set_id);
235         fru.fruRecType = record->record_type;
236         fru.fruNum = record->num_fru_fields;
237         fru.fruEncodeType = record->encoding_type;
238 
239         index += 5;
240 
241         std::ranges::for_each(std::views::iota(0, (int)record->num_fru_fields),
242                               [fruData, &fru, &index](int) {
243             auto tlv =
244                 reinterpret_cast<const pldm_fru_record_tlv*>(fruData + index);
245             FruTLV frutlv;
246             frutlv.fruFieldType = tlv->type;
247             frutlv.fruFieldLen = tlv->length;
248             frutlv.fruFieldValue.resize(tlv->length);
249             for (const auto& i : std::views::iota(0, (int)tlv->length))
250             {
251                 memcpy(frutlv.fruFieldValue.data() + i, tlv->value + i, 1);
252             }
253             fru.fruTLV.push_back(frutlv);
254 
255             // 2: 1byte FRU Field Type, 1byte FRU Field Length
256             index += fruFieldTypeLength + (unsigned)tlv->length;
257         });
258 
259         frus.push_back(fru);
260     }
261 
262     return frus;
263 }
264 
265 size_t getEffecterDataSize(uint8_t effecterDataSize)
266 {
267     switch (effecterDataSize)
268     {
269         case PLDM_EFFECTER_DATA_SIZE_UINT8:
270             return sizeof(uint8_t);
271         case PLDM_EFFECTER_DATA_SIZE_SINT8:
272             return sizeof(int8_t);
273         case PLDM_EFFECTER_DATA_SIZE_UINT16:
274             return sizeof(uint16_t);
275         case PLDM_EFFECTER_DATA_SIZE_SINT16:
276             return sizeof(int16_t);
277         case PLDM_EFFECTER_DATA_SIZE_UINT32:
278             return sizeof(uint32_t);
279         case PLDM_EFFECTER_DATA_SIZE_SINT32:
280             return sizeof(int32_t);
281         default:
282             return 0;
283     }
284 }
285 
286 } // namespace pdr_utils
287 } // namespace responder
288 } // namespace pldm
289