diff options
author | Lei YU <mine260309@gmail.com> | 2019-02-21 17:47:05 +0800 |
---|---|---|
committer | Lei YU <mine260309@gmail.com> | 2019-03-13 11:01:53 +0800 |
commit | dec8cf9c11e7f34be9b50fd45e85bec9187cf1d0 (patch) | |
tree | 1934901611474e5bafdc5feb684a04271159de39 | |
parent | 322f3f4702cda3c2114091c51fa7d88014b7cef8 (diff) | |
download | openpower-pnor-code-mgmt-dec8cf9c11e7f34be9b50fd45e85bec9187cf1d0.tar.gz openpower-pnor-code-mgmt-dec8cf9c11e7f34be9b50fd45e85bec9187cf1d0.zip |
Static layout: Read PNOR VERSION using pflash
Use pflash to read VERSION partition to get the PNOR version
Add code to parse pflash's VERSION partition string.
Tested: Verify that the version and extended version are
retrieved correctly on Romulus and Palmetto.
Change-Id: Ia053c1683a5a969be0773d251cb88c4c5c9b6c60
Signed-off-by: Lei YU <mine260309@gmail.com>
-rw-r--r-- | static/item_updater_static.cpp | 147 | ||||
-rw-r--r-- | version.cpp | 39 | ||||
-rw-r--r-- | version.hpp | 10 |
3 files changed, 195 insertions, 1 deletions
diff --git a/static/item_updater_static.cpp b/static/item_updater_static.cpp index 95912a5bf..5937e13eb 100644 --- a/static/item_updater_static.cpp +++ b/static/item_updater_static.cpp @@ -2,13 +2,112 @@ #include "item_updater_static.hpp" +#include "activation.hpp" +#include "version.hpp" + +#include <cstring> +#include <filesystem> +#include <fstream> +#include <phosphor-logging/elog-errors.hpp> +#include <phosphor-logging/log.hpp> +#include <string> + +using namespace sdbusplus::xyz::openbmc_project::Common::Error; +using namespace phosphor::logging; + +// When you see server:: you know we're referencing our base class +namespace server = sdbusplus::xyz::openbmc_project::Software::server; +namespace fs = std::filesystem; + +namespace utils +{ + +template <typename... Ts> +std::string concat_string(Ts const&... ts) +{ + std::stringstream s; + ((s << ts << " "), ...) << std::endl; + return s.str(); +} + +// Helper function to run pflash command +template <typename... Ts> +std::string pflash(Ts const&... ts) +{ + std::array<char, 512> buffer; + std::string cmd = concat_string("pflash", ts...); + std::stringstream result; + std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(cmd.c_str(), "r"), + pclose); + if (!pipe) + { + throw std::runtime_error("popen() failed!"); + } + while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) + { + result << buffer.data(); + } + return result.str(); +} + +std::string getPNORVersion() +{ + // A signed version partition will have an extra 4K header starting with + // the magic number 17082011 in big endian: + // https://github.com/open-power/skiboot/blob/master/libstb/container.h#L47 + + constexpr uint8_t MAGIC[] = {0x17, 0x08, 0x20, 0x11}; + constexpr auto MAGIC_SIZE = sizeof(MAGIC); + static_assert(MAGIC_SIZE == 4); + + auto tmp = fs::temp_directory_path(); + std::string tmpDir(tmp / "versionXXXXXX"); + if (!mkdtemp(tmpDir.data())) + { + log<level::ERR>("Failed to create temp dir"); + return {}; + } + + fs::path versionFile = tmpDir; + versionFile /= "version"; + + pflash("-P VERSION -r", versionFile.string(), "2>&1 > /dev/null"); + std::ifstream f(versionFile.c_str(), std::ios::in | std::ios::binary); + uint8_t magic[MAGIC_SIZE]; + std::string version; + + f.read(reinterpret_cast<char*>(magic), MAGIC_SIZE); + f.seekg(0, std::ios::beg); + if (std::memcmp(magic, MAGIC, MAGIC_SIZE) == 0) + { + // Skip the first 4K header + f.ignore(4096); + } + + getline(f, version, '\0'); + f.close(); + + // Clear the temp dir + std::error_code ec; + fs::remove_all(tmpDir, ec); + if (ec) + { + log<level::ERR>("Failed to remove temp dir", + entry("DIR=%s", tmpDir.c_str()), + entry("ERR=%s", ec.message().c_str())); + } + + return version; +} + +} // namespace utils + namespace openpower { namespace software { namespace updater { - std::unique_ptr<Activation> ItemUpdaterStatic::createActivationObject( const std::string& path, const std::string& versionId, const std::string& extVersion, @@ -36,6 +135,52 @@ bool ItemUpdaterStatic::validateImage(const std::string& path) void ItemUpdaterStatic::processPNORImage() { + auto fullVersion = utils::getPNORVersion(); + + const auto& [version, extendedVersion] = Version::getVersions(fullVersion); + auto id = Version::getId(version); + + auto activationState = server::Activation::Activations::Active; + if (version.empty()) + { + log<level::ERR>("Failed to read version", + entry("VERSION=%s", fullVersion.c_str())); + activationState = server::Activation::Activations::Invalid; + } + + if (extendedVersion.empty()) + { + log<level::ERR>("Failed to read extendedVersion", + entry("VERSION=%s", fullVersion.c_str())); + activationState = server::Activation::Activations::Invalid; + } + + auto purpose = server::Version::VersionPurpose::Host; + auto path = fs::path(SOFTWARE_OBJPATH) / id; + AssociationList associations = {}; + + if (activationState == server::Activation::Activations::Active) + { + // Create an association to the host inventory item + associations.emplace_back(std::make_tuple(ACTIVATION_FWD_ASSOCIATION, + ACTIVATION_REV_ASSOCIATION, + HOST_INVENTORY_PATH)); + + // Create an active association since this image is active + createActiveAssociation(path); + } + + // Create Version instance for this version. + auto versionPtr = std::make_unique<Version>( + bus, path, *this, id, version, purpose, "", + std::bind(&ItemUpdaterStatic::erase, this, std::placeholders::_1)); + versionPtr->deleteObject = std::make_unique<Delete>(bus, path, *versionPtr); + versions.insert(std::make_pair(id, std::move(versionPtr))); + + if (!id.empty()) + { + updateFunctionalAssociation(id); + } } void ItemUpdaterStatic::reset() diff --git a/version.cpp b/version.cpp index 69ab41558..d9ad3954f 100644 --- a/version.cpp +++ b/version.cpp @@ -96,6 +96,45 @@ std::map<std::string, std::string> return keys; } +std::pair<std::string, std::string> + Version::getVersions(const std::string& versionPart) +{ + // versionPart contains strings like below: + // open-power-romulus-v2.2-rc1-48-g268344f-dirty + // buildroot-2018.11.1-7-g5d7cc8c + // skiboot-v6.2 + std::istringstream iss(versionPart); + std::string line; + std::string version; + std::stringstream ss; + std::string extendedVersion; + + if (!std::getline(iss, line)) + { + log<level::ERR>("Unable to read from version", + entry("VERSION=%s", versionPart.c_str())); + return {}; + } + version = line; + + while (std::getline(iss, line)) + { + // Each line starts with a tab, let's trim it + line.erase(line.begin(), + std::find_if(line.begin(), line.end(), + [](int c) { return !std::isspace(c); })); + ss << line << ','; + } + extendedVersion = ss.str(); + + // Erase the last ',', if there is one + if (!extendedVersion.empty()) + { + extendedVersion.pop_back(); + } + return {version, extendedVersion}; +} + void Delete::delete_() { if (parent.eraseCallback) diff --git a/version.hpp b/version.hpp index 2b5a55ad5..831b20175 100644 --- a/version.hpp +++ b/version.hpp @@ -147,6 +147,16 @@ class Version : public VersionInherit std::map<std::string, std::string> keys); /** + * @brief Get version and extended version from VERSION partition string. + * + * @param[in] versionPart - The string containing the VERSION partition. + * + * @return The pair contains the version and extended version. + **/ + static std::pair<std::string, std::string> + getVersions(const std::string& versionPart); + + /** * @brief Calculate the version id from the version string. * * @details The version id is a unique 8 hexadecimal digit id |