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