aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kvm/svm.c
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/kvm/svm.c
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/kvm/svm.c')
-rw-r--r--arch/x86/kvm/svm.c64
1 files changed, 29 insertions, 35 deletions
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)