Skip to content

Commit

Permalink
KVM: SVM: Make lazy FPU switching work with nested svm
Browse files Browse the repository at this point in the history
The new lazy fpu switching code may disable cr0 intercepts
when running nested. This is a bug because the nested
hypervisor may still want to intercept cr0 which will break
in this situation. This patch fixes this issue and makes
lazy fpu switching working with nested svm.

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 06fc777 commit 66a562f
Showing 1 changed file with 39 additions and 4 deletions.
43 changes: 39 additions & 4 deletions arch/x86/kvm/svm.c
Original file line number Diff line number Diff line change
Expand Up @@ -979,6 +979,7 @@ static void svm_decache_cr4_guest_bits(struct kvm_vcpu *vcpu)

static void update_cr0_intercept(struct vcpu_svm *svm)
{
struct vmcb *vmcb = svm->vmcb;
ulong gcr0 = svm->vcpu.arch.cr0;
u64 *hcr0 = &svm->vmcb->save.cr0;

Expand All @@ -990,11 +991,25 @@ static void update_cr0_intercept(struct vcpu_svm *svm)


if (gcr0 == *hcr0 && svm->vcpu.fpu_active) {
svm->vmcb->control.intercept_cr_read &= ~INTERCEPT_CR0_MASK;
svm->vmcb->control.intercept_cr_write &= ~INTERCEPT_CR0_MASK;
vmcb->control.intercept_cr_read &= ~INTERCEPT_CR0_MASK;
vmcb->control.intercept_cr_write &= ~INTERCEPT_CR0_MASK;
if (is_nested(svm)) {
struct vmcb *hsave = svm->nested.hsave;

hsave->control.intercept_cr_read &= ~INTERCEPT_CR0_MASK;
hsave->control.intercept_cr_write &= ~INTERCEPT_CR0_MASK;
vmcb->control.intercept_cr_read |= svm->nested.intercept_cr_read;
vmcb->control.intercept_cr_write |= svm->nested.intercept_cr_write;
}
} else {
svm->vmcb->control.intercept_cr_read |= INTERCEPT_CR0_MASK;
svm->vmcb->control.intercept_cr_write |= INTERCEPT_CR0_MASK;
if (is_nested(svm)) {
struct vmcb *hsave = svm->nested.hsave;

hsave->control.intercept_cr_read |= INTERCEPT_CR0_MASK;
hsave->control.intercept_cr_write |= INTERCEPT_CR0_MASK;
}
}
}

Expand Down Expand Up @@ -1269,7 +1284,22 @@ static int ud_interception(struct vcpu_svm *svm)
static void svm_fpu_activate(struct kvm_vcpu *vcpu)
{
struct vcpu_svm *svm = to_svm(vcpu);
svm->vmcb->control.intercept_exceptions &= ~(1 << NM_VECTOR);
u32 excp;

if (is_nested(svm)) {
u32 h_excp, n_excp;

h_excp = svm->nested.hsave->control.intercept_exceptions;
n_excp = svm->nested.intercept_exceptions;
h_excp &= ~(1 << NM_VECTOR);
excp = h_excp | n_excp;
} else {
excp = svm->vmcb->control.intercept_exceptions;
excp &= ~(1 << NM_VECTOR);
}

svm->vmcb->control.intercept_exceptions = excp;

svm->vcpu.fpu_active = 1;
update_cr0_intercept(svm);
}
Expand Down Expand Up @@ -1513,6 +1543,9 @@ static int nested_svm_exit_special(struct vcpu_svm *svm)
if (!npt_enabled)
return NESTED_EXIT_HOST;
break;
case SVM_EXIT_EXCP_BASE + NM_VECTOR:
nm_interception(svm);
break;
default:
break;
}
Expand Down Expand Up @@ -2980,8 +3013,10 @@ static void svm_fpu_deactivate(struct kvm_vcpu *vcpu)
{
struct vcpu_svm *svm = to_svm(vcpu);

update_cr0_intercept(svm);
svm->vmcb->control.intercept_exceptions |= 1 << NM_VECTOR;
if (is_nested(svm))
svm->nested.hsave->control.intercept_exceptions |= 1 << NM_VECTOR;
update_cr0_intercept(svm);
}

static struct kvm_x86_ops svm_x86_ops = {
Expand Down

0 comments on commit 66a562f

Please sign in to comment.