diff options
author | Jan Kiszka <jan.kiszka@siemens.com> | 2010-01-20 12:20:20 -0500 |
---|---|---|
committer | Marcelo Tosatti <mtosatti@redhat.com> | 2010-03-01 10:36:02 -0500 |
commit | c76de350c8a3ba770becc17eaa744dc3c7642295 (patch) | |
tree | e8a50babf616fa41f39a86962f60641027996d8f /arch/x86/kvm/svm.c | |
parent | fd7373cce767a8803e79f51bd3fc5f531234657f (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.c | 64 |
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 | ||
1125 | static unsigned long svm_get_dr(struct kvm_vcpu *vcpu, int dr) | 1125 | static 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 | ||
1153 | static void svm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long value, | 1158 | static 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 | ||
1197 | static int pf_interception(struct vcpu_svm *svm) | 1191 | static int pf_interception(struct vcpu_svm *svm) |