xref: /openbmc/entity-manager/src/fru_utils.hpp (revision 5a80703cab896fcf5de2d5ed111dd4d1ab589709)
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 = {
86      "MANUFACTURER", "PRODUCT_NAME", "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  
operator ++(fruAreas & x)95  inline fruAreas operator++(fruAreas& x)
96  {
97      return x = static_cast<fruAreas>(
98                 std::underlying_type<fruAreas>::type(x) + 1);
99  }
100  
getFruAreaName(fruAreas area)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> decodeFRUData(
121      std::vector<uint8_t>::const_iterator& iter,
122      const std::vector<uint8_t>::const_iterator& end, bool isLangEng);
123  
124  bool checkLangEng(uint8_t lang);
125  
126  resCodes formatIPMIFRU(
127      const std::vector<uint8_t>& fruBytes,
128      boost::container::flat_map<std::string, std::string>& result);
129  
130  std::vector<uint8_t>& getFRUInfo(const uint16_t& bus, const uint8_t& address);
131  
132  uint8_t calculateChecksum(std::vector<uint8_t>::const_iterator iter,
133                            std::vector<uint8_t>::const_iterator end);
134  
135  uint8_t calculateChecksum(std::vector<uint8_t>& fruAreaData);
136  
137  unsigned int updateFRUAreaLenAndChecksum(
138      std::vector<uint8_t>& fruData, size_t fruAreaStart,
139      size_t fruAreaEndOfFieldsOffset, size_t fruAreaEndOffset);
140  
141  ssize_t getFieldLength(uint8_t fruFieldTypeLenValue);
142  
143  /// \brief Find a FRU header.
144  /// \param reader the FRUReader to read via
145  /// \param errorHelp and a helper string for failures
146  /// \param blockData buffer to return the last read block
147  /// \param baseOffset the offset to start the search at;
148  ///        set to 0 to perform search;
149  ///        returns the offset at which a header was found
150  /// \return whether a header was found
151  bool findFRUHeader(FRUReader& reader, const std::string& errorHelp,
152                     std::array<uint8_t, I2C_SMBUS_BLOCK_MAX>& blockData,
153                     off_t& baseOffset);
154  
155  /// \brief Read and validate FRU contents.
156  /// \param reader the FRUReader to read via
157  /// \param errorHelp and a helper string for failures
158  /// \return the FRU contents from the file and bool indicating if the FRU Header
159  /// was found
160  std::pair<std::vector<uint8_t>, bool> readFRUContents(
161      FRUReader& reader, const std::string& errorHelp);
162  
163  /// \brief Validate an IPMI FRU common header
164  /// \param blockData the bytes comprising the common header
165  /// \return true if valid
166  bool validateHeader(const std::array<uint8_t, I2C_SMBUS_BLOCK_MAX>& blockData);
167  
168  /// \brief Get offset for a common header area
169  /// \param area - the area
170  /// \return the field offset
171  unsigned int getHeaderAreaFieldOffset(fruAreas area);
172  
173  /// \brief Iterate fruArea Names and find offset/location and fields and size of
174  /// properties
175  /// \param fruData - vector to store fru data
176  /// \param propertyName - fru property Name
177  /// \param fruAreaParams - struct to have fru Area parameters like length,
178  /// size.
179  /// \return true if fru field is found, fruAreaParams like updateFieldLoc,
180  /// Start, Size, End are updated with fruArea and field info.
181  bool findFruAreaLocationAndField(std::vector<uint8_t>& fruData,
182                                   const std::string& propertyName,
183                                   struct FruArea& fruAreaParams);
184  
185  /// \brief Copy the fru Area fields and properties into restFRUAreaFieldsData.
186  /// restFRUAreaField is the rest of the fields in FRU area after the field that
187  /// is being updated.
188  /// \param fruData - vector to store fru data
189  /// \param propertyName - fru property Name
190  /// \param fruAreaParams - struct to have fru Area parameters like length
191  /// \param restFRUAreaFieldsData - vector to store fru Area Fields and
192  /// properties.
193  /// \return true on success false on failure. restFieldLoc and restFieldEnd
194  /// are updated.
195  
196  bool copyRestFRUArea(std::vector<uint8_t>& fruData,
197                       const std::string& propertyName,
198                       struct FruArea& fruAreaParams,
199                       std::vector<uint8_t>& restFRUAreaFieldsData);
200  
201  /// \brief Get all device dbus path and match path with product name using
202  /// regular expression and find the device index for all devices.
203  /// \param dbusInterfaceMap - Map to store fru device dbus path and interface
204  /// \param productName - fru device product name.
205  /// \return optional<int> highest index for fru device on success, return
206  /// nullopt on failure.
207  std::optional<int> findIndexForFRU(
208      boost::container::flat_map<
209          std::pair<size_t, size_t>,
210          std::shared_ptr<sdbusplus::asio::dbus_interface>>& dbusInterfaceMap,
211      std::string& productName);
212  
213  /// \brief It does format fru data and find productName in the formatted
214  /// fru data and return productName.
215  /// \param device - vector that contains device list
216  /// \param formattedFRU - map that contains formatted FRU data
217  /// \param bus - bus number of the device
218  /// \param address - address of the device
219  /// \param unknownBusObjectCount - Unknown Bus object counter variable
220  /// \return optional string. it returns productName or NULL
221  
222  std::optional<std::string> getProductName(
223      std::vector<uint8_t>& device,
224      boost::container::flat_map<std::string, std::string>& formattedFRU,
225      uint32_t bus, uint32_t address, size_t& unknownBusObjectCount);
226  
227  bool getFruData(std::vector<uint8_t>& fruData, uint32_t bus, uint32_t address);
228