diff options
author | Andre Przywara <andre.przywara@amd.com> | 2010-12-21 05:12:00 -0500 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2011-01-12 04:30:58 -0500 |
commit | eea1cff9ab732ea56358ff5e1bd8b99db2e8402d (patch) | |
tree | 000abd8fa64f58602ebfc03b09e1f394c72f4ad7 | |
parent | a63512a4d711c9bd6a5d03847f45fcf88cdea0c6 (diff) |
KVM: x86: fix CR8 handling
The handling of CR8 writes in KVM is currently somewhat cumbersome.
This patch makes it look like the other CR register handlers
and fixes a possible issue in VMX, where the RIP would be incremented
despite an injected #GP.
Signed-off-by: Andre Przywara <andre.przywara@amd.com>
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
-rw-r--r-- | arch/x86/include/asm/kvm_host.h | 2 | ||||
-rw-r--r-- | arch/x86/kvm/svm.c | 7 | ||||
-rw-r--r-- | arch/x86/kvm/vmx.c | 4 | ||||
-rw-r--r-- | arch/x86/kvm/x86.c | 18 |
4 files changed, 15 insertions, 16 deletions
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 4461429957a9..cb5cad2f2d46 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h | |||
@@ -661,7 +661,7 @@ int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int reason, | |||
661 | int kvm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0); | 661 | int kvm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0); |
662 | int kvm_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3); | 662 | int kvm_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3); |
663 | int kvm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4); | 663 | int kvm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4); |
664 | void kvm_set_cr8(struct kvm_vcpu *vcpu, unsigned long cr8); | 664 | int kvm_set_cr8(struct kvm_vcpu *vcpu, unsigned long cr8); |
665 | int kvm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long val); | 665 | int kvm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long val); |
666 | int kvm_get_dr(struct kvm_vcpu *vcpu, int dr, unsigned long *val); | 666 | int kvm_get_dr(struct kvm_vcpu *vcpu, int dr, unsigned long *val); |
667 | unsigned long kvm_get_cr8(struct kvm_vcpu *vcpu); | 667 | unsigned long kvm_get_cr8(struct kvm_vcpu *vcpu); |
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index 73461b1cfb05..3d4b88af50f9 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c | |||
@@ -2676,16 +2676,17 @@ static int cr0_write_interception(struct vcpu_svm *svm) | |||
2676 | static int cr8_write_interception(struct vcpu_svm *svm) | 2676 | static int cr8_write_interception(struct vcpu_svm *svm) |
2677 | { | 2677 | { |
2678 | struct kvm_run *kvm_run = svm->vcpu.run; | 2678 | struct kvm_run *kvm_run = svm->vcpu.run; |
2679 | int r; | ||
2679 | 2680 | ||
2680 | u8 cr8_prev = kvm_get_cr8(&svm->vcpu); | 2681 | u8 cr8_prev = kvm_get_cr8(&svm->vcpu); |
2681 | /* instruction emulation calls kvm_set_cr8() */ | 2682 | /* instruction emulation calls kvm_set_cr8() */ |
2682 | emulate_instruction(&svm->vcpu, 0, 0, 0); | 2683 | r = emulate_instruction(&svm->vcpu, 0, 0, 0); |
2683 | if (irqchip_in_kernel(svm->vcpu.kvm)) { | 2684 | if (irqchip_in_kernel(svm->vcpu.kvm)) { |
2684 | clr_cr_intercept(svm, INTERCEPT_CR8_WRITE); | 2685 | clr_cr_intercept(svm, INTERCEPT_CR8_WRITE); |
2685 | return 1; | 2686 | return r == EMULATE_DONE; |
2686 | } | 2687 | } |
2687 | if (cr8_prev <= kvm_get_cr8(&svm->vcpu)) | 2688 | if (cr8_prev <= kvm_get_cr8(&svm->vcpu)) |
2688 | return 1; | 2689 | return r == EMULATE_DONE; |
2689 | kvm_run->exit_reason = KVM_EXIT_SET_TPR; | 2690 | kvm_run->exit_reason = KVM_EXIT_SET_TPR; |
2690 | return 0; | 2691 | return 0; |
2691 | } | 2692 | } |
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index c1952603d580..8e87bae09a7a 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c | |||
@@ -3185,8 +3185,8 @@ static int handle_cr(struct kvm_vcpu *vcpu) | |||
3185 | case 8: { | 3185 | case 8: { |
3186 | u8 cr8_prev = kvm_get_cr8(vcpu); | 3186 | u8 cr8_prev = kvm_get_cr8(vcpu); |
3187 | u8 cr8 = kvm_register_read(vcpu, reg); | 3187 | u8 cr8 = kvm_register_read(vcpu, reg); |
3188 | kvm_set_cr8(vcpu, cr8); | 3188 | err = kvm_set_cr8(vcpu, cr8); |
3189 | skip_emulated_instruction(vcpu); | 3189 | complete_insn_gp(vcpu, err); |
3190 | if (irqchip_in_kernel(vcpu->kvm)) | 3190 | if (irqchip_in_kernel(vcpu->kvm)) |
3191 | return 1; | 3191 | return 1; |
3192 | if (cr8_prev <= cr8) | 3192 | if (cr8_prev <= cr8) |
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index f569da8ff839..2dbf68cd46e3 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c | |||
@@ -662,7 +662,7 @@ int kvm_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3) | |||
662 | } | 662 | } |
663 | EXPORT_SYMBOL_GPL(kvm_set_cr3); | 663 | EXPORT_SYMBOL_GPL(kvm_set_cr3); |
664 | 664 | ||
665 | int __kvm_set_cr8(struct kvm_vcpu *vcpu, unsigned long cr8) | 665 | int kvm_set_cr8(struct kvm_vcpu *vcpu, unsigned long cr8) |
666 | { | 666 | { |
667 | if (cr8 & CR8_RESERVED_BITS) | 667 | if (cr8 & CR8_RESERVED_BITS) |
668 | return 1; | 668 | return 1; |
@@ -672,12 +672,6 @@ int __kvm_set_cr8(struct kvm_vcpu *vcpu, unsigned long cr8) | |||
672 | vcpu->arch.cr8 = cr8; | 672 | vcpu->arch.cr8 = cr8; |
673 | return 0; | 673 | return 0; |
674 | } | 674 | } |
675 | |||
676 | void kvm_set_cr8(struct kvm_vcpu *vcpu, unsigned long cr8) | ||
677 | { | ||
678 | if (__kvm_set_cr8(vcpu, cr8)) | ||
679 | kvm_inject_gp(vcpu, 0); | ||
680 | } | ||
681 | EXPORT_SYMBOL_GPL(kvm_set_cr8); | 675 | EXPORT_SYMBOL_GPL(kvm_set_cr8); |
682 | 676 | ||
683 | unsigned long kvm_get_cr8(struct kvm_vcpu *vcpu) | 677 | unsigned long kvm_get_cr8(struct kvm_vcpu *vcpu) |
@@ -4104,7 +4098,7 @@ static int emulator_set_cr(int cr, unsigned long val, struct kvm_vcpu *vcpu) | |||
4104 | res = kvm_set_cr4(vcpu, mk_cr_64(kvm_read_cr4(vcpu), val)); | 4098 | res = kvm_set_cr4(vcpu, mk_cr_64(kvm_read_cr4(vcpu), val)); |
4105 | break; | 4099 | break; |
4106 | case 8: | 4100 | case 8: |
4107 | res = __kvm_set_cr8(vcpu, val & 0xfUL); | 4101 | res = kvm_set_cr8(vcpu, val); |
4108 | break; | 4102 | break; |
4109 | default: | 4103 | default: |
4110 | vcpu_printf(vcpu, "%s: unexpected cr %u\n", __func__, cr); | 4104 | vcpu_printf(vcpu, "%s: unexpected cr %u\n", __func__, cr); |
@@ -5381,8 +5375,12 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) | |||
5381 | } | 5375 | } |
5382 | 5376 | ||
5383 | /* re-sync apic's tpr */ | 5377 | /* re-sync apic's tpr */ |
5384 | if (!irqchip_in_kernel(vcpu->kvm)) | 5378 | if (!irqchip_in_kernel(vcpu->kvm)) { |
5385 | kvm_set_cr8(vcpu, kvm_run->cr8); | 5379 | if (kvm_set_cr8(vcpu, kvm_run->cr8) != 0) { |
5380 | r = -EINVAL; | ||
5381 | goto out; | ||
5382 | } | ||
5383 | } | ||
5386 | 5384 | ||
5387 | if (vcpu->arch.pio.count || vcpu->mmio_needed) { | 5385 | if (vcpu->arch.pio.count || vcpu->mmio_needed) { |
5388 | if (vcpu->mmio_needed) { | 5386 | if (vcpu->mmio_needed) { |