diff options
author | Joerg Roedel <joerg.roedel@amd.com> | 2011-04-04 06:39:35 -0400 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2011-05-11 07:57:03 -0400 |
commit | f6511935f424b9a25059ae18e91ad11dd24980e6 (patch) | |
tree | 8f3b8108255f943b2e3f355a9cdd12d31c92c16e | |
parent | bf608f88faef1245ff87e731512517fc676ffe02 (diff) |
KVM: SVM: Add checks for IO instructions
This patch adds code to check for IOIO intercepts on
instructions decoded by the KVM instruction emulator.
[avi: fix build error due to missing #define D2bvIP]
Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
-rw-r--r-- | arch/x86/include/asm/kvm_emulate.h | 4 | ||||
-rw-r--r-- | arch/x86/kvm/emulate.c | 45 | ||||
-rw-r--r-- | arch/x86/kvm/svm.c | 36 |
3 files changed, 70 insertions, 15 deletions
diff --git a/arch/x86/include/asm/kvm_emulate.h b/arch/x86/include/asm/kvm_emulate.h index f30650f00907..081844860a3d 100644 --- a/arch/x86/include/asm/kvm_emulate.h +++ b/arch/x86/include/asm/kvm_emulate.h | |||
@@ -346,6 +346,10 @@ enum x86_intercept { | |||
346 | x86_intercept_mwait, | 346 | x86_intercept_mwait, |
347 | x86_intercept_rdmsr, | 347 | x86_intercept_rdmsr, |
348 | x86_intercept_wrmsr, | 348 | x86_intercept_wrmsr, |
349 | x86_intercept_in, | ||
350 | x86_intercept_ins, | ||
351 | x86_intercept_out, | ||
352 | x86_intercept_outs, | ||
349 | 353 | ||
350 | nr_x86_intercepts | 354 | nr_x86_intercepts |
351 | }; | 355 | }; |
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index cc32e72fe175..d88dcfd66a8f 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c | |||
@@ -2623,6 +2623,28 @@ static int check_rdpmc(struct x86_emulate_ctxt *ctxt) | |||
2623 | return X86EMUL_CONTINUE; | 2623 | return X86EMUL_CONTINUE; |
2624 | } | 2624 | } |
2625 | 2625 | ||
2626 | static int check_perm_in(struct x86_emulate_ctxt *ctxt) | ||
2627 | { | ||
2628 | struct decode_cache *c = &ctxt->decode; | ||
2629 | |||
2630 | c->dst.bytes = min(c->dst.bytes, 4u); | ||
2631 | if (!emulator_io_permited(ctxt, ctxt->ops, c->src.val, c->dst.bytes)) | ||
2632 | return emulate_gp(ctxt, 0); | ||
2633 | |||
2634 | return X86EMUL_CONTINUE; | ||
2635 | } | ||
2636 | |||
2637 | static int check_perm_out(struct x86_emulate_ctxt *ctxt) | ||
2638 | { | ||
2639 | struct decode_cache *c = &ctxt->decode; | ||
2640 | |||
2641 | c->src.bytes = min(c->src.bytes, 4u); | ||
2642 | if (!emulator_io_permited(ctxt, ctxt->ops, c->dst.val, c->src.bytes)) | ||
2643 | return emulate_gp(ctxt, 0); | ||
2644 | |||
2645 | return X86EMUL_CONTINUE; | ||
2646 | } | ||
2647 | |||
2626 | #define D(_y) { .flags = (_y) } | 2648 | #define D(_y) { .flags = (_y) } |
2627 | #define DI(_y, _i) { .flags = (_y), .intercept = x86_intercept_##_i } | 2649 | #define DI(_y, _i) { .flags = (_y), .intercept = x86_intercept_##_i } |
2628 | #define DIP(_y, _i, _p) { .flags = (_y), .intercept = x86_intercept_##_i, \ | 2650 | #define DIP(_y, _i, _p) { .flags = (_y), .intercept = x86_intercept_##_i, \ |
@@ -2640,6 +2662,7 @@ static int check_rdpmc(struct x86_emulate_ctxt *ctxt) | |||
2640 | #define GP(_f, _g) { .flags = ((_f) | Prefix), .u.gprefix = (_g) } | 2662 | #define GP(_f, _g) { .flags = ((_f) | Prefix), .u.gprefix = (_g) } |
2641 | 2663 | ||
2642 | #define D2bv(_f) D((_f) | ByteOp), D(_f) | 2664 | #define D2bv(_f) D((_f) | ByteOp), D(_f) |
2665 | #define D2bvIP(_f, _i, _p) DIP((_f) | ByteOp, _i, _p), DIP(_f, _i, _p) | ||
2643 | #define I2bv(_f, _e) I((_f) | ByteOp, _e), I(_f, _e) | 2666 | #define I2bv(_f, _e) I((_f) | ByteOp, _e), I(_f, _e) |
2644 | 2667 | ||
2645 | #define D6ALU(_f) D2bv((_f) | DstMem | SrcReg | ModRM), \ | 2668 | #define D6ALU(_f) D2bv((_f) | DstMem | SrcReg | ModRM), \ |
@@ -2773,8 +2796,8 @@ static struct opcode opcode_table[256] = { | |||
2773 | I(DstReg | SrcMem | ModRM | Src2Imm, em_imul_3op), | 2796 | I(DstReg | SrcMem | ModRM | Src2Imm, em_imul_3op), |
2774 | I(SrcImmByte | Mov | Stack, em_push), | 2797 | I(SrcImmByte | Mov | Stack, em_push), |
2775 | I(DstReg | SrcMem | ModRM | Src2ImmByte, em_imul_3op), | 2798 | I(DstReg | SrcMem | ModRM | Src2ImmByte, em_imul_3op), |
2776 | D2bv(DstDI | Mov | String), /* insb, insw/insd */ | 2799 | D2bvIP(DstDI | Mov | String, ins, check_perm_in), /* insb, insw/insd */ |
2777 | D2bv(SrcSI | ImplicitOps | String), /* outsb, outsw/outsd */ | 2800 | D2bvIP(SrcSI | ImplicitOps | String, outs, check_perm_out), /* outsb, outsw/outsd */ |
2778 | /* 0x70 - 0x7F */ | 2801 | /* 0x70 - 0x7F */ |
2779 | X16(D(SrcImmByte)), | 2802 | X16(D(SrcImmByte)), |
2780 | /* 0x80 - 0x87 */ | 2803 | /* 0x80 - 0x87 */ |
@@ -2825,11 +2848,13 @@ static struct opcode opcode_table[256] = { | |||
2825 | N, N, N, N, N, N, N, N, | 2848 | N, N, N, N, N, N, N, N, |
2826 | /* 0xE0 - 0xE7 */ | 2849 | /* 0xE0 - 0xE7 */ |
2827 | X4(D(SrcImmByte)), | 2850 | X4(D(SrcImmByte)), |
2828 | D2bv(SrcImmUByte | DstAcc), D2bv(SrcAcc | DstImmUByte), | 2851 | D2bvIP(SrcImmUByte | DstAcc, in, check_perm_in), |
2852 | D2bvIP(SrcAcc | DstImmUByte, out, check_perm_out), | ||
2829 | /* 0xE8 - 0xEF */ | 2853 | /* 0xE8 - 0xEF */ |
2830 | D(SrcImm | Stack), D(SrcImm | ImplicitOps), | 2854 | D(SrcImm | Stack), D(SrcImm | ImplicitOps), |
2831 | D(SrcImmFAddr | No64), D(SrcImmByte | ImplicitOps), | 2855 | D(SrcImmFAddr | No64), D(SrcImmByte | ImplicitOps), |
2832 | D2bv(SrcNone | DstAcc), D2bv(SrcAcc | ImplicitOps), | 2856 | D2bvIP(SrcNone | DstAcc, in, check_perm_in), |
2857 | D2bvIP(SrcAcc | ImplicitOps, out, check_perm_out), | ||
2833 | /* 0xF0 - 0xF7 */ | 2858 | /* 0xF0 - 0xF7 */ |
2834 | N, DI(ImplicitOps, icebp), N, N, | 2859 | N, DI(ImplicitOps, icebp), N, N, |
2835 | DI(ImplicitOps | Priv, hlt), D(ImplicitOps), | 2860 | DI(ImplicitOps | Priv, hlt), D(ImplicitOps), |
@@ -2923,6 +2948,7 @@ static struct opcode twobyte_table[256] = { | |||
2923 | #undef EXT | 2948 | #undef EXT |
2924 | 2949 | ||
2925 | #undef D2bv | 2950 | #undef D2bv |
2951 | #undef D2bvIP | ||
2926 | #undef I2bv | 2952 | #undef I2bv |
2927 | #undef D6ALU | 2953 | #undef D6ALU |
2928 | 2954 | ||
@@ -3731,11 +3757,6 @@ special_insn: | |||
3731 | case 0xed: /* in (e/r)ax,dx */ | 3757 | case 0xed: /* in (e/r)ax,dx */ |
3732 | c->src.val = c->regs[VCPU_REGS_RDX]; | 3758 | c->src.val = c->regs[VCPU_REGS_RDX]; |
3733 | do_io_in: | 3759 | do_io_in: |
3734 | c->dst.bytes = min(c->dst.bytes, 4u); | ||
3735 | if (!emulator_io_permited(ctxt, ops, c->src.val, c->dst.bytes)) { | ||
3736 | rc = emulate_gp(ctxt, 0); | ||
3737 | goto done; | ||
3738 | } | ||
3739 | if (!pio_in_emulated(ctxt, ops, c->dst.bytes, c->src.val, | 3760 | if (!pio_in_emulated(ctxt, ops, c->dst.bytes, c->src.val, |
3740 | &c->dst.val)) | 3761 | &c->dst.val)) |
3741 | goto done; /* IO is needed */ | 3762 | goto done; /* IO is needed */ |
@@ -3744,12 +3765,6 @@ special_insn: | |||
3744 | case 0xef: /* out dx,(e/r)ax */ | 3765 | case 0xef: /* out dx,(e/r)ax */ |
3745 | c->dst.val = c->regs[VCPU_REGS_RDX]; | 3766 | c->dst.val = c->regs[VCPU_REGS_RDX]; |
3746 | do_io_out: | 3767 | do_io_out: |
3747 | c->src.bytes = min(c->src.bytes, 4u); | ||
3748 | if (!emulator_io_permited(ctxt, ops, c->dst.val, | ||
3749 | c->src.bytes)) { | ||
3750 | rc = emulate_gp(ctxt, 0); | ||
3751 | goto done; | ||
3752 | } | ||
3753 | ops->pio_out_emulated(c->src.bytes, c->dst.val, | 3768 | ops->pio_out_emulated(c->src.bytes, c->dst.val, |
3754 | &c->src.val, 1, ctxt->vcpu); | 3769 | &c->src.val, 1, ctxt->vcpu); |
3755 | c->dst.type = OP_NONE; /* Disable writeback. */ | 3770 | c->dst.type = OP_NONE; /* Disable writeback. */ |
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index 9eb27100e2ea..5c6512dbac7c 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c | |||
@@ -3925,6 +3925,10 @@ static struct __x86_intercept { | |||
3925 | [x86_intercept_iret] = PRE_EX(SVM_EXIT_IRET), | 3925 | [x86_intercept_iret] = PRE_EX(SVM_EXIT_IRET), |
3926 | [x86_intercept_icebp] = PRE_EX(SVM_EXIT_ICEBP), | 3926 | [x86_intercept_icebp] = PRE_EX(SVM_EXIT_ICEBP), |
3927 | [x86_intercept_hlt] = POST_EX(SVM_EXIT_HLT), | 3927 | [x86_intercept_hlt] = POST_EX(SVM_EXIT_HLT), |
3928 | [x86_intercept_in] = POST_EX(SVM_EXIT_IOIO), | ||
3929 | [x86_intercept_ins] = POST_EX(SVM_EXIT_IOIO), | ||
3930 | [x86_intercept_out] = POST_EX(SVM_EXIT_IOIO), | ||
3931 | [x86_intercept_outs] = POST_EX(SVM_EXIT_IOIO), | ||
3928 | }; | 3932 | }; |
3929 | 3933 | ||
3930 | #undef PRE_EX | 3934 | #undef PRE_EX |
@@ -4001,6 +4005,38 @@ static int svm_check_intercept(struct kvm_vcpu *vcpu, | |||
4001 | */ | 4005 | */ |
4002 | if (info->rep_prefix != REPE_PREFIX) | 4006 | if (info->rep_prefix != REPE_PREFIX) |
4003 | goto out; | 4007 | goto out; |
4008 | case SVM_EXIT_IOIO: { | ||
4009 | u64 exit_info; | ||
4010 | u32 bytes; | ||
4011 | |||
4012 | exit_info = (vcpu->arch.regs[VCPU_REGS_RDX] & 0xffff) << 16; | ||
4013 | |||
4014 | if (info->intercept == x86_intercept_in || | ||
4015 | info->intercept == x86_intercept_ins) { | ||
4016 | exit_info |= SVM_IOIO_TYPE_MASK; | ||
4017 | bytes = info->src_bytes; | ||
4018 | } else { | ||
4019 | bytes = info->dst_bytes; | ||
4020 | } | ||
4021 | |||
4022 | if (info->intercept == x86_intercept_outs || | ||
4023 | info->intercept == x86_intercept_ins) | ||
4024 | exit_info |= SVM_IOIO_STR_MASK; | ||
4025 | |||
4026 | if (info->rep_prefix) | ||
4027 | exit_info |= SVM_IOIO_REP_MASK; | ||
4028 | |||
4029 | bytes = min(bytes, 4u); | ||
4030 | |||
4031 | exit_info |= bytes << SVM_IOIO_SIZE_SHIFT; | ||
4032 | |||
4033 | exit_info |= (u32)info->ad_bytes << (SVM_IOIO_ASIZE_SHIFT - 1); | ||
4034 | |||
4035 | vmcb->control.exit_info_1 = exit_info; | ||
4036 | vmcb->control.exit_info_2 = info->next_rip; | ||
4037 | |||
4038 | break; | ||
4039 | } | ||
4004 | default: | 4040 | default: |
4005 | break; | 4041 | break; |
4006 | } | 4042 | } |