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 = 178 [&possibleStates, &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