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
127 formatIPMIFRU(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>
161 readFRUContents(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