blob: 57e121b49429dc88d7ba3f59419b2e0b6bcb3e37 [file] [log] [blame]
/*
// 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.
*/
#include "pfr_mgr.hpp"
#include "file.hpp"
namespace pfr
{
inline void printVersion(const std::string& path, const std::string& version)
{
lg2::info("VERSION INFO - {TYPE} - {VER}", "TYPE", path, "VER", version);
}
static constexpr uint8_t activeImage = 0;
static constexpr uint8_t recoveryImage = 1;
std::shared_ptr<sdbusplus::asio::dbus_interface> associationIface;
std::set<std::tuple<std::string, std::string, std::string>> associations;
using GetSubTreeType = std::vector<
std::pair<std::string,
std::vector<std::pair<std::string, std::vector<std::string>>>>>;
PfrVersion::PfrVersion(sdbusplus::asio::object_server& srv_,
std::shared_ptr<sdbusplus::asio::connection>& conn_,
const std::string& path_, const ImageType& imgType_,
const std::string& purpose_) :
server(srv_),
conn(conn_), path(path_), imgType(imgType_), purpose(purpose_)
{
version = getFirmwareVersion(imgType);
if (!(version == "0.0" || version.empty()))
{
printVersion(path, version);
}
std::string objPath = "/xyz/openbmc_project/software/" + path;
versionIface = server.add_interface(objPath,
"xyz.openbmc_project.Software.Version");
if (versionIface != nullptr)
{
versionIface->register_property("Purpose", purpose);
versionIface->register_property(
versionStr, version,
// Override set
[this](const std::string& req, std::string& propertyValue) {
if (internalSet)
{
if (req != propertyValue)
{
version = req;
propertyValue = req;
return 1;
}
}
return 0;
});
versionIface->initialize();
}
std::string activation =
"xyz.openbmc_project.Software.Activation.Activations.StandbySpare";
if ((imgType == ImageType::bmcActive) ||
(imgType == ImageType::biosActive) ||
(imgType == ImageType::cpldActive) || (imgType == ImageType::afmActive))
{
// Running images so set Activations to "Active"
activation =
"xyz.openbmc_project.Software.Activation.Activations.Active";
// For all Active images, functional endpoints must be added. This is
// used in bmcweb & ipmi for fetching active component versions.
// TODO: We have redundant active firmware version objects for BMC
// and BIOS active images. BMC version is read from /etc/os-release
// BIOS version is read from SMBIOS. Since it provides more
// version information, Lets expose those as functional.
// Down the line, Redundant inventory objects need to be addressed.
if ((imgType == ImageType::cpldActive) ||
(imgType == ImageType::afmActive))
{
associations.emplace("functional", "software_version", objPath);
}
}
std::string reqActNone =
"xyz.openbmc_project.Software.Activation.RequestedActivations.None";
auto activationIface = server.add_interface(
objPath, "xyz.openbmc_project.Software.Activation");
if (activationIface != nullptr)
{
activationIface->register_property("Activation", activation);
activationIface->register_property("RequestedActivation", reqActNone);
activationIface->initialize();
}
// All the components exposed under PFR.Manager are updateable.
// Lets add objPath endpoints to 'updatable' association
associations.emplace("updateable", "software_version", objPath);
associationIface->set_property("Associations", associations);
}
void PfrVersion::updateVersion()
{
if (versionIface && versionIface->is_initialized())
{
std::string ver = getFirmwareVersion(imgType);
printVersion(path, ver);
internalSet = true;
versionIface->set_property(versionStr, ver);
internalSet = false;
}
return;
}
PfrConfig::PfrConfig(sdbusplus::asio::object_server& srv_,
std::shared_ptr<sdbusplus::asio::connection>& conn_) :
server(srv_),
conn(conn_)
{
pfrCfgIface = server.add_interface("/xyz/openbmc_project/pfr",
"xyz.openbmc_project.PFR.Attributes");
ufmLocked = false;
ufmProvisioned = false;
ufmSupport = false;
getProvisioningStatus(ufmLocked, ufmProvisioned, ufmSupport);
pfrCfgIface->register_property(ufmProvisionedStr, ufmProvisioned,
// Override set
[this](const bool req, bool propertyValue) {
if (internalSet)
{
if (req != propertyValue)
{
ufmProvisioned = req;
propertyValue = req;
return 1;
}
}
return 0;
});
pfrCfgIface->register_property(ufmLockedStr, ufmLocked,
// Override set
[this](const bool req, bool propertyValue) {
if (internalSet)
{
if (req != propertyValue)
{
ufmLocked = req;
propertyValue = req;
return 1;
}
}
return 0;
});
pfrCfgIface->register_property(ufmSupportStr, ufmSupport,
// Override set
[this](const bool req, bool propertyValue) {
if (internalSet)
{
if (req != propertyValue)
{
ufmSupport = req;
propertyValue = req;
return 1;
}
}
return 0;
});
pfrCfgIface->initialize();
/*BMCBusy period MailBox handling */
pfrMBIface = server.add_interface("/xyz/openbmc_project/pfr",
"xyz.openbmc_project.PFR.Mailbox");
pfrMBIface->register_method("InitiateBMCBusyPeriod", [](bool setReset) {
if (setBMCBusy(setReset) < 0)
{
return false;
}
return true;
});
pfrMBIface->register_method("ReadMBRegister", [](uint32_t regAddr) {
uint8_t mailBoxReply = 0;
try
{
getMBRegister(regAddr, mailBoxReply);
}
catch (const std::exception& e)
{
throw;
}
return mailBoxReply;
});
pfrMBIface->initialize();
associationIface =
server.add_interface("/xyz/openbmc_project/software",
"xyz.openbmc_project.Association.Definitions");
associationIface->register_property("Associations", associations);
associationIface->initialize();
}
void PfrConfig::updateProvisioningStatus()
{
if (pfrCfgIface && pfrCfgIface->is_initialized())
{
bool lockVal = false;
bool provVal = false;
bool supportVal = false;
getProvisioningStatus(lockVal, provVal, supportVal);
internalSet = true;
pfrCfgIface->set_property(ufmProvisionedStr, provVal);
pfrCfgIface->set_property(ufmLockedStr, lockVal);
pfrCfgIface->set_property(ufmSupportStr, supportVal);
internalSet = false;
}
return;
}
static constexpr const char* postcodeStrProp = "PlatformState";
static constexpr const char* postcodeStrDefault = "Unknown";
static constexpr const char* postcodeDataProp = "Data";
static constexpr const char* postcodeIface =
"xyz.openbmc_project.State.Boot.Platform";
PfrPostcode::PfrPostcode(sdbusplus::asio::object_server& srv_,
std::shared_ptr<sdbusplus::asio::connection>& conn_) :
server(srv_),
conn(conn_)
{
if (getPlatformState(postcode) < 0)
{
postcode = 0;
}
pfrPostcodeIface = server.add_interface("/xyz/openbmc_project/pfr",
postcodeIface);
if (pfrPostcodeIface != nullptr)
{
pfrPostcodeIface->register_property(
postcodeDataProp, postcode,
// Override set
[this](const uint8_t req, uint8_t& propertyValue) {
if (internalSet)
{
if (req != propertyValue)
{
postcode = req;
propertyValue = req;
return 1;
}
}
return 0;
},
[this](uint8_t& propertyValue) {
updatePostcode();
propertyValue = postcode;
return propertyValue;
});
pfrPostcodeIface->register_property(postcodeStrProp,
std::string(postcodeStrDefault));
pfrPostcodeIface->initialize();
auto it = postcodeMap.find(postcode);
if (it != postcodeMap.end())
{
pfrPostcodeIface->set_property(postcodeStrProp, it->second);
}
}
}
void PfrPostcode::updatePostcode()
{
if (pfrPostcodeIface && pfrPostcodeIface->is_initialized())
{
if (getPlatformState(postcode) < 0)
{
postcode = 0;
}
internalSet = true;
pfrPostcodeIface->set_property(postcodeDataProp, postcode);
auto it = postcodeMap.find(postcode);
if (it == postcodeMap.end())
{
pfrPostcodeIface->set_property(postcodeStrProp, postcodeStrDefault);
}
else
{
pfrPostcodeIface->set_property(postcodeStrProp, it->second);
}
internalSet = false;
}
return;
}
} // namespace pfr