1 // SPDX-License-Identifier: Apache-2.0 2 // SPDX-FileCopyrightText: Copyright 2018 Intel Corporation 3 4 #pragma once 5 #include "fru_reader.hpp" 6 7 #include <boost/container/flat_map.hpp> 8 #include <sdbusplus/asio/object_server.hpp> 9 10 #include <cstdint> 11 #include <cstdio> 12 #include <functional> 13 #include <regex> 14 #include <string> 15 #include <utility> 16 #include <vector> 17 extern "C" 18 { 19 // Include for I2C_SMBUS_BLOCK_MAX 20 #include <linux/i2c.h> 21 } 22 23 constexpr size_t fruBlockSize = 8; 24 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 28 // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) 29 inline BusMap busMap; 30 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 45 enum class fruAreas 46 { 47 fruAreaInternal = 0, 48 fruAreaChassis, 49 fruAreaBoard, 50 fruAreaProduct, 51 fruAreaMultirecord 52 }; 53 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 60 size_t restFieldsLoc; // Starting location of restFRUArea data 61 size_t restFieldsEnd; // Ending location of restFRUArea data 62 }; 63 64 const std::vector<std::string> fruAreaNames = {"INTERNAL", "CHASSIS", "BOARD", 65 "PRODUCT", "MULTIRECORD"}; 66 const std::regex nonAsciiRegex("[^\x01-\x7f]"); 67 68 const std::vector<std::string> chassisFruAreas = {"PART_NUMBER", 69 "SERIAL_NUMBER"}; 70 71 const std::vector<std::string> boardFruAreas = { 72 "MANUFACTURER", "PRODUCT_NAME", "SERIAL_NUMBER", "PART_NUMBER", 73 "FRU_VERSION_ID"}; 74 75 const std::vector<std::string> productFruAreas = { 76 "MANUFACTURER", "PRODUCT_NAME", "PART_NUMBER", "VERSION", 77 "SERIAL_NUMBER", "ASSET_TAG", "FRU_VERSION_ID"}; 78 79 const std::string fruCustomFieldName = "INFO_AM"; 80 81 inline fruAreas operator++(fruAreas& x) 82 { 83 return x = static_cast<fruAreas>( 84 std::underlying_type<fruAreas>::type(x) + 1); 85 } 86 87 inline const std::string& getFruAreaName(fruAreas area) 88 { 89 return fruAreaNames[static_cast<unsigned int>(area)]; 90 } 91 92 std::tm intelEpoch(); 93 94 char sixBitToChar(uint8_t val); 95 96 /* 0xd - 0xf are reserved values, but not fatal; use a placeholder char. */ 97 constexpr std::array<char, 6> bcdHighChars = { 98 ' ', '-', '.', 'X', 'X', 'X', 99 }; 100 101 char bcdPlusToChar(uint8_t val); 102 103 bool verifyOffset(std::span<const uint8_t> fruBytes, fruAreas currentArea, 104 uint8_t len); 105 106 std::pair<DecodeState, std::string> decodeFRUData( 107 std::span<const uint8_t>::const_iterator& iter, 108 std::span<const uint8_t>::const_iterator& end, bool isLangEng); 109 110 bool checkLangEng(uint8_t lang); 111 112 resCodes formatIPMIFRU( 113 std::span<const uint8_t> fruBytes, 114 boost::container::flat_map<std::string, std::string>& result); 115 116 std::vector<uint8_t>& getFRUInfo(const uint16_t& bus, const uint8_t& address); 117 118 uint8_t calculateChecksum(std::span<const uint8_t>::const_iterator iter, 119 std::span<const uint8_t>::const_iterator end); 120 121 uint8_t calculateChecksum(std::span<const uint8_t> fruAreaData); 122 123 unsigned int updateFRUAreaLenAndChecksum( 124 std::vector<uint8_t>& fruData, size_t fruAreaStart, 125 size_t fruAreaEndOfFieldsOffset, size_t fruAreaEndOffset); 126 127 ssize_t getFieldLength(uint8_t fruFieldTypeLenValue); 128 129 struct FruSections 130 { 131 off_t IpmiFruOffset = 0; 132 std::array<uint8_t, I2C_SMBUS_BLOCK_MAX> ipmiFruBlock; 133 134 off_t GigabyteXmlOffset = 0; 135 }; 136 137 /// \brief Find a FRU header. 138 /// \param reader the FRUReader to read via 139 /// \param errorHelp and a helper string for failures 140 /// \param blockData buffer to return the last read block 141 /// \param baseOffset the offset to start the search at; 142 /// set to 0 to perform search; 143 /// returns the offset at which a header was found 144 /// \return whether a header was found 145 std::optional<FruSections> findFRUHeader( 146 FRUReader& reader, const std::string& errorHelp, off_t offset); 147 148 /// \brief Read and validate FRU contents. 149 /// \param reader the FRUReader to read via 150 /// \param errorHelp and a helper string for failures 151 /// \return the FRU contents from the file and bool indicating if the FRU Header 152 /// was found 153 std::pair<std::vector<uint8_t>, bool> readFRUContents( 154 FRUReader& reader, const std::string& errorHelp); 155 156 /// \brief Validate an IPMI FRU common header 157 /// \param blockData the bytes comprising the common header 158 /// \return true if valid 159 bool validateHeader(const std::array<uint8_t, I2C_SMBUS_BLOCK_MAX>& blockData); 160 161 /// \brief Get offset for a common header area 162 /// \param area - the area 163 /// \return the field offset 164 unsigned int getHeaderAreaFieldOffset(fruAreas area); 165 166 /// \brief Iterate fruArea Names and find offset/location and fields and size of 167 /// properties 168 /// \param fruData - vector to store fru data 169 /// \param propertyName - fru property Name 170 /// \param fruAreaParams - struct to have fru Area parameters like length, 171 /// size. 172 /// \return true if fru field is found, fruAreaParams like updateFieldLoc, 173 /// Start, Size, End are updated with fruArea and field info. 174 bool findFruAreaLocationAndField(std::vector<uint8_t>& fruData, 175 const std::string& propertyName, 176 struct FruArea& fruAreaParams); 177 178 /// \brief Copy the fru Area fields and properties into restFRUAreaFieldsData. 179 /// restFRUAreaField is the rest of the fields in FRU area after the field that 180 /// is being updated. 181 /// \param fruData - vector to store fru data 182 /// \param propertyName - fru property Name 183 /// \param fruAreaParams - struct to have fru Area parameters like length 184 /// \param restFRUAreaFieldsData - vector to store fru Area Fields and 185 /// properties. 186 /// \return true on success false on failure. restFieldLoc and restFieldEnd 187 /// are updated. 188 189 bool copyRestFRUArea(std::vector<uint8_t>& fruData, 190 const std::string& propertyName, 191 struct FruArea& fruAreaParams, 192 std::vector<uint8_t>& restFRUAreaFieldsData); 193 194 /// \brief Get all device dbus path and match path with product name using 195 /// regular expression and find the device index for all devices. 196 /// \param dbusInterfaceMap - Map to store fru device dbus path and interface 197 /// \param productName - fru device product name. 198 /// \return optional<int> highest index for fru device on success, return 199 /// nullopt on failure. 200 std::optional<int> findIndexForFRU( 201 boost::container::flat_map< 202 std::pair<size_t, size_t>, 203 std::shared_ptr<sdbusplus::asio::dbus_interface>>& dbusInterfaceMap, 204 std::string& productName); 205 206 /// \brief It does format fru data and find productName in the formatted 207 /// fru data and return productName. 208 /// \param device - vector that contains device list 209 /// \param formattedFRU - map that contains formatted FRU data 210 /// \param bus - bus number of the device 211 /// \param address - address of the device 212 /// \param unknownBusObjectCount - Unknown Bus object counter variable 213 /// \return optional string. it returns productName or NULL 214 215 std::optional<std::string> getProductName( 216 std::vector<uint8_t>& device, 217 boost::container::flat_map<std::string, std::string>& formattedFRU, 218 uint32_t bus, uint32_t address, size_t& unknownBusObjectCount); 219 220 bool getFruData(std::vector<uint8_t>& fruData, uint32_t bus, uint32_t address); 221 222 bool isFieldEditable(std::string_view fieldName); 223 224 bool updateAreaChecksum(std::vector<uint8_t>& fruArea); 225 226 bool disassembleFruData(std::vector<uint8_t>& fruData, 227 std::vector<std::vector<uint8_t>>& areasData); 228 229 bool createDummyArea(fruAreas fruArea, std::vector<uint8_t>& areaData); 230 231 bool assembleFruData(std::vector<uint8_t>& fruData, 232 const std::vector<std::vector<uint8_t>>& areasData); 233 234 bool setField(const fruAreas& fruAreaToUpdate, std::vector<uint8_t>& areaData, 235 const std::string& propertyName, const std::string& value); 236 237 bool updateAddProperty(const std::string& propertyValue, 238 const std::string& propertyName, 239 std::vector<uint8_t>& fruData); 240 241 std::string parseMacFromGzipXmlHeader(FRUReader& reader, off_t offset); 242