Skip to content

Commit

Permalink
KVM: SVM: Don't sync nested cr8 to lapic and back
Browse files Browse the repository at this point in the history
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: Joerg Roedel <joerg.roedel@amd.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
  • Loading branch information
Joerg Roedel authored and Avi Kivity committed Apr 25, 2010
1 parent 4c7da8c commit 88ab24a
Showing 1 changed file with 31 additions and 15 deletions.
46 changes: 31 additions & 15 deletions arch/x86/kvm/svm.c
Original file line number Diff line number Diff line change
Expand Up @@ -1832,21 +1832,6 @@ static bool nested_svm_vmrun(struct vcpu_svm *svm)
svm->vmcb->save.dr6 = nested_vmcb->save.dr6;
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;

/* cache intercepts */
Expand All @@ -1864,6 +1849,28 @@ static bool nested_svm_vmrun(struct vcpu_svm *svm)
else
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_state = nested_vmcb->control.int_state;
svm->vmcb->control.tsc_offset += nested_vmcb->control.tsc_offset;
Expand Down Expand Up @@ -2526,6 +2533,9 @@ static void update_cr8_intercept(struct kvm_vcpu *vcpu, int tpr, int irr)
{
struct vcpu_svm *svm = to_svm(vcpu);

if (is_nested(svm) && (vcpu->arch.hflags & HF_VINTR_MASK))
return;

if (irr == -1)
return;

Expand Down Expand Up @@ -2629,6 +2639,9 @@ static inline void sync_cr8_to_lapic(struct kvm_vcpu *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)) {
int cr8 = svm->vmcb->control.int_ctl & V_TPR_MASK;
kvm_set_cr8(vcpu, cr8);
Expand All @@ -2640,6 +2653,9 @@ static inline void sync_lapic_to_cr8(struct kvm_vcpu *vcpu)
struct vcpu_svm *svm = to_svm(vcpu);
u64 cr8;

if (is_nested(svm) && (vcpu->arch.hflags & HF_VINTR_MASK))
return;

cr8 = kvm_get_cr8(vcpu);
svm->vmcb->control.int_ctl &= ~V_TPR_MASK;
svm->vmcb->control.int_ctl |= cr8 & V_TPR_MASK;
Expand Down

0 comments on commit 88ab24a

Please sign in to comment.