diff options
author | Laurent Vivier <Laurent.Vivier@bull.net> | 2007-08-05 03:36:40 -0400 |
---|---|---|
committer | Avi Kivity <avi@qumranet.com> | 2007-10-13 04:18:23 -0400 |
commit | e70669abd4e60dfea3ac1639848e20e2b8dd1255 (patch) | |
tree | 4625f787efdf5f586514cd6306e045a97edb490e /drivers/kvm/x86_emulate.c | |
parent | 9fdaaac38e8c8a63c6383b807b91fea2d51da95d (diff) |
KVM: Cleanup string I/O instruction emulation
Both vmx and svm decode the I/O instructions, and both botch the job,
requiring the instruction prefixes to be fetched in order to completely
decode the instruction.
So, if we see a string I/O instruction, use the x86 emulator to decode it,
as it already has all the prefix decoding machinery.
This patch defines ins/outs opcodes in x86_emulate.c and calls
emulate_instruction() from io_interception() (svm.c) and from handle_io()
(vmx.c). It removes all vmx/svm prefix instruction decoders
(get_addr_size(), io_get_override(), io_address(), get_io_count())
Signed-off-by: Laurent Vivier <Laurent.Vivier@bull.net>
Signed-off-by: Avi Kivity <avi@qumranet.com>
Diffstat (limited to 'drivers/kvm/x86_emulate.c')
-rw-r--r-- | drivers/kvm/x86_emulate.c | 49 |
1 files changed, 44 insertions, 5 deletions
diff --git a/drivers/kvm/x86_emulate.c b/drivers/kvm/x86_emulate.c index 44eb28d31499..d553719fc4cb 100644 --- a/drivers/kvm/x86_emulate.c +++ b/drivers/kvm/x86_emulate.c | |||
@@ -103,9 +103,12 @@ static u8 opcode_table[256] = { | |||
103 | /* 0x58 - 0x5F */ | 103 | /* 0x58 - 0x5F */ |
104 | ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, | 104 | ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, |
105 | ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, | 105 | ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, |
106 | /* 0x60 - 0x6F */ | 106 | /* 0x60 - 0x6B */ |
107 | 0, 0, 0, DstReg | SrcMem32 | ModRM | Mov /* movsxd (x86/64) */ , | 107 | 0, 0, 0, DstReg | SrcMem32 | ModRM | Mov /* movsxd (x86/64) */ , |
108 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | 108 | 0, 0, 0, 0, 0, 0, 0, 0, |
109 | /* 0x6C - 0x6F */ | ||
110 | SrcNone | ByteOp | ImplicitOps, SrcNone | ImplicitOps, /* insb, insw/insd */ | ||
111 | SrcNone | ByteOp | ImplicitOps, SrcNone | ImplicitOps, /* outsb, outsw/outsd */ | ||
109 | /* 0x70 - 0x7F */ | 112 | /* 0x70 - 0x7F */ |
110 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | 113 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
111 | /* 0x80 - 0x87 */ | 114 | /* 0x80 - 0x87 */ |
@@ -428,10 +431,11 @@ struct operand { | |||
428 | }) | 431 | }) |
429 | 432 | ||
430 | /* Access/update address held in a register, based on addressing mode. */ | 433 | /* Access/update address held in a register, based on addressing mode. */ |
434 | #define address_mask(reg) \ | ||
435 | ((ad_bytes == sizeof(unsigned long)) ? \ | ||
436 | (reg) : ((reg) & ((1UL << (ad_bytes << 3)) - 1))) | ||
431 | #define register_address(base, reg) \ | 437 | #define register_address(base, reg) \ |
432 | ((base) + ((ad_bytes == sizeof(unsigned long)) ? (reg) : \ | 438 | ((base) + address_mask(reg)) |
433 | ((reg) & ((1UL << (ad_bytes << 3)) - 1)))) | ||
434 | |||
435 | #define register_address_increment(reg, inc) \ | 439 | #define register_address_increment(reg, inc) \ |
436 | do { \ | 440 | do { \ |
437 | /* signed type ensures sign extension to long */ \ | 441 | /* signed type ensures sign extension to long */ \ |
@@ -1116,6 +1120,41 @@ done: | |||
1116 | special_insn: | 1120 | special_insn: |
1117 | if (twobyte) | 1121 | if (twobyte) |
1118 | goto twobyte_special_insn; | 1122 | goto twobyte_special_insn; |
1123 | switch(b) { | ||
1124 | case 0x6c: /* insb */ | ||
1125 | case 0x6d: /* insw/insd */ | ||
1126 | if (kvm_setup_pio(ctxt->vcpu, NULL, | ||
1127 | 1, /* in */ | ||
1128 | (d & ByteOp) ? 1 : op_bytes, /* size */ | ||
1129 | rep_prefix ? | ||
1130 | address_mask(_regs[VCPU_REGS_RCX]) : 1, /* count */ | ||
1131 | 1, /* strings */ | ||
1132 | (_eflags & EFLG_DF), /* down */ | ||
1133 | register_address(ctxt->es_base, | ||
1134 | _regs[VCPU_REGS_RDI]), /* address */ | ||
1135 | rep_prefix, | ||
1136 | _regs[VCPU_REGS_RDX] /* port */ | ||
1137 | ) == 0) | ||
1138 | return -1; | ||
1139 | return 0; | ||
1140 | case 0x6e: /* outsb */ | ||
1141 | case 0x6f: /* outsw/outsd */ | ||
1142 | if (kvm_setup_pio(ctxt->vcpu, NULL, | ||
1143 | 0, /* in */ | ||
1144 | (d & ByteOp) ? 1 : op_bytes, /* size */ | ||
1145 | rep_prefix ? | ||
1146 | address_mask(_regs[VCPU_REGS_RCX]) : 1, /* count */ | ||
1147 | 1, /* strings */ | ||
1148 | (_eflags & EFLG_DF), /* down */ | ||
1149 | register_address(override_base ? | ||
1150 | *override_base : ctxt->ds_base, | ||
1151 | _regs[VCPU_REGS_RSI]), /* address */ | ||
1152 | rep_prefix, | ||
1153 | _regs[VCPU_REGS_RDX] /* port */ | ||
1154 | ) == 0) | ||
1155 | return -1; | ||
1156 | return 0; | ||
1157 | } | ||
1119 | if (rep_prefix) { | 1158 | if (rep_prefix) { |
1120 | if (_regs[VCPU_REGS_RCX] == 0) { | 1159 | if (_regs[VCPU_REGS_RCX] == 0) { |
1121 | ctxt->vcpu->rip = _eip; | 1160 | ctxt->vcpu->rip = _eip; |