aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86
diff options
context:
space:
mode:
authorJan Kiszka <jan.kiszka@siemens.com>2010-01-20 12:20:20 -0500
committerMarcelo Tosatti <mtosatti@redhat.com>2010-03-01 10:36:02 -0500
commitc76de350c8a3ba770becc17eaa744dc3c7642295 (patch)
treee8a50babf616fa41f39a86962f60641027996d8f /arch/x86
parentfd7373cce767a8803e79f51bd3fc5f531234657f (diff)
KVM: SVM: Clean up and enhance mov dr emulation
Enhance mov dr instruction emulation used by SVM so that it properly handles dr4/5: alias to dr6/7 if cr4.de is cleared. Otherwise return EMULATE_FAIL which will let our only possible caller in that scenario, ud_interception, re-inject UD. We do not need to inject faults, SVM does this for us (exceptions take precedence over instruction interceptions). For the same reason, the value overflow checks can be removed. Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com> Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Diffstat (limited to 'arch/x86')
-rw-r--r--arch/x86/include/asm/kvm_host.h5
-rw-r--r--arch/x86/kvm/svm.c64
-rw-r--r--arch/x86/kvm/x86.c19
3 files changed, 33 insertions, 55 deletions
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index a1f0b5dd7d75..d73ed48587e4 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -506,9 +506,8 @@ struct kvm_x86_ops {
506 void (*set_idt)(struct kvm_vcpu *vcpu, struct descriptor_table *dt); 506 void (*set_idt)(struct kvm_vcpu *vcpu, struct descriptor_table *dt);
507 void (*get_gdt)(struct kvm_vcpu *vcpu, struct descriptor_table *dt); 507 void (*get_gdt)(struct kvm_vcpu *vcpu, struct descriptor_table *dt);
508 void (*set_gdt)(struct kvm_vcpu *vcpu, struct descriptor_table *dt); 508 void (*set_gdt)(struct kvm_vcpu *vcpu, struct descriptor_table *dt);
509 unsigned long (*get_dr)(struct kvm_vcpu *vcpu, int dr); 509 int (*get_dr)(struct kvm_vcpu *vcpu, int dr, unsigned long *dest);
510 void (*set_dr)(struct kvm_vcpu *vcpu, int dr, unsigned long value, 510 int (*set_dr)(struct kvm_vcpu *vcpu, int dr, unsigned long value);
511 int *exception);
512 void (*cache_reg)(struct kvm_vcpu *vcpu, enum kvm_reg reg); 511 void (*cache_reg)(struct kvm_vcpu *vcpu, enum kvm_reg reg);
513 unsigned long (*get_rflags)(struct kvm_vcpu *vcpu); 512 unsigned long (*get_rflags)(struct kvm_vcpu *vcpu);
514 void (*set_rflags)(struct kvm_vcpu *vcpu, unsigned long rflags); 513 void (*set_rflags)(struct kvm_vcpu *vcpu, unsigned long rflags);
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index 8d7cb62ebef6..4295dfcc6031 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -1122,76 +1122,70 @@ static void new_asid(struct vcpu_svm *svm, struct svm_cpu_data *sd)
1122 svm->vmcb->control.asid = sd->next_asid++; 1122 svm->vmcb->control.asid = sd->next_asid++;
1123} 1123}
1124 1124
1125static unsigned long svm_get_dr(struct kvm_vcpu *vcpu, int dr) 1125static int svm_get_dr(struct kvm_vcpu *vcpu, int dr, unsigned long *dest)
1126{ 1126{
1127 struct vcpu_svm *svm = to_svm(vcpu); 1127 struct vcpu_svm *svm = to_svm(vcpu);
1128 unsigned long val;
1129 1128
1130 switch (dr) { 1129 switch (dr) {
1131 case 0 ... 3: 1130 case 0 ... 3:
1132 val = vcpu->arch.db[dr]; 1131 *dest = vcpu->arch.db[dr];
1133 break; 1132 break;
1133 case 4:
1134 if (kvm_read_cr4_bits(vcpu, X86_CR4_DE))
1135 return EMULATE_FAIL; /* will re-inject UD */
1136 /* fall through */
1134 case 6: 1137 case 6:
1135 if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP) 1138 if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP)
1136 val = vcpu->arch.dr6; 1139 *dest = vcpu->arch.dr6;
1137 else 1140 else
1138 val = svm->vmcb->save.dr6; 1141 *dest = svm->vmcb->save.dr6;
1139 break; 1142 break;
1143 case 5:
1144 if (kvm_read_cr4_bits(vcpu, X86_CR4_DE))
1145 return EMULATE_FAIL; /* will re-inject UD */
1146 /* fall through */
1140 case 7: 1147 case 7:
1141 if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP) 1148 if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP)
1142 val = vcpu->arch.dr7; 1149 *dest = vcpu->arch.dr7;
1143 else 1150 else
1144 val = svm->vmcb->save.dr7; 1151 *dest = svm->vmcb->save.dr7;
1145 break; 1152 break;
1146 default:
1147 val = 0;
1148 } 1153 }
1149 1154
1150 return val; 1155 return EMULATE_DONE;
1151} 1156}
1152 1157
1153static void svm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long value, 1158static int svm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long value)
1154 int *exception)
1155{ 1159{
1156 struct vcpu_svm *svm = to_svm(vcpu); 1160 struct vcpu_svm *svm = to_svm(vcpu);
1157 1161
1158 *exception = 0;
1159
1160 switch (dr) { 1162 switch (dr) {
1161 case 0 ... 3: 1163 case 0 ... 3:
1162 vcpu->arch.db[dr] = value; 1164 vcpu->arch.db[dr] = value;
1163 if (!(vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP)) 1165 if (!(vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP))
1164 vcpu->arch.eff_db[dr] = value; 1166 vcpu->arch.eff_db[dr] = value;
1165 return; 1167 break;
1166 case 4 ... 5: 1168 case 4:
1167 if (vcpu->arch.cr4 & X86_CR4_DE) 1169 if (kvm_read_cr4_bits(vcpu, X86_CR4_DE))
1168 *exception = UD_VECTOR; 1170 return EMULATE_FAIL; /* will re-inject UD */
1169 return; 1171 /* fall through */
1170 case 6: 1172 case 6:
1171 if (value & 0xffffffff00000000ULL) {
1172 *exception = GP_VECTOR;
1173 return;
1174 }
1175 vcpu->arch.dr6 = (value & DR6_VOLATILE) | DR6_FIXED_1; 1173 vcpu->arch.dr6 = (value & DR6_VOLATILE) | DR6_FIXED_1;
1176 return; 1174 break;
1175 case 5:
1176 if (kvm_read_cr4_bits(vcpu, X86_CR4_DE))
1177 return EMULATE_FAIL; /* will re-inject UD */
1178 /* fall through */
1177 case 7: 1179 case 7:
1178 if (value & 0xffffffff00000000ULL) {
1179 *exception = GP_VECTOR;
1180 return;
1181 }
1182 vcpu->arch.dr7 = (value & DR7_VOLATILE) | DR7_FIXED_1; 1180 vcpu->arch.dr7 = (value & DR7_VOLATILE) | DR7_FIXED_1;
1183 if (!(vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP)) { 1181 if (!(vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP)) {
1184 svm->vmcb->save.dr7 = vcpu->arch.dr7; 1182 svm->vmcb->save.dr7 = vcpu->arch.dr7;
1185 vcpu->arch.switch_db_regs = (value & DR7_BP_EN_MASK); 1183 vcpu->arch.switch_db_regs = (value & DR7_BP_EN_MASK);
1186 } 1184 }
1187 return; 1185 break;
1188 default:
1189 /* FIXME: Possible case? */
1190 printk(KERN_DEBUG "%s: unexpected dr %u\n",
1191 __func__, dr);
1192 *exception = UD_VECTOR;
1193 return;
1194 } 1186 }
1187
1188 return EMULATE_DONE;
1195} 1189}
1196 1190
1197static int pf_interception(struct vcpu_svm *svm) 1191static int pf_interception(struct vcpu_svm *svm)
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 322c2c5f9bc4..fd5101b57fa3 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -3270,29 +3270,14 @@ int emulate_clts(struct kvm_vcpu *vcpu)
3270 3270
3271int emulator_get_dr(struct x86_emulate_ctxt *ctxt, int dr, unsigned long *dest) 3271int emulator_get_dr(struct x86_emulate_ctxt *ctxt, int dr, unsigned long *dest)
3272{ 3272{
3273 struct kvm_vcpu *vcpu = ctxt->vcpu; 3273 return kvm_x86_ops->get_dr(ctxt->vcpu, dr, dest);
3274
3275 switch (dr) {
3276 case 0 ... 3:
3277 *dest = kvm_x86_ops->get_dr(vcpu, dr);
3278 return X86EMUL_CONTINUE;
3279 default:
3280 pr_unimpl(vcpu, "%s: unexpected dr %u\n", __func__, dr);
3281 return X86EMUL_UNHANDLEABLE;
3282 }
3283} 3274}
3284 3275
3285int emulator_set_dr(struct x86_emulate_ctxt *ctxt, int dr, unsigned long value) 3276int emulator_set_dr(struct x86_emulate_ctxt *ctxt, int dr, unsigned long value)
3286{ 3277{
3287 unsigned long mask = (ctxt->mode == X86EMUL_MODE_PROT64) ? ~0ULL : ~0U; 3278 unsigned long mask = (ctxt->mode == X86EMUL_MODE_PROT64) ? ~0ULL : ~0U;
3288 int exception;
3289 3279
3290 kvm_x86_ops->set_dr(ctxt->vcpu, dr, value & mask, &exception); 3280 return kvm_x86_ops->set_dr(ctxt->vcpu, dr, value & mask);
3291 if (exception) {
3292 /* FIXME: better handling */
3293 return X86EMUL_UNHANDLEABLE;
3294 }
3295 return X86EMUL_CONTINUE;
3296} 3281}
3297 3282
3298void kvm_report_emulation_failure(struct kvm_vcpu *vcpu, const char *context) 3283void kvm_report_emulation_failure(struct kvm_vcpu *vcpu, const char *context)