diff options
-rw-r--r-- | arch/x86/include/asm/kvm_host.h | 5 | ||||
-rw-r--r-- | arch/x86/kvm/svm.c | 64 | ||||
-rw-r--r-- | arch/x86/kvm/x86.c | 19 |
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 | ||
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) |
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 | ||
3271 | int emulator_get_dr(struct x86_emulate_ctxt *ctxt, int dr, unsigned long *dest) | 3271 | int 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 | ||
3285 | int emulator_set_dr(struct x86_emulate_ctxt *ctxt, int dr, unsigned long value) | 3276 | int 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 | ||
3298 | void kvm_report_emulation_failure(struct kvm_vcpu *vcpu, const char *context) | 3283 | void kvm_report_emulation_failure(struct kvm_vcpu *vcpu, const char *context) |