diff options
Diffstat (limited to 'arch/x86/kvm')
-rw-r--r-- | arch/x86/kvm/svm.c | 32 | ||||
-rw-r--r-- | arch/x86/kvm/vmx.c | 49 | ||||
-rw-r--r-- | arch/x86/kvm/x86.c | 2 |
3 files changed, 58 insertions, 25 deletions
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index f994c6df78be..8b5ffbd55c11 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c | |||
@@ -202,6 +202,27 @@ static int is_external_interrupt(u32 info) | |||
202 | return info == (SVM_EVTINJ_VALID | SVM_EVTINJ_TYPE_INTR); | 202 | return info == (SVM_EVTINJ_VALID | SVM_EVTINJ_TYPE_INTR); |
203 | } | 203 | } |
204 | 204 | ||
205 | static u32 svm_get_interrupt_shadow(struct kvm_vcpu *vcpu, int mask) | ||
206 | { | ||
207 | struct vcpu_svm *svm = to_svm(vcpu); | ||
208 | u32 ret = 0; | ||
209 | |||
210 | if (svm->vmcb->control.int_state & SVM_INTERRUPT_SHADOW_MASK) | ||
211 | ret |= X86_SHADOW_INT_STI | X86_SHADOW_INT_MOV_SS; | ||
212 | return ret & mask; | ||
213 | } | ||
214 | |||
215 | static void svm_set_interrupt_shadow(struct kvm_vcpu *vcpu, int mask) | ||
216 | { | ||
217 | struct vcpu_svm *svm = to_svm(vcpu); | ||
218 | |||
219 | if (mask == 0) | ||
220 | svm->vmcb->control.int_state &= ~SVM_INTERRUPT_SHADOW_MASK; | ||
221 | else | ||
222 | svm->vmcb->control.int_state |= SVM_INTERRUPT_SHADOW_MASK; | ||
223 | |||
224 | } | ||
225 | |||
205 | static void skip_emulated_instruction(struct kvm_vcpu *vcpu) | 226 | static void skip_emulated_instruction(struct kvm_vcpu *vcpu) |
206 | { | 227 | { |
207 | struct vcpu_svm *svm = to_svm(vcpu); | 228 | struct vcpu_svm *svm = to_svm(vcpu); |
@@ -215,7 +236,7 @@ static void skip_emulated_instruction(struct kvm_vcpu *vcpu) | |||
215 | __func__, kvm_rip_read(vcpu), svm->next_rip); | 236 | __func__, kvm_rip_read(vcpu), svm->next_rip); |
216 | 237 | ||
217 | kvm_rip_write(vcpu, svm->next_rip); | 238 | kvm_rip_write(vcpu, svm->next_rip); |
218 | svm->vmcb->control.int_state &= ~SVM_INTERRUPT_SHADOW_MASK; | 239 | svm_set_interrupt_shadow(vcpu, 0); |
219 | } | 240 | } |
220 | 241 | ||
221 | static int has_svm(void) | 242 | static int has_svm(void) |
@@ -2259,12 +2280,6 @@ static void pre_svm_run(struct vcpu_svm *svm) | |||
2259 | new_asid(svm, svm_data); | 2280 | new_asid(svm, svm_data); |
2260 | } | 2281 | } |
2261 | 2282 | ||
2262 | static void svm_drop_interrupt_shadow(struct kvm_vcpu *vcpu) | ||
2263 | { | ||
2264 | struct vcpu_svm *svm = to_svm(vcpu); | ||
2265 | svm->vmcb->control.int_state &= ~SVM_INTERRUPT_SHADOW_MASK; | ||
2266 | } | ||
2267 | |||
2268 | static void svm_inject_nmi(struct kvm_vcpu *vcpu) | 2283 | static void svm_inject_nmi(struct kvm_vcpu *vcpu) |
2269 | { | 2284 | { |
2270 | struct vcpu_svm *svm = to_svm(vcpu); | 2285 | struct vcpu_svm *svm = to_svm(vcpu); |
@@ -2667,6 +2682,8 @@ static struct kvm_x86_ops svm_x86_ops = { | |||
2667 | .run = svm_vcpu_run, | 2682 | .run = svm_vcpu_run, |
2668 | .handle_exit = handle_exit, | 2683 | .handle_exit = handle_exit, |
2669 | .skip_emulated_instruction = skip_emulated_instruction, | 2684 | .skip_emulated_instruction = skip_emulated_instruction, |
2685 | .set_interrupt_shadow = svm_set_interrupt_shadow, | ||
2686 | .get_interrupt_shadow = svm_get_interrupt_shadow, | ||
2670 | .patch_hypercall = svm_patch_hypercall, | 2687 | .patch_hypercall = svm_patch_hypercall, |
2671 | .set_irq = svm_set_irq, | 2688 | .set_irq = svm_set_irq, |
2672 | .set_nmi = svm_inject_nmi, | 2689 | .set_nmi = svm_inject_nmi, |
@@ -2676,7 +2693,6 @@ static struct kvm_x86_ops svm_x86_ops = { | |||
2676 | .enable_nmi_window = enable_nmi_window, | 2693 | .enable_nmi_window = enable_nmi_window, |
2677 | .enable_irq_window = enable_irq_window, | 2694 | .enable_irq_window = enable_irq_window, |
2678 | .update_cr8_intercept = update_cr8_intercept, | 2695 | .update_cr8_intercept = update_cr8_intercept, |
2679 | .drop_interrupt_shadow = svm_drop_interrupt_shadow, | ||
2680 | 2696 | ||
2681 | .set_tss_addr = svm_set_tss_addr, | 2697 | .set_tss_addr = svm_set_tss_addr, |
2682 | .get_tdp_level = get_npt_level, | 2698 | .get_tdp_level = get_npt_level, |
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index e8a5649f9c15..f3ab27b5a6b2 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c | |||
@@ -736,23 +736,45 @@ static void vmx_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags) | |||
736 | vmcs_writel(GUEST_RFLAGS, rflags); | 736 | vmcs_writel(GUEST_RFLAGS, rflags); |
737 | } | 737 | } |
738 | 738 | ||
739 | static u32 vmx_get_interrupt_shadow(struct kvm_vcpu *vcpu, int mask) | ||
740 | { | ||
741 | u32 interruptibility = vmcs_read32(GUEST_INTERRUPTIBILITY_INFO); | ||
742 | int ret = 0; | ||
743 | |||
744 | if (interruptibility & GUEST_INTR_STATE_STI) | ||
745 | ret |= X86_SHADOW_INT_STI; | ||
746 | if (interruptibility & GUEST_INTR_STATE_MOV_SS) | ||
747 | ret |= X86_SHADOW_INT_MOV_SS; | ||
748 | |||
749 | return ret & mask; | ||
750 | } | ||
751 | |||
752 | static void vmx_set_interrupt_shadow(struct kvm_vcpu *vcpu, int mask) | ||
753 | { | ||
754 | u32 interruptibility_old = vmcs_read32(GUEST_INTERRUPTIBILITY_INFO); | ||
755 | u32 interruptibility = interruptibility_old; | ||
756 | |||
757 | interruptibility &= ~(GUEST_INTR_STATE_STI | GUEST_INTR_STATE_MOV_SS); | ||
758 | |||
759 | if (mask & X86_SHADOW_INT_MOV_SS) | ||
760 | interruptibility |= GUEST_INTR_STATE_MOV_SS; | ||
761 | if (mask & X86_SHADOW_INT_STI) | ||
762 | interruptibility |= GUEST_INTR_STATE_STI; | ||
763 | |||
764 | if ((interruptibility != interruptibility_old)) | ||
765 | vmcs_write32(GUEST_INTERRUPTIBILITY_INFO, interruptibility); | ||
766 | } | ||
767 | |||
739 | static void skip_emulated_instruction(struct kvm_vcpu *vcpu) | 768 | static void skip_emulated_instruction(struct kvm_vcpu *vcpu) |
740 | { | 769 | { |
741 | unsigned long rip; | 770 | unsigned long rip; |
742 | u32 interruptibility; | ||
743 | 771 | ||
744 | rip = kvm_rip_read(vcpu); | 772 | rip = kvm_rip_read(vcpu); |
745 | rip += vmcs_read32(VM_EXIT_INSTRUCTION_LEN); | 773 | rip += vmcs_read32(VM_EXIT_INSTRUCTION_LEN); |
746 | kvm_rip_write(vcpu, rip); | 774 | kvm_rip_write(vcpu, rip); |
747 | 775 | ||
748 | /* | 776 | /* skipping an emulated instruction also counts */ |
749 | * We emulated an instruction, so temporary interrupt blocking | 777 | vmx_set_interrupt_shadow(vcpu, 0); |
750 | * should be removed, if set. | ||
751 | */ | ||
752 | interruptibility = vmcs_read32(GUEST_INTERRUPTIBILITY_INFO); | ||
753 | if (interruptibility & 3) | ||
754 | vmcs_write32(GUEST_INTERRUPTIBILITY_INFO, | ||
755 | interruptibility & ~3); | ||
756 | } | 778 | } |
757 | 779 | ||
758 | static void vmx_queue_exception(struct kvm_vcpu *vcpu, unsigned nr, | 780 | static void vmx_queue_exception(struct kvm_vcpu *vcpu, unsigned nr, |
@@ -2400,12 +2422,6 @@ out: | |||
2400 | return ret; | 2422 | return ret; |
2401 | } | 2423 | } |
2402 | 2424 | ||
2403 | void vmx_drop_interrupt_shadow(struct kvm_vcpu *vcpu) | ||
2404 | { | ||
2405 | vmcs_clear_bits(GUEST_INTERRUPTIBILITY_INFO, | ||
2406 | GUEST_INTR_STATE_STI | GUEST_INTR_STATE_MOV_SS); | ||
2407 | } | ||
2408 | |||
2409 | static void enable_irq_window(struct kvm_vcpu *vcpu) | 2425 | static void enable_irq_window(struct kvm_vcpu *vcpu) |
2410 | { | 2426 | { |
2411 | u32 cpu_based_vm_exec_control; | 2427 | u32 cpu_based_vm_exec_control; |
@@ -3649,6 +3665,8 @@ static struct kvm_x86_ops vmx_x86_ops = { | |||
3649 | .run = vmx_vcpu_run, | 3665 | .run = vmx_vcpu_run, |
3650 | .handle_exit = vmx_handle_exit, | 3666 | .handle_exit = vmx_handle_exit, |
3651 | .skip_emulated_instruction = skip_emulated_instruction, | 3667 | .skip_emulated_instruction = skip_emulated_instruction, |
3668 | .set_interrupt_shadow = vmx_set_interrupt_shadow, | ||
3669 | .get_interrupt_shadow = vmx_get_interrupt_shadow, | ||
3652 | .patch_hypercall = vmx_patch_hypercall, | 3670 | .patch_hypercall = vmx_patch_hypercall, |
3653 | .set_irq = vmx_inject_irq, | 3671 | .set_irq = vmx_inject_irq, |
3654 | .set_nmi = vmx_inject_nmi, | 3672 | .set_nmi = vmx_inject_nmi, |
@@ -3658,7 +3676,6 @@ static struct kvm_x86_ops vmx_x86_ops = { | |||
3658 | .enable_nmi_window = enable_nmi_window, | 3676 | .enable_nmi_window = enable_nmi_window, |
3659 | .enable_irq_window = enable_irq_window, | 3677 | .enable_irq_window = enable_irq_window, |
3660 | .update_cr8_intercept = update_cr8_intercept, | 3678 | .update_cr8_intercept = update_cr8_intercept, |
3661 | .drop_interrupt_shadow = vmx_drop_interrupt_shadow, | ||
3662 | 3679 | ||
3663 | .set_tss_addr = vmx_set_tss_addr, | 3680 | .set_tss_addr = vmx_set_tss_addr, |
3664 | .get_tdp_level = get_ept_level, | 3681 | .get_tdp_level = get_ept_level, |
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 3c4c327490af..7475b029b2ad 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c | |||
@@ -3178,7 +3178,7 @@ static void inject_pending_irq(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) | |||
3178 | kvm_run->request_interrupt_window; | 3178 | kvm_run->request_interrupt_window; |
3179 | 3179 | ||
3180 | if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP) | 3180 | if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP) |
3181 | kvm_x86_ops->drop_interrupt_shadow(vcpu); | 3181 | kvm_x86_ops->set_interrupt_shadow(vcpu, 0); |
3182 | 3182 | ||
3183 | inject_irq(vcpu); | 3183 | inject_irq(vcpu); |
3184 | 3184 | ||