| #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 |