Commit 01de8b09 authored by Joerg Roedel's avatar Joerg Roedel Committed by Avi Kivity

KVM: SVM: Add intercept checks for SVM instructions

This patch adds the necessary code changes in the
instruction emulator and the extensions to svm.c to
implement intercept checks for the svm instructions.
Signed-off-by: default avatarJoerg Roedel <joerg.roedel@amd.com>
Signed-off-by: default avatarAvi Kivity <avi@redhat.com>
parent dee6bb70
...@@ -77,6 +77,7 @@ ...@@ -77,6 +77,7 @@
#define GroupDual (1<<15) /* Alternate decoding of mod == 3 */ #define GroupDual (1<<15) /* Alternate decoding of mod == 3 */
#define Prefix (1<<16) /* Instruction varies with 66/f2/f3 prefix */ #define Prefix (1<<16) /* Instruction varies with 66/f2/f3 prefix */
#define Sse (1<<17) /* SSE Vector instruction */ #define Sse (1<<17) /* SSE Vector instruction */
#define RMExt (1<<18) /* Opcode extension in ModRM r/m if mod == 3 */
/* Misc flags */ /* Misc flags */
#define Prot (1<<21) /* instruction generates #UD if not in prot-mode */ #define Prot (1<<21) /* instruction generates #UD if not in prot-mode */
#define VendorSpecific (1<<22) /* Vendor specific instruction */ #define VendorSpecific (1<<22) /* Vendor specific instruction */
...@@ -2580,11 +2581,35 @@ static int check_dr_write(struct x86_emulate_ctxt *ctxt) ...@@ -2580,11 +2581,35 @@ static int check_dr_write(struct x86_emulate_ctxt *ctxt)
return check_dr_read(ctxt); return check_dr_read(ctxt);
} }
static int check_svme(struct x86_emulate_ctxt *ctxt)
{
u64 efer;
ctxt->ops->get_msr(ctxt->vcpu, MSR_EFER, &efer);
if (!(efer & EFER_SVME))
return emulate_ud(ctxt);
return X86EMUL_CONTINUE;
}
static int check_svme_pa(struct x86_emulate_ctxt *ctxt)
{
u64 rax = kvm_register_read(ctxt->vcpu, VCPU_REGS_RAX);
/* Valid physical address? */
if (rax & 0xffff000000000000)
return emulate_gp(ctxt, 0);
return check_svme(ctxt);
}
#define D(_y) { .flags = (_y) } #define D(_y) { .flags = (_y) }
#define DI(_y, _i) { .flags = (_y), .intercept = x86_intercept_##_i } #define DI(_y, _i) { .flags = (_y), .intercept = x86_intercept_##_i }
#define DIP(_y, _i, _p) { .flags = (_y), .intercept = x86_intercept_##_i, \ #define DIP(_y, _i, _p) { .flags = (_y), .intercept = x86_intercept_##_i, \
.check_perm = (_p) } .check_perm = (_p) }
#define N D(0) #define N D(0)
#define EXT(_f, _e) { .flags = ((_f) | RMExt), .u.group = (_e) }
#define G(_f, _g) { .flags = ((_f) | Group), .u.group = (_g) } #define G(_f, _g) { .flags = ((_f) | Group), .u.group = (_g) }
#define GD(_f, _g) { .flags = ((_f) | Group | GroupDual), .u.gdual = (_g) } #define GD(_f, _g) { .flags = ((_f) | Group | GroupDual), .u.gdual = (_g) }
#define I(_f, _e) { .flags = (_f), .u.execute = (_e) } #define I(_f, _e) { .flags = (_f), .u.execute = (_e) }
...@@ -2602,6 +2627,16 @@ static int check_dr_write(struct x86_emulate_ctxt *ctxt) ...@@ -2602,6 +2627,16 @@ static int check_dr_write(struct x86_emulate_ctxt *ctxt)
D2bv(((_f) | DstReg | SrcMem | ModRM) & ~Lock), \ D2bv(((_f) | DstReg | SrcMem | ModRM) & ~Lock), \
D2bv(((_f) & ~Lock) | DstAcc | SrcImm) D2bv(((_f) & ~Lock) | DstAcc | SrcImm)
static struct opcode group7_rm3[] = {
DIP(SrcNone | ModRM | Prot | Priv, vmrun, check_svme_pa),
DIP(SrcNone | ModRM | Prot , vmmcall, check_svme),
DIP(SrcNone | ModRM | Prot | Priv, vmload, check_svme_pa),
DIP(SrcNone | ModRM | Prot | Priv, vmsave, check_svme_pa),
DIP(SrcNone | ModRM | Prot | Priv, stgi, check_svme),
DIP(SrcNone | ModRM | Prot | Priv, clgi, check_svme),
DIP(SrcNone | ModRM | Prot | Priv, skinit, check_svme),
DIP(SrcNone | ModRM | Prot | Priv, invlpga, check_svme),
};
static struct opcode group1[] = { static struct opcode group1[] = {
X7(D(Lock)), N X7(D(Lock)), N
...@@ -2647,7 +2682,7 @@ static struct group_dual group7 = { { ...@@ -2647,7 +2682,7 @@ static struct group_dual group7 = { {
DI(SrcMem | ModRM | ByteOp | Priv | NoAccess, invlpg), DI(SrcMem | ModRM | ByteOp | Priv | NoAccess, invlpg),
}, { }, {
D(SrcNone | ModRM | Priv | VendorSpecific), N, D(SrcNone | ModRM | Priv | VendorSpecific), N,
N, D(SrcNone | ModRM | Priv | VendorSpecific), N, EXT(0, group7_rm3),
DI(SrcNone | ModRM | DstMem | Mov, smsw), N, DI(SrcNone | ModRM | DstMem | Mov, smsw), N,
DI(SrcMem16 | ModRM | Mov | Priv, lmsw), N, DI(SrcMem16 | ModRM | Mov | Priv, lmsw), N,
} }; } };
...@@ -2853,6 +2888,7 @@ static struct opcode twobyte_table[256] = { ...@@ -2853,6 +2888,7 @@ static struct opcode twobyte_table[256] = {
#undef GD #undef GD
#undef I #undef I
#undef GP #undef GP
#undef EXT
#undef D2bv #undef D2bv
#undef I2bv #undef I2bv
...@@ -3030,6 +3066,12 @@ x86_decode_insn(struct x86_emulate_ctxt *ctxt, void *insn, int insn_len) ...@@ -3030,6 +3066,12 @@ x86_decode_insn(struct x86_emulate_ctxt *ctxt, void *insn, int insn_len)
opcode = g_mod3[goffset]; opcode = g_mod3[goffset];
else else
opcode = g_mod012[goffset]; opcode = g_mod012[goffset];
if (opcode.flags & RMExt) {
goffset = c->modrm & 7;
opcode = opcode.u.group[goffset];
}
c->d |= opcode.flags; c->d |= opcode.flags;
} }
......
...@@ -3892,6 +3892,14 @@ static struct __x86_intercept { ...@@ -3892,6 +3892,14 @@ static struct __x86_intercept {
[x86_intercept_sidt] = POST_EX(SVM_EXIT_IDTR_READ), [x86_intercept_sidt] = POST_EX(SVM_EXIT_IDTR_READ),
[x86_intercept_lgdt] = POST_EX(SVM_EXIT_GDTR_WRITE), [x86_intercept_lgdt] = POST_EX(SVM_EXIT_GDTR_WRITE),
[x86_intercept_lidt] = POST_EX(SVM_EXIT_IDTR_WRITE), [x86_intercept_lidt] = POST_EX(SVM_EXIT_IDTR_WRITE),
[x86_intercept_vmrun] = POST_EX(SVM_EXIT_VMRUN),
[x86_intercept_vmmcall] = POST_EX(SVM_EXIT_VMMCALL),
[x86_intercept_vmload] = POST_EX(SVM_EXIT_VMLOAD),
[x86_intercept_vmsave] = POST_EX(SVM_EXIT_VMSAVE),
[x86_intercept_stgi] = POST_EX(SVM_EXIT_STGI),
[x86_intercept_clgi] = POST_EX(SVM_EXIT_CLGI),
[x86_intercept_skinit] = POST_EX(SVM_EXIT_SKINIT),
[x86_intercept_invlpga] = POST_EX(SVM_EXIT_INVLPGA),
}; };
#undef POST_EX #undef POST_EX
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment