From 030f918b90ea45104bccf68082c2d634c6694238 Mon Sep 17 00:00:00 2001 From: Vikram Bodireddy Date: Tue, 13 Aug 2019 22:43:12 +0530 Subject: [PATCH] PFR images support in phosphor-software-manager This commit adds support for handling the PFR images upload and processing. Testing: tested PFR image uploads and updates Signed-off-by: Vikram Bodireddy --- Makefile.am | 18 +++- activation.cpp | 2 +- configure.ac | 7 ++ item_updater.cpp | 6 +- pfr_image_manager.cpp | 217 ++++++++++++++++++++++++++++++++++++++++++ pfr_image_manager.hpp | 75 +++++++++++++++ 6 files changed, 320 insertions(+), 5 deletions(-) create mode 100644 pfr_image_manager.cpp create mode 100644 pfr_image_manager.hpp diff --git a/Makefile.am b/Makefile.am index 6c3ec16..59ebecc 100755 --- a/Makefile.am +++ b/Makefile.am @@ -6,13 +6,20 @@ noinst_HEADERS = \ watch.hpp \ version.hpp \ images.hpp \ - image_manager.hpp \ item_updater.hpp \ activation.hpp \ flash.hpp \ item_updater_helper.hpp \ utils.hpp +if PFR_UPDATE +noinst_HEADERS += \ + pfr_image_manager.hpp +else +noinst_HEADERS += \ + image_manager.hpp +endif + bin_PROGRAMS = \ phosphor-version-software-manager \ phosphor-download-manager \ @@ -24,8 +31,15 @@ dist_bin_SCRIPTS = \ phosphor_version_software_manager_SOURCES = \ image_manager_main.cpp \ watch.cpp \ - version.cpp \ + version.cpp + +if PFR_UPDATE +phosphor_version_software_manager_SOURCES += \ + pfr_image_manager.cpp +else +phosphor_version_software_manager_SOURCES += \ image_manager.cpp +endif BUILT_SOURCES = \ xyz/openbmc_project/Software/Image/error.cpp \ diff --git a/activation.cpp b/activation.cpp index cea1e50..7ff4196 100644 --- a/activation.cpp +++ b/activation.cpp @@ -197,7 +197,7 @@ auto Activation::activation(Activations value) -> Activations } else if (activationProgress->progress() == 100) { - log("[Jennifer] progress == 100..."); + log("progress == 100..."); if (!redundancyPriority) { redundancyPriority = diff --git a/configure.ac b/configure.ac index 720e704..e527682 100755 --- a/configure.ac +++ b/configure.ac @@ -191,6 +191,13 @@ AS_IF([test "x$enable_fwupd_script" == "xyes"], \ [AC_DEFINE([FWUPD_SCRIPT],[],[Enable fwupd script support.])]) AM_CONDITIONAL([FWUPD_SCRIPT], [test "x$enable_fwupd_script" == "xyes"]) +# setup pfr image update support +AC_ARG_ENABLE([pfr_update], + AS_HELP_STRING([--enable-pfr_update], [Enable pfr image update support.])) +AS_IF([test "x$enable_pfr_update" == "xyes"], \ + [AC_DEFINE([PFR_UPDATE],[],[Enable pfr image update support.])]) +AM_CONDITIONAL([PFR_UPDATE], [test "x$enable_pfr_update" == "xyes"]) + # Check for header files. AC_CHECK_HEADER(systemd/sd-bus.h, ,[AC_MSG_ERROR([Could not find systemd/sd-bus.h...systemd development package required])]) AC_CHECK_HEADER(sdbusplus/server.hpp, ,[AC_MSG_ERROR([Could not find sdbusplus/server.hpp...openbmc/sdbusplus package required])]) diff --git a/item_updater.cpp b/item_updater.cpp index 21fb6e0..fd76a7f 100644 --- a/item_updater.cpp +++ b/item_updater.cpp @@ -64,7 +64,8 @@ void ItemUpdater::createActivation(sdbusplus::message::message& msg) auto value = SVersion::convertVersionPurposeFromString( variant_ns::get(property.second)); if (value == VersionPurpose::BMC || - value == VersionPurpose::System) + value == VersionPurpose::Host || + value == VersionPurpose::Other) { purpose = value; } @@ -356,6 +357,7 @@ void ItemUpdater::deleteAll() ItemUpdater::ActivationStatus ItemUpdater::validateSquashFSImage(const std::string& filePath) { +#ifndef PFR_UPDATE bool invalid = false; for (auto& bmcImage : bmcImages) @@ -375,7 +377,7 @@ ItemUpdater::ActivationStatus { return ItemUpdater::ActivationStatus::invalid; } - +#endif return ItemUpdater::ActivationStatus::ready; } diff --git a/pfr_image_manager.cpp b/pfr_image_manager.cpp new file mode 100644 index 0000000..242a6ca --- /dev/null +++ b/pfr_image_manager.cpp @@ -0,0 +1,217 @@ +#include "config.h" + +#include "pfr_image_manager.hpp" + +#include "version.hpp" +#include "watch.hpp" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace phosphor +{ +namespace software +{ +namespace manager +{ + +using namespace sdbusplus::xyz::openbmc_project::Software::Image::Error; +namespace Software = phosphor::logging::xyz::openbmc_project::Software; + +static constexpr const uint32_t pfmPos = 2054; + +static int getPFRImgInfo(const std::filesystem::path imgPath, uint8_t& imgType, + std::string& version) +{ + struct pfrImgBlock0 block0Data; + uint8_t verData[2]; + + if (std::filesystem::exists(imgPath)) + { + try + { + std::ifstream imgFile(imgPath, std::ios::binary | std::ios::in); + + if (!imgFile.good()) + { + phosphor::logging::log( + "Image file read failed"); + return -1; + } + + imgFile.read(reinterpret_cast(&block0Data), + sizeof(block0Data)); + imgType = block0Data.pcType[0]; + imgFile.seekg(pfmPos, + std::ios::beg); // Version is at 0x806 in the PFM + imgFile.read(reinterpret_cast(&verData), sizeof(verData)); + imgFile.close(); + version = + std::to_string(verData[0]) + "." + std::to_string(verData[1]); + phosphor::logging::log( + "PFR image", + phosphor::logging::entry("PCType=%d", block0Data.pcType[0]), + phosphor::logging::entry("VERSION=%s", version.c_str())); + } + catch (std::exception& e) + { + phosphor::logging::log(e.what()); + return -1; + } + } + + return 0; +} + +int Manager::processImage(const std::string& imgFilePath) +{ + std::filesystem::path imgPath(imgFilePath); + + if (!std::filesystem::exists(imgPath)) + return -1; + + uint8_t imgType; + int retry = 3; + std::string ver; + std::string purposeString; + + if (0 != getPFRImgInfo(imgFilePath, imgType, ver)) + { + phosphor::logging::log( + "Error reading uploaded image type and version"); + return -1; + } + + if (ver.empty()) + { + phosphor::logging::log( + "Empty version from image file"); + return -1; + } + + if (imgType == pfrBMCUpdateCap) + { + purposeString = + "xyz.openbmc_project.Software.Version.VersionPurpose.BMC"; + } + else if (imgType == pfrPCHUpdateCap) + { + purposeString = + "xyz.openbmc_project.Software.Version.VersionPurpose.Host"; + } + else if (imgType == pfrCPLDUpdateCap) + { + purposeString = + "xyz.openbmc_project.Software.Version.VersionPurpose.Other"; + } + else + { + purposeString = + "xyz.openbmc_project.Software.Version.VersionPurpose.Unknown"; + + phosphor::logging::log( + "Unknown image type"); + return -1; + } + + sdbusplus::xyz::openbmc_project::Software::server::Version::VersionPurpose + purpose = Version::VersionPurpose::Unknown; + try + { + purpose = Version::convertVersionPurposeFromString(purposeString); + } + catch (const sdbusplus::exception::InvalidEnumString& e) + { + phosphor::logging::log( + "Error: Failed to convert purpose to enum." + " Setting to Unknown."); + } + + // Compute id + std::string id = Version::getId(ver); + + // Append a random number after the original version hash + // This will allow forcing image update onto the same version + // with 3 retries on random number generation. + do + { + srand(time(NULL)); + id = id + "_" + std::to_string(rand()); + } while ((versions.find(id) != versions.end()) && retry--); + + if (versions.find(id) != versions.end()) + { + phosphor::logging::log( + "Software Object with the same version already exists, exiting " + "the update", + phosphor::logging::entry("VERSION_ID=%s", id.c_str())); + + return -1; + } + + std::filesystem::path imageDirPath(IMG_UPLOAD_DIR); + imageDirPath /= id; + + std::filesystem::create_directory(imageDirPath); + + std::filesystem::path newFileName = imageDirPath / "image-runtime"; + std::filesystem::rename(imgFilePath, newFileName); + + // Create Version object + std::string objPath = std::string{SOFTWARE_OBJPATH} + '/' + id; + + auto versionPtr = std::make_unique( + bus, objPath, ver, purpose, imageDirPath.string(), + std::bind(&Manager::erase, this, std::placeholders::_1)); + versionPtr->deleteObject = + std::make_unique(bus, objPath, + *versionPtr); + versions.insert(std::make_pair(id, std::move(versionPtr))); + + return 0; +} + +void Manager::erase(std::string entryId) +{ + auto it = versions.find(entryId); + if (it == versions.end()) + { + return; + } + + if (it->second->isFunctional()) + { + phosphor::logging::log( + ("Error: Version " + entryId + + " is currently running on the BMC." + " Unable to remove.") + .c_str()); + return; + } + + // Delete image dir + std::filesystem::path imageDirPath = (*(it->second)).path(); + if (std::filesystem::exists(imageDirPath)) + { + std::filesystem::remove_all(imageDirPath); + } + this->versions.erase(entryId); +} + +} // namespace manager +} // namespace software +} // namespace phosphor diff --git a/pfr_image_manager.hpp b/pfr_image_manager.hpp new file mode 100644 index 0000000..c6ee6a4 --- /dev/null +++ b/pfr_image_manager.hpp @@ -0,0 +1,75 @@ +#pragma once +#include "version.hpp" + +#include + +namespace phosphor +{ +namespace software +{ +namespace manager +{ + +enum pfrImgPCType { + pfrCPLDUpdateCap = 0x00, + pfrPCHPFM = 0x01, + pfrPCHUpdateCap = 0x02, + pfrBMCPFM = 0x03, + pfrBMCUpdateCap = 0x04 +}; + +/* PFR image block 0 - As defined in HAS */ +struct pfrImgBlock0 { + uint8_t tag[4]; + uint8_t pcLength[4]; + uint8_t pcType[4]; + uint8_t reserved1[4]; + uint8_t hash256[32]; + uint8_t hash384[48]; + uint8_t reserved2[32]; +}__attribute__((packed)); + +/** @class Manager + * @brief Contains a map of Version dbus objects. + * @details The software image manager class that contains the Version dbus + * objects and their version ids. + */ +class Manager +{ + public: + /** @brief Constructs Manager Class + * + * @param[in] bus - The Dbus bus object + */ + Manager(sdbusplus::bus::bus& bus) : bus(bus){}; + + /** + * @brief Verify the image and provide the image to updater. + * Create and populate the version and file path interfaces. + * + * @param[in] uploaded image. + * @param[out] result - 0 if successful. + */ + int processImage(const std::string& imageFilePath); + + /** + * @brief Erase specified entry d-bus object + * and deletes the image file. + * + * @param[in] entryId - unique identifier of the entry + */ + void erase(std::string entryId); + + private: + /** @brief Persistent map of Version dbus objects and their + * version id */ + std::map> versions; + + /** @brief Persistent sdbusplus DBus bus connection. */ + sdbusplus::bus::bus& bus; + +}; + +} // namespace manager +} // namespace software +} // namespace phosphor -- 2.17.1