blob: 8a117a76970b5b5fc79ec79c7a3fd6142bf2aee8 [file] [log] [blame] [edit]
/*
// Copyright (c) 2018 Intel Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
*/
/// \file fru_utils.hpp
#pragma once
#include "fru_reader.hpp"
#include <boost/container/flat_map.hpp>
#include <sdbusplus/asio/object_server.hpp>
#include <cstdint>
#include <cstdio>
#include <functional>
#include <regex>
#include <string>
#include <utility>
#include <vector>
extern "C"
{
// Include for I2C_SMBUS_BLOCK_MAX
#include <linux/i2c.h>
}
constexpr size_t fruBlockSize = 8;
using DeviceMap = boost::container::flat_map<int, std::vector<uint8_t>>;
using BusMap = boost::container::flat_map<int, std::shared_ptr<DeviceMap>>;
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
inline BusMap busMap;
enum class DecodeState
{
ok,
end,
err,
};
enum class resCodes
{
resOK,
resWarn,
resErr
};
enum class fruAreas
{
fruAreaInternal = 0,
fruAreaChassis,
fruAreaBoard,
fruAreaProduct,
fruAreaMultirecord
};
struct FruArea
{
size_t start; // Fru Area Start offset
size_t size; // Fru Area Size
size_t end; // Fru Area end offset
size_t updateFieldLoc; // Fru Area update Field Location
size_t restFieldsLoc; // Starting location of restFRUArea data
size_t restFieldsEnd; // Ending location of restFRUArea data
};
const std::vector<std::string> fruAreaNames = {"INTERNAL", "CHASSIS", "BOARD",
"PRODUCT", "MULTIRECORD"};
const std::regex nonAsciiRegex("[^\x01-\x7f]");
const std::vector<std::string> chassisFruAreas = {"PART_NUMBER",
"SERIAL_NUMBER"};
const std::vector<std::string> boardFruAreas = {
"MANUFACTURER", "PRODUCT_NAME", "SERIAL_NUMBER", "PART_NUMBER",
"FRU_VERSION_ID"};
const std::vector<std::string> productFruAreas = {
"MANUFACTURER", "PRODUCT_NAME", "PART_NUMBER", "VERSION",
"SERIAL_NUMBER", "ASSET_TAG", "FRU_VERSION_ID"};
const std::string fruCustomFieldName = "INFO_AM";
inline fruAreas operator++(fruAreas& x)
{
return x = static_cast<fruAreas>(
std::underlying_type<fruAreas>::type(x) + 1);
}
inline const std::string& getFruAreaName(fruAreas area)
{
return fruAreaNames[static_cast<unsigned int>(area)];
}
std::tm intelEpoch();
char sixBitToChar(uint8_t val);
/* 0xd - 0xf are reserved values, but not fatal; use a placeholder char. */
constexpr std::array<char, 6> bcdHighChars = {
' ', '-', '.', 'X', 'X', 'X',
};
char bcdPlusToChar(uint8_t val);
bool verifyOffset(const std::vector<uint8_t>& fruBytes, fruAreas currentArea,
uint8_t len);
std::pair<DecodeState, std::string> decodeFRUData(
std::vector<uint8_t>::const_iterator& iter,
const std::vector<uint8_t>::const_iterator& end, bool isLangEng);
bool checkLangEng(uint8_t lang);
resCodes
formatIPMIFRU(const std::vector<uint8_t>& fruBytes,
boost::container::flat_map<std::string, std::string>& result);
std::vector<uint8_t>& getFRUInfo(const uint16_t& bus, const uint8_t& address);
uint8_t calculateChecksum(std::vector<uint8_t>::const_iterator iter,
std::vector<uint8_t>::const_iterator end);
uint8_t calculateChecksum(std::vector<uint8_t>& fruAreaData);
unsigned int updateFRUAreaLenAndChecksum(
std::vector<uint8_t>& fruData, size_t fruAreaStart,
size_t fruAreaEndOfFieldsOffset, size_t fruAreaEndOffset);
ssize_t getFieldLength(uint8_t fruFieldTypeLenValue);
/// \brief Find a FRU header.
/// \param reader the FRUReader to read via
/// \param errorHelp and a helper string for failures
/// \param blockData buffer to return the last read block
/// \param baseOffset the offset to start the search at;
/// set to 0 to perform search;
/// returns the offset at which a header was found
/// \return whether a header was found
bool findFRUHeader(FRUReader& reader, const std::string& errorHelp,
std::array<uint8_t, I2C_SMBUS_BLOCK_MAX>& blockData,
off_t& baseOffset);
/// \brief Read and validate FRU contents.
/// \param reader the FRUReader to read via
/// \param errorHelp and a helper string for failures
/// \return the FRU contents from the file and bool indicating if the FRU Header
/// was found
std::pair<std::vector<uint8_t>, bool>
readFRUContents(FRUReader& reader, const std::string& errorHelp);
/// \brief Validate an IPMI FRU common header
/// \param blockData the bytes comprising the common header
/// \return true if valid
bool validateHeader(const std::array<uint8_t, I2C_SMBUS_BLOCK_MAX>& blockData);
/// \brief Get offset for a common header area
/// \param area - the area
/// \return the field offset
unsigned int getHeaderAreaFieldOffset(fruAreas area);
/// \brief Iterate fruArea Names and find offset/location and fields and size of
/// properties
/// \param fruData - vector to store fru data
/// \param propertyName - fru property Name
/// \param fruAreaParams - struct to have fru Area parameters like length,
/// size.
/// \return true if fru field is found, fruAreaParams like updateFieldLoc,
/// Start, Size, End are updated with fruArea and field info.
bool findFruAreaLocationAndField(std::vector<uint8_t>& fruData,
const std::string& propertyName,
struct FruArea& fruAreaParams);
/// \brief Copy the fru Area fields and properties into restFRUAreaFieldsData.
/// restFRUAreaField is the rest of the fields in FRU area after the field that
/// is being updated.
/// \param fruData - vector to store fru data
/// \param propertyName - fru property Name
/// \param fruAreaParams - struct to have fru Area parameters like length
/// \param restFRUAreaFieldsData - vector to store fru Area Fields and
/// properties.
/// \return true on success false on failure. restFieldLoc and restFieldEnd
/// are updated.
bool copyRestFRUArea(std::vector<uint8_t>& fruData,
const std::string& propertyName,
struct FruArea& fruAreaParams,
std::vector<uint8_t>& restFRUAreaFieldsData);
/// \brief Get all device dbus path and match path with product name using
/// regular expression and find the device index for all devices.
/// \param dbusInterfaceMap - Map to store fru device dbus path and interface
/// \param productName - fru device product name.
/// \return optional<int> highest index for fru device on success, return
/// nullopt on failure.
std::optional<int> findIndexForFRU(
boost::container::flat_map<
std::pair<size_t, size_t>,
std::shared_ptr<sdbusplus::asio::dbus_interface>>& dbusInterfaceMap,
std::string& productName);
/// \brief It does format fru data and find productName in the formatted
/// fru data and return productName.
/// \param device - vector that contains device list
/// \param formattedFRU - map that contains formatted FRU data
/// \param bus - bus number of the device
/// \param address - address of the device
/// \param unknownBusObjectCount - Unknown Bus object counter variable
/// \return optional string. it returns productName or NULL
std::optional<std::string> getProductName(
std::vector<uint8_t>& device,
boost::container::flat_map<std::string, std::string>& formattedFRU,
uint32_t bus, uint32_t address, size_t& unknownBusObjectCount);
bool getFruData(std::vector<uint8_t>& fruData, uint32_t bus, uint32_t address);