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 <like.yan@intel.com>
Acked-by: Eddie Dong <eddie.dong@intel.com>
This commit is contained in:
Yan, Like 2019-11-26 14:06:40 +08:00 committed by wenlingz
parent e61412981d
commit 97916364fc
1 changed files with 26 additions and 4 deletions

View File

@ -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 vlapic_get_tsc_deadline_msr(const struct acrn_vlapic *vlapic)
{ {
uint64_t ret; uint64_t ret;
if (is_lapic_pt_enabled(vlapic->vcpu)) { 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)) { } else if (!vlapic_lvtt_tsc_deadline(vlapic)) {
ret = 0UL; ret = 0UL;
} else { } else {
@ -437,7 +447,6 @@ uint64_t vlapic_get_tsc_deadline_msr(const struct acrn_vlapic *vlapic)
} }
return ret; return ret;
} }
void vlapic_set_tsc_deadline_msr(struct acrn_vlapic *vlapic, uint64_t val_arg) 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)) { if (is_lapic_pt_enabled(vlapic->vcpu)) {
vcpu_set_guest_msr(vlapic->vcpu, MSR_IA32_TSC_DEADLINE, val); vcpu_set_guest_msr(vlapic->vcpu, MSR_IA32_TSC_DEADLINE, val);
val -= exec_vmread64(VMX_TSC_OFFSET_FULL); /* If val is not zero, which mean guest intends to arm the tsc_deadline timer,
msr_write(MSR_IA32_TSC_DEADLINE, val); * 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)) { } else if (vlapic_lvtt_tsc_deadline(vlapic)) {
vcpu_set_guest_msr(vlapic->vcpu, MSR_IA32_TSC_DEADLINE, val); vcpu_set_guest_msr(vlapic->vcpu, MSR_IA32_TSC_DEADLINE, val);