aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGleb Natapov <gleb@redhat.com>2012-09-03 08:24:29 -0400
committerAvi Kivity <avi@redhat.com>2012-09-06 11:07:38 -0400
commitb3356bf0dbb34980620f2f7def7d1b9a0d325225 (patch)
tree508f58ece4a7ff5613181584fd0461e7cbfd5d20
parentf3bd64c68a8f1245e3d037f70c6936cd7bb1196b (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.h4
-rw-r--r--arch/x86/kvm/emulate.c33
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. */
215struct operand { 215struct 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,
2793static void string_addr_inc(struct x86_emulate_ctxt *ctxt, int reg, 2808static 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 /*