Commit d3994940 authored by Joerg Roedel's avatar Joerg Roedel Committed by Greg Kroah-Hartman

KVM: SVM: Don't sync nested cr8 to lapic and back

This patch makes syncing of the guest tpr to the lapic
conditional on !nested. Otherwise a nested guest using the
TPR could freeze the guest.
Another important change this patch introduces is that the
cr8 intercept bits are no longer ORed at vmrun emulation if
the guest sets VINTR_MASKING in its VMCB. The reason is that
nested cr8 accesses need alway be handled by the nested
hypervisor because they change the shadow version of the
tpr.

Cc: stable@kernel.org
Signed-off-by: default avatarJoerg Roedel <joerg.roedel@amd.com>
Signed-off-by: default avatarAvi Kivity <avi@redhat.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>

(Cherry-picked from commit 88ab24ad)
parent db8125fa
...@@ -1830,21 +1830,6 @@ static bool nested_svm_vmrun(struct vcpu_svm *svm) ...@@ -1830,21 +1830,6 @@ static bool nested_svm_vmrun(struct vcpu_svm *svm)
svm->vmcb->save.dr6 = nested_vmcb->save.dr6; svm->vmcb->save.dr6 = nested_vmcb->save.dr6;
svm->vmcb->save.cpl = nested_vmcb->save.cpl; svm->vmcb->save.cpl = nested_vmcb->save.cpl;
/* We don't want a nested guest to be more powerful than the guest,
so all intercepts are ORed */
svm->vmcb->control.intercept_cr_read |=
nested_vmcb->control.intercept_cr_read;
svm->vmcb->control.intercept_cr_write |=
nested_vmcb->control.intercept_cr_write;
svm->vmcb->control.intercept_dr_read |=
nested_vmcb->control.intercept_dr_read;
svm->vmcb->control.intercept_dr_write |=
nested_vmcb->control.intercept_dr_write;
svm->vmcb->control.intercept_exceptions |=
nested_vmcb->control.intercept_exceptions;
svm->vmcb->control.intercept |= nested_vmcb->control.intercept;
svm->nested.vmcb_msrpm = nested_vmcb->control.msrpm_base_pa; svm->nested.vmcb_msrpm = nested_vmcb->control.msrpm_base_pa;
/* cache intercepts */ /* cache intercepts */
...@@ -1862,6 +1847,28 @@ static bool nested_svm_vmrun(struct vcpu_svm *svm) ...@@ -1862,6 +1847,28 @@ static bool nested_svm_vmrun(struct vcpu_svm *svm)
else else
svm->vcpu.arch.hflags &= ~HF_VINTR_MASK; svm->vcpu.arch.hflags &= ~HF_VINTR_MASK;
if (svm->vcpu.arch.hflags & HF_VINTR_MASK) {
/* We only want the cr8 intercept bits of the guest */
svm->vmcb->control.intercept_cr_read &= ~INTERCEPT_CR8_MASK;
svm->vmcb->control.intercept_cr_write &= ~INTERCEPT_CR8_MASK;
}
/* We don't want a nested guest to be more powerful than the guest,
so all intercepts are ORed */
svm->vmcb->control.intercept_cr_read |=
nested_vmcb->control.intercept_cr_read;
svm->vmcb->control.intercept_cr_write |=
nested_vmcb->control.intercept_cr_write;
svm->vmcb->control.intercept_dr_read |=
nested_vmcb->control.intercept_dr_read;
svm->vmcb->control.intercept_dr_write |=
nested_vmcb->control.intercept_dr_write;
svm->vmcb->control.intercept_exceptions |=
nested_vmcb->control.intercept_exceptions;
svm->vmcb->control.intercept |= nested_vmcb->control.intercept;
svm->vmcb->control.lbr_ctl = nested_vmcb->control.lbr_ctl;
svm->vmcb->control.int_vector = nested_vmcb->control.int_vector; svm->vmcb->control.int_vector = nested_vmcb->control.int_vector;
svm->vmcb->control.int_state = nested_vmcb->control.int_state; svm->vmcb->control.int_state = nested_vmcb->control.int_state;
svm->vmcb->control.tsc_offset += nested_vmcb->control.tsc_offset; svm->vmcb->control.tsc_offset += nested_vmcb->control.tsc_offset;
...@@ -2524,6 +2531,9 @@ static void update_cr8_intercept(struct kvm_vcpu *vcpu, int tpr, int irr) ...@@ -2524,6 +2531,9 @@ static void update_cr8_intercept(struct kvm_vcpu *vcpu, int tpr, int irr)
{ {
struct vcpu_svm *svm = to_svm(vcpu); struct vcpu_svm *svm = to_svm(vcpu);
if (is_nested(svm) && (vcpu->arch.hflags & HF_VINTR_MASK))
return;
if (irr == -1) if (irr == -1)
return; return;
...@@ -2627,6 +2637,9 @@ static inline void sync_cr8_to_lapic(struct kvm_vcpu *vcpu) ...@@ -2627,6 +2637,9 @@ static inline void sync_cr8_to_lapic(struct kvm_vcpu *vcpu)
{ {
struct vcpu_svm *svm = to_svm(vcpu); struct vcpu_svm *svm = to_svm(vcpu);
if (is_nested(svm) && (vcpu->arch.hflags & HF_VINTR_MASK))
return;
if (!(svm->vmcb->control.intercept_cr_write & INTERCEPT_CR8_MASK)) { if (!(svm->vmcb->control.intercept_cr_write & INTERCEPT_CR8_MASK)) {
int cr8 = svm->vmcb->control.int_ctl & V_TPR_MASK; int cr8 = svm->vmcb->control.int_ctl & V_TPR_MASK;
kvm_set_cr8(vcpu, cr8); kvm_set_cr8(vcpu, cr8);
...@@ -2638,6 +2651,9 @@ static inline void sync_lapic_to_cr8(struct kvm_vcpu *vcpu) ...@@ -2638,6 +2651,9 @@ static inline void sync_lapic_to_cr8(struct kvm_vcpu *vcpu)
struct vcpu_svm *svm = to_svm(vcpu); struct vcpu_svm *svm = to_svm(vcpu);
u64 cr8; u64 cr8;
if (is_nested(svm) && (vcpu->arch.hflags & HF_VINTR_MASK))
return;
cr8 = kvm_get_cr8(vcpu); cr8 = kvm_get_cr8(vcpu);
svm->vmcb->control.int_ctl &= ~V_TPR_MASK; svm->vmcb->control.int_ctl &= ~V_TPR_MASK;
svm->vmcb->control.int_ctl |= cr8 & V_TPR_MASK; svm->vmcb->control.int_ctl |= cr8 & V_TPR_MASK;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment