196232827SLei YU #include "bmc_epoch.hpp" 296232827SLei YU 3*7b218796SLei YU #include <phosphor-logging/elog.hpp> 4*7b218796SLei YU #include <phosphor-logging/elog-errors.hpp> 596232827SLei YU #include <phosphor-logging/log.hpp> 6*7b218796SLei YU #include <xyz/openbmc_project/Common/error.hpp> 7*7b218796SLei YU 8*7b218796SLei YU #include <sys/timerfd.h> 9*7b218796SLei YU #include <unistd.h> 10*7b218796SLei YU 11*7b218796SLei YU 12*7b218796SLei YU // Neeed to do this since its not exported outside of the kernel. 13*7b218796SLei YU // Refer : https://gist.github.com/lethean/446cea944b7441228298 14*7b218796SLei YU #ifndef TFD_TIMER_CANCEL_ON_SET 15*7b218796SLei YU #define TFD_TIMER_CANCEL_ON_SET (1 << 1) 16*7b218796SLei YU #endif 17*7b218796SLei YU 18*7b218796SLei YU // Needed to make sure timerfd does not misfire even though we set CANCEL_ON_SET 19*7b218796SLei YU #define TIME_T_MAX (time_t)((1UL << ((sizeof(time_t) << 3) - 1)) - 1) 2096232827SLei YU 2196232827SLei YU namespace phosphor 2296232827SLei YU { 2396232827SLei YU namespace time 2496232827SLei YU { 2596232827SLei YU namespace server = sdbusplus::xyz::openbmc_project::Time::server; 2696232827SLei YU using namespace phosphor::logging; 2796232827SLei YU 2896232827SLei YU BmcEpoch::BmcEpoch(sdbusplus::bus::bus& bus, 2996232827SLei YU const char* objPath) 30*7b218796SLei YU : EpochBase(bus, objPath), 31*7b218796SLei YU bus(bus) 3296232827SLei YU { 33*7b218796SLei YU initialize(); 34*7b218796SLei YU } 35*7b218796SLei YU 36*7b218796SLei YU void BmcEpoch::initialize() 37*7b218796SLei YU { 38*7b218796SLei YU using InternalFailure = sdbusplus::xyz::openbmc_project::Common:: 39*7b218796SLei YU Error::InternalFailure; 40*7b218796SLei YU 41*7b218796SLei YU // Subscribe time change event 42*7b218796SLei YU // Choose the MAX time that is possible to avoid mis fires. 43*7b218796SLei YU constexpr itimerspec maxTime = { 44*7b218796SLei YU {0, 0}, // it_interval 45*7b218796SLei YU {TIME_T_MAX, 0}, //it_value 46*7b218796SLei YU }; 47*7b218796SLei YU 48*7b218796SLei YU timeFd = timerfd_create(CLOCK_REALTIME, 0); 49*7b218796SLei YU if (timeFd == -1) 50*7b218796SLei YU { 51*7b218796SLei YU log<level::ERR>("Failed to create timerfd", 52*7b218796SLei YU entry("ERRNO=%d", errno), 53*7b218796SLei YU entry("ERR=%s", strerror(errno))); 54*7b218796SLei YU elog<InternalFailure>(); 55*7b218796SLei YU } 56*7b218796SLei YU 57*7b218796SLei YU auto r = timerfd_settime(timeFd, 58*7b218796SLei YU TFD_TIMER_ABSTIME | TFD_TIMER_CANCEL_ON_SET, 59*7b218796SLei YU &maxTime, 60*7b218796SLei YU nullptr); 61*7b218796SLei YU if (r != 0) 62*7b218796SLei YU { 63*7b218796SLei YU log<level::ERR>("Failed to set timerfd", 64*7b218796SLei YU entry("ERRNO=%d", errno), 65*7b218796SLei YU entry("ERR=%s", strerror(errno))); 66*7b218796SLei YU elog<InternalFailure>(); 67*7b218796SLei YU } 68*7b218796SLei YU 69*7b218796SLei YU sd_event_source* es; 70*7b218796SLei YU r = sd_event_add_io(bus.get_event(), &es, 71*7b218796SLei YU timeFd, EPOLLIN, onTimeChange, this); 72*7b218796SLei YU if (r < 0) 73*7b218796SLei YU { 74*7b218796SLei YU log<level::ERR>("Failed to add event", 75*7b218796SLei YU entry("ERRNO=%d", -r), 76*7b218796SLei YU entry("ERR=%s", strerror(-r))); 77*7b218796SLei YU elog<InternalFailure>(); 78*7b218796SLei YU } 79*7b218796SLei YU timeChangeEventSource.reset(es); 80*7b218796SLei YU } 81*7b218796SLei YU 82*7b218796SLei YU BmcEpoch::~BmcEpoch() 83*7b218796SLei YU { 84*7b218796SLei YU close(timeFd); 8596232827SLei YU } 8696232827SLei YU 8796232827SLei YU uint64_t BmcEpoch::elapsed() const 8896232827SLei YU { 8996232827SLei YU // It does not needs to check owner when getting time 9096232827SLei YU return getTime().count(); 9196232827SLei YU } 9296232827SLei YU 9396232827SLei YU uint64_t BmcEpoch::elapsed(uint64_t value) 9496232827SLei YU { 95*7b218796SLei YU /* 96*7b218796SLei YU Mode | Owner | Set BMC Time 97*7b218796SLei YU ----- | ----- | ------------- 98*7b218796SLei YU NTP | BMC | Not allowed 99*7b218796SLei YU NTP | HOST | Not allowed 100*7b218796SLei YU NTP | SPLIT | Not allowed 101*7b218796SLei YU NTP | BOTH | Not allowed 102*7b218796SLei YU MANUAL| BMC | OK 103*7b218796SLei YU MANUAL| HOST | Not allowed 104*7b218796SLei YU MANUAL| SPLIT | OK 105*7b218796SLei YU MANUAL| BOTH | OK 106*7b218796SLei YU */ 107e7abcdc7SLei YU if (timeMode == Mode::NTP) 108e7abcdc7SLei YU { 109e7abcdc7SLei YU log<level::ERR>("Setting BmcTime with NTP mode is not allowed"); 110e7abcdc7SLei YU // TODO: throw NotAllowed exception 111e7abcdc7SLei YU return 0; 112e7abcdc7SLei YU } 113e7abcdc7SLei YU if (timeOwner == Owner::HOST) 114e7abcdc7SLei YU { 115e7abcdc7SLei YU log<level::ERR>("Setting BmcTime with HOST owner is not allowed"); 116e7abcdc7SLei YU // TODO: throw NotAllowed exception 117e7abcdc7SLei YU return 0; 118e7abcdc7SLei YU } 119e7abcdc7SLei YU 120*7b218796SLei YU auto time = microseconds(value); 12196232827SLei YU setTime(time); 122e7abcdc7SLei YU 123*7b218796SLei YU notifyBmcTimeChange(time); 124*7b218796SLei YU 12596232827SLei YU server::EpochTime::elapsed(value); 12696232827SLei YU return value; 12796232827SLei YU } 12896232827SLei YU 129*7b218796SLei YU void BmcEpoch::setBmcTimeChangeListener(BmcTimeChangeListener* listener) 130*7b218796SLei YU { 131*7b218796SLei YU timeChangeListener = listener; 132*7b218796SLei YU } 133*7b218796SLei YU 134*7b218796SLei YU void BmcEpoch::notifyBmcTimeChange(const microseconds& time) 135*7b218796SLei YU { 136*7b218796SLei YU // Notify listener if it exists 137*7b218796SLei YU if (timeChangeListener) 138*7b218796SLei YU { 139*7b218796SLei YU timeChangeListener->onBmcTimeChanged(time); 140*7b218796SLei YU } 141*7b218796SLei YU } 142*7b218796SLei YU 143*7b218796SLei YU int BmcEpoch::onTimeChange(sd_event_source* es, int fd, 144*7b218796SLei YU uint32_t /* revents */, void* userdata) 145*7b218796SLei YU { 146*7b218796SLei YU auto bmcEpoch = static_cast<BmcEpoch*>(userdata); 147*7b218796SLei YU 148*7b218796SLei YU std::array<char, 64> time {}; 149*7b218796SLei YU 150*7b218796SLei YU // We are not interested in the data here. 151*7b218796SLei YU // So read until there is no new data here in the FD 152*7b218796SLei YU while (read(fd, time.data(), time.max_size()) > 0); 153*7b218796SLei YU 154*7b218796SLei YU log<level::INFO>("BMC system time is changed"); 155*7b218796SLei YU bmcEpoch->notifyBmcTimeChange(bmcEpoch->getTime()); 156*7b218796SLei YU 157*7b218796SLei YU return 0; 158*7b218796SLei YU } 159*7b218796SLei YU 160af5abc57SLei YU } // namespace time 161af5abc57SLei YU } // namespace phosphor 16296232827SLei YU 163