Skip to content

Commit

Permalink
KVM: SVM: Add intercept check for accessing dr registers
Browse files Browse the repository at this point in the history
This patch adds the intercept checks for instruction
accessing the debug registers.

Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
  • Loading branch information
Joerg Roedel authored and Avi Kivity committed May 11, 2011
1 parent cfec82c commit 3b88e41
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 15 deletions.
2 changes: 2 additions & 0 deletions arch/x86/include/asm/kvm_emulate.h
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,8 @@ enum x86_intercept {
x86_intercept_clts,
x86_intercept_lmsw,
x86_intercept_smsw,
x86_intercept_dr_read,
x86_intercept_dr_write,
x86_intercept_lidt,
x86_intercept_sidt,
x86_intercept_lgdt,
Expand Down
63 changes: 48 additions & 15 deletions arch/x86/kvm/emulate.c
Original file line number Diff line number Diff line change
Expand Up @@ -509,6 +509,11 @@ static int emulate_exception(struct x86_emulate_ctxt *ctxt, int vec,
return X86EMUL_PROPAGATE_FAULT;
}

static int emulate_db(struct x86_emulate_ctxt *ctxt)
{
return emulate_exception(ctxt, DB_VECTOR, 0, false);
}

static int emulate_gp(struct x86_emulate_ctxt *ctxt, int err)
{
return emulate_exception(ctxt, GP_VECTOR, err, true);
Expand Down Expand Up @@ -2534,6 +2539,47 @@ static int check_cr_write(struct x86_emulate_ctxt *ctxt)
return X86EMUL_CONTINUE;
}

static int check_dr7_gd(struct x86_emulate_ctxt *ctxt)
{
unsigned long dr7;

ctxt->ops->get_dr(7, &dr7, ctxt->vcpu);

/* Check if DR7.Global_Enable is set */
return dr7 & (1 << 13);
}

static int check_dr_read(struct x86_emulate_ctxt *ctxt)
{
struct decode_cache *c = &ctxt->decode;
int dr = c->modrm_reg;
u64 cr4;

if (dr > 7)
return emulate_ud(ctxt);

cr4 = ctxt->ops->get_cr(4, ctxt->vcpu);
if ((cr4 & X86_CR4_DE) && (dr == 4 || dr == 5))
return emulate_ud(ctxt);

if (check_dr7_gd(ctxt))
return emulate_db(ctxt);

return X86EMUL_CONTINUE;
}

static int check_dr_write(struct x86_emulate_ctxt *ctxt)
{
struct decode_cache *c = &ctxt->decode;
u64 new_val = c->src.val64;
int dr = c->modrm_reg;

if ((dr == 6 || dr == 7) && (new_val & 0xffffffff00000000ULL))
return emulate_gp(ctxt, 0);

return check_dr_read(ctxt);
}

#define D(_y) { .flags = (_y) }
#define DI(_y, _i) { .flags = (_y), .intercept = x86_intercept_##_i }
#define DIP(_y, _i, _p) { .flags = (_y), .intercept = x86_intercept_##_i, \
Expand Down Expand Up @@ -2728,9 +2774,9 @@ static struct opcode twobyte_table[256] = {
N, N, N, N, N, N, N, N, D(ImplicitOps | ModRM), N, N, N, N, N, N, N,
/* 0x20 - 0x2F */
DIP(ModRM | DstMem | Priv | Op3264, cr_read, check_cr_read),
D(ModRM | DstMem | Priv | Op3264),
DIP(ModRM | DstMem | Priv | Op3264, dr_read, check_dr_read),
DIP(ModRM | SrcMem | Priv | Op3264, cr_write, check_cr_write),
D(ModRM | SrcMem | Priv | Op3264),
DIP(ModRM | SrcMem | Priv | Op3264, dr_write, check_dr_write),
N, N, N, N,
N, N, N, N, N, N, N, N,
/* 0x30 - 0x3F */
Expand Down Expand Up @@ -3818,12 +3864,6 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt)
c->dst.val = ops->get_cr(c->modrm_reg, ctxt->vcpu);
break;
case 0x21: /* mov from dr to reg */
if ((ops->get_cr(4, ctxt->vcpu) & X86_CR4_DE) &&
(c->modrm_reg == 4 || c->modrm_reg == 5)) {
emulate_ud(ctxt);
rc = X86EMUL_PROPAGATE_FAULT;
goto done;
}
ops->get_dr(c->modrm_reg, &c->dst.val, ctxt->vcpu);
break;
case 0x22: /* mov reg, cr */
Expand All @@ -3835,13 +3875,6 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt)
c->dst.type = OP_NONE;
break;
case 0x23: /* mov from reg to dr */
if ((ops->get_cr(4, ctxt->vcpu) & X86_CR4_DE) &&
(c->modrm_reg == 4 || c->modrm_reg == 5)) {
emulate_ud(ctxt);
rc = X86EMUL_PROPAGATE_FAULT;
goto done;
}

if (ops->set_dr(c->modrm_reg, c->src.val &
((ctxt->mode == X86EMUL_MODE_PROT64) ?
~0ULL : ~0U), ctxt->vcpu) < 0) {
Expand Down
6 changes: 6 additions & 0 deletions arch/x86/kvm/svm.c
Original file line number Diff line number Diff line change
Expand Up @@ -3882,6 +3882,8 @@ static struct __x86_intercept {
[x86_intercept_clts] = POST_EX(SVM_EXIT_WRITE_CR0),
[x86_intercept_lmsw] = POST_EX(SVM_EXIT_WRITE_CR0),
[x86_intercept_smsw] = POST_EX(SVM_EXIT_READ_CR0),
[x86_intercept_dr_read] = POST_EX(SVM_EXIT_READ_DR0),
[x86_intercept_dr_write] = POST_EX(SVM_EXIT_WRITE_DR0),
};

#undef POST_EX
Expand Down Expand Up @@ -3939,6 +3941,10 @@ static int svm_check_intercept(struct kvm_vcpu *vcpu,

break;
}
case SVM_EXIT_READ_DR0:
case SVM_EXIT_WRITE_DR0:
icpt_info.exit_code += info->modrm_reg;
break;
default:
break;
}
Expand Down

0 comments on commit 3b88e41

Please sign in to comment.