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
getPdr() const29 pldm_pdr* Repo::getPdr() const
30 {
31 return repo;
32 }
33
addRecord(const PdrEntry & pdrEntry)34 RecordHandle Repo::addRecord(const PdrEntry& pdrEntry)
35 {
36 uint32_t handle = pdrEntry.handle.recordHandle;
37 int rc = pldm_pdr_add(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
getFirstRecord(PdrEntry & pdrEntry)47 const pldm_pdr_record* Repo::getFirstRecord(PdrEntry& pdrEntry)
48 {
49 constexpr uint32_t firstNum = 0;
50 uint8_t* pdrData = nullptr;
51 auto record =
52 pldm_pdr_find_record(getPdr(), firstNum, &pdrData, &pdrEntry.size,
53 &pdrEntry.handle.nextRecordHandle);
54 if (record)
55 {
56 pdrEntry.data = pdrData;
57 }
58
59 return record;
60 }
61
getNextRecord(const pldm_pdr_record * currRecord,PdrEntry & pdrEntry)62 const pldm_pdr_record* Repo::getNextRecord(const pldm_pdr_record* currRecord,
63 PdrEntry& pdrEntry)
64 {
65 uint8_t* pdrData = nullptr;
66 auto record =
67 pldm_pdr_get_next_record(getPdr(), currRecord, &pdrData, &pdrEntry.size,
68 &pdrEntry.handle.nextRecordHandle);
69 if (record)
70 {
71 pdrEntry.data = pdrData;
72 }
73
74 return record;
75 }
76
getRecordHandle(const pldm_pdr_record * record) const77 uint32_t Repo::getRecordHandle(const pldm_pdr_record* record) const
78 {
79 return pldm_pdr_get_record_handle(getPdr(), record);
80 }
81
getRecordCount()82 uint32_t Repo::getRecordCount()
83 {
84 return pldm_pdr_get_record_count(getPdr());
85 }
86
empty()87 bool Repo::empty()
88 {
89 return !getRecordCount();
90 }
91
populateMapping(const std::string & type,const Json & dBusValues,const PossibleValues & pv)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>
parseStateSensorPDR(const std::vector<uint8_t> & stateSensorPdr)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,size_t fruLen)213 parseFruRecordTable(const uint8_t* fruData, 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(
243 std::views::iota(0, (int)record->num_fru_fields),
244 [fruData, &fru, &index](int) {
245 auto tlv = reinterpret_cast<const pldm_fru_record_tlv*>(
246 fruData + index);
247 FruTLV frutlv;
248 frutlv.fruFieldType = tlv->type;
249 frutlv.fruFieldLen = tlv->length;
250 frutlv.fruFieldValue.resize(tlv->length);
251 for (const auto& i : std::views::iota(0, (int)tlv->length))
252 {
253 memcpy(frutlv.fruFieldValue.data() + i, tlv->value + i, 1);
254 }
255 fru.fruTLV.push_back(frutlv);
256
257 // 2: 1byte FRU Field Type, 1byte FRU Field Length
258 index += fruFieldTypeLength + (unsigned)tlv->length;
259 });
260
261 frus.push_back(fru);
262 }
263
264 return frus;
265 }
266
getEffecterDataSize(uint8_t effecterDataSize)267 size_t getEffecterDataSize(uint8_t effecterDataSize)
268 {
269 switch (effecterDataSize)
270 {
271 case PLDM_EFFECTER_DATA_SIZE_UINT8:
272 return sizeof(uint8_t);
273 case PLDM_EFFECTER_DATA_SIZE_SINT8:
274 return sizeof(int8_t);
275 case PLDM_EFFECTER_DATA_SIZE_UINT16:
276 return sizeof(uint16_t);
277 case PLDM_EFFECTER_DATA_SIZE_SINT16:
278 return sizeof(int16_t);
279 case PLDM_EFFECTER_DATA_SIZE_UINT32:
280 return sizeof(uint32_t);
281 case PLDM_EFFECTER_DATA_SIZE_SINT32:
282 return sizeof(int32_t);
283 default:
284 return 0;
285 }
286 }
287
288 } // namespace pdr_utils
289 } // namespace responder
290 } // namespace pldm
291