blob: 2023a9922ab45449965ddce25b5a407ad0f04484 [file] [log] [blame]
#include "inband_code_update.hpp"
#include "libpldm/entity.h"
#include "libpldmresponder/pdr.hpp"
#include "oem_ibm_handler.hpp"
#include "xyz/openbmc_project/Common/error.hpp"
#include <arpa/inet.h>
#include <sdbusplus/server.hpp>
#include <xyz/openbmc_project/Dump/NewDump/server.hpp>
#include <exception>
#include <fstream>
namespace pldm
{
namespace responder
{
using namespace oem_ibm_platform;
std::string CodeUpdate::fetchCurrentBootSide()
{
return currBootSide;
}
std::string CodeUpdate::fetchNextBootSide()
{
return nextBootSide;
}
int CodeUpdate::setCurrentBootSide(const std::string& currSide)
{
currBootSide = currSide;
return PLDM_SUCCESS;
}
int CodeUpdate::setNextBootSide(const std::string& nextSide)
{
nextBootSide = nextSide;
std::string objPath{};
if (nextBootSide == currBootSide)
{
objPath = runningVersion;
}
else
{
objPath = nonRunningVersion;
}
if (objPath.empty())
{
std::cerr << "no nonRunningVersion present \n";
return PLDM_PLATFORM_INVALID_STATE_VALUE;
}
pldm::utils::DBusMapping dbusMapping{objPath, redundancyIntf, "Priority",
"uint8_t"};
uint8_t val = 0;
pldm::utils::PropertyValue value = static_cast<uint8_t>(val);
try
{
dBusIntf->setDbusProperty(dbusMapping, value);
}
catch (const std::exception& e)
{
std::cerr << "failed to set the next boot side to " << objPath.c_str()
<< " ERROR=" << e.what() << "\n";
return PLDM_ERROR;
}
return PLDM_SUCCESS;
}
void CodeUpdate::setVersions()
{
static constexpr auto mapperService = "xyz.openbmc_project.ObjectMapper";
static constexpr auto functionalObjPath =
"/xyz/openbmc_project/software/functional";
static constexpr auto activeObjPath =
"/xyz/openbmc_project/software/active";
static constexpr auto propIntf = "org.freedesktop.DBus.Properties";
auto& bus = dBusIntf->getBus();
try
{
auto method = bus.new_method_call(mapperService, functionalObjPath,
propIntf, "Get");
method.append("xyz.openbmc_project.Association", "endpoints");
std::variant<std::vector<std::string>> paths;
auto reply = bus.call(method);
reply.read(paths);
runningVersion = std::get<std::vector<std::string>>(paths)[0];
auto method1 =
bus.new_method_call(mapperService, activeObjPath, propIntf, "Get");
method1.append("xyz.openbmc_project.Association", "endpoints");
auto reply1 = bus.call(method1);
reply1.read(paths);
for (const auto& path : std::get<std::vector<std::string>>(paths))
{
if (path != runningVersion)
{
nonRunningVersion = path;
break;
}
}
}
catch (const std::exception& e)
{
std::cerr << "failed to make a d-bus call to Object Mapper "
"Association, ERROR="
<< e.what() << "\n";
return;
}
using namespace sdbusplus::bus::match::rules;
captureNextBootSideChange.push_back(
std::make_unique<sdbusplus::bus::match::match>(
pldm::utils::DBusHandler::getBus(),
propertiesChanged(runningVersion, redundancyIntf),
[this](sdbusplus::message::message& msg) {
DbusChangedProps props;
std::string iface;
msg.read(iface, props);
processPriorityChangeNotification(props);
}));
fwUpdateMatcher = std::make_unique<sdbusplus::bus::match::match>(
pldm::utils::DBusHandler::getBus(),
"interface='org.freedesktop.DBus.ObjectManager',type='signal',"
"member='InterfacesAdded',path='/xyz/openbmc_project/software'",
[this](sdbusplus::message::message& msg) {
DBusInterfaceAdded interfaces;
sdbusplus::message::object_path path;
msg.read(path, interfaces);
for (auto& interface : interfaces)
{
if (interface.first ==
"xyz.openbmc_project.Software.Activation")
{
newImageId = path.str;
break;
}
}
});
}
void CodeUpdate::processPriorityChangeNotification(
const DbusChangedProps& chProperties)
{
static constexpr auto propName = "Priority";
const auto it = chProperties.find(propName);
if (it == chProperties.end())
{
return;
}
uint8_t newVal = std::get<uint8_t>(it->second);
nextBootSide = (newVal == 0) ? currBootSide
: ((currBootSide == Tside) ? Pside : Tside);
}
void CodeUpdate::setOemPlatformHandler(
pldm::responder::oem_platform::Handler* handler)
{
oemPlatformHandler = handler;
}
uint8_t fetchBootSide(uint16_t entityInstance, CodeUpdate* codeUpdate)
{
uint8_t sensorOpState = tSideNum;
if (entityInstance == 0)
{
auto currSide = codeUpdate->fetchCurrentBootSide();
if (currSide == Pside)
{
sensorOpState = pSideNum;
}
}
else if (entityInstance == 1)
{
auto nextSide = codeUpdate->fetchNextBootSide();
if (nextSide == Pside)
{
sensorOpState = pSideNum;
}
}
else
{
sensorOpState = PLDM_SENSOR_UNKNOWN;
}
return sensorOpState;
}
int setBootSide(uint16_t entityInstance, uint8_t currState,
const std::vector<set_effecter_state_field>& stateField,
CodeUpdate* codeUpdate)
{
int rc = PLDM_SUCCESS;
auto side = (stateField[currState].effecter_state == pSideNum) ? "P" : "T";
if (entityInstance == 0)
{
rc = codeUpdate->setCurrentBootSide(side);
}
else if (entityInstance == 1)
{
rc = codeUpdate->setNextBootSide(side);
}
else
{
rc = PLDM_PLATFORM_INVALID_STATE_VALUE;
}
return rc;
}
int processCodeUpdateLid(const std::string& filePath)
{
struct LidHeader
{
uint16_t magicNumber;
uint16_t headerVersion;
uint32_t lidNumber;
uint32_t lidDate;
uint16_t lidTime;
uint16_t lidClass;
uint32_t lidCrc;
uint32_t lidSize;
uint32_t headerSize;
};
LidHeader header;
std::ifstream ifs(filePath, std::ios::in | std::ios::binary);
if (!ifs)
{
std::cerr << "ifstream open error: " << filePath << "\n";
return PLDM_ERROR;
}
ifs.seekg(0);
ifs.read(reinterpret_cast<char*>(&header), sizeof(header));
ifs.close();
// File size should be the value of lid size minus the header size
auto fileSize = fs::file_size(filePath);
fileSize -= htonl(header.headerSize);
if (fileSize < htonl(header.lidSize))
{
// File is not completely written yet
return PLDM_SUCCESS;
}
constexpr auto magicNumber = 0x0222;
if (htons(header.magicNumber) != magicNumber)
{
std::cerr << "Invalid magic number: " << filePath << "\n";
return PLDM_ERROR;
}
return PLDM_SUCCESS;
}
} // namespace responder
} // namespace pldm