1 #pragma once 2 3 #include "types.hpp" 4 5 #include <libpldm/base.h> 6 #include <libpldm/bios.h> 7 #include <libpldm/entity.h> 8 #include <libpldm/pdr.h> 9 #include <libpldm/platform.h> 10 #include <libpldm/utils.h> 11 #include <stdint.h> 12 #include <systemd/sd-bus.h> 13 #include <unistd.h> 14 15 #include <nlohmann/json.hpp> 16 #include <sdbusplus/server.hpp> 17 #include <xyz/openbmc_project/Logging/Entry/server.hpp> 18 19 #include <deque> 20 #include <exception> 21 #include <filesystem> 22 #include <iostream> 23 #include <map> 24 #include <string> 25 #include <variant> 26 #include <vector> 27 28 constexpr uint64_t dbusTimeout = 29 std::chrono::duration_cast<std::chrono::microseconds>( 30 std::chrono::seconds(DBUS_TIMEOUT)) 31 .count(); 32 33 namespace pldm 34 { 35 using Severity = pldm::PelSeverity; 36 37 // mapping of severity enum to severity interface 38 static std::unordered_map<Severity, std::string> sevMap = { 39 {Severity::Informational, 40 "xyz.openbmc_project.Logging.Entry.Level.Informational"}, 41 {Severity::Debug, "xyz.openbmc_project.Logging.Entry.Level.Debug"}, 42 {Severity::Notice, "xyz.openbmc_project.Logging.Entry.Level.Notice"}, 43 {Severity::Warning, "xyz.openbmc_project.Logging.Entry.Level.Warning"}, 44 {Severity::Critical, "xyz.openbmc_project.Logging.Entry.Level.Critical"}, 45 {Severity::Emergency, "xyz.openbmc_project.Logging.Entry.Level.Emergency"}, 46 {Severity::Error, "xyz.openbmc_project.Logging.Entry.Level.Error"}, 47 {Severity::Alert, "xyz.openbmc_project.Logging.Entry.Level.Alert"}}; 48 49 namespace utils 50 { 51 namespace fs = std::filesystem; 52 using Json = nlohmann::json; 53 constexpr bool Tx = true; 54 constexpr bool Rx = false; 55 56 using EntityName = std::string; 57 using EntityType = uint16_t; 58 59 using Entities = std::vector<pldm_entity_node*>; 60 using EntityAssociations = std::vector<Entities>; 61 using ObjectPathMaps = std::map<fs::path, pldm_entity_node*>; 62 63 const std::map<EntityType, EntityName> entityMaps = { 64 {PLDM_ENTITY_SYSTEM_CHASSIS, "chassis"}, 65 {PLDM_ENTITY_BOARD, "io_board"}, 66 {PLDM_ENTITY_SYS_BOARD, "motherboard"}, 67 {PLDM_ENTITY_POWER_SUPPLY, "powersupply"}, 68 {PLDM_ENTITY_PROC, "cpu"}, 69 {PLDM_ENTITY_SYSTEM_CHASSIS | 0x8000, "system"}, 70 {PLDM_ENTITY_PROC_MODULE, "dcm"}, 71 {PLDM_ENTITY_PROC | 0x8000, "core"}, 72 {PLDM_ENTITY_IO_MODULE, "io_module"}, 73 {PLDM_ENTITY_FAN, "fan"}, 74 {PLDM_ENTITY_SYS_MGMT_MODULE, "system_management_module"}, 75 {PLDM_ENTITY_POWER_CONVERTER, "power_converter"}, 76 {PLDM_ENTITY_SLOT, "slot"}, 77 {PLDM_ENTITY_CONNECTOR, "connector"}}; 78 79 /** @brief Vector a entity name to pldm_entity from entity association tree 80 * @param[in] entityAssoc - Vector of associated pldm entities 81 * @param[in] entityTree - entity association tree 82 * @param[out] objPathMap - maps an object path to pldm_entity from the 83 * BMC's entity association tree 84 * @return 85 */ 86 void updateEntityAssociation(const EntityAssociations& entityAssoc, 87 pldm_entity_association_tree* entityTree, 88 ObjectPathMaps& objPathMap); 89 90 /** @struct CustomFD 91 * 92 * RAII wrapper for file descriptor. 93 */ 94 struct CustomFD 95 { 96 CustomFD(const CustomFD&) = delete; 97 CustomFD& operator=(const CustomFD&) = delete; 98 CustomFD(CustomFD&&) = delete; 99 CustomFD& operator=(CustomFD&&) = delete; 100 101 CustomFD(int fd) : fd(fd) {} 102 103 ~CustomFD() 104 { 105 if (fd >= 0) 106 { 107 close(fd); 108 } 109 } 110 111 int operator()() const 112 { 113 return fd; 114 } 115 116 private: 117 int fd = -1; 118 }; 119 120 /** @brief Calculate the pad for PLDM data 121 * 122 * @param[in] data - Length of the data 123 * @return - uint8_t - number of pad bytes 124 */ 125 uint8_t getNumPadBytes(uint32_t data); 126 127 /** @brief Convert uint64 to date 128 * 129 * @param[in] data - time date of uint64 130 * @param[out] year - year number in dec 131 * @param[out] month - month number in dec 132 * @param[out] day - day of the month in dec 133 * @param[out] hour - number of hours in dec 134 * @param[out] min - number of minutes in dec 135 * @param[out] sec - number of seconds in dec 136 * @return true if decode success, false if decode faild 137 */ 138 bool uintToDate(uint64_t data, uint16_t* year, uint8_t* month, uint8_t* day, 139 uint8_t* hour, uint8_t* min, uint8_t* sec); 140 141 /** @brief Convert effecter data to structure of set_effecter_state_field 142 * 143 * @param[in] effecterData - the date of effecter 144 * @param[in] effecterCount - the number of individual sets of effecter 145 * information 146 * @return[out] parse success and get a valid set_effecter_state_field 147 * structure, return nullopt means parse failed 148 */ 149 std::optional<std::vector<set_effecter_state_field>> 150 parseEffecterData(const std::vector<uint8_t>& effecterData, 151 uint8_t effecterCount); 152 153 /** 154 * @brief creates an error log 155 * @param[in] errorMsg - the error message 156 * @param[in] sev - severity of the log 157 * 158 */ 159 void reportError(const char* errorMsg, 160 const PelSeverity& sev = pldm::PelSeverity::Error); 161 162 /** @brief Convert any Decimal number to BCD 163 * 164 * @tparam[in] decimal - Decimal number 165 * @return Corresponding BCD number 166 */ 167 template <typename T> 168 T decimalToBcd(T decimal) 169 { 170 T bcd = 0; 171 T rem = 0; 172 auto cnt = 0; 173 174 while (decimal) 175 { 176 rem = decimal % 10; 177 bcd = bcd + (rem << cnt); 178 decimal = decimal / 10; 179 cnt += 4; 180 } 181 182 return bcd; 183 } 184 185 constexpr auto dbusProperties = "org.freedesktop.DBus.Properties"; 186 constexpr auto mapperService = "xyz.openbmc_project.ObjectMapper"; 187 188 struct DBusMapping 189 { 190 std::string objectPath; //!< D-Bus object path 191 std::string interface; //!< D-Bus interface 192 std::string propertyName; //!< D-Bus property name 193 std::string propertyType; //!< D-Bus property type 194 }; 195 196 using PropertyValue = 197 std::variant<bool, uint8_t, int16_t, uint16_t, int32_t, uint32_t, int64_t, 198 uint64_t, double, std::string, std::vector<std::string>>; 199 using DbusProp = std::string; 200 using DbusChangedProps = std::map<DbusProp, PropertyValue>; 201 using DBusInterfaceAdded = std::vector< 202 std::pair<pldm::dbus::Interface, 203 std::vector<std::pair<pldm::dbus::Property, 204 std::variant<pldm::dbus::Property>>>>>; 205 using ObjectPath = std::string; 206 using ServiceName = std::string; 207 using Interfaces = std::vector<std::string>; 208 using MapperServiceMap = std::vector<std::pair<ServiceName, Interfaces>>; 209 using GetSubTreeResponse = std::vector<std::pair<ObjectPath, MapperServiceMap>>; 210 using PropertyMap = std::map<std::string, PropertyValue>; 211 using InterfaceMap = std::map<std::string, PropertyMap>; 212 213 /** 214 * @brief The interface for DBusHandler 215 */ 216 class DBusHandlerInterface 217 { 218 public: 219 virtual ~DBusHandlerInterface() = default; 220 221 virtual std::string getService(const char* path, 222 const char* interface) const = 0; 223 virtual GetSubTreeResponse 224 getSubtree(const std::string& path, int depth, 225 const std::vector<std::string>& ifaceList) const = 0; 226 227 virtual void setDbusProperty(const DBusMapping& dBusMap, 228 const PropertyValue& value) const = 0; 229 230 virtual PropertyValue 231 getDbusPropertyVariant(const char* objPath, const char* dbusProp, 232 const char* dbusInterface) const = 0; 233 }; 234 235 /** 236 * @class DBusHandler 237 * 238 * Wrapper class to handle the D-Bus calls 239 * 240 * This class contains the APIs to handle the D-Bus calls 241 * to cater the request from pldm requester. 242 * A class is created to mock the apis in the test cases 243 */ 244 class DBusHandler : public DBusHandlerInterface 245 { 246 public: 247 /** @brief Get the bus connection. */ 248 static auto& getBus() 249 { 250 static auto bus = sdbusplus::bus::new_default(); 251 return bus; 252 } 253 254 /** 255 * @brief Get the DBUS Service name for the input dbus path 256 * 257 * @param[in] path - DBUS object path 258 * @param[in] interface - DBUS Interface 259 * 260 * @return std::string - the dbus service name 261 * 262 * @throw sdbusplus::exception_t when it fails 263 */ 264 std::string getService(const char* path, 265 const char* interface) const override; 266 267 /** 268 * @brief Get the Subtree response from the mapper 269 * 270 * @param[in] path - DBUS object path 271 * @param[in] depth - Search depth 272 * @param[in] ifaceList - list of the interface that are being 273 * queried from the mapper 274 * 275 * @return GetSubTreeResponse - the mapper subtree response 276 * 277 * @throw sdbusplus::exception_t when it fails 278 */ 279 GetSubTreeResponse 280 getSubtree(const std::string& path, int depth, 281 const std::vector<std::string>& ifaceList) const override; 282 283 /** @brief Get property(type: variant) from the requested dbus 284 * 285 * @param[in] objPath - The Dbus object path 286 * @param[in] dbusProp - The property name to get 287 * @param[in] dbusInterface - The Dbus interface 288 * 289 * @return The value of the property(type: variant) 290 * 291 * @throw sdbusplus::exception_t when it fails 292 */ 293 PropertyValue 294 getDbusPropertyVariant(const char* objPath, const char* dbusProp, 295 const char* dbusInterface) const override; 296 297 /** @brief The template function to get property from the requested dbus 298 * path 299 * 300 * @tparam Property - Excepted type of the property on dbus 301 * 302 * @param[in] objPath - The Dbus object path 303 * @param[in] dbusProp - The property name to get 304 * @param[in] dbusInterface - The Dbus interface 305 * 306 * @return The value of the property 307 * 308 * @throw sdbusplus::exception_t when dbus request fails 309 * std::bad_variant_access when \p Property and property on dbus do 310 * not match 311 */ 312 template <typename Property> 313 auto getDbusProperty(const char* objPath, const char* dbusProp, 314 const char* dbusInterface) 315 { 316 auto VariantValue = getDbusPropertyVariant(objPath, dbusProp, 317 dbusInterface); 318 return std::get<Property>(VariantValue); 319 } 320 321 /** @brief Set Dbus property 322 * 323 * @param[in] dBusMap - Object path, property name, interface and property 324 * type for the D-Bus object 325 * @param[in] value - The value to be set 326 * 327 * @throw sdbusplus::exception_t when it fails 328 */ 329 void setDbusProperty(const DBusMapping& dBusMap, 330 const PropertyValue& value) const override; 331 }; 332 333 /** @brief Fetch parent D-Bus object based on pathname 334 * 335 * @param[in] dbusObj - child D-Bus object 336 * 337 * @return std::string - the parent D-Bus object path 338 */ 339 inline std::string findParent(const std::string& dbusObj) 340 { 341 fs::path p(dbusObj); 342 return p.parent_path().string(); 343 } 344 345 /** @brief Read (static) MCTP EID of host firmware from a file 346 * 347 * @return uint8_t - MCTP EID 348 */ 349 uint8_t readHostEID(); 350 351 /** @brief Convert a value in the JSON to a D-Bus property value 352 * 353 * @param[in] type - type of the D-Bus property 354 * @param[in] value - value in the JSON file 355 * 356 * @return PropertyValue - the D-Bus property value 357 */ 358 PropertyValue jsonEntryToDbusVal(std::string_view type, 359 const nlohmann::json& value); 360 361 /** @brief Find State Effecter PDR 362 * @param[in] tid - PLDM terminus ID. 363 * @param[in] entityID - entity that can be associated with PLDM State set. 364 * @param[in] stateSetId - value that identifies PLDM State set. 365 * @param[in] repo - pointer to BMC's primary PDR repo. 366 * @return array[array[uint8_t]] - StateEffecterPDRs 367 */ 368 std::vector<std::vector<uint8_t>> findStateEffecterPDR(uint8_t tid, 369 uint16_t entityID, 370 uint16_t stateSetId, 371 const pldm_pdr* repo); 372 /** @brief Find State Sensor PDR 373 * @param[in] tid - PLDM terminus ID. 374 * @param[in] entityID - entity that can be associated with PLDM State set. 375 * @param[in] stateSetId - value that identifies PLDM State set. 376 * @param[in] repo - pointer to BMC's primary PDR repo. 377 * @return array[array[uint8_t]] - StateSensorPDRs 378 */ 379 std::vector<std::vector<uint8_t>> findStateSensorPDR(uint8_t tid, 380 uint16_t entityID, 381 uint16_t stateSetId, 382 const pldm_pdr* repo); 383 384 /** @brief Find sensor id from a state sensor PDR 385 * 386 * @param[in] pdrRepo - PDR repository 387 * @param[in] tid - terminus id 388 * @param[in] entityType - entity type 389 * @param[in] entityInstance - entity instance number 390 * @param[in] containerId - container id 391 * @param[in] stateSetId - state set id 392 * 393 * @return uint16_t - the sensor id 394 */ 395 uint16_t findStateSensorId(const pldm_pdr* pdrRepo, uint8_t tid, 396 uint16_t entityType, uint16_t entityInstance, 397 uint16_t containerId, uint16_t stateSetId); 398 399 /** @brief Find effecter id from a state effecter pdr 400 * @param[in] pdrRepo - PDR repository 401 * @param[in] entityType - entity type 402 * @param[in] entityInstance - entity instance number 403 * @param[in] containerId - container id 404 * @param[in] stateSetId - state set id 405 * @param[in] localOrRemote - true for checking local repo and false for remote 406 * repo 407 * 408 * @return uint16_t - the effecter id 409 */ 410 uint16_t findStateEffecterId(const pldm_pdr* pdrRepo, uint16_t entityType, 411 uint16_t entityInstance, uint16_t containerId, 412 uint16_t stateSetId, bool localOrRemote); 413 414 /** @brief Emit the sensor event signal 415 * 416 * @param[in] tid - the terminus id 417 * @param[in] sensorId - sensorID value of the sensor 418 * @param[in] sensorOffset - Identifies which state sensor within a 419 * composite state sensor the event is being returned for 420 * @param[in] eventState - The event state value from the state change that 421 * triggered the event message 422 * @param[in] previousEventState - The event state value for the state from 423 * which the present event state was entered. 424 * @return PLDM completion code 425 */ 426 int emitStateSensorEventSignal(uint8_t tid, uint16_t sensorId, 427 uint8_t sensorOffset, uint8_t eventState, 428 uint8_t previousEventState); 429 430 /** @brief Print the buffer 431 * 432 * @param[in] isTx - True if the buffer is an outgoing PLDM message, false if 433 the buffer is an incoming PLDM message 434 * @param[in] buffer - Buffer to print 435 * 436 * @return - None 437 */ 438 void printBuffer(bool isTx, const std::vector<uint8_t>& buffer); 439 440 /** @brief Convert the buffer to std::string 441 * 442 * If there are characters that are not printable characters, it is replaced 443 * with space(0x20). 444 * 445 * @param[in] var - pointer to data and length of the data 446 * 447 * @return std::string equivalent of variable field 448 */ 449 std::string toString(const struct variable_field& var); 450 451 /** @brief Split strings according to special identifiers 452 * 453 * We can split the string according to the custom identifier(';', ',', '&' or 454 * others) and store it to vector. 455 * 456 * @param[in] srcStr - The string to be split 457 * @param[in] delim - The custom identifier 458 * @param[in] trimStr - The first and last string to be trimmed 459 * 460 * @return std::vector<std::string> Vectors are used to store strings 461 */ 462 std::vector<std::string> split(std::string_view srcStr, std::string_view delim, 463 std::string_view trimStr = ""); 464 /** @brief Get the current system time in readable format 465 * 466 * @return - std::string equivalent of the system time 467 */ 468 std::string getCurrentSystemTime(); 469 470 /** @brief checks if the FRU is actually present. 471 * @param[in] objPath - FRU object path. 472 * 473 * @return bool to indicate presence or absence of FRU. 474 */ 475 bool checkForFruPresence(const std::string& objPath); 476 477 /** @brief Method to check if the logical bit is set 478 * 479 * @param[containerId] - container id of the entity 480 * 481 * @return true or false based on the logic bit set 482 */ 483 bool checkIfLogicalBitSet(const uint16_t& containerId); 484 485 /** @brief setting the present property 486 * 487 * @param[in] objPath - the object path of the fru 488 * @param[in] present - status to set either true/false 489 */ 490 void setFruPresence(const std::string& fruObjPath, bool present); 491 } // namespace utils 492 } // namespace pldm 493