xref: /openbmc/entity-manager/src/fru_utils.hpp (revision ee1db76f)
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 <functional>
26 #include <regex>
27 #include <string>
28 #include <utility>
29 #include <vector>
30 extern "C"
31 {
32 // Include for I2C_SMBUS_BLOCK_MAX
33 #include <linux/i2c.h>
34 }
35 
36 constexpr size_t fruBlockSize = 8;
37 
38 using DeviceMap = boost::container::flat_map<int, std::vector<uint8_t>>;
39 using BusMap = boost::container::flat_map<int, std::shared_ptr<DeviceMap>>;
40 
41 inline BusMap busMap;
42 
43 enum class DecodeState
44 {
45     ok,
46     end,
47     err,
48 };
49 
50 enum class resCodes
51 {
52     resOK,
53     resWarn,
54     resErr
55 };
56 
57 enum class fruAreas
58 {
59     fruAreaInternal = 0,
60     fruAreaChassis,
61     fruAreaBoard,
62     fruAreaProduct,
63     fruAreaMultirecord
64 };
65 
66 struct FruArea
67 {
68     size_t start;          // Fru Area Start offset
69     size_t size;           // Fru Area Size
70     size_t end;            // Fru Area end offset
71     size_t updateFieldLoc; // Fru Area update Field Location
72     size_t restFieldsLoc;  // Starting location of restFRUArea data
73     size_t restFieldsEnd;  // Ending location of restFRUArea data
74 };
75 
76 const std::vector<std::string> fruAreaNames = {"INTERNAL", "CHASSIS", "BOARD",
77                                                "PRODUCT", "MULTIRECORD"};
78 const std::regex nonAsciiRegex("[^\x01-\x7f]");
79 
80 const std::vector<std::string> chassisFruAreas = {"PART_NUMBER",
81                                                   "SERIAL_NUMBER"};
82 
83 const std::vector<std::string> boardFruAreas = {"MANUFACTURER", "PRODUCT_NAME",
84                                                 "SERIAL_NUMBER", "PART_NUMBER",
85                                                 "FRU_VERSION_ID"};
86 
87 const std::vector<std::string> productFruAreas = {
88     "MANUFACTURER",  "PRODUCT_NAME", "PART_NUMBER",   "VERSION",
89     "SERIAL_NUMBER", "ASSET_TAG",    "FRU_VERSION_ID"};
90 
91 const std::string fruCustomFieldName = "INFO_AM";
92 
93 inline fruAreas operator++(fruAreas& x)
94 {
95     return x = static_cast<fruAreas>(std::underlying_type<fruAreas>::type(x) +
96                                      1);
97 }
98 
99 inline const std::string& getFruAreaName(fruAreas area)
100 {
101     return fruAreaNames[static_cast<unsigned int>(area)];
102 }
103 
104 std::tm intelEpoch(void);
105 
106 char sixBitToChar(uint8_t val);
107 
108 /* 0xd - 0xf are reserved values, but not fatal; use a placeholder char. */
109 constexpr std::array<char, 6> bcdHighChars = {
110     ' ', '-', '.', 'X', 'X', 'X',
111 };
112 
113 char bcdPlusToChar(uint8_t val);
114 
115 bool verifyOffset(const std::vector<uint8_t>& fruBytes, fruAreas currentArea,
116                   uint8_t len);
117 
118 std::pair<DecodeState, std::string>
119     decodeFRUData(std::vector<uint8_t>::const_iterator& iter,
120                   const std::vector<uint8_t>::const_iterator& end,
121                   bool isLangEng);
122 
123 bool checkLangEng(uint8_t lang);
124 
125 resCodes
126     formatIPMIFRU(const std::vector<uint8_t>& fruBytes,
127                   boost::container::flat_map<std::string, std::string>& result);
128 
129 std::vector<uint8_t>& getFRUInfo(const uint16_t& bus, const uint8_t& address);
130 
131 uint8_t calculateChecksum(std::vector<uint8_t>::const_iterator iter,
132                           std::vector<uint8_t>::const_iterator end);
133 
134 uint8_t calculateChecksum(std::vector<uint8_t>& fruAreaData);
135 
136 unsigned int updateFRUAreaLenAndChecksum(std::vector<uint8_t>& fruData,
137                                          size_t fruAreaStart,
138                                          size_t fruAreaEndOfFieldsOffset,
139                                          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
159 std::vector<uint8_t> readFRUContents(FRUReader& reader,
160                                      const std::string& errorHelp);
161 
162 /// \brief Validate an IPMI FRU common header
163 /// \param blockData the bytes comprising the common header
164 /// \return true if valid
165 bool validateHeader(const std::array<uint8_t, I2C_SMBUS_BLOCK_MAX>& blockData);
166 
167 /// \brief Get offset for a common header area
168 /// \param area - the area
169 /// \return the field offset
170 unsigned int getHeaderAreaFieldOffset(fruAreas area);
171 
172 /// \brief Iterate fruArea Names and find offset/location and fields and size of
173 /// properties
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 /// size.
178 /// \return true if fru field is found, fruAreaParams like updateFieldLoc,
179 /// Start, Size, End are updated with fruArea and field info.
180 bool findFruAreaLocationAndField(std::vector<uint8_t>& fruData,
181                                  const std::string& propertyName,
182                                  struct FruArea& fruAreaParams);
183 
184 /// \brief Copy the fru Area fields and properties into restFRUAreaFieldsData.
185 /// restFRUAreaField is the rest of the fields in FRU area after the field that
186 /// is being updated.
187 /// \param fruData - vector to store fru data
188 /// \param propertyName - fru property Name
189 /// \param fruAreaParams - struct to have fru Area parameters like length
190 /// \param restFRUAreaFieldsData - vector to store fru Area Fields and
191 /// properties.
192 /// \return true on success false on failure. restFieldLoc and restFieldEnd
193 /// are updated.
194 
195 bool copyRestFRUArea(std::vector<uint8_t>& fruData,
196                      const std::string& propertyName,
197                      struct FruArea& fruAreaParams,
198                      std::vector<uint8_t>& restFRUAreaFieldsData);
199 
200 /// \brief Get all device dbus path and match path with product name using
201 /// regular expression and find the device index for all devices.
202 /// \param dbusInterfaceMap - Map to store fru device dbus path and interface
203 /// \param productName - fru device product name.
204 /// \return optional<int> highest index for fru device on success, return
205 /// nullopt on failure.
206 std::optional<int> findIndexForFRU(
207     boost::container::flat_map<
208         std::pair<size_t, size_t>,
209         std::shared_ptr<sdbusplus::asio::dbus_interface>>& dbusInterfaceMap,
210     std::string& productName);
211 
212 /// \brief It does format fru data and find productName in the formatted
213 /// fru data and return productName.
214 /// \param device - vector that contains device list
215 /// \param formattedFRU - map that contains formatted FRU data
216 /// \param bus - bus number of the device
217 /// \param address - address of the device
218 /// \param unknownBusObjectCount - Unknown Bus object counter variable
219 /// \return optional string. it returns productName or NULL
220 
221 std::optional<std::string> getProductName(
222     std::vector<uint8_t>& device,
223     boost::container::flat_map<std::string, std::string>& formattedFRU,
224     uint32_t bus, uint32_t address, size_t& unknownBusObjectCount);
225 
226 bool getFruData(std::vector<uint8_t>& fruData, uint32_t bus, uint32_t address);
227