dm: vRTC: use monotonic time for vrtc base time

The dm vrtc has been using time(NULL) as the vrtc base time. When
service VM system time is adjusted, the vrtc will experience time jump
which will make the vrtc time inaccurate. Change the source of base
time to monotonic time can resolve this issue, as the monotonic time is
not setable.

Tracked-On: #8547
Signed-off-by: Wu Zhou <wu.zhou@intel.com>
Reviewed-by: Jian Jun Chen <jian.jun.chen@intel.com>
This commit is contained in:
Wu Zhou 2023-09-22 15:29:51 +08:00 committed by acrnsi-robot
parent 85e5dc788d
commit 9197529da9
1 changed files with 17 additions and 6 deletions

View File

@ -220,6 +220,17 @@ update_enabled(struct vrtc *vrtc)
return true; return true;
} }
/* monotonic time is number of seconds that the system has been running
* since it was booted. It is none setable. It is more suitable to be used
* as base time.
*/
static time_t monotonic_time(void)
{
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return ts.tv_sec;
}
static time_t static time_t
vrtc_curtime(struct vrtc *vrtc, time_t *basetime) vrtc_curtime(struct vrtc *vrtc, time_t *basetime)
{ {
@ -229,7 +240,7 @@ vrtc_curtime(struct vrtc *vrtc, time_t *basetime)
t = vrtc->base_rtctime; t = vrtc->base_rtctime;
*basetime = vrtc->base_uptime; *basetime = vrtc->base_uptime;
if (update_enabled(vrtc)) { if (update_enabled(vrtc)) {
now = time(NULL); now = monotonic_time();
delta = now - vrtc->base_uptime; delta = now - vrtc->base_uptime;
secs = delta; secs = delta;
t += secs; t += secs;
@ -736,7 +747,7 @@ vrtc_set_reg_b(struct vrtc *vrtc, uint8_t newval)
if (changed & RTCSB_HALT) { if (changed & RTCSB_HALT) {
if ((newval & RTCSB_HALT) == 0) { if ((newval & RTCSB_HALT) == 0) {
rtctime = rtc_to_secs(vrtc); rtctime = rtc_to_secs(vrtc);
basetime = time(NULL); basetime = monotonic_time();
if (rtctime == VRTC_BROKEN_TIME) { if (rtctime == VRTC_BROKEN_TIME) {
if (rtc_flag_broken_time) if (rtc_flag_broken_time)
return -1; return -1;
@ -810,7 +821,7 @@ vrtc_set_reg_a(struct vrtc *vrtc, uint8_t newval)
* maintain the illusion that the RTC date/time was frozen * maintain the illusion that the RTC date/time was frozen
* while the dividers were disabled. * while the dividers were disabled.
*/ */
vrtc->base_uptime = time(NULL); vrtc->base_uptime = monotonic_time();
RTC_DEBUG("RTC divider out of reset at %#lx/%#lx\n", RTC_DEBUG("RTC divider out of reset at %#lx/%#lx\n",
vrtc->base_rtctime, vrtc->base_uptime); vrtc->base_rtctime, vrtc->base_uptime);
} else { } else {
@ -972,7 +983,7 @@ vrtc_data_handler(struct vmctx *ctx, int vcpu, int in, int port,
*/ */
if (vrtc_is_time_register(offset) && !rtc_halted(vrtc)) { if (vrtc_is_time_register(offset) && !rtc_halted(vrtc)) {
curtime = rtc_to_secs(vrtc); curtime = rtc_to_secs(vrtc);
error = vrtc_time_update(vrtc, curtime, time(NULL)); error = vrtc_time_update(vrtc, curtime, monotonic_time());
if ((error != 0) || (curtime == VRTC_BROKEN_TIME && rtc_flag_broken_time)) if ((error != 0) || (curtime == VRTC_BROKEN_TIME && rtc_flag_broken_time))
error = -1; error = -1;
} }
@ -989,7 +1000,7 @@ vrtc_set_time(struct vrtc *vrtc, time_t secs)
int error; int error;
pthread_mutex_lock(&vrtc->mtx); pthread_mutex_lock(&vrtc->mtx);
error = vrtc_time_update(vrtc, secs, time(NULL)); error = vrtc_time_update(vrtc, secs, monotonic_time());
pthread_mutex_unlock(&vrtc->mtx); pthread_mutex_unlock(&vrtc->mtx);
if (error) if (error)
@ -1102,7 +1113,7 @@ vrtc_init(struct vmctx *ctx)
pthread_mutex_lock(&vrtc->mtx); pthread_mutex_lock(&vrtc->mtx);
vrtc->base_rtctime = VRTC_BROKEN_TIME; vrtc->base_rtctime = VRTC_BROKEN_TIME;
vrtc_time_update(vrtc, curtime, time(NULL)); vrtc_time_update(vrtc, curtime, monotonic_time());
secs_to_rtc(curtime, vrtc, 0); secs_to_rtc(curtime, vrtc, 0);
pthread_mutex_unlock(&vrtc->mtx); pthread_mutex_unlock(&vrtc->mtx);