This patch adds code to check for IOIO intercepts on
instructions decoded by the KVM instruction emulator.

Signed-off-by: Joerg Roedel <[email protected]>
---
 arch/x86/include/asm/kvm_emulate.h |    4 ++++
 arch/x86/kvm/emulate.c             |   10 ++++++----
 arch/x86/kvm/svm.c                 |   36 ++++++++++++++++++++++++++++++++++++
 3 files changed, 46 insertions(+), 4 deletions(-)

diff --git a/arch/x86/include/asm/kvm_emulate.h 
b/arch/x86/include/asm/kvm_emulate.h
index 41c0120..0b2e2de 100644
--- a/arch/x86/include/asm/kvm_emulate.h
+++ b/arch/x86/include/asm/kvm_emulate.h
@@ -317,6 +317,10 @@ enum x86_intercept {
        x86_intercept_mwait,
        x86_intercept_rdmsr,
        x86_intercept_wrmsr,
+       x86_intercept_in,
+       x86_intercept_ins,
+       x86_intercept_out,
+       x86_intercept_outs,
 
        nr_x86_intercepts
 };
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index 4c0939d..879ce78 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -2339,6 +2339,7 @@ static int em_mov(struct x86_emulate_ctxt *ctxt)
        { .flags = (_f), .u.execute = (_e), .intercept = x86_intercept_##_i }
 
 #define D2bv(_f)      D((_f) | ByteOp), D(_f)
+#define D2bvI(_f, _i) DI((_f) | ByteOp, _i), DI((_f), _i)
 #define I2bv(_f, _e)  I((_f) | ByteOp, _e), I(_f, _e)
 
 #define D6ALU(_f) D2bv((_f) | DstMem | SrcReg | ModRM),                        
\
@@ -2468,8 +2469,8 @@ static struct opcode opcode_table[256] = {
        I(DstReg | SrcMem | ModRM | Src2Imm, em_imul_3op),
        I(SrcImmByte | Mov | Stack, em_push),
        I(DstReg | SrcMem | ModRM | Src2ImmByte, em_imul_3op),
-       D2bv(DstDI | Mov | String), /* insb, insw/insd */
-       D2bv(SrcSI | ImplicitOps | String), /* outsb, outsw/outsd */
+       D2bvI(DstDI | Mov | String, ins), /* insb, insw/insd */
+       D2bvI(SrcSI | ImplicitOps | String, outs), /* outsb, outsw/outsd */
        /* 0x70 - 0x7F */
        X16(D(SrcImmByte)),
        /* 0x80 - 0x87 */
@@ -2520,11 +2521,11 @@ static struct opcode opcode_table[256] = {
        N, N, N, N, N, N, N, N,
        /* 0xE0 - 0xE7 */
        X4(D(SrcImmByte)),
-       D2bv(SrcImmUByte | DstAcc), D2bv(SrcAcc | DstImmUByte),
+       D2bvI(SrcImmUByte | DstAcc, in), D2bvI(SrcAcc | DstImmUByte, out),
        /* 0xE8 - 0xEF */
        D(SrcImm | Stack), D(SrcImm | ImplicitOps),
        D(SrcImmFAddr | No64), D(SrcImmByte | ImplicitOps),
-       D2bv(SrcNone | DstAcc), D2bv(SrcAcc | ImplicitOps),
+       D2bvI(SrcNone | DstAcc, in), D2bvI(SrcAcc | ImplicitOps, out),
        /* 0xF0 - 0xF7 */
        N, DI(ImplicitOps, icebp), N, N,
        DI(ImplicitOps | Priv, hlt), D(ImplicitOps),
@@ -2609,6 +2610,7 @@ static struct opcode twobyte_table[256] = {
 #undef EXT
 
 #undef D2bv
+#undef D2bvI
 #undef I2bv
 #undef D6ALU
 
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index 847a3f9..1672e3c 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -3929,6 +3929,10 @@ static struct __x86_intercept {
        [x86_intercept_iret]            = PRE_EX(SVM_EXIT_IRET),
        [x86_intercept_icebp]           = PRE_EX(SVM_EXIT_ICEBP),
        [x86_intercept_hlt]             = POST_EX(SVM_EXIT_HLT),
+       [x86_intercept_in]              = POST_EX(SVM_EXIT_IOIO),
+       [x86_intercept_ins]             = POST_EX(SVM_EXIT_IOIO),
+       [x86_intercept_out]             = POST_EX(SVM_EXIT_IOIO),
+       [x86_intercept_outs]            = POST_EX(SVM_EXIT_IOIO),
 };
 
 #undef PRE_EX
@@ -4004,6 +4008,38 @@ static int svm_check_intercept(struct kvm_vcpu *vcpu,
                 */
                if (info->rep_prefix != REPE_PREFIX)
                        goto out;
+       case SVM_EXIT_IOIO: {
+               u64 exit_info;
+               u32 bytes;
+
+               exit_info = (vcpu->arch.regs[VCPU_REGS_RDX] & 0xffff) << 16;
+
+               if (info->intercept == x86_intercept_in ||
+                   info->intercept == x86_intercept_ins) {
+                       exit_info |= SVM_IOIO_TYPE_MASK;
+                       bytes = info->src_bytes;
+               } else {
+                       bytes = info->dst_bytes;
+               }
+
+               if (info->intercept == x86_intercept_outs ||
+                   info->intercept == x86_intercept_ins)
+                       exit_info |= SVM_IOIO_STR_MASK;
+
+               if (info->rep_prefix)
+                       exit_info |= SVM_IOIO_REP_MASK;
+
+               bytes = min(bytes, 4u);
+
+               exit_info |= bytes << SVM_IOIO_SIZE_SHIFT;
+
+               exit_info |= (u32)info->ad_bytes << (SVM_IOIO_ASIZE_SHIFT - 1);
+
+               vmcb->control.exit_info_1 = exit_info;
+               vmcb->control.exit_info_2 = info->next_rip;
+
+               break;
+       }
        default:
                break;
        }
-- 
1.7.1


--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to