diff options
-rw-r--r-- | intel-pfr-manager/libpfr/inc/pfr.hpp | 2 | ||||
-rw-r--r-- | intel-pfr-manager/libpfr/inc/spiDev.hpp | 95 | ||||
-rw-r--r-- | intel-pfr-manager/libpfr/src/pfr.cpp | 149 | ||||
-rw-r--r-- | intel-pfr-manager/service/src/pfr_mgr.cpp | 4 |
4 files changed, 201 insertions, 49 deletions
diff --git a/intel-pfr-manager/libpfr/inc/pfr.hpp b/intel-pfr-manager/libpfr/inc/pfr.hpp index 42af3f7..542cb51 100644 --- a/intel-pfr-manager/libpfr/inc/pfr.hpp +++ b/intel-pfr-manager/libpfr/inc/pfr.hpp @@ -42,7 +42,7 @@ enum class ActionType }; std::string toHexString(const uint8_t val); -std::string getVersionInfoCPLD(ImageType &imgType); +std::string getFirmwareVersion(const ImageType &imgType); int getProvisioningStatus(bool &ufmLocked, bool &ufmProvisioned); int readCpldReg(const ActionType &action, uint8_t &value); int setBMCBootCheckpoint(const uint8_t checkPoint); diff --git a/intel-pfr-manager/libpfr/inc/spiDev.hpp b/intel-pfr-manager/libpfr/inc/spiDev.hpp new file mode 100644 index 0000000..17a4f63 --- /dev/null +++ b/intel-pfr-manager/libpfr/inc/spiDev.hpp @@ -0,0 +1,95 @@ +/* +// Copyright (c) 2019 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. +*/ + +#pragma once + +#include <stdio.h> +#include <cstring> +#include <experimental/filesystem> + +namespace intel +{ +namespace pfr +{ + +/** @class SPIDev + * @brief Responsible for handling file pointer + */ +class SPIDev +{ + private: + /** @brief handler for operating on file */ + int fd = -1; + + public: + SPIDev() = delete; + SPIDev(const SPIDev&) = delete; + SPIDev& operator=(const SPIDev&) = delete; + SPIDev(SPIDev&&) = delete; + SPIDev& operator=(SPIDev&&) = delete; + + /** @brief Opens spi(mtd) device file + * + * @param[in] devNo - MTD device number + */ + SPIDev(const std::string& spiDev) : + fd(open(spiDev.c_str(), O_RDWR | O_CLOEXEC)) + { + if (fd < 0) + { + std::string msg = "Unable to open mtd device. errno=" + + std::string(std::strerror(errno)); + throw std::runtime_error(msg); + } + } + + /** @brief Reads the byte data from SPI(MTD) device + * + * @param[in] startAddr - start address + * @param[in] dataLen - No of byte to read + * @param[out] dataRes - Out data pointer + */ + void spiReadData(const uint32_t startAddr, const size_t dataLen, + void* dataRes) + { + if (lseek(fd, startAddr, SEEK_SET) < 0) + { + std::string msg = "Failed to do lseek on mtd device. errno=" + + std::string(std::strerror(errno)); + throw std::runtime_error(msg); + } + + if (read(fd, dataRes, dataLen) != dataLen) + { + std::string msg = "Failed to read on mtd device. errno=" + + std::string(std::strerror(errno)); + throw std::runtime_error(msg); + } + + return; + } + + virtual ~SPIDev() + { + if (!(fd < 0)) + { + close(fd); + } + } +}; + +} // namespace pfr +} // namespace intel diff --git a/intel-pfr-manager/libpfr/src/pfr.cpp b/intel-pfr-manager/libpfr/src/pfr.cpp index 955b6d7..a61f72e 100644 --- a/intel-pfr-manager/libpfr/src/pfr.cpp +++ b/intel-pfr-manager/libpfr/src/pfr.cpp @@ -20,6 +20,7 @@ #include <iomanip> #include "pfr.hpp" #include "file.hpp" +#include "spiDev.hpp" namespace intel { @@ -44,16 +45,24 @@ static constexpr uint8_t provisioningStatus = 0x0A; static constexpr uint8_t bmcBootCheckpoint = 0x0F; static constexpr uint8_t pchActiveMajorVersion = 0x15; static constexpr uint8_t pchActiveMinorVersion = 0x16; -static constexpr uint8_t bmcActiveMajorVersion = 0x18; -static constexpr uint8_t bmcActiveMinorVersion = 0x19; static constexpr uint8_t pchRecoveryMajorVersion = 0x1B; static constexpr uint8_t pchRecoveryMinorVersion = 0x1C; -static constexpr uint8_t bmcRecoveryMajorVersion = 0x1E; -static constexpr uint8_t bmcRecoveryMinorVersion = 0x1F; static constexpr uint8_t ufmLockedMask = (0x1 << 0x04); static constexpr uint8_t ufmProvisionedMask = (0x1 << 0x05); +// PFR MTD devices +static constexpr const char* bmcActiveImgPfmMTDDev = "/dev/mtd/pfm"; +static constexpr const char* bmcRecoveryImgMTDDev = "/dev/mtd/rc-image"; + +// PFM offset in full image +static constexpr const uint32_t pfmBaseOffsetInImage = 0x400; + +// OFFSET values in PFM +static constexpr const uint32_t verOffsetInPFM = 0x406; +static constexpr const uint32_t buildNumOffsetInPFM = 0x40C; +static constexpr const uint32_t buildHashOffsetInPFM = 0x40D; + std::string toHexString(const uint8_t val) { std::stringstream stream; @@ -62,50 +71,11 @@ std::string toHexString(const uint8_t val) return stream.str(); } -std::string getVersionInfoCPLD(ImageType& imgType) +static std::string readVersionFromCPLD(const uint8_t majorReg, + const uint8_t minorReg) { try { - uint8_t majorReg; - uint8_t minorReg; - - switch (imgType) - { - case (ImageType::cpld): - { - majorReg = cpldROTVersion; - minorReg = cpldROTSvn; - break; - } - case (ImageType::biosActive): - { - majorReg = pchActiveMajorVersion; - minorReg = pchActiveMinorVersion; - break; - } - case (ImageType::biosRecovery): - { - majorReg = pchRecoveryMajorVersion; - minorReg = pchRecoveryMinorVersion; - break; - } - case (ImageType::bmcActive): - { - majorReg = bmcActiveMajorVersion; - minorReg = bmcActiveMinorVersion; - break; - } - case (ImageType::bmcRecovery): - { - majorReg = bmcRecoveryMajorVersion; - minorReg = bmcRecoveryMinorVersion; - break; - } - default: - // Invalid image Type. - return ""; - } - I2CFile cpldDev(i2cBusNumber, i2cSlaveAddress, O_RDWR | O_CLOEXEC); uint8_t majorVer = cpldDev.i2cReadByteData(majorReg); uint8_t minorVer = cpldDev.i2cReadByteData(minorReg); @@ -116,10 +86,97 @@ std::string getVersionInfoCPLD(ImageType& imgType) catch (const std::exception& e) { phosphor::logging::log<phosphor::logging::level::ERR>( - "Exception caught in getVersionInfoCPLD.", + "Exception caught in readVersionFromCPLD.", + phosphor::logging::entry("MSG=%s", e.what())); + return ""; + } +} + +static std::string readBMCVersionFromSPI(const ImageType& imgType) +{ + std::string mtdDev; + uint32_t verOffset = verOffsetInPFM; + uint32_t bldNumOffset = buildNumOffsetInPFM; + uint32_t bldHashOffset = buildHashOffsetInPFM; + + if (imgType == ImageType::bmcActive) + { + // For Active image, PFM is emulated as separate MTD device. + mtdDev = bmcActiveImgPfmMTDDev; + } + else if (imgType == ImageType::bmcRecovery) + { + // For Recovery image, PFM is part of compressed Image + // at offset 0x400. + mtdDev = bmcRecoveryImgMTDDev; + verOffset += pfmBaseOffsetInImage; + bldNumOffset += pfmBaseOffsetInImage; + bldHashOffset += pfmBaseOffsetInImage; + } + else + { + phosphor::logging::log<phosphor::logging::level::ERR>( + "Invalid image type passed to readBMCVersionFromSPI."); + return ""; + } + + uint8_t buildNo = 0; + std::array<uint8_t, 2> ver; + std::array<uint8_t, 3> buildHash; + + try + { + SPIDev spiDev(mtdDev); + spiDev.spiReadData(verOffset, ver.size(), + reinterpret_cast<void*>(ver.data())); + spiDev.spiReadData(bldNumOffset, sizeof(buildNo), + reinterpret_cast<void*>(&buildNo)); + spiDev.spiReadData(bldHashOffset, buildHash.size(), + reinterpret_cast<void*>(buildHash.data())); + } + catch (const std::exception& e) + { + phosphor::logging::log<phosphor::logging::level::ERR>( + "Exception caught in readBMCVersionFromSPI.", phosphor::logging::entry("MSG=%s", e.what())); return ""; } + // Version format: <major>.<minor>-<build bum>-<build hash> + // Example: 00.11-07-1e5c2d + std::string version = toHexString(ver[0]) + "." + toHexString(ver[1]) + + "-" + toHexString(buildNo) + "-" + + toHexString(buildHash[0]) + + toHexString(buildHash[1]) + toHexString(buildHash[2]); + return version; +} + +std::string getFirmwareVersion(const ImageType& imgType) +{ + switch (imgType) + { + case (ImageType::cpld): + { + return readVersionFromCPLD(cpldROTVersion, cpldROTSvn); + } + case (ImageType::biosActive): + { + return readVersionFromCPLD(pchActiveMajorVersion, + pchActiveMinorVersion); + } + case (ImageType::biosRecovery): + { + return readVersionFromCPLD(pchRecoveryMajorVersion, + pchRecoveryMinorVersion); + } + case (ImageType::bmcActive): + case (ImageType::bmcRecovery): + { + return readBMCVersionFromSPI(imgType); + } + default: + // Invalid image Type. + return ""; + } } int getProvisioningStatus(bool& ufmLocked, bool& ufmProvisioned) diff --git a/intel-pfr-manager/service/src/pfr_mgr.cpp b/intel-pfr-manager/service/src/pfr_mgr.cpp index d5fba5f..d5f1f59 100644 --- a/intel-pfr-manager/service/src/pfr_mgr.cpp +++ b/intel-pfr-manager/service/src/pfr_mgr.cpp @@ -31,7 +31,7 @@ PfrVersion::PfrVersion(sdbusplus::asio::object_server &srv_, server(srv_), conn(conn_), path(path_), imgType(imgType_), purpose(purpose_) { - version = getVersionInfoCPLD(imgType); + version = getFirmwareVersion(imgType); std::string objPath = "/xyz/openbmc_project/software/" + path; versionIface = @@ -75,7 +75,7 @@ void PfrVersion::updateVersion() { if (versionIface && versionIface->is_initialized()) { - std::string ver = getVersionInfoCPLD(imgType); + std::string ver = getFirmwareVersion(imgType); internalSet = true; versionIface->set_property(versionStr, ver); internalSet = false; |