1 #pragma once 2 3 #include "fru_parser.hpp" 4 #include "libpldmresponder/pdr_utils.hpp" 5 #include "oem_handler.hpp" 6 #include "pldmd/handler.hpp" 7 8 #include <libpldm/fru.h> 9 #include <libpldm/pdr.h> 10 11 #include <sdbusplus/message.hpp> 12 13 #include <map> 14 #include <string> 15 #include <variant> 16 #include <vector> 17 18 namespace pldm 19 { 20 21 namespace responder 22 { 23 namespace platform 24 { 25 class Handler; // forward declaration 26 } 27 28 namespace dbus 29 { 30 31 using Value = 32 std::variant<bool, uint8_t, int16_t, uint16_t, int32_t, uint32_t, int64_t, 33 uint64_t, double, std::string, std::vector<uint8_t>, 34 std::vector<uint64_t>, std::vector<std::string>>; 35 using PropertyMap = std::map<Property, Value>; 36 using InterfaceMap = std::map<Interface, PropertyMap>; 37 using ObjectValueTree = std::map<sdbusplus::message::object_path, InterfaceMap>; 38 using ObjectPath = std::string; 39 using AssociatedEntityMap = std::map<ObjectPath, pldm_entity>; 40 using ObjectPathToRSIMap = std::map<ObjectPath, uint16_t>; 41 42 } // namespace dbus 43 44 /** @class FruImpl 45 * 46 * @brief Builds the PLDM FRU table containing the FRU records 47 */ 48 class FruImpl 49 { 50 public: 51 /* @brief Header size for FRU record, it includes the FRU record set 52 * identifier, FRU record type, Number of FRU fields, Encoding type 53 * of FRU fields 54 */ 55 static constexpr size_t recHeaderSize = 56 sizeof(struct pldm_fru_record_data_format) - 57 sizeof(struct pldm_fru_record_tlv); 58 59 /** @brief Constructor for FruImpl, the configPath is consumed to build the 60 * FruParser object. 61 * 62 * @param[in] configPath - path to the directory containing config files 63 * for PLDM FRU 64 * @param[in] fruMasterJsonPath - path to the file containing the FRU D-Bus 65 * Lookup Map 66 * @param[in] pdrRepo - opaque pointer to PDR repository 67 * @param[in] entityTree - opaque pointer to the entity association tree 68 * @param[in] bmcEntityTree - opaque pointer to bmc's entity association 69 * tree 70 * @param[in] oemFruHandler - OEM fru handler 71 */ FruImpl(const std::string & configPath,const std::filesystem::path & fruMasterJsonPath,pldm_pdr * pdrRepo,pldm_entity_association_tree * entityTree,pldm_entity_association_tree * bmcEntityTree)72 FruImpl(const std::string& configPath, 73 const std::filesystem::path& fruMasterJsonPath, pldm_pdr* pdrRepo, 74 pldm_entity_association_tree* entityTree, 75 pldm_entity_association_tree* bmcEntityTree) : 76 parser(configPath, fruMasterJsonPath), pdrRepo(pdrRepo), 77 entityTree(entityTree), bmcEntityTree(bmcEntityTree) 78 {} 79 80 /** @brief Total length of the FRU table in bytes, this includes the pad 81 * bytes and the checksum. 82 * 83 * @return size of the FRU table 84 */ size() const85 uint32_t size() const 86 { 87 return table.size(); 88 } 89 90 /** @brief The checksum of the contents of the FRU table 91 * 92 * @return checksum 93 */ checkSum() const94 uint32_t checkSum() const 95 { 96 return checksum; 97 } 98 99 /** @brief Number of record set identifiers in the FRU tables 100 * 101 * @return number of record set identifiers 102 */ numRSI() const103 uint16_t numRSI() const 104 { 105 return rsi; 106 } 107 108 /** @brief The number of FRU records in the table 109 * 110 * @return number of FRU records 111 */ numRecords() const112 uint16_t numRecords() const 113 { 114 return numRecs; 115 } 116 117 /** @brief Get the FRU table 118 * 119 * @param[out] - Populate response with the FRU table 120 */ 121 void getFRUTable(Response& response); 122 123 /** @brief Get the Fru Table MetaData 124 * 125 */ 126 void getFRURecordTableMetadata(); 127 128 /** @brief Get FRU Record Table By Option 129 * @param[out] response - Populate response with the FRU table got by 130 * options 131 * @param[in] fruTableHandle - The fru table handle 132 * @param[in] recordSetIdentifer - The record set identifier 133 * @param[in] recordType - The record type 134 * @param[in] fieldType - The field type 135 */ 136 int getFRURecordByOption(Response& response, uint16_t fruTableHandle, 137 uint16_t recordSetIdentifer, uint8_t recordType, 138 uint8_t fieldType); 139 140 /** @brief FRU table is built by processing the D-Bus inventory namespace 141 * based on the config files for FRU. The table is populated based 142 * on the isBuilt flag. 143 */ 144 void buildFRUTable(); 145 146 /** @brief Get std::map associated with the entity 147 * key: object path 148 * value: pldm_entity 149 * 150 * @return std::map<ObjectPath, pldm_entity> 151 */ 152 inline const pldm::responder::dbus::AssociatedEntityMap& getAssociateEntityMap() const153 getAssociateEntityMap() const 154 { 155 return associatedEntityMap; 156 } 157 158 /* @brief Method to set the oem platform handler in FRU handler class 159 * 160 * @param[in] handler - oem platform handler 161 */ setOemPlatformHandler(pldm::responder::oem_platform::Handler * handler)162 inline void setOemPlatformHandler( 163 pldm::responder::oem_platform::Handler* handler) 164 { 165 oemPlatformHandler = handler; 166 } 167 168 /** @brief Get pldm entity by the object path 169 * 170 * @param[in] intfMaps - D-Bus interfaces and the associated property 171 * values for the FRU 172 * 173 * @return pldm_entity 174 */ 175 std::optional<pldm_entity> getEntityByObjectPath( 176 const dbus::InterfaceMap& intfMaps); 177 178 /** @brief Update pldm entity to association tree 179 * 180 * @param[in] objects - std::map The object value tree 181 * @param[in] path - Object path 182 * 183 * Ex: Input path = 184 * "/xyz/openbmc_project/inventory/system/chassis/motherboard/powersupply0" 185 * 186 * Get the parent class in turn and store it in a temporary vector 187 * 188 * Output tmpObjPaths = { 189 * "/xyz/openbmc_project/inventory/system", 190 * "/xyz/openbmc_project/inventory/system/chassis/", 191 * "/xyz/openbmc_project/inventory/system/chassis/motherboard", 192 * "/xyz/openbmc_project/inventory/system/chassis/motherboard/powersupply0"} 193 * 194 */ 195 void updateAssociationTree(const dbus::ObjectValueTree& objects, 196 const std::string& path); 197 198 /* @brief Method to populate the firmware version ID 199 * 200 * @return firmware version ID 201 */ 202 std::string populatefwVersion(); 203 204 /* @brief Method to resize the table 205 * 206 * @return resized table 207 */ 208 std::vector<uint8_t> tableResize(); 209 210 /* @brief set FRU Record Table 211 * 212 * @param[in] fruData - the data of the fru 213 * 214 * @return PLDM completion code 215 */ 216 int setFRUTable(const std::vector<uint8_t>& fruData); 217 218 /* @brief Method to set the oem platform handler in fru handler class 219 * 220 * @param[in] handler - oem fru handler 221 */ setOemFruHandler(pldm::responder::oem_fru::Handler * handler)222 inline void setOemFruHandler(pldm::responder::oem_fru::Handler* handler) 223 { 224 oemFruHandler = handler; 225 } 226 setPlatformHandler(pldm::responder::platform::Handler * handler)227 inline void setPlatformHandler(pldm::responder::platform::Handler* handler) 228 { 229 platformHandler = handler; 230 } 231 232 private: nextRSI()233 uint16_t nextRSI() 234 { 235 return ++rsi; 236 } 237 nextRecordHandle()238 uint32_t nextRecordHandle() 239 { 240 return ++rh; 241 } 242 243 uint32_t rh = 0; 244 uint16_t rsi = 0; 245 uint16_t numRecs = 0; 246 uint8_t padBytes = 0; 247 std::vector<uint8_t> table; 248 uint32_t checksum = 0; 249 bool isBuilt = false; 250 251 fru_parser::FruParser parser; 252 pldm_pdr* pdrRepo; 253 pldm_entity_association_tree* entityTree; 254 pldm_entity_association_tree* bmcEntityTree; 255 pldm::responder::oem_fru::Handler* oemFruHandler = nullptr; 256 dbus::ObjectValueTree objects; 257 pldm::responder::platform::Handler* platformHandler = nullptr; 258 259 /** @OEM platform handler */ 260 pldm::responder::oem_platform::Handler* oemPlatformHandler; 261 262 std::map<dbus::ObjectPath, pldm_entity_node*> objToEntityNode{}; 263 264 dbus::ObjectPathToRSIMap objectPathToRSIMap{}; 265 266 pdr_utils::DbusObjMaps effecterDbusObjMaps{}; 267 pdr_utils::DbusObjMaps sensorDbusObjMaps{}; 268 269 /** @brief populateRecord builds the FRU records for an instance of FRU and 270 * updates the FRU table with the FRU records. 271 * 272 * @param[in] interfaces - D-Bus interfaces and the associated property 273 * values for the FRU 274 * @param[in] recordInfos - FRU record info to build the FRU records 275 * @param[in/out] entity - PLDM entity corresponding to FRU instance 276 */ 277 void populateRecords(const dbus::InterfaceMap& interfaces, 278 const fru_parser::FruRecordInfos& recordInfos, 279 const pldm_entity& entity); 280 281 /** @brief Add hotplug record that was modified or added to the PDR entry 282 * HotPlug is a feature where a FRU can be removed or added when 283 * the system is running, without needing it to power off. 284 * 285 * @param[in] pdrEntry - PDR record structure in PDR repository 286 * 287 * @return record handle of added or modified hotplug record 288 */ 289 uint32_t addHotPlugRecord(pldm::responder::pdr_utils::PdrEntry pdrEntry); 290 291 /** @brief Deletes a FRU record from record set table. 292 * @param[in] rsi - the FRU Record Set Identifier 293 * 294 * @return 295 */ 296 void deleteFRURecord(uint16_t rsi); 297 298 /** @brief Deletes a FRU record set PDR and it's associated PDRs after 299 * a concurrent remove operation. 300 * @param[in] fruObjectPath - the FRU object path 301 * @return 302 */ 303 void removeIndividualFRU(const std::string& fruObjPath); 304 305 /** @brief Associate sensor/effecter to FRU entity 306 */ 307 dbus::AssociatedEntityMap associatedEntityMap; 308 }; 309 310 namespace fru 311 { 312 313 class Handler : public CmdHandler 314 { 315 public: Handler(const std::string & configPath,const std::filesystem::path & fruMasterJsonPath,pldm_pdr * pdrRepo,pldm_entity_association_tree * entityTree,pldm_entity_association_tree * bmcEntityTree)316 Handler(const std::string& configPath, 317 const std::filesystem::path& fruMasterJsonPath, pldm_pdr* pdrRepo, 318 pldm_entity_association_tree* entityTree, 319 pldm_entity_association_tree* bmcEntityTree) : 320 impl(configPath, fruMasterJsonPath, pdrRepo, entityTree, bmcEntityTree) 321 { 322 handlers.emplace( 323 PLDM_GET_FRU_RECORD_TABLE_METADATA, 324 [this](pldm_tid_t, const pldm_msg* request, size_t payloadLength) { 325 return this->getFRURecordTableMetadata(request, payloadLength); 326 }); 327 handlers.emplace( 328 PLDM_GET_FRU_RECORD_TABLE, 329 [this](pldm_tid_t, const pldm_msg* request, size_t payloadLength) { 330 return this->getFRURecordTable(request, payloadLength); 331 }); 332 handlers.emplace( 333 PLDM_GET_FRU_RECORD_BY_OPTION, 334 [this](pldm_tid_t, const pldm_msg* request, size_t payloadLength) { 335 return this->getFRURecordByOption(request, payloadLength); 336 }); 337 handlers.emplace( 338 PLDM_SET_FRU_RECORD_TABLE, 339 [this](pldm_tid_t, const pldm_msg* request, size_t payloadLength) { 340 return this->setFRURecordTable(request, payloadLength); 341 }); 342 } 343 344 /** @brief Handler for Get FRURecordTableMetadata 345 * 346 * @param[in] request - Request message payload 347 * @param[in] payloadLength - Request payload length 348 * 349 * @return PLDM response message 350 */ 351 Response getFRURecordTableMetadata(const pldm_msg* request, 352 size_t payloadLength); 353 354 /** @brief Handler for GetFRURecordTable 355 * 356 * @param[in] request - Request message payload 357 * @param[in] payloadLength - Request payload length 358 * 359 * @return PLDM response message 360 */ 361 Response getFRURecordTable(const pldm_msg* request, size_t payloadLength); 362 363 /** @brief Build FRU table is bnot already built 364 * 365 */ buildFRUTable()366 void buildFRUTable() 367 { 368 impl.buildFRUTable(); 369 } 370 371 /** @brief Get std::map associated with the entity 372 * key: object path 373 * value: pldm_entity 374 * 375 * @return std::map<ObjectPath, pldm_entity> 376 */ getAssociateEntityMap() const377 const pldm::responder::dbus::AssociatedEntityMap& getAssociateEntityMap() 378 const 379 { 380 return impl.getAssociateEntityMap(); 381 } 382 383 /* @brief Method to set the oem platform handler in host pdr handler class 384 * 385 * @param[in] handler - oem platform handler 386 */ setOemPlatformHandler(pldm::responder::oem_platform::Handler * handler)387 void setOemPlatformHandler(pldm::responder::oem_platform::Handler* handler) 388 { 389 return impl.setOemPlatformHandler(handler); 390 } 391 392 /** @brief Handler for GetFRURecordByOption 393 * 394 * @param[in] request - Request message payload 395 * @param[in] payloadLength - Request payload length 396 * 397 * @return PLDM response message 398 */ 399 Response getFRURecordByOption(const pldm_msg* request, 400 size_t payloadLength); 401 402 /** @brief Handler for SetFRURecordTable 403 * 404 * @param[in] request - Request message 405 * @param[in] payloadLength - Request payload length 406 * 407 * @return PLDM response message 408 */ 409 Response setFRURecordTable(const pldm_msg* request, size_t payloadLength); 410 411 /* @brief Method to set the oem platform handler in fru handler class 412 * 413 * @param[in] handler - oem fru handler 414 */ setOemFruHandler(pldm::responder::oem_fru::Handler * handler)415 void setOemFruHandler(pldm::responder::oem_fru::Handler* handler) 416 { 417 impl.setOemFruHandler(handler); 418 } 419 setPlatformHandler(pldm::responder::platform::Handler * handler)420 void setPlatformHandler(pldm::responder::platform::Handler* handler) 421 { 422 impl.setPlatformHandler(handler); 423 } 424 425 using Table = std::vector<uint8_t>; 426 427 private: 428 FruImpl impl; 429 }; 430 431 } // namespace fru 432 433 } // namespace responder 434 435 } // namespace pldm 436