diff options
author | Gleb Natapov <gleb@redhat.com> | 2012-09-03 08:24:29 -0400 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2012-09-06 11:07:38 -0400 |
commit | b3356bf0dbb34980620f2f7def7d1b9a0d325225 (patch) | |
tree | 508f58ece4a7ff5613181584fd0461e7cbfd5d20 | |
parent | f3bd64c68a8f1245e3d037f70c6936cd7bb1196b (diff) |
KVM: emulator: optimize "rep ins" handling
Optimize "rep ins" by allowing emulator to write back more than one
datum at a time. Introduce new operand type OP_MEM_STR which tells
writeback() that dst contains pointer to an array that should be written
back as opposite to just one data element.
Signed-off-by: Gleb Natapov <gleb@redhat.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 | 33 |
2 files changed, 31 insertions, 6 deletions
diff --git a/arch/x86/include/asm/kvm_emulate.h b/arch/x86/include/asm/kvm_emulate.h index e9e5675c0dfb..15f960c06ff7 100644 --- a/arch/x86/include/asm/kvm_emulate.h +++ b/arch/x86/include/asm/kvm_emulate.h | |||
@@ -213,8 +213,9 @@ typedef u32 __attribute__((vector_size(16))) sse128_t; | |||
213 | 213 | ||
214 | /* Type, address-of, and value of an instruction's operand. */ | 214 | /* Type, address-of, and value of an instruction's operand. */ |
215 | struct operand { | 215 | struct operand { |
216 | enum { OP_REG, OP_MEM, OP_IMM, OP_XMM, OP_MM, OP_NONE } type; | 216 | enum { OP_REG, OP_MEM, OP_MEM_STR, OP_IMM, OP_XMM, OP_MM, OP_NONE } type; |
217 | unsigned int bytes; | 217 | unsigned int bytes; |
218 | unsigned int count; | ||
218 | union { | 219 | union { |
219 | unsigned long orig_val; | 220 | unsigned long orig_val; |
220 | u64 orig_val64; | 221 | u64 orig_val64; |
@@ -234,6 +235,7 @@ struct operand { | |||
234 | char valptr[sizeof(unsigned long) + 2]; | 235 | char valptr[sizeof(unsigned long) + 2]; |
235 | sse128_t vec_val; | 236 | sse128_t vec_val; |
236 | u64 mm_val; | 237 | u64 mm_val; |
238 | void *data; | ||
237 | }; | 239 | }; |
238 | }; | 240 | }; |
239 | 241 | ||
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index 415f903facd3..39171cb307ea 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c | |||
@@ -1301,8 +1301,15 @@ static int pio_in_emulated(struct x86_emulate_ctxt *ctxt, | |||
1301 | rc->end = n * size; | 1301 | rc->end = n * size; |
1302 | } | 1302 | } |
1303 | 1303 | ||
1304 | memcpy(dest, rc->data + rc->pos, size); | 1304 | if (ctxt->rep_prefix && !(ctxt->eflags & EFLG_DF)) { |
1305 | rc->pos += size; | 1305 | ctxt->dst.data = rc->data + rc->pos; |
1306 | ctxt->dst.type = OP_MEM_STR; | ||
1307 | ctxt->dst.count = (rc->end - rc->pos) / size; | ||
1308 | rc->pos = rc->end; | ||
1309 | } else { | ||
1310 | memcpy(dest, rc->data + rc->pos, size); | ||
1311 | rc->pos += size; | ||
1312 | } | ||
1306 | return 1; | 1313 | return 1; |
1307 | } | 1314 | } |
1308 | 1315 | ||
@@ -1546,6 +1553,14 @@ static int writeback(struct x86_emulate_ctxt *ctxt) | |||
1546 | if (rc != X86EMUL_CONTINUE) | 1553 | if (rc != X86EMUL_CONTINUE) |
1547 | return rc; | 1554 | return rc; |
1548 | break; | 1555 | break; |
1556 | case OP_MEM_STR: | ||
1557 | rc = segmented_write(ctxt, | ||
1558 | ctxt->dst.addr.mem, | ||
1559 | ctxt->dst.data, | ||
1560 | ctxt->dst.bytes * ctxt->dst.count); | ||
1561 | if (rc != X86EMUL_CONTINUE) | ||
1562 | return rc; | ||
1563 | break; | ||
1549 | case OP_XMM: | 1564 | case OP_XMM: |
1550 | write_sse_reg(ctxt, &ctxt->dst.vec_val, ctxt->dst.addr.xmm); | 1565 | write_sse_reg(ctxt, &ctxt->dst.vec_val, ctxt->dst.addr.xmm); |
1551 | break; | 1566 | break; |
@@ -2793,7 +2808,7 @@ int emulator_task_switch(struct x86_emulate_ctxt *ctxt, | |||
2793 | static void string_addr_inc(struct x86_emulate_ctxt *ctxt, int reg, | 2808 | static void string_addr_inc(struct x86_emulate_ctxt *ctxt, int reg, |
2794 | struct operand *op) | 2809 | struct operand *op) |
2795 | { | 2810 | { |
2796 | int df = (ctxt->eflags & EFLG_DF) ? -1 : 1; | 2811 | int df = (ctxt->eflags & EFLG_DF) ? -op->count : op->count; |
2797 | 2812 | ||
2798 | register_address_increment(ctxt, reg_rmw(ctxt, reg), df * op->bytes); | 2813 | register_address_increment(ctxt, reg_rmw(ctxt, reg), df * op->bytes); |
2799 | op->addr.mem.ea = register_address(ctxt, reg_read(ctxt, reg)); | 2814 | op->addr.mem.ea = register_address(ctxt, reg_read(ctxt, reg)); |
@@ -3733,7 +3748,7 @@ static const struct opcode opcode_table[256] = { | |||
3733 | I(DstReg | SrcMem | ModRM | Src2Imm, em_imul_3op), | 3748 | I(DstReg | SrcMem | ModRM | Src2Imm, em_imul_3op), |
3734 | I(SrcImmByte | Mov | Stack, em_push), | 3749 | I(SrcImmByte | Mov | Stack, em_push), |
3735 | I(DstReg | SrcMem | ModRM | Src2ImmByte, em_imul_3op), | 3750 | I(DstReg | SrcMem | ModRM | Src2ImmByte, em_imul_3op), |
3736 | I2bvIP(DstDI | SrcDX | Mov | String, em_in, ins, check_perm_in), /* insb, insw/insd */ | 3751 | I2bvIP(DstDI | SrcDX | Mov | String | Unaligned, em_in, ins, check_perm_in), /* insb, insw/insd */ |
3737 | I2bvIP(SrcSI | DstDX | String, em_out, outs, check_perm_out), /* outsb, outsw/outsd */ | 3752 | I2bvIP(SrcSI | DstDX | String, em_out, outs, check_perm_out), /* outsb, outsw/outsd */ |
3738 | /* 0x70 - 0x7F */ | 3753 | /* 0x70 - 0x7F */ |
3739 | X16(D(SrcImmByte)), | 3754 | X16(D(SrcImmByte)), |
@@ -3991,6 +4006,7 @@ static int decode_operand(struct x86_emulate_ctxt *ctxt, struct operand *op, | |||
3991 | register_address(ctxt, reg_read(ctxt, VCPU_REGS_RDI)); | 4006 | register_address(ctxt, reg_read(ctxt, VCPU_REGS_RDI)); |
3992 | op->addr.mem.seg = VCPU_SREG_ES; | 4007 | op->addr.mem.seg = VCPU_SREG_ES; |
3993 | op->val = 0; | 4008 | op->val = 0; |
4009 | op->count = 1; | ||
3994 | break; | 4010 | break; |
3995 | case OpDX: | 4011 | case OpDX: |
3996 | op->type = OP_REG; | 4012 | op->type = OP_REG; |
@@ -4034,6 +4050,7 @@ static int decode_operand(struct x86_emulate_ctxt *ctxt, struct operand *op, | |||
4034 | register_address(ctxt, reg_read(ctxt, VCPU_REGS_RSI)); | 4050 | register_address(ctxt, reg_read(ctxt, VCPU_REGS_RSI)); |
4035 | op->addr.mem.seg = seg_override(ctxt); | 4051 | op->addr.mem.seg = seg_override(ctxt); |
4036 | op->val = 0; | 4052 | op->val = 0; |
4053 | op->count = 1; | ||
4037 | break; | 4054 | break; |
4038 | case OpImmFAddr: | 4055 | case OpImmFAddr: |
4039 | op->type = OP_IMM; | 4056 | op->type = OP_IMM; |
@@ -4575,8 +4592,14 @@ writeback: | |||
4575 | string_addr_inc(ctxt, VCPU_REGS_RDI, &ctxt->dst); | 4592 | string_addr_inc(ctxt, VCPU_REGS_RDI, &ctxt->dst); |
4576 | 4593 | ||
4577 | if (ctxt->rep_prefix && (ctxt->d & String)) { | 4594 | if (ctxt->rep_prefix && (ctxt->d & String)) { |
4595 | unsigned int count; | ||
4578 | struct read_cache *r = &ctxt->io_read; | 4596 | struct read_cache *r = &ctxt->io_read; |
4579 | register_address_increment(ctxt, reg_rmw(ctxt, VCPU_REGS_RCX), -1); | 4597 | if ((ctxt->d & SrcMask) == SrcSI) |
4598 | count = ctxt->src.count; | ||
4599 | else | ||
4600 | count = ctxt->dst.count; | ||
4601 | register_address_increment(ctxt, reg_rmw(ctxt, VCPU_REGS_RCX), | ||
4602 | -count); | ||
4580 | 4603 | ||
4581 | if (!string_insn_completed(ctxt)) { | 4604 | if (!string_insn_completed(ctxt)) { |
4582 | /* | 4605 | /* |