KVM: x86 emulator: make (get|set)_dr() callback return error if it fails
authorGleb Natapov <gleb@redhat.com>
Wed, 28 Apr 2010 16:15:32 +0000 (19:15 +0300)
committerAvi Kivity <avi@redhat.com>
Sun, 1 Aug 2010 07:35:32 +0000 (10:35 +0300)
Make (get|set)_dr() callback return error if it fails instead of
injecting exception behind emulator's back.

Signed-off-by: Gleb Natapov <gleb@redhat.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
arch/x86/kvm/emulate.c
arch/x86/kvm/x86.c

index 061f7d3..d5979ec 100644 (file)
@@ -3151,9 +3151,14 @@ twobyte_insn:
                        goto done;
                }
 
-               ops->set_dr(c->modrm_reg,c->regs[c->modrm_rm] &
-                           ((ctxt->mode == X86EMUL_MODE_PROT64) ? ~0ULL : ~0U),
-                       ctxt->vcpu);
+               if (ops->set_dr(c->modrm_reg, c->regs[c->modrm_rm] &
+                               ((ctxt->mode == X86EMUL_MODE_PROT64) ?
+                                ~0ULL : ~0U), ctxt->vcpu) < 0) {
+                       /* #UD condition is already handled by the code above */
+                       kvm_inject_gp(ctxt->vcpu, 0);
+                       goto done;
+               }
+
                c->dst.type = OP_NONE;  /* no writeback */
                break;
        case 0x30:
index 64c6e7a..44a546b 100644 (file)
@@ -573,7 +573,7 @@ unsigned long kvm_get_cr8(struct kvm_vcpu *vcpu)
 }
 EXPORT_SYMBOL_GPL(kvm_get_cr8);
 
-int kvm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long val)
+static int __kvm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long val)
 {
        switch (dr) {
        case 0 ... 3:
@@ -582,29 +582,21 @@ int kvm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long val)
                        vcpu->arch.eff_db[dr] = val;
                break;
        case 4:
-               if (kvm_read_cr4_bits(vcpu, X86_CR4_DE)) {
-                       kvm_queue_exception(vcpu, UD_VECTOR);
-                       return 1;
-               }
+               if (kvm_read_cr4_bits(vcpu, X86_CR4_DE))
+                       return 1; /* #UD */
                /* fall through */
        case 6:
-               if (val & 0xffffffff00000000ULL) {
-                       kvm_inject_gp(vcpu, 0);
-                       return 1;
-               }
+               if (val & 0xffffffff00000000ULL)
+                       return -1; /* #GP */
                vcpu->arch.dr6 = (val & DR6_VOLATILE) | DR6_FIXED_1;
                break;
        case 5:
-               if (kvm_read_cr4_bits(vcpu, X86_CR4_DE)) {
-                       kvm_queue_exception(vcpu, UD_VECTOR);
-                       return 1;
-               }
+               if (kvm_read_cr4_bits(vcpu, X86_CR4_DE))
+                       return 1; /* #UD */
                /* fall through */
        default: /* 7 */
-               if (val & 0xffffffff00000000ULL) {
-                       kvm_inject_gp(vcpu, 0);
-                       return 1;
-               }
+               if (val & 0xffffffff00000000ULL)
+                       return -1; /* #GP */
                vcpu->arch.dr7 = (val & DR7_VOLATILE) | DR7_FIXED_1;
                if (!(vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP)) {
                        kvm_x86_ops->set_dr7(vcpu, vcpu->arch.dr7);
@@ -615,28 +607,37 @@ int kvm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long val)
 
        return 0;
 }
+
+int kvm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long val)
+{
+       int res;
+
+       res = __kvm_set_dr(vcpu, dr, val);
+       if (res > 0)
+               kvm_queue_exception(vcpu, UD_VECTOR);
+       else if (res < 0)
+               kvm_inject_gp(vcpu, 0);
+
+       return res;
+}
 EXPORT_SYMBOL_GPL(kvm_set_dr);
 
-int kvm_get_dr(struct kvm_vcpu *vcpu, int dr, unsigned long *val)
+static int _kvm_get_dr(struct kvm_vcpu *vcpu, int dr, unsigned long *val)
 {
        switch (dr) {
        case 0 ... 3:
                *val = vcpu->arch.db[dr];
                break;
        case 4:
-               if (kvm_read_cr4_bits(vcpu, X86_CR4_DE)) {
-                       kvm_queue_exception(vcpu, UD_VECTOR);
+               if (kvm_read_cr4_bits(vcpu, X86_CR4_DE))
                        return 1;
-               }
                /* fall through */
        case 6:
                *val = vcpu->arch.dr6;
                break;
        case 5:
-               if (kvm_read_cr4_bits(vcpu, X86_CR4_DE)) {
-                       kvm_queue_exception(vcpu, UD_VECTOR);
+               if (kvm_read_cr4_bits(vcpu, X86_CR4_DE))
                        return 1;
-               }
                /* fall through */
        default: /* 7 */
                *val = vcpu->arch.dr7;
@@ -645,6 +646,15 @@ int kvm_get_dr(struct kvm_vcpu *vcpu, int dr, unsigned long *val)
 
        return 0;
 }
+
+int kvm_get_dr(struct kvm_vcpu *vcpu, int dr, unsigned long *val)
+{
+       if (_kvm_get_dr(vcpu, dr, val)) {
+               kvm_queue_exception(vcpu, UD_VECTOR);
+               return 1;
+       }
+       return 0;
+}
 EXPORT_SYMBOL_GPL(kvm_get_dr);
 
 static inline u32 bit(int bitno)
@@ -3619,12 +3629,13 @@ int emulate_clts(struct kvm_vcpu *vcpu)
 
 int emulator_get_dr(int dr, unsigned long *dest, struct kvm_vcpu *vcpu)
 {
-       return kvm_get_dr(vcpu, dr, dest);
+       return _kvm_get_dr(vcpu, dr, dest);
 }
 
 int emulator_set_dr(int dr, unsigned long value, struct kvm_vcpu *vcpu)
 {
-       return kvm_set_dr(vcpu, dr, value);
+
+       return __kvm_set_dr(vcpu, dr, value);
 }
 
 void kvm_report_emulation_failure(struct kvm_vcpu *vcpu, const char *context)