aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/include/asm/kvm_emulate.h2
-rw-r--r--arch/x86/kvm/emulate.c63
-rw-r--r--arch/x86/kvm/svm.c6
3 files changed, 56 insertions, 15 deletions
diff --git a/arch/x86/include/asm/kvm_emulate.h b/arch/x86/include/asm/kvm_emulate.h
index 2c0b5b47464f..fdaf59ac1c07 100644
--- a/arch/x86/include/asm/kvm_emulate.h
+++ b/arch/x86/include/asm/kvm_emulate.h
@@ -309,6 +309,8 @@ enum x86_intercept {
309 x86_intercept_clts, 309 x86_intercept_clts,
310 x86_intercept_lmsw, 310 x86_intercept_lmsw,
311 x86_intercept_smsw, 311 x86_intercept_smsw,
312 x86_intercept_dr_read,
313 x86_intercept_dr_write,
312 x86_intercept_lidt, 314 x86_intercept_lidt,
313 x86_intercept_sidt, 315 x86_intercept_sidt,
314 x86_intercept_lgdt, 316 x86_intercept_lgdt,
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index d2e77755efe8..cd9ed9f45275 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -509,6 +509,11 @@ static int emulate_exception(struct x86_emulate_ctxt *ctxt, int vec,
509 return X86EMUL_PROPAGATE_FAULT; 509 return X86EMUL_PROPAGATE_FAULT;
510} 510}
511 511
512static int emulate_db(struct x86_emulate_ctxt *ctxt)
513{
514 return emulate_exception(ctxt, DB_VECTOR, 0, false);
515}
516
512static int emulate_gp(struct x86_emulate_ctxt *ctxt, int err) 517static int emulate_gp(struct x86_emulate_ctxt *ctxt, int err)
513{ 518{
514 return emulate_exception(ctxt, GP_VECTOR, err, true); 519 return emulate_exception(ctxt, GP_VECTOR, err, true);
@@ -2534,6 +2539,47 @@ static int check_cr_write(struct x86_emulate_ctxt *ctxt)
2534 return X86EMUL_CONTINUE; 2539 return X86EMUL_CONTINUE;
2535} 2540}
2536 2541
2542static int check_dr7_gd(struct x86_emulate_ctxt *ctxt)
2543{
2544 unsigned long dr7;
2545
2546 ctxt->ops->get_dr(7, &dr7, ctxt->vcpu);
2547
2548 /* Check if DR7.Global_Enable is set */
2549 return dr7 & (1 << 13);
2550}
2551
2552static int check_dr_read(struct x86_emulate_ctxt *ctxt)
2553{
2554 struct decode_cache *c = &ctxt->decode;
2555 int dr = c->modrm_reg;
2556 u64 cr4;
2557
2558 if (dr > 7)
2559 return emulate_ud(ctxt);
2560
2561 cr4 = ctxt->ops->get_cr(4, ctxt->vcpu);
2562 if ((cr4 & X86_CR4_DE) && (dr == 4 || dr == 5))
2563 return emulate_ud(ctxt);
2564
2565 if (check_dr7_gd(ctxt))
2566 return emulate_db(ctxt);
2567
2568 return X86EMUL_CONTINUE;
2569}
2570
2571static int check_dr_write(struct x86_emulate_ctxt *ctxt)
2572{
2573 struct decode_cache *c = &ctxt->decode;
2574 u64 new_val = c->src.val64;
2575 int dr = c->modrm_reg;
2576
2577 if ((dr == 6 || dr == 7) && (new_val & 0xffffffff00000000ULL))
2578 return emulate_gp(ctxt, 0);
2579
2580 return check_dr_read(ctxt);
2581}
2582
2537#define D(_y) { .flags = (_y) } 2583#define D(_y) { .flags = (_y) }
2538#define DI(_y, _i) { .flags = (_y), .intercept = x86_intercept_##_i } 2584#define DI(_y, _i) { .flags = (_y), .intercept = x86_intercept_##_i }
2539#define DIP(_y, _i, _p) { .flags = (_y), .intercept = x86_intercept_##_i, \ 2585#define DIP(_y, _i, _p) { .flags = (_y), .intercept = x86_intercept_##_i, \
@@ -2728,9 +2774,9 @@ static struct opcode twobyte_table[256] = {
2728 N, N, N, N, N, N, N, N, D(ImplicitOps | ModRM), N, N, N, N, N, N, N, 2774 N, N, N, N, N, N, N, N, D(ImplicitOps | ModRM), N, N, N, N, N, N, N,
2729 /* 0x20 - 0x2F */ 2775 /* 0x20 - 0x2F */
2730 DIP(ModRM | DstMem | Priv | Op3264, cr_read, check_cr_read), 2776 DIP(ModRM | DstMem | Priv | Op3264, cr_read, check_cr_read),
2731 D(ModRM | DstMem | Priv | Op3264), 2777 DIP(ModRM | DstMem | Priv | Op3264, dr_read, check_dr_read),
2732 DIP(ModRM | SrcMem | Priv | Op3264, cr_write, check_cr_write), 2778 DIP(ModRM | SrcMem | Priv | Op3264, cr_write, check_cr_write),
2733 D(ModRM | SrcMem | Priv | Op3264), 2779 DIP(ModRM | SrcMem | Priv | Op3264, dr_write, check_dr_write),
2734 N, N, N, N, 2780 N, N, N, N,
2735 N, N, N, N, N, N, N, N, 2781 N, N, N, N, N, N, N, N,
2736 /* 0x30 - 0x3F */ 2782 /* 0x30 - 0x3F */
@@ -3818,12 +3864,6 @@ twobyte_insn:
3818 c->dst.val = ops->get_cr(c->modrm_reg, ctxt->vcpu); 3864 c->dst.val = ops->get_cr(c->modrm_reg, ctxt->vcpu);
3819 break; 3865 break;
3820 case 0x21: /* mov from dr to reg */ 3866 case 0x21: /* mov from dr to reg */
3821 if ((ops->get_cr(4, ctxt->vcpu) & X86_CR4_DE) &&
3822 (c->modrm_reg == 4 || c->modrm_reg == 5)) {
3823 emulate_ud(ctxt);
3824 rc = X86EMUL_PROPAGATE_FAULT;
3825 goto done;
3826 }
3827 ops->get_dr(c->modrm_reg, &c->dst.val, ctxt->vcpu); 3867 ops->get_dr(c->modrm_reg, &c->dst.val, ctxt->vcpu);
3828 break; 3868 break;
3829 case 0x22: /* mov reg, cr */ 3869 case 0x22: /* mov reg, cr */
@@ -3835,13 +3875,6 @@ twobyte_insn:
3835 c->dst.type = OP_NONE; 3875 c->dst.type = OP_NONE;
3836 break; 3876 break;
3837 case 0x23: /* mov from reg to dr */ 3877 case 0x23: /* mov from reg to dr */
3838 if ((ops->get_cr(4, ctxt->vcpu) & X86_CR4_DE) &&
3839 (c->modrm_reg == 4 || c->modrm_reg == 5)) {
3840 emulate_ud(ctxt);
3841 rc = X86EMUL_PROPAGATE_FAULT;
3842 goto done;
3843 }
3844
3845 if (ops->set_dr(c->modrm_reg, c->src.val & 3878 if (ops->set_dr(c->modrm_reg, c->src.val &
3846 ((ctxt->mode == X86EMUL_MODE_PROT64) ? 3879 ((ctxt->mode == X86EMUL_MODE_PROT64) ?
3847 ~0ULL : ~0U), ctxt->vcpu) < 0) { 3880 ~0ULL : ~0U), ctxt->vcpu) < 0) {
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index ff4ed3619d00..381b038c0d01 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -3882,6 +3882,8 @@ static struct __x86_intercept {
3882 [x86_intercept_clts] = POST_EX(SVM_EXIT_WRITE_CR0), 3882 [x86_intercept_clts] = POST_EX(SVM_EXIT_WRITE_CR0),
3883 [x86_intercept_lmsw] = POST_EX(SVM_EXIT_WRITE_CR0), 3883 [x86_intercept_lmsw] = POST_EX(SVM_EXIT_WRITE_CR0),
3884 [x86_intercept_smsw] = POST_EX(SVM_EXIT_READ_CR0), 3884 [x86_intercept_smsw] = POST_EX(SVM_EXIT_READ_CR0),
3885 [x86_intercept_dr_read] = POST_EX(SVM_EXIT_READ_DR0),
3886 [x86_intercept_dr_write] = POST_EX(SVM_EXIT_WRITE_DR0),
3885}; 3887};
3886 3888
3887#undef POST_EX 3889#undef POST_EX
@@ -3939,6 +3941,10 @@ static int svm_check_intercept(struct kvm_vcpu *vcpu,
3939 3941
3940 break; 3942 break;
3941 } 3943 }
3944 case SVM_EXIT_READ_DR0:
3945 case SVM_EXIT_WRITE_DR0:
3946 icpt_info.exit_code += info->modrm_reg;
3947 break;
3942 default: 3948 default:
3943 break; 3949 break;
3944 } 3950 }