Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7b262e90 authored by Gleb Natapov's avatar Gleb Natapov Committed by Avi Kivity
Browse files

KVM: x86 emulator: introduce pio in string read ahead.



To optimize "rep ins" instruction do IO in big chunks ahead of time
instead of doing it only when required during instruction emulation.

Signed-off-by: default avatarGleb Natapov <gleb@redhat.com>
Signed-off-by: default avatarMarcelo Tosatti <mtosatti@redhat.com>
parent 5cd21917
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -151,6 +151,12 @@ struct fetch_cache {
	unsigned long end;
};

struct read_cache {
	u8 data[1024];
	unsigned long pos;
	unsigned long end;
};

struct decode_cache {
	u8 twobyte;
	u8 b;
@@ -178,6 +184,7 @@ struct decode_cache {
	void *modrm_ptr;
	unsigned long modrm_val;
	struct fetch_cache fetch;
	struct read_cache io_read;
};

struct x86_emulate_ctxt {
+41 −5
Original line number Diff line number Diff line
@@ -1257,6 +1257,36 @@ x86_decode_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
	return (rc == X86EMUL_UNHANDLEABLE) ? -1 : 0;
}

static int pio_in_emulated(struct x86_emulate_ctxt *ctxt,
			   struct x86_emulate_ops *ops,
			   unsigned int size, unsigned short port,
			   void *dest)
{
	struct read_cache *rc = &ctxt->decode.io_read;

	if (rc->pos == rc->end) { /* refill pio read ahead */
		struct decode_cache *c = &ctxt->decode;
		unsigned int in_page, n;
		unsigned int count = c->rep_prefix ?
			address_mask(c, c->regs[VCPU_REGS_RCX]) : 1;
		in_page = (ctxt->eflags & EFLG_DF) ?
			offset_in_page(c->regs[VCPU_REGS_RDI]) :
			PAGE_SIZE - offset_in_page(c->regs[VCPU_REGS_RDI]);
		n = min(min(in_page, (unsigned int)sizeof(rc->data)) / size,
			count);
		if (n == 0)
			n = 1;
		rc->pos = rc->end = 0;
		if (!ops->pio_in_emulated(size, port, rc->data, n, ctxt->vcpu))
			return 0;
		rc->end = n * size;
	}

	memcpy(dest, rc->data + rc->pos, size);
	rc->pos += size;
	return 1;
}

static u32 desc_limit_scaled(struct desc_struct *desc)
{
	u32 limit = get_desc_limit(desc);
@@ -2622,8 +2652,8 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
			kvm_inject_gp(ctxt->vcpu, 0);
			goto done;
		}
		if (!ops->pio_in_emulated(c->dst.bytes, c->regs[VCPU_REGS_RDX],
					  &c->dst.val, 1, ctxt->vcpu))
		if (!pio_in_emulated(ctxt, ops, c->dst.bytes,
				     c->regs[VCPU_REGS_RDX], &c->dst.val))
			goto done; /* IO is needed, skip writeback */
		break;
	case 0x6e:		/* outsb */
@@ -2839,8 +2869,8 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
			kvm_inject_gp(ctxt->vcpu, 0);
			goto done;
		}
		if (!ops->pio_in_emulated(c->dst.bytes, c->src.val,
					  &c->dst.val, 1, ctxt->vcpu))
		if (!pio_in_emulated(ctxt, ops, c->dst.bytes, c->src.val,
				     &c->dst.val))
			goto done; /* IO is needed */
		break;
	case 0xee: /* out al,dx */
@@ -2928,8 +2958,14 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
		string_addr_inc(ctxt, es_base(ctxt), VCPU_REGS_RDI, &c->dst);

	if (c->rep_prefix && (c->d & String)) {
		struct read_cache *rc = &ctxt->decode.io_read;
		register_address_increment(c, &c->regs[VCPU_REGS_RCX], -1);
		if (!(c->regs[VCPU_REGS_RCX] & 0x3ff))
		/*
		 * Re-enter guest when pio read ahead buffer is empty or,
		 * if it is not used, after each 1024 iteration.
		 */
		if ((rc->end == 0 && !(c->regs[VCPU_REGS_RCX] & 0x3ff)) ||
		    (rc->end != 0 && rc->end == rc->pos))
			ctxt->restart = false;
	}