diff options
author | Jan Kiszka <jan.kiszka@siemens.com> | 2010-02-23 11:47:56 -0500 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2010-04-25 06:00:43 -0400 |
commit | 66b7138f913635b40822890ba8913548f8b285b8 (patch) | |
tree | 1dd5faf941e04ae911e0bc9e9f00869f6a0aebd2 /arch/x86/kvm/svm.c | |
parent | f92653eeb496fe8624ac4b0d628c916a06a3d25c (diff) |
KVM: SVM: Emulate nRIP feature when reinjecting INT3
When in guest debugging mode, we have to reinject those #BP software
exceptions that are caused by guest-injected INT3. As older AMD
processors do not support the required nRIP VMCB field, try to emulate
it by moving RIP past the instruction on exception injection. Fix it up
again in case the injection failed and we were able to catch this. This
does not work for unintercepted faults, but it is better than doing
nothing.
Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
Diffstat (limited to 'arch/x86/kvm/svm.c')
-rw-r--r-- | arch/x86/kvm/svm.c | 38 |
1 files changed, 35 insertions, 3 deletions
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index 908ec61895ce..468ff6e721ce 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c | |||
@@ -47,6 +47,7 @@ MODULE_LICENSE("GPL"); | |||
47 | #define SVM_FEATURE_NPT (1 << 0) | 47 | #define SVM_FEATURE_NPT (1 << 0) |
48 | #define SVM_FEATURE_LBRV (1 << 1) | 48 | #define SVM_FEATURE_LBRV (1 << 1) |
49 | #define SVM_FEATURE_SVML (1 << 2) | 49 | #define SVM_FEATURE_SVML (1 << 2) |
50 | #define SVM_FEATURE_NRIP (1 << 3) | ||
50 | #define SVM_FEATURE_PAUSE_FILTER (1 << 10) | 51 | #define SVM_FEATURE_PAUSE_FILTER (1 << 10) |
51 | 52 | ||
52 | #define NESTED_EXIT_HOST 0 /* Exit handled on host level */ | 53 | #define NESTED_EXIT_HOST 0 /* Exit handled on host level */ |
@@ -110,6 +111,9 @@ struct vcpu_svm { | |||
110 | struct nested_state nested; | 111 | struct nested_state nested; |
111 | 112 | ||
112 | bool nmi_singlestep; | 113 | bool nmi_singlestep; |
114 | |||
115 | unsigned int3_injected; | ||
116 | unsigned long int3_rip; | ||
113 | }; | 117 | }; |
114 | 118 | ||
115 | /* enable NPT for AMD64 and X86 with PAE */ | 119 | /* enable NPT for AMD64 and X86 with PAE */ |
@@ -291,6 +295,22 @@ static void svm_queue_exception(struct kvm_vcpu *vcpu, unsigned nr, | |||
291 | if (nested_svm_check_exception(svm, nr, has_error_code, error_code)) | 295 | if (nested_svm_check_exception(svm, nr, has_error_code, error_code)) |
292 | return; | 296 | return; |
293 | 297 | ||
298 | if (nr == BP_VECTOR && !svm_has(SVM_FEATURE_NRIP)) { | ||
299 | unsigned long rip, old_rip = kvm_rip_read(&svm->vcpu); | ||
300 | |||
301 | /* | ||
302 | * For guest debugging where we have to reinject #BP if some | ||
303 | * INT3 is guest-owned: | ||
304 | * Emulate nRIP by moving RIP forward. Will fail if injection | ||
305 | * raises a fault that is not intercepted. Still better than | ||
306 | * failing in all cases. | ||
307 | */ | ||
308 | skip_emulated_instruction(&svm->vcpu); | ||
309 | rip = kvm_rip_read(&svm->vcpu); | ||
310 | svm->int3_rip = rip + svm->vmcb->save.cs.base; | ||
311 | svm->int3_injected = rip - old_rip; | ||
312 | } | ||
313 | |||
294 | svm->vmcb->control.event_inj = nr | 314 | svm->vmcb->control.event_inj = nr |
295 | | SVM_EVTINJ_VALID | 315 | | SVM_EVTINJ_VALID |
296 | | (has_error_code ? SVM_EVTINJ_VALID_ERR : 0) | 316 | | (has_error_code ? SVM_EVTINJ_VALID_ERR : 0) |
@@ -2701,6 +2721,9 @@ static void svm_complete_interrupts(struct vcpu_svm *svm) | |||
2701 | u8 vector; | 2721 | u8 vector; |
2702 | int type; | 2722 | int type; |
2703 | u32 exitintinfo = svm->vmcb->control.exit_int_info; | 2723 | u32 exitintinfo = svm->vmcb->control.exit_int_info; |
2724 | unsigned int3_injected = svm->int3_injected; | ||
2725 | |||
2726 | svm->int3_injected = 0; | ||
2704 | 2727 | ||
2705 | if (svm->vcpu.arch.hflags & HF_IRET_MASK) | 2728 | if (svm->vcpu.arch.hflags & HF_IRET_MASK) |
2706 | svm->vcpu.arch.hflags &= ~(HF_NMI_MASK | HF_IRET_MASK); | 2729 | svm->vcpu.arch.hflags &= ~(HF_NMI_MASK | HF_IRET_MASK); |
@@ -2720,12 +2743,21 @@ static void svm_complete_interrupts(struct vcpu_svm *svm) | |||
2720 | svm->vcpu.arch.nmi_injected = true; | 2743 | svm->vcpu.arch.nmi_injected = true; |
2721 | break; | 2744 | break; |
2722 | case SVM_EXITINTINFO_TYPE_EXEPT: | 2745 | case SVM_EXITINTINFO_TYPE_EXEPT: |
2723 | /* In case of software exception do not reinject an exception | ||
2724 | vector, but re-execute and instruction instead */ | ||
2725 | if (is_nested(svm)) | 2746 | if (is_nested(svm)) |
2726 | break; | 2747 | break; |
2727 | if (kvm_exception_is_soft(vector)) | 2748 | /* |
2749 | * In case of software exceptions, do not reinject the vector, | ||
2750 | * but re-execute the instruction instead. Rewind RIP first | ||
2751 | * if we emulated INT3 before. | ||
2752 | */ | ||
2753 | if (kvm_exception_is_soft(vector)) { | ||
2754 | if (vector == BP_VECTOR && int3_injected && | ||
2755 | kvm_is_linear_rip(&svm->vcpu, svm->int3_rip)) | ||
2756 | kvm_rip_write(&svm->vcpu, | ||
2757 | kvm_rip_read(&svm->vcpu) - | ||
2758 | int3_injected); | ||
2728 | break; | 2759 | break; |
2760 | } | ||
2729 | if (exitintinfo & SVM_EXITINTINFO_VALID_ERR) { | 2761 | if (exitintinfo & SVM_EXITINTINFO_VALID_ERR) { |
2730 | u32 err = svm->vmcb->control.exit_int_info_err; | 2762 | u32 err = svm->vmcb->control.exit_int_info_err; |
2731 | kvm_queue_exception_e(&svm->vcpu, vector, err); | 2763 | kvm_queue_exception_e(&svm->vcpu, vector, err); |