1 #include "libpldm/fru.h"
2 
3 #include "pdr.hpp"
4 
5 #include <libpldm/platform.h>
6 
7 #include <phosphor-logging/lg2.hpp>
8 
9 #include <climits>
10 
11 PHOSPHOR_LOG2_USING;
12 
13 using namespace pldm::pdr;
14 
15 namespace pldm
16 {
17 namespace responder
18 {
19 namespace pdr_utils
20 {
21 // Refer: DSP0257_1.0.0 Table 2
22 // 7: uint16_t(FRU Record Set Identifier), uint8_t(FRU Record Type),
23 // uint8_t(Number of FRU fields), uint8_t(Encoding Type for FRU fields),
24 // uint8_t(FRU Field Type), uint8_t(FRU Field Length)
25 static constexpr uint8_t fruRecordDataFormatLength = 7;
26 
27 // // 2: 1byte FRU Field Type, 1byte FRU Field Length
28 static constexpr uint8_t fruFieldTypeLength = 2;
29 
30 pldm_pdr* Repo::getPdr() const
31 {
32     return repo;
33 }
34 
35 RecordHandle Repo::addRecord(const PdrEntry& pdrEntry)
36 {
37     uint32_t handle = pdrEntry.handle.recordHandle;
38     int rc = pldm_pdr_add_check(repo, pdrEntry.data, pdrEntry.size, false,
39                                 TERMINUS_HANDLE, &handle);
40     if (rc)
41     {
42         // pldm_pdr_add() assert()ed on failure to add PDR
43         throw std::runtime_error("Failed to add PDR");
44     }
45     return handle;
46 }
47 
48 const pldm_pdr_record* Repo::getFirstRecord(PdrEntry& pdrEntry)
49 {
50     constexpr uint32_t firstNum = 0;
51     uint8_t* pdrData = nullptr;
52     auto record = pldm_pdr_find_record(getPdr(), firstNum, &pdrData,
53                                        &pdrEntry.size,
54                                        &pdrEntry.handle.nextRecordHandle);
55     if (record)
56     {
57         pdrEntry.data = pdrData;
58     }
59 
60     return record;
61 }
62 
63 const pldm_pdr_record* Repo::getNextRecord(const pldm_pdr_record* currRecord,
64                                            PdrEntry& pdrEntry)
65 {
66     uint8_t* pdrData = nullptr;
67     auto record = pldm_pdr_get_next_record(getPdr(), currRecord, &pdrData,
68                                            &pdrEntry.size,
69                                            &pdrEntry.handle.nextRecordHandle);
70     if (record)
71     {
72         pdrEntry.data = pdrData;
73     }
74 
75     return record;
76 }
77 
78 uint32_t Repo::getRecordHandle(const pldm_pdr_record* record) const
79 {
80     return pldm_pdr_get_record_handle(getPdr(), record);
81 }
82 
83 uint32_t Repo::getRecordCount()
84 {
85     return pldm_pdr_get_record_count(getPdr());
86 }
87 
88 bool Repo::empty()
89 {
90     return !getRecordCount();
91 }
92 
93 StatestoDbusVal populateMapping(const std::string& type, const Json& dBusValues,
94                                 const PossibleValues& pv)
95 {
96     size_t pos = 0;
97     pldm::utils::PropertyValue value;
98     StatestoDbusVal valueMap;
99     if (dBusValues.size() != pv.size())
100     {
101         error(
102             "dBusValues size is not equal to pv size, dBusValues Size: {DBUS_VAL_SIZE}, pv Size: {PV_SIZE}",
103             "DBUS_VAL_SIZE", dBusValues.size(), "PV_SIZE", 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={OTHER_TYPE}",
152                   "OTHER_TYPE", type.c_str());
153             return {};
154         }
155 
156         valueMap.emplace(pv[pos], value);
157     }
158 
159     return valueMap;
160 }
161 
162 std::tuple<TerminusHandle, SensorID, SensorInfo>
163     parseStateSensorPDR(const std::vector<uint8_t>& stateSensorPdr)
164 {
165     auto pdr =
166         reinterpret_cast<const pldm_state_sensor_pdr*>(stateSensorPdr.data());
167     CompositeSensorStates sensors{};
168     auto statesPtr = pdr->possible_states;
169     auto compositeSensorCount = pdr->composite_sensor_count;
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         if (compositeSensorCount)
194         {
195             statesPtr += sizeof(state_sensor_possible_states) +
196                          state->possible_states_size - 1;
197         }
198     }
199 
200     auto entityInfo =
201         std::make_tuple(static_cast<ContainerID>(pdr->container_id),
202                         static_cast<EntityType>(pdr->entity_type),
203                         static_cast<EntityInstance>(pdr->entity_instance));
204     auto sensorInfo = std::make_tuple(std::move(entityInfo),
205                                       std::move(sensors));
206     return std::make_tuple(pdr->terminus_handle, pdr->sensor_id,
207                            std::move(sensorInfo));
208 }
209 
210 std::vector<FruRecordDataFormat> parseFruRecordTable(const uint8_t* fruData,
211                                                      size_t fruLen)
212 {
213     // Refer: DSP0257_1.0.0 Table 2
214     // 7: uint16_t(FRU Record Set Identifier), uint8_t(FRU Record Type),
215     // uint8_t(Number of FRU fields), uint8_t(Encoding Type for FRU fields),
216     // uint8_t(FRU Field Type), uint8_t(FRU Field Length)
217     if (fruLen < fruRecordDataFormatLength)
218     {
219         lg2::error("Invalid fru len: {FRULEN}", "FRULEN", fruLen);
220         return {};
221     }
222 
223     std::vector<FruRecordDataFormat> frus;
224 
225     size_t index = 0;
226     while (index < fruLen)
227     {
228         FruRecordDataFormat fru;
229 
230         auto record = reinterpret_cast<const pldm_fru_record_data_format*>(
231             fruData + index);
232         fru.fruRSI = (int)le16toh(record->record_set_id);
233         fru.fruRecType = record->record_type;
234         fru.fruNum = record->num_fru_fields;
235         fru.fruEncodeType = record->encoding_type;
236 
237         index += 5;
238 
239         std::ranges::for_each(std::views::iota(0, (int)record->num_fru_fields),
240                               [fruData, &fru, &index](int) {
241             auto tlv =
242                 reinterpret_cast<const pldm_fru_record_tlv*>(fruData + index);
243             FruTLV frutlv;
244             frutlv.fruFieldType = tlv->type;
245             frutlv.fruFieldLen = tlv->length;
246             frutlv.fruFieldValue.resize(tlv->length);
247             for (const auto& i : std::views::iota(0, (int)tlv->length))
248             {
249                 memcpy(frutlv.fruFieldValue.data() + i, tlv->value + i, 1);
250             }
251             fru.fruTLV.push_back(frutlv);
252 
253             // 2: 1byte FRU Field Type, 1byte FRU Field Length
254             index += fruFieldTypeLength + (unsigned)tlv->length;
255         });
256 
257         frus.push_back(fru);
258     }
259 
260     return frus;
261 }
262 } // namespace pdr_utils
263 } // namespace responder
264 } // namespace pldm
265