[PATCH v4 6/8] hv: add time modification of vrtc


Zhao, Yuanyuan
 

VRTC for hv used to ignore writes to vRTC register.

This patch add time modification to vRTC.
Add base RTC time and TSC offset to get the current time. Convert
current time to vRTC register values (`struct rtcdev`). Then
modify a register, and calculate a new time. Get RTC offset by
substrcting new time from current time.
Thereafter, add RTC offset also when get current time. Then user
can get the modified time.

Signed-off-by: Yuanyuan Zhao <yuanyuan.zhao@...>
---
hypervisor/dm/vrtc.c | 14 +++++++++++++-
hypervisor/include/dm/vrtc.h | 2 ++
2 files changed, 15 insertions(+), 1 deletion(-)

diff --git a/hypervisor/dm/vrtc.c b/hypervisor/dm/vrtc.c
index 565720e45..ba0f510e2 100644
--- a/hypervisor/dm/vrtc.c
+++ b/hypervisor/dm/vrtc.c
@@ -383,7 +383,7 @@ static time_t vrtc_get_current_time(struct acrn_vrtc *vrtc)

if (vrtc->base_rtctime > 0) {
offset = (cpu_ticks() - vrtc->base_tsc) / (get_tsc_khz() * 1000U);
- second = vrtc->base_rtctime + (time_t)offset;
+ second = vrtc->base_rtctime + vrtc->offset_rtctime + (time_t)offset;
}
return second;
}
@@ -527,6 +527,7 @@ static bool vrtc_read(struct acrn_vcpu *vcpu, uint16_t addr, __unused size_t wid
static bool vrtc_write(struct acrn_vcpu *vcpu, uint16_t addr, size_t width,
uint32_t value)
{
+ time_t current, after;
struct acrn_vrtc *vrtc = &vcpu->vm->vrtc;

if ((width == 1U) && (addr == CMOS_ADDR_PORT)) {
@@ -552,7 +553,18 @@ static bool vrtc_write(struct acrn_vcpu *vcpu, uint16_t addr, size_t width,
*((uint8_t *)&vrtc->rtcdev + vrtc->addr) = (uint8_t)(value & 0x7FU);
RTC_DEBUG("RTC alarm reg(%d) set to %#x (ignored)\n", vrtc->addr, value);
break;
+ case 0:
+ /*
+ * High order bit of 'seconds' is readonly.
+ */
+ value &= 0x7f;
+ /* FALLTHRU */
default:
+ RTC_DEBUG("RTC offset %#x set to %#x\n", vrtc->addr, value);
+ *((uint8_t *)&vrtc->rtcdev + vrtc->addr) = (uint8_t)(value & 0xFFU);
+ current = vrtc_get_current_time(vrtc);
+ after = rtc_to_secs(vrtc);
+ vrtc->offset_rtctime += after - current;
break;
}
}
diff --git a/hypervisor/include/dm/vrtc.h b/hypervisor/include/dm/vrtc.h
index fff2559d2..b760ce445 100644
--- a/hypervisor/include/dm/vrtc.h
+++ b/hypervisor/include/dm/vrtc.h
@@ -34,6 +34,8 @@ struct acrn_vrtc {
uint32_t addr; /* RTC register to read or write */

time_t base_rtctime; /* Base time calulated from physical rtc register. */
+ time_t offset_rtctime; /* RTC offset against base time. */
+
uint64_t base_tsc; /* Base tsc value */

struct rtcdev rtcdev; /* RTC register */
--
2.25.1


Junjie Mao
 

Yuanyuan Zhao <yuanyuan.zhao@...> writes:

VRTC for hv used to ignore writes to vRTC register.

This patch add time modification to vRTC.
Add base RTC time and TSC offset to get the current time. Convert
current time to vRTC register values (`struct rtcdev`). Then
modify a register, and calculate a new time. Get RTC offset by
substrcting new time from current time.
Thereafter, add RTC offset also when get current time. Then user
can get the modified time.

Signed-off-by: Yuanyuan Zhao <yuanyuan.zhao@...>
---
hypervisor/dm/vrtc.c | 14 +++++++++++++-
hypervisor/include/dm/vrtc.h | 2 ++
2 files changed, 15 insertions(+), 1 deletion(-)

diff --git a/hypervisor/dm/vrtc.c b/hypervisor/dm/vrtc.c
index 565720e45..ba0f510e2 100644
--- a/hypervisor/dm/vrtc.c
+++ b/hypervisor/dm/vrtc.c
@@ -383,7 +383,7 @@ static time_t vrtc_get_current_time(struct acrn_vrtc *vrtc)

if (vrtc->base_rtctime > 0) {
offset = (cpu_ticks() - vrtc->base_tsc) / (get_tsc_khz() * 1000U);
- second = vrtc->base_rtctime + (time_t)offset;
+ second = vrtc->base_rtctime + vrtc->offset_rtctime + (time_t)offset;
}
return second;
}
@@ -527,6 +527,7 @@ static bool vrtc_read(struct acrn_vcpu *vcpu, uint16_t addr, __unused size_t wid
static bool vrtc_write(struct acrn_vcpu *vcpu, uint16_t addr, size_t width,
uint32_t value)
{
+ time_t current, after;
struct acrn_vrtc *vrtc = &vcpu->vm->vrtc;

if ((width == 1U) && (addr == CMOS_ADDR_PORT)) {
@@ -552,7 +553,18 @@ static bool vrtc_write(struct acrn_vcpu *vcpu, uint16_t addr, size_t width,
*((uint8_t *)&vrtc->rtcdev + vrtc->addr) = (uint8_t)(value & 0x7FU);
RTC_DEBUG("RTC alarm reg(%d) set to %#x (ignored)\n", vrtc->addr, value);
break;
+ case 0:
What does "0" mean here? If the switch statement is checking rtc->addr,
keep using the macros RTC_xxx here.

+ /*
+ * High order bit of 'seconds' is readonly.
+ */
+ value &= 0x7f;
+ /* FALLTHRU */
default:
+ RTC_DEBUG("RTC offset %#x set to %#x\n", vrtc->addr, value);
+ *((uint8_t *)&vrtc->rtcdev + vrtc->addr) = (uint8_t)(value & 0xFFU);
+ current = vrtc_get_current_time(vrtc);
+ after = rtc_to_secs(vrtc);
+ vrtc->offset_rtctime += after - current;
break;
}
}
diff --git a/hypervisor/include/dm/vrtc.h b/hypervisor/include/dm/vrtc.h
index fff2559d2..b760ce445 100644
--- a/hypervisor/include/dm/vrtc.h
+++ b/hypervisor/include/dm/vrtc.h
@@ -34,6 +34,8 @@ struct acrn_vrtc {
uint32_t addr; /* RTC register to read or write */

time_t base_rtctime; /* Base time calulated from physical rtc register. */
+ time_t offset_rtctime; /* RTC offset against base time. */
+
uint64_t base_tsc; /* Base tsc value */

struct rtcdev rtcdev; /* RTC register */
--
Best Regards
Junjie Mao


Zhao, Yuanyuan
 

On 5/6/2022 9:32 AM, Junjie Mao wrote:
Yuanyuan Zhao <yuanyuan.zhao@...> writes:

VRTC for hv used to ignore writes to vRTC register.

This patch add time modification to vRTC.
Add base RTC time and TSC offset to get the current time. Convert
current time to vRTC register values (`struct rtcdev`). Then
modify a register, and calculate a new time. Get RTC offset by
substrcting new time from current time.
Thereafter, add RTC offset also when get current time. Then user
can get the modified time.

Signed-off-by: Yuanyuan Zhao <yuanyuan.zhao@...>
---
hypervisor/dm/vrtc.c | 14 +++++++++++++-
hypervisor/include/dm/vrtc.h | 2 ++
2 files changed, 15 insertions(+), 1 deletion(-)

diff --git a/hypervisor/dm/vrtc.c b/hypervisor/dm/vrtc.c
index 565720e45..ba0f510e2 100644
--- a/hypervisor/dm/vrtc.c
+++ b/hypervisor/dm/vrtc.c
@@ -383,7 +383,7 @@ static time_t vrtc_get_current_time(struct acrn_vrtc *vrtc)
if (vrtc->base_rtctime > 0) {
offset = (cpu_ticks() - vrtc->base_tsc) / (get_tsc_khz() * 1000U);
- second = vrtc->base_rtctime + (time_t)offset;
+ second = vrtc->base_rtctime + vrtc->offset_rtctime + (time_t)offset;
}
return second;
}
@@ -527,6 +527,7 @@ static bool vrtc_read(struct acrn_vcpu *vcpu, uint16_t addr, __unused size_t wid
static bool vrtc_write(struct acrn_vcpu *vcpu, uint16_t addr, size_t width,
uint32_t value)
{
+ time_t current, after;
struct acrn_vrtc *vrtc = &vcpu->vm->vrtc;
if ((width == 1U) && (addr == CMOS_ADDR_PORT)) {
@@ -552,7 +553,18 @@ static bool vrtc_write(struct acrn_vcpu *vcpu, uint16_t addr, size_t width,
*((uint8_t *)&vrtc->rtcdev + vrtc->addr) = (uint8_t)(value & 0x7FU);
RTC_DEBUG("RTC alarm reg(%d) set to %#x (ignored)\n", vrtc->addr, value);
break;
+ case 0:
What does "0" mean here? If the switch statement is checking rtc->addr,
keep using the macros RTC_xxx here.
OK.

+ /*
+ * High order bit of 'seconds' is readonly.
+ */
+ value &= 0x7f;
+ /* FALLTHRU */
default:
+ RTC_DEBUG("RTC offset %#x set to %#x\n", vrtc->addr, value);
+ *((uint8_t *)&vrtc->rtcdev + vrtc->addr) = (uint8_t)(value & 0xFFU);
+ current = vrtc_get_current_time(vrtc);
+ after = rtc_to_secs(vrtc);
+ vrtc->offset_rtctime += after - current;
break;
}
}
diff --git a/hypervisor/include/dm/vrtc.h b/hypervisor/include/dm/vrtc.h
index fff2559d2..b760ce445 100644
--- a/hypervisor/include/dm/vrtc.h
+++ b/hypervisor/include/dm/vrtc.h
@@ -34,6 +34,8 @@ struct acrn_vrtc {
uint32_t addr; /* RTC register to read or write */
time_t base_rtctime; /* Base time calulated from physical rtc register. */
+ time_t offset_rtctime; /* RTC offset against base time. */
+
uint64_t base_tsc; /* Base tsc value */
struct rtcdev rtcdev; /* RTC register */