xref: /openbmc/entity-manager/src/fru_device/fru_utils.hpp (revision 10c57656f31ed1c20778425b6090cfae7d788ab6)
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 
operator ++(fruAreas & x)81 inline fruAreas operator++(fruAreas& x)
82 {
83     return x = static_cast<fruAreas>(
84                std::underlying_type<fruAreas>::type(x) + 1);
85 }
86 
getFruAreaName(fruAreas area)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