#include "host_epoch.hpp" #include "utils.hpp" #include #include #include namespace phosphor { namespace time { using namespace sdbusplus::xyz::openbmc_project::Time; using namespace phosphor::logging; using namespace std::chrono; using NotAllowedError = sdbusplus::xyz::openbmc_project::Time::Error::NotAllowed; HostEpoch::HostEpoch(sdbusplus::bus::bus& bus, const char* objPath) : EpochBase(bus, objPath), offset(utils::readData(offsetFile)) { // Initialize the diffToSteadyClock auto steadyTime = duration_cast(steady_clock::now().time_since_epoch()); diffToSteadyClock = getTime() + offset - steadyTime; } uint64_t HostEpoch::elapsed() const { auto ret = getTime(); if (timeOwner == Owner::Split) { ret += offset; } return ret.count(); } uint64_t HostEpoch::elapsed(uint64_t value) { /* Mode | Owner | Set Host Time ----- | ----- | ------------- NTP | BMC | Not allowed NTP | HOST | Not allowed NTP | SPLIT | OK, and just save offset NTP | BOTH | Not allowed MANUAL| BMC | Not allowed MANUAL| HOST | OK, and set time to BMC MANUAL| SPLIT | OK, and just save offset MANUAL| BOTH | OK, and set time to BMC */ if (timeOwner == Owner::BMC || (timeMode == Mode::NTP && (timeOwner == Owner::Host || timeOwner == Owner::Both))) { using namespace xyz::openbmc_project::Time; elog( NotAllowed::OWNER(utils::ownerToStr(timeOwner).c_str()), NotAllowed::SYNC_METHOD(utils::modeToStr(timeMode).c_str()), NotAllowed::REASON("Setting HostTime is not allowed")); } auto time = microseconds(value); if (timeOwner == Owner::Split) { // Calculate the offset between host and bmc time offset = time - getTime(); saveOffset(); // Calculate the diff between host and steady time auto steadyTime = duration_cast(steady_clock::now().time_since_epoch()); diffToSteadyClock = time - steadyTime; } else { // Set time to BMC setTime(time); } server::EpochTime::elapsed(value); return value; } void HostEpoch::onOwnerChanged(Owner owner) { // If timeOwner is changed to SPLIT, the offset shall be preserved // Otherwise it shall be cleared; timeOwner = owner; if (timeOwner != Owner::Split) { offset = microseconds(0); saveOffset(); } else { // In SPLIT, need to re-calculate the diff between // host and steady time auto steadyTime = duration_cast(steady_clock::now().time_since_epoch()); diffToSteadyClock = getTime() - steadyTime; } } void HostEpoch::saveOffset() { // Store the offset to file utils::writeData(offsetFile, offset.count()); } void HostEpoch::onBmcTimeChanged(const microseconds& bmcTime) { // If owner is split and BMC time is changed, // the offset shall be adjusted if (timeOwner == Owner::Split) { auto steadyTime = duration_cast(steady_clock::now().time_since_epoch()); auto hostTime = steadyTime + diffToSteadyClock; offset = hostTime - bmcTime; saveOffset(); } } } // namespace time } // namespace phosphor