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