| Alexander Hansen | 4e1142d | 2025-07-25 17:07:27 +0200 | [diff] [blame] | 1 | // SPDX-License-Identifier: Apache-2.0 | 
|  | 2 | // SPDX-FileCopyrightText: Copyright 2018 Intel Corporation | 
| Patrick Venture | ab29641 | 2020-12-30 13:39:37 -0800 | [diff] [blame] | 3 |  | 
|  | 4 | #pragma once | 
| Zev Weiss | 309c0b1 | 2022-02-25 01:44:12 +0000 | [diff] [blame] | 5 | #include "fru_reader.hpp" | 
| Ed Tanous | 3013fb4 | 2022-07-09 08:27:06 -0700 | [diff] [blame] | 6 |  | 
| Kumar Thangavel | c8dc4af | 2021-01-12 10:36:38 +0530 | [diff] [blame] | 7 | #include <boost/container/flat_map.hpp> | 
| Kumar Thangavel | d79d025 | 2022-08-24 14:26:01 +0530 | [diff] [blame] | 8 | #include <sdbusplus/asio/object_server.hpp> | 
| Patrick Venture | ab29641 | 2020-12-30 13:39:37 -0800 | [diff] [blame] | 9 |  | 
|  | 10 | #include <cstdint> | 
| Patrick Williams | b9a1f96 | 2024-07-13 16:34:49 -0500 | [diff] [blame] | 11 | #include <cstdio> | 
| Patrick Venture | ab29641 | 2020-12-30 13:39:37 -0800 | [diff] [blame] | 12 | #include <functional> | 
| Kumar Thangavel | c8dc4af | 2021-01-12 10:36:38 +0530 | [diff] [blame] | 13 | #include <regex> | 
| Patrick Venture | ab29641 | 2020-12-30 13:39:37 -0800 | [diff] [blame] | 14 | #include <string> | 
| Kumar Thangavel | c8dc4af | 2021-01-12 10:36:38 +0530 | [diff] [blame] | 15 | #include <utility> | 
| Patrick Venture | ab29641 | 2020-12-30 13:39:37 -0800 | [diff] [blame] | 16 | #include <vector> | 
| Patrick Venture | ab29641 | 2020-12-30 13:39:37 -0800 | [diff] [blame] | 17 | extern "C" | 
|  | 18 | { | 
|  | 19 | // Include for I2C_SMBUS_BLOCK_MAX | 
|  | 20 | #include <linux/i2c.h> | 
|  | 21 | } | 
|  | 22 |  | 
| Kumar Thangavel | c8dc4af | 2021-01-12 10:36:38 +0530 | [diff] [blame] | 23 | constexpr size_t fruBlockSize = 8; | 
|  | 24 |  | 
| Kumar Thangavel | c74e751 | 2022-02-03 22:53:05 +0530 | [diff] [blame] | 25 | using DeviceMap = boost::container::flat_map<int, std::vector<uint8_t>>; | 
|  | 26 | using BusMap = boost::container::flat_map<int, std::shared_ptr<DeviceMap>>; | 
|  | 27 |  | 
| Ed Tanous | fc17142 | 2024-04-04 17:18:16 -0700 | [diff] [blame] | 28 | // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) | 
| Kumar Thangavel | c74e751 | 2022-02-03 22:53:05 +0530 | [diff] [blame] | 29 | inline BusMap busMap; | 
|  | 30 |  | 
| Kumar Thangavel | c8dc4af | 2021-01-12 10:36:38 +0530 | [diff] [blame] | 31 | enum class DecodeState | 
|  | 32 | { | 
|  | 33 | ok, | 
|  | 34 | end, | 
|  | 35 | err, | 
|  | 36 | }; | 
|  | 37 |  | 
|  | 38 | enum class resCodes | 
|  | 39 | { | 
|  | 40 | resOK, | 
|  | 41 | resWarn, | 
|  | 42 | resErr | 
|  | 43 | }; | 
|  | 44 |  | 
| Patrick Venture | ab29641 | 2020-12-30 13:39:37 -0800 | [diff] [blame] | 45 | enum class fruAreas | 
|  | 46 | { | 
|  | 47 | fruAreaInternal = 0, | 
|  | 48 | fruAreaChassis, | 
|  | 49 | fruAreaBoard, | 
|  | 50 | fruAreaProduct, | 
|  | 51 | fruAreaMultirecord | 
|  | 52 | }; | 
| Kumar Thangavel | c8dc4af | 2021-01-12 10:36:38 +0530 | [diff] [blame] | 53 |  | 
| Kumar Thangavel | bdfc5ec | 2022-08-29 22:23:00 +0530 | [diff] [blame] | 54 | struct FruArea | 
|  | 55 | { | 
|  | 56 | size_t start;          // Fru Area Start offset | 
|  | 57 | size_t size;           // Fru Area Size | 
|  | 58 | size_t end;            // Fru Area end offset | 
|  | 59 | size_t updateFieldLoc; // Fru Area update Field Location | 
| Kumar Thangavel | 51b557b | 2022-09-13 13:40:47 +0530 | [diff] [blame] | 60 | size_t restFieldsLoc;  // Starting location of restFRUArea data | 
|  | 61 | size_t restFieldsEnd;  // Ending location of restFRUArea data | 
| Kumar Thangavel | bdfc5ec | 2022-08-29 22:23:00 +0530 | [diff] [blame] | 62 | }; | 
|  | 63 |  | 
| Ed Tanous | 07d467b | 2021-02-23 14:48:37 -0800 | [diff] [blame] | 64 | const std::vector<std::string> fruAreaNames = {"INTERNAL", "CHASSIS", "BOARD", | 
|  | 65 | "PRODUCT", "MULTIRECORD"}; | 
|  | 66 | const std::regex nonAsciiRegex("[^\x01-\x7f]"); | 
| Kumar Thangavel | c8dc4af | 2021-01-12 10:36:38 +0530 | [diff] [blame] | 67 |  | 
| Ed Tanous | 07d467b | 2021-02-23 14:48:37 -0800 | [diff] [blame] | 68 | const std::vector<std::string> chassisFruAreas = {"PART_NUMBER", | 
|  | 69 | "SERIAL_NUMBER"}; | 
| Kumar Thangavel | c8dc4af | 2021-01-12 10:36:38 +0530 | [diff] [blame] | 70 |  | 
| Patrick Williams | b707743 | 2024-08-16 15:22:21 -0400 | [diff] [blame] | 71 | const std::vector<std::string> boardFruAreas = { | 
|  | 72 | "MANUFACTURER", "PRODUCT_NAME", "SERIAL_NUMBER", "PART_NUMBER", | 
|  | 73 | "FRU_VERSION_ID"}; | 
| Kumar Thangavel | c8dc4af | 2021-01-12 10:36:38 +0530 | [diff] [blame] | 74 |  | 
| Ed Tanous | 07d467b | 2021-02-23 14:48:37 -0800 | [diff] [blame] | 75 | const std::vector<std::string> productFruAreas = { | 
| Kumar Thangavel | c8dc4af | 2021-01-12 10:36:38 +0530 | [diff] [blame] | 76 | "MANUFACTURER",  "PRODUCT_NAME", "PART_NUMBER",   "VERSION", | 
|  | 77 | "SERIAL_NUMBER", "ASSET_TAG",    "FRU_VERSION_ID"}; | 
|  | 78 |  | 
| Ed Tanous | 07d467b | 2021-02-23 14:48:37 -0800 | [diff] [blame] | 79 | const std::string fruCustomFieldName = "INFO_AM"; | 
| Kumar Thangavel | c8dc4af | 2021-01-12 10:36:38 +0530 | [diff] [blame] | 80 |  | 
| Patrick Venture | ab29641 | 2020-12-30 13:39:37 -0800 | [diff] [blame] | 81 | inline fruAreas operator++(fruAreas& x) | 
|  | 82 | { | 
| Patrick Williams | b707743 | 2024-08-16 15:22:21 -0400 | [diff] [blame] | 83 | return x = static_cast<fruAreas>( | 
|  | 84 | std::underlying_type<fruAreas>::type(x) + 1); | 
| Patrick Venture | ab29641 | 2020-12-30 13:39:37 -0800 | [diff] [blame] | 85 | } | 
|  | 86 |  | 
| Kumar Thangavel | c8dc4af | 2021-01-12 10:36:38 +0530 | [diff] [blame] | 87 | inline const std::string& getFruAreaName(fruAreas area) | 
|  | 88 | { | 
| Ed Tanous | 07d467b | 2021-02-23 14:48:37 -0800 | [diff] [blame] | 89 | return fruAreaNames[static_cast<unsigned int>(area)]; | 
| Kumar Thangavel | c8dc4af | 2021-01-12 10:36:38 +0530 | [diff] [blame] | 90 | } | 
|  | 91 |  | 
| Delphine CC Chiu | a3ca14a | 2024-03-27 17:02:24 +0800 | [diff] [blame] | 92 | std::tm intelEpoch(); | 
| Kumar Thangavel | c8dc4af | 2021-01-12 10:36:38 +0530 | [diff] [blame] | 93 |  | 
|  | 94 | char sixBitToChar(uint8_t val); | 
|  | 95 |  | 
|  | 96 | /* 0xd - 0xf are reserved values, but not fatal; use a placeholder char. */ | 
| Ed Tanous | 3013fb4 | 2022-07-09 08:27:06 -0700 | [diff] [blame] | 97 | constexpr std::array<char, 6> bcdHighChars = { | 
| Kumar Thangavel | c8dc4af | 2021-01-12 10:36:38 +0530 | [diff] [blame] | 98 | ' ', '-', '.', 'X', 'X', 'X', | 
|  | 99 | }; | 
|  | 100 |  | 
|  | 101 | char bcdPlusToChar(uint8_t val); | 
|  | 102 |  | 
| Ed Tanous | 23e3f45 | 2025-04-08 10:37:56 -0700 | [diff] [blame] | 103 | bool verifyOffset(std::span<const uint8_t> fruBytes, fruAreas currentArea, | 
| Kumar Thangavel | c8dc4af | 2021-01-12 10:36:38 +0530 | [diff] [blame] | 104 | uint8_t len); | 
|  | 105 |  | 
| Patrick Williams | b707743 | 2024-08-16 15:22:21 -0400 | [diff] [blame] | 106 | std::pair<DecodeState, std::string> decodeFRUData( | 
| Ed Tanous | 23e3f45 | 2025-04-08 10:37:56 -0700 | [diff] [blame] | 107 | std::span<const uint8_t>::const_iterator& iter, | 
|  | 108 | std::span<const uint8_t>::const_iterator& end, bool isLangEng); | 
| Kumar Thangavel | c8dc4af | 2021-01-12 10:36:38 +0530 | [diff] [blame] | 109 |  | 
|  | 110 | bool checkLangEng(uint8_t lang); | 
|  | 111 |  | 
| Patrick Williams | 5a80703 | 2025-03-03 11:20:39 -0500 | [diff] [blame] | 112 | resCodes formatIPMIFRU( | 
| Ed Tanous | 23e3f45 | 2025-04-08 10:37:56 -0700 | [diff] [blame] | 113 | std::span<const uint8_t> fruBytes, | 
| Patrick Williams | 5a80703 | 2025-03-03 11:20:39 -0500 | [diff] [blame] | 114 | boost::container::flat_map<std::string, std::string>& result); | 
| Kumar Thangavel | c8dc4af | 2021-01-12 10:36:38 +0530 | [diff] [blame] | 115 |  | 
| krishnar4 | 213ee21 | 2022-11-11 15:39:30 +0530 | [diff] [blame] | 116 | std::vector<uint8_t>& getFRUInfo(const uint16_t& bus, const uint8_t& address); | 
| Kumar Thangavel | c8dc4af | 2021-01-12 10:36:38 +0530 | [diff] [blame] | 117 |  | 
| Ed Tanous | 23e3f45 | 2025-04-08 10:37:56 -0700 | [diff] [blame] | 118 | uint8_t calculateChecksum(std::span<const uint8_t>::const_iterator iter, | 
|  | 119 | std::span<const uint8_t>::const_iterator end); | 
| Kumar Thangavel | c8dc4af | 2021-01-12 10:36:38 +0530 | [diff] [blame] | 120 |  | 
| Ed Tanous | 23e3f45 | 2025-04-08 10:37:56 -0700 | [diff] [blame] | 121 | uint8_t calculateChecksum(std::span<const uint8_t> fruAreaData); | 
| Kumar Thangavel | c8dc4af | 2021-01-12 10:36:38 +0530 | [diff] [blame] | 122 |  | 
| Patrick Williams | b707743 | 2024-08-16 15:22:21 -0400 | [diff] [blame] | 123 | unsigned int updateFRUAreaLenAndChecksum( | 
|  | 124 | std::vector<uint8_t>& fruData, size_t fruAreaStart, | 
|  | 125 | size_t fruAreaEndOfFieldsOffset, size_t fruAreaEndOffset); | 
| Kumar Thangavel | c8dc4af | 2021-01-12 10:36:38 +0530 | [diff] [blame] | 126 |  | 
|  | 127 | ssize_t getFieldLength(uint8_t fruFieldTypeLenValue); | 
|  | 128 |  | 
| Oskar Senft | bd4075f | 2021-10-05 23:42:43 -0400 | [diff] [blame] | 129 | /// \brief Find a FRU header. | 
| Zev Weiss | 309c0b1 | 2022-02-25 01:44:12 +0000 | [diff] [blame] | 130 | /// \param reader the FRUReader to read via | 
| Oskar Senft | bd4075f | 2021-10-05 23:42:43 -0400 | [diff] [blame] | 131 | /// \param errorHelp and a helper string for failures | 
|  | 132 | /// \param blockData buffer to return the last read block | 
|  | 133 | /// \param baseOffset the offset to start the search at; | 
|  | 134 | ///        set to 0 to perform search; | 
|  | 135 | ///        returns the offset at which a header was found | 
|  | 136 | /// \return whether a header was found | 
| Zev Weiss | 309c0b1 | 2022-02-25 01:44:12 +0000 | [diff] [blame] | 137 | bool findFRUHeader(FRUReader& reader, const std::string& errorHelp, | 
| Oskar Senft | bd4075f | 2021-10-05 23:42:43 -0400 | [diff] [blame] | 138 | std::array<uint8_t, I2C_SMBUS_BLOCK_MAX>& blockData, | 
| Zev Weiss | 1525e85 | 2022-03-22 22:27:43 +0000 | [diff] [blame] | 139 | off_t& baseOffset); | 
| Oskar Senft | bd4075f | 2021-10-05 23:42:43 -0400 | [diff] [blame] | 140 |  | 
| Patrick Venture | ab29641 | 2020-12-30 13:39:37 -0800 | [diff] [blame] | 141 | /// \brief Read and validate FRU contents. | 
| Zev Weiss | 309c0b1 | 2022-02-25 01:44:12 +0000 | [diff] [blame] | 142 | /// \param reader the FRUReader to read via | 
| Patrick Venture | ab29641 | 2020-12-30 13:39:37 -0800 | [diff] [blame] | 143 | /// \param errorHelp and a helper string for failures | 
| Marvin Drees | 2b3ed30 | 2023-04-14 16:35:14 +0200 | [diff] [blame] | 144 | /// \return the FRU contents from the file and bool indicating if the FRU Header | 
|  | 145 | /// was found | 
| Patrick Williams | 5a80703 | 2025-03-03 11:20:39 -0500 | [diff] [blame] | 146 | std::pair<std::vector<uint8_t>, bool> readFRUContents( | 
|  | 147 | FRUReader& reader, const std::string& errorHelp); | 
| Patrick Venture | ab29641 | 2020-12-30 13:39:37 -0800 | [diff] [blame] | 148 |  | 
|  | 149 | /// \brief Validate an IPMI FRU common header | 
|  | 150 | /// \param blockData the bytes comprising the common header | 
|  | 151 | /// \return true if valid | 
|  | 152 | bool validateHeader(const std::array<uint8_t, I2C_SMBUS_BLOCK_MAX>& blockData); | 
|  | 153 |  | 
|  | 154 | /// \brief Get offset for a common header area | 
|  | 155 | /// \param area - the area | 
|  | 156 | /// \return the field offset | 
|  | 157 | unsigned int getHeaderAreaFieldOffset(fruAreas area); | 
| Kumar Thangavel | bdfc5ec | 2022-08-29 22:23:00 +0530 | [diff] [blame] | 158 |  | 
|  | 159 | /// \brief Iterate fruArea Names and find offset/location and fields and size of | 
|  | 160 | /// properties | 
|  | 161 | /// \param fruData - vector to store fru data | 
|  | 162 | /// \param propertyName - fru property Name | 
| Kumar Thangavel | 51b557b | 2022-09-13 13:40:47 +0530 | [diff] [blame] | 163 | /// \param fruAreaParams - struct to have fru Area parameters like length, | 
|  | 164 | /// size. | 
|  | 165 | /// \return true if fru field is found, fruAreaParams like updateFieldLoc, | 
|  | 166 | /// Start, Size, End are updated with fruArea and field info. | 
| Kumar Thangavel | bdfc5ec | 2022-08-29 22:23:00 +0530 | [diff] [blame] | 167 | bool findFruAreaLocationAndField(std::vector<uint8_t>& fruData, | 
|  | 168 | const std::string& propertyName, | 
| Kumar Thangavel | 51b557b | 2022-09-13 13:40:47 +0530 | [diff] [blame] | 169 | struct FruArea& fruAreaParams); | 
|  | 170 |  | 
|  | 171 | /// \brief Copy the fru Area fields and properties into restFRUAreaFieldsData. | 
|  | 172 | /// restFRUAreaField is the rest of the fields in FRU area after the field that | 
|  | 173 | /// is being updated. | 
|  | 174 | /// \param fruData - vector to store fru data | 
|  | 175 | /// \param propertyName - fru property Name | 
|  | 176 | /// \param fruAreaParams - struct to have fru Area parameters like length | 
|  | 177 | /// \param restFRUAreaFieldsData - vector to store fru Area Fields and | 
|  | 178 | /// properties. | 
|  | 179 | /// \return true on success false on failure. restFieldLoc and restFieldEnd | 
|  | 180 | /// are updated. | 
| Kumar Thangavel | 9f2162a | 2022-08-10 18:05:20 +0530 | [diff] [blame] | 181 |  | 
| Kumar Thangavel | 51b557b | 2022-09-13 13:40:47 +0530 | [diff] [blame] | 182 | bool copyRestFRUArea(std::vector<uint8_t>& fruData, | 
|  | 183 | const std::string& propertyName, | 
|  | 184 | struct FruArea& fruAreaParams, | 
|  | 185 | std::vector<uint8_t>& restFRUAreaFieldsData); | 
| Kumar Thangavel | d79d025 | 2022-08-24 14:26:01 +0530 | [diff] [blame] | 186 |  | 
|  | 187 | /// \brief Get all device dbus path and match path with product name using | 
|  | 188 | /// regular expression and find the device index for all devices. | 
|  | 189 | /// \param dbusInterfaceMap - Map to store fru device dbus path and interface | 
|  | 190 | /// \param productName - fru device product name. | 
|  | 191 | /// \return optional<int> highest index for fru device on success, return | 
|  | 192 | /// nullopt on failure. | 
|  | 193 | std::optional<int> findIndexForFRU( | 
|  | 194 | boost::container::flat_map< | 
|  | 195 | std::pair<size_t, size_t>, | 
|  | 196 | std::shared_ptr<sdbusplus::asio::dbus_interface>>& dbusInterfaceMap, | 
|  | 197 | std::string& productName); | 
| Kumar Thangavel | 9f2162a | 2022-08-10 18:05:20 +0530 | [diff] [blame] | 198 |  | 
|  | 199 | /// \brief It does format fru data and find productName in the formatted | 
|  | 200 | /// fru data and return productName. | 
|  | 201 | /// \param device - vector that contains device list | 
|  | 202 | /// \param formattedFRU - map that contains formatted FRU data | 
|  | 203 | /// \param bus - bus number of the device | 
|  | 204 | /// \param address - address of the device | 
|  | 205 | /// \param unknownBusObjectCount - Unknown Bus object counter variable | 
|  | 206 | /// \return optional string. it returns productName or NULL | 
|  | 207 |  | 
|  | 208 | std::optional<std::string> getProductName( | 
|  | 209 | std::vector<uint8_t>& device, | 
|  | 210 | boost::container::flat_map<std::string, std::string>& formattedFRU, | 
|  | 211 | uint32_t bus, uint32_t address, size_t& unknownBusObjectCount); | 
| Kumar Thangavel | 9d6f590 | 2022-08-26 16:52:14 +0530 | [diff] [blame] | 212 |  | 
|  | 213 | bool getFruData(std::vector<uint8_t>& fruData, uint32_t bus, uint32_t address); | 
| Naresh Solanki | 89092a9 | 2025-06-02 15:48:04 +0530 | [diff] [blame] | 214 |  | 
|  | 215 | bool isFieldEditable(std::string_view fieldName); |