diff options
-rw-r--r-- | arch/x86/include/asm/svm.h | 2 | ||||
-rw-r--r-- | arch/x86/kvm/svm.c | 90 |
2 files changed, 81 insertions, 11 deletions
diff --git a/arch/x86/include/asm/svm.h b/arch/x86/include/asm/svm.h index f7087bf9caf0..f0ffb8184089 100644 --- a/arch/x86/include/asm/svm.h +++ b/arch/x86/include/asm/svm.h | |||
@@ -260,6 +260,8 @@ struct __attribute__ ((__packed__)) vmcb { | |||
260 | #define SVM_EXITINFOSHIFT_TS_REASON_JMP 38 | 260 | #define SVM_EXITINFOSHIFT_TS_REASON_JMP 38 |
261 | #define SVM_EXITINFOSHIFT_TS_HAS_ERROR_CODE 44 | 261 | #define SVM_EXITINFOSHIFT_TS_HAS_ERROR_CODE 44 |
262 | 262 | ||
263 | #define SVM_EXITINFO_REG_MASK 0x0F | ||
264 | |||
263 | #define SVM_EXIT_READ_CR0 0x000 | 265 | #define SVM_EXIT_READ_CR0 0x000 |
264 | #define SVM_EXIT_READ_CR3 0x003 | 266 | #define SVM_EXIT_READ_CR3 0x003 |
265 | #define SVM_EXIT_READ_CR4 0x004 | 267 | #define SVM_EXIT_READ_CR4 0x004 |
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index 2830a73ea736..5abaa5b2f624 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c | |||
@@ -2660,12 +2660,80 @@ static int emulate_on_interception(struct vcpu_svm *svm) | |||
2660 | return emulate_instruction(&svm->vcpu, 0) == EMULATE_DONE; | 2660 | return emulate_instruction(&svm->vcpu, 0) == EMULATE_DONE; |
2661 | } | 2661 | } |
2662 | 2662 | ||
2663 | #define CR_VALID (1ULL << 63) | ||
2664 | |||
2665 | static int cr_interception(struct vcpu_svm *svm) | ||
2666 | { | ||
2667 | int reg, cr; | ||
2668 | unsigned long val; | ||
2669 | int err; | ||
2670 | |||
2671 | if (!static_cpu_has(X86_FEATURE_DECODEASSISTS)) | ||
2672 | return emulate_on_interception(svm); | ||
2673 | |||
2674 | if (unlikely((svm->vmcb->control.exit_info_1 & CR_VALID) == 0)) | ||
2675 | return emulate_on_interception(svm); | ||
2676 | |||
2677 | reg = svm->vmcb->control.exit_info_1 & SVM_EXITINFO_REG_MASK; | ||
2678 | cr = svm->vmcb->control.exit_code - SVM_EXIT_READ_CR0; | ||
2679 | |||
2680 | err = 0; | ||
2681 | if (cr >= 16) { /* mov to cr */ | ||
2682 | cr -= 16; | ||
2683 | val = kvm_register_read(&svm->vcpu, reg); | ||
2684 | switch (cr) { | ||
2685 | case 0: | ||
2686 | err = kvm_set_cr0(&svm->vcpu, val); | ||
2687 | break; | ||
2688 | case 3: | ||
2689 | err = kvm_set_cr3(&svm->vcpu, val); | ||
2690 | break; | ||
2691 | case 4: | ||
2692 | err = kvm_set_cr4(&svm->vcpu, val); | ||
2693 | break; | ||
2694 | case 8: | ||
2695 | err = kvm_set_cr8(&svm->vcpu, val); | ||
2696 | break; | ||
2697 | default: | ||
2698 | WARN(1, "unhandled write to CR%d", cr); | ||
2699 | kvm_queue_exception(&svm->vcpu, UD_VECTOR); | ||
2700 | return 1; | ||
2701 | } | ||
2702 | } else { /* mov from cr */ | ||
2703 | switch (cr) { | ||
2704 | case 0: | ||
2705 | val = kvm_read_cr0(&svm->vcpu); | ||
2706 | break; | ||
2707 | case 2: | ||
2708 | val = svm->vcpu.arch.cr2; | ||
2709 | break; | ||
2710 | case 3: | ||
2711 | val = svm->vcpu.arch.cr3; | ||
2712 | break; | ||
2713 | case 4: | ||
2714 | val = kvm_read_cr4(&svm->vcpu); | ||
2715 | break; | ||
2716 | case 8: | ||
2717 | val = kvm_get_cr8(&svm->vcpu); | ||
2718 | break; | ||
2719 | default: | ||
2720 | WARN(1, "unhandled read from CR%d", cr); | ||
2721 | kvm_queue_exception(&svm->vcpu, UD_VECTOR); | ||
2722 | return 1; | ||
2723 | } | ||
2724 | kvm_register_write(&svm->vcpu, reg, val); | ||
2725 | } | ||
2726 | kvm_complete_insn_gp(&svm->vcpu, err); | ||
2727 | |||
2728 | return 1; | ||
2729 | } | ||
2730 | |||
2663 | static int cr0_write_interception(struct vcpu_svm *svm) | 2731 | static int cr0_write_interception(struct vcpu_svm *svm) |
2664 | { | 2732 | { |
2665 | struct kvm_vcpu *vcpu = &svm->vcpu; | 2733 | struct kvm_vcpu *vcpu = &svm->vcpu; |
2666 | int r; | 2734 | int r; |
2667 | 2735 | ||
2668 | r = emulate_instruction(&svm->vcpu, 0); | 2736 | r = cr_interception(svm); |
2669 | 2737 | ||
2670 | if (svm->nested.vmexit_rip) { | 2738 | if (svm->nested.vmexit_rip) { |
2671 | kvm_register_write(vcpu, VCPU_REGS_RIP, svm->nested.vmexit_rip); | 2739 | kvm_register_write(vcpu, VCPU_REGS_RIP, svm->nested.vmexit_rip); |
@@ -2674,7 +2742,7 @@ static int cr0_write_interception(struct vcpu_svm *svm) | |||
2674 | svm->nested.vmexit_rip = 0; | 2742 | svm->nested.vmexit_rip = 0; |
2675 | } | 2743 | } |
2676 | 2744 | ||
2677 | return r == EMULATE_DONE; | 2745 | return r; |
2678 | } | 2746 | } |
2679 | 2747 | ||
2680 | static int cr8_write_interception(struct vcpu_svm *svm) | 2748 | static int cr8_write_interception(struct vcpu_svm *svm) |
@@ -2684,13 +2752,13 @@ static int cr8_write_interception(struct vcpu_svm *svm) | |||
2684 | 2752 | ||
2685 | u8 cr8_prev = kvm_get_cr8(&svm->vcpu); | 2753 | u8 cr8_prev = kvm_get_cr8(&svm->vcpu); |
2686 | /* instruction emulation calls kvm_set_cr8() */ | 2754 | /* instruction emulation calls kvm_set_cr8() */ |
2687 | r = emulate_instruction(&svm->vcpu, 0); | 2755 | r = cr_interception(svm); |
2688 | if (irqchip_in_kernel(svm->vcpu.kvm)) { | 2756 | if (irqchip_in_kernel(svm->vcpu.kvm)) { |
2689 | clr_cr_intercept(svm, INTERCEPT_CR8_WRITE); | 2757 | clr_cr_intercept(svm, INTERCEPT_CR8_WRITE); |
2690 | return r == EMULATE_DONE; | 2758 | return r; |
2691 | } | 2759 | } |
2692 | if (cr8_prev <= kvm_get_cr8(&svm->vcpu)) | 2760 | if (cr8_prev <= kvm_get_cr8(&svm->vcpu)) |
2693 | return r == EMULATE_DONE; | 2761 | return r; |
2694 | kvm_run->exit_reason = KVM_EXIT_SET_TPR; | 2762 | kvm_run->exit_reason = KVM_EXIT_SET_TPR; |
2695 | return 0; | 2763 | return 0; |
2696 | } | 2764 | } |
@@ -2933,14 +3001,14 @@ static int pause_interception(struct vcpu_svm *svm) | |||
2933 | } | 3001 | } |
2934 | 3002 | ||
2935 | static int (*svm_exit_handlers[])(struct vcpu_svm *svm) = { | 3003 | static int (*svm_exit_handlers[])(struct vcpu_svm *svm) = { |
2936 | [SVM_EXIT_READ_CR0] = emulate_on_interception, | 3004 | [SVM_EXIT_READ_CR0] = cr_interception, |
2937 | [SVM_EXIT_READ_CR3] = emulate_on_interception, | 3005 | [SVM_EXIT_READ_CR3] = cr_interception, |
2938 | [SVM_EXIT_READ_CR4] = emulate_on_interception, | 3006 | [SVM_EXIT_READ_CR4] = cr_interception, |
2939 | [SVM_EXIT_READ_CR8] = emulate_on_interception, | 3007 | [SVM_EXIT_READ_CR8] = cr_interception, |
2940 | [SVM_EXIT_CR0_SEL_WRITE] = emulate_on_interception, | 3008 | [SVM_EXIT_CR0_SEL_WRITE] = emulate_on_interception, |
2941 | [SVM_EXIT_WRITE_CR0] = cr0_write_interception, | 3009 | [SVM_EXIT_WRITE_CR0] = cr0_write_interception, |
2942 | [SVM_EXIT_WRITE_CR3] = emulate_on_interception, | 3010 | [SVM_EXIT_WRITE_CR3] = cr_interception, |
2943 | [SVM_EXIT_WRITE_CR4] = emulate_on_interception, | 3011 | [SVM_EXIT_WRITE_CR4] = cr_interception, |
2944 | [SVM_EXIT_WRITE_CR8] = cr8_write_interception, | 3012 | [SVM_EXIT_WRITE_CR8] = cr8_write_interception, |
2945 | [SVM_EXIT_READ_DR0] = emulate_on_interception, | 3013 | [SVM_EXIT_READ_DR0] = emulate_on_interception, |
2946 | [SVM_EXIT_READ_DR1] = emulate_on_interception, | 3014 | [SVM_EXIT_READ_DR1] = emulate_on_interception, |