diff options
author | Gleb Natapov <gleb@redhat.com> | 2010-03-18 09:20:23 -0400 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2010-05-17 05:16:25 -0400 |
commit | cf8f70bfe38b326bb80b10f76d6544f571040229 (patch) | |
tree | d646456d773a887ca592d174b3d45a57d2779d85 /arch/x86/kvm/emulate.c | |
parent | d9271123a46011af26da680baeb7fdf67b498abf (diff) |
KVM: x86 emulator: fix in/out emulation.
in/out emulation is broken now. The breakage is different depending
on where IO device resides. If it is in userspace emulator reports
emulation failure since it incorrectly interprets kvm_emulate_pio()
return value. If IO device is in the kernel emulation of 'in' will do
nothing since kvm_emulate_pio() stores result directly into vcpu
registers, so emulator will overwrite result of emulation during
commit of shadowed register.
Signed-off-by: Gleb Natapov <gleb@redhat.com>
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Diffstat (limited to 'arch/x86/kvm/emulate.c')
-rw-r--r-- | arch/x86/kvm/emulate.c | 50 |
1 files changed, 24 insertions, 26 deletions
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index 594574d8b9e9..2d095ce9dc87 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c | |||
@@ -210,13 +210,13 @@ static u32 opcode_table[256] = { | |||
210 | 0, 0, 0, 0, 0, 0, 0, 0, | 210 | 0, 0, 0, 0, 0, 0, 0, 0, |
211 | /* 0xE0 - 0xE7 */ | 211 | /* 0xE0 - 0xE7 */ |
212 | 0, 0, 0, 0, | 212 | 0, 0, 0, 0, |
213 | ByteOp | SrcImmUByte, SrcImmUByte, | 213 | ByteOp | SrcImmUByte | DstAcc, SrcImmUByte | DstAcc, |
214 | ByteOp | SrcImmUByte, SrcImmUByte, | 214 | ByteOp | SrcImmUByte | DstAcc, SrcImmUByte | DstAcc, |
215 | /* 0xE8 - 0xEF */ | 215 | /* 0xE8 - 0xEF */ |
216 | SrcImm | Stack, SrcImm | ImplicitOps, | 216 | SrcImm | Stack, SrcImm | ImplicitOps, |
217 | SrcImmU | Src2Imm16 | No64, SrcImmByte | ImplicitOps, | 217 | SrcImmU | Src2Imm16 | No64, SrcImmByte | ImplicitOps, |
218 | SrcNone | ByteOp | ImplicitOps, SrcNone | ImplicitOps, | 218 | SrcNone | ByteOp | DstAcc, SrcNone | DstAcc, |
219 | SrcNone | ByteOp | ImplicitOps, SrcNone | ImplicitOps, | 219 | SrcNone | ByteOp | DstAcc, SrcNone | DstAcc, |
220 | /* 0xF0 - 0xF7 */ | 220 | /* 0xF0 - 0xF7 */ |
221 | 0, 0, 0, 0, | 221 | 0, 0, 0, 0, |
222 | ImplicitOps | Priv, ImplicitOps, Group | Group3_Byte, Group | Group3, | 222 | ImplicitOps | Priv, ImplicitOps, Group | Group3_Byte, Group | Group3, |
@@ -2426,8 +2426,6 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops) | |||
2426 | u64 msr_data; | 2426 | u64 msr_data; |
2427 | unsigned long saved_eip = 0; | 2427 | unsigned long saved_eip = 0; |
2428 | struct decode_cache *c = &ctxt->decode; | 2428 | struct decode_cache *c = &ctxt->decode; |
2429 | unsigned int port; | ||
2430 | int io_dir_in; | ||
2431 | int rc = X86EMUL_CONTINUE; | 2429 | int rc = X86EMUL_CONTINUE; |
2432 | 2430 | ||
2433 | ctxt->interruptibility = 0; | 2431 | ctxt->interruptibility = 0; |
@@ -2823,14 +2821,10 @@ special_insn: | |||
2823 | break; | 2821 | break; |
2824 | case 0xe4: /* inb */ | 2822 | case 0xe4: /* inb */ |
2825 | case 0xe5: /* in */ | 2823 | case 0xe5: /* in */ |
2826 | port = c->src.val; | 2824 | goto do_io_in; |
2827 | io_dir_in = 1; | ||
2828 | goto do_io; | ||
2829 | case 0xe6: /* outb */ | 2825 | case 0xe6: /* outb */ |
2830 | case 0xe7: /* out */ | 2826 | case 0xe7: /* out */ |
2831 | port = c->src.val; | 2827 | goto do_io_out; |
2832 | io_dir_in = 0; | ||
2833 | goto do_io; | ||
2834 | case 0xe8: /* call (near) */ { | 2828 | case 0xe8: /* call (near) */ { |
2835 | long int rel = c->src.val; | 2829 | long int rel = c->src.val; |
2836 | c->src.val = (unsigned long) c->eip; | 2830 | c->src.val = (unsigned long) c->eip; |
@@ -2855,25 +2849,29 @@ special_insn: | |||
2855 | break; | 2849 | break; |
2856 | case 0xec: /* in al,dx */ | 2850 | case 0xec: /* in al,dx */ |
2857 | case 0xed: /* in (e/r)ax,dx */ | 2851 | case 0xed: /* in (e/r)ax,dx */ |
2858 | port = c->regs[VCPU_REGS_RDX]; | 2852 | c->src.val = c->regs[VCPU_REGS_RDX]; |
2859 | io_dir_in = 1; | 2853 | do_io_in: |
2860 | goto do_io; | 2854 | c->dst.bytes = min(c->dst.bytes, 4u); |
2855 | if (!emulator_io_permited(ctxt, ops, c->src.val, c->dst.bytes)) { | ||
2856 | kvm_inject_gp(ctxt->vcpu, 0); | ||
2857 | goto done; | ||
2858 | } | ||
2859 | if (!ops->pio_in_emulated(c->dst.bytes, c->src.val, | ||
2860 | &c->dst.val, 1, ctxt->vcpu)) | ||
2861 | goto done; /* IO is needed */ | ||
2862 | break; | ||
2861 | case 0xee: /* out al,dx */ | 2863 | case 0xee: /* out al,dx */ |
2862 | case 0xef: /* out (e/r)ax,dx */ | 2864 | case 0xef: /* out (e/r)ax,dx */ |
2863 | port = c->regs[VCPU_REGS_RDX]; | 2865 | c->src.val = c->regs[VCPU_REGS_RDX]; |
2864 | io_dir_in = 0; | 2866 | do_io_out: |
2865 | do_io: | 2867 | c->dst.bytes = min(c->dst.bytes, 4u); |
2866 | if (!emulator_io_permited(ctxt, ops, port, | 2868 | if (!emulator_io_permited(ctxt, ops, c->src.val, c->dst.bytes)) { |
2867 | (c->d & ByteOp) ? 1 : c->op_bytes)) { | ||
2868 | kvm_inject_gp(ctxt->vcpu, 0); | 2869 | kvm_inject_gp(ctxt->vcpu, 0); |
2869 | goto done; | 2870 | goto done; |
2870 | } | 2871 | } |
2871 | if (kvm_emulate_pio(ctxt->vcpu, io_dir_in, | 2872 | ops->pio_out_emulated(c->dst.bytes, c->src.val, &c->dst.val, 1, |
2872 | (c->d & ByteOp) ? 1 : c->op_bytes, | 2873 | ctxt->vcpu); |
2873 | port) != 0) { | 2874 | c->dst.type = OP_NONE; /* Disable writeback. */ |
2874 | c->eip = saved_eip; | ||
2875 | goto cannot_emulate; | ||
2876 | } | ||
2877 | break; | 2875 | break; |
2878 | case 0xf4: /* hlt */ | 2876 | case 0xf4: /* hlt */ |
2879 | ctxt->vcpu->arch.halt_request = 1; | 2877 | ctxt->vcpu->arch.halt_request = 1; |