From 97916364fc3b4bb90758dd1978dfea4df4abb680 Mon Sep 17 00:00:00 2001 From: "Yan, Like" Date: Tue, 26 Nov 2019 14:06:40 +0800 Subject: [PATCH] hv: fix virtual TSC_DEADLINE msr read/write issues When write to virtual TSC_DEADLINE, if virtual TSC_ADJUST is not zero: - when guest intends to disarm the tsc_deadline timer, should not arm the timer falsely; - when guest intends to arm the tsc_deadline timer, should not disarm the timer falsely. When read from virtual TSC_DEADLINE, if virtual TSC_ADJUST is not zero: - if physical TSC_DEADLINE is not zero, return the virtual TSC_DEADLINE value; - if physical TSC_DEADLINE is zero which means it's not armed (automatically disarmed after timer triggered), return 0 and reset the virtual TSC_DEADLINE. Tracked-On: #4162 Signed-off-by: Yan, Like Acked-by: Eddie Dong --- hypervisor/arch/x86/guest/vlapic.c | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/hypervisor/arch/x86/guest/vlapic.c b/hypervisor/arch/x86/guest/vlapic.c index 78a82b98c..9ec000d0d 100644 --- a/hypervisor/arch/x86/guest/vlapic.c +++ b/hypervisor/arch/x86/guest/vlapic.c @@ -427,8 +427,18 @@ static void vlapic_icrtmr_write_handler(struct acrn_vlapic *vlapic) uint64_t vlapic_get_tsc_deadline_msr(const struct acrn_vlapic *vlapic) { uint64_t ret; + if (is_lapic_pt_enabled(vlapic->vcpu)) { - ret = msr_read(MSR_IA32_TSC_DEADLINE) + exec_vmread64(VMX_TSC_OFFSET_FULL); + /* If physical TSC_DEADLINE is zero which means it's not armed (automatically disarmed + * after timer triggered), return 0 and reset the virtual TSC_DEADLINE; + * If physical TSC_DEADLINE is not zero, return the virtual TSC_DEADLINE value. + */ + if (msr_read(MSR_IA32_TSC_DEADLINE) == 0UL) { + vcpu_set_guest_msr(vlapic->vcpu, MSR_IA32_TSC_DEADLINE, 0UL); + ret = 0UL; + } else { + ret = vcpu_get_guest_msr(vlapic->vcpu, MSR_IA32_TSC_DEADLINE); + } } else if (!vlapic_lvtt_tsc_deadline(vlapic)) { ret = 0UL; } else { @@ -437,7 +447,6 @@ uint64_t vlapic_get_tsc_deadline_msr(const struct acrn_vlapic *vlapic) } return ret; - } void vlapic_set_tsc_deadline_msr(struct acrn_vlapic *vlapic, uint64_t val_arg) @@ -447,8 +456,21 @@ void vlapic_set_tsc_deadline_msr(struct acrn_vlapic *vlapic, uint64_t val_arg) if (is_lapic_pt_enabled(vlapic->vcpu)) { vcpu_set_guest_msr(vlapic->vcpu, MSR_IA32_TSC_DEADLINE, val); - val -= exec_vmread64(VMX_TSC_OFFSET_FULL); - msr_write(MSR_IA32_TSC_DEADLINE, val); + /* If val is not zero, which mean guest intends to arm the tsc_deadline timer, + * if the calculated value to write to the physical TSC_DEADLINE msr is zero, + * we plus 1 to not disarm the physcial timer falsely; + * If val is zero, which means guest intends to disarm the tsc_deadline timer, + * we disarm the physical timer. + */ + if (val != 0UL) { + val -= exec_vmread64(VMX_TSC_OFFSET_FULL); + if (val == 0UL) { + val += 1UL; + } + msr_write(MSR_IA32_TSC_DEADLINE, val); + } else { + msr_write(MSR_IA32_TSC_DEADLINE, 0); + } } else if (vlapic_lvtt_tsc_deadline(vlapic)) { vcpu_set_guest_msr(vlapic->vcpu, MSR_IA32_TSC_DEADLINE, val);