From: Avi Kivity Date: Tue, 20 Nov 2007 11:15:52 +0000 (+0200) Subject: KVM: x86 emulator: prefetch up to 15 bytes of the instruction executed X-Git-Tag: v2.6.25-rc1~1138^2~109 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=6226686954c4cce3d63ffe1777e60360fcbf0b83;p=platform%2Fkernel%2Flinux-3.10.git KVM: x86 emulator: prefetch up to 15 bytes of the instruction executed Instead of fetching one byte at a time, prefetch 15 bytes (or until the next page boundary) to avoid guest page table walks. Signed-off-by: Avi Kivity --- diff --git a/drivers/kvm/x86_emulate.c b/drivers/kvm/x86_emulate.c index 8e2162f..6e7f774 100644 --- a/drivers/kvm/x86_emulate.c +++ b/drivers/kvm/x86_emulate.c @@ -414,8 +414,7 @@ static u16 twobyte_table[256] = { /* Fetch next part of the instruction being emulated. */ #define insn_fetch(_type, _size, _eip) \ ({ unsigned long _x; \ - rc = ops->read_std((unsigned long)(_eip) + ctxt->cs_base, &_x, \ - (_size), ctxt->vcpu); \ + rc = do_insn_fetch(ctxt, ops, (_eip), &_x, (_size)); \ if (rc != 0) \ goto done; \ (_eip) += (_size); \ @@ -446,6 +445,41 @@ static u16 twobyte_table[256] = { register_address_increment(c->eip, rel); \ } while (0) +static int do_fetch_insn_byte(struct x86_emulate_ctxt *ctxt, + struct x86_emulate_ops *ops, + unsigned long linear, u8 *dest) +{ + struct fetch_cache *fc = &ctxt->decode.fetch; + int rc; + int size; + + if (linear < fc->start || linear >= fc->end) { + size = min(15UL, PAGE_SIZE - offset_in_page(linear)); + rc = ops->read_std(linear, fc->data, size, ctxt->vcpu); + if (rc) + return rc; + fc->start = linear; + fc->end = linear + size; + } + *dest = fc->data[linear - fc->start]; + return 0; +} + +static int do_insn_fetch(struct x86_emulate_ctxt *ctxt, + struct x86_emulate_ops *ops, + unsigned long eip, void *dest, unsigned size) +{ + int rc = 0; + + eip += ctxt->cs_base; + while (size--) { + rc = do_fetch_insn_byte(ctxt, ops, eip++, dest++); + if (rc) + return rc; + } + return 0; +} + /* * Given the 'reg' portion of a ModRM byte, and a register block, return a * pointer into the block that addresses the relevant register. diff --git a/drivers/kvm/x86_emulate.h b/drivers/kvm/x86_emulate.h index a62bf14..4603b2b 100644 --- a/drivers/kvm/x86_emulate.h +++ b/drivers/kvm/x86_emulate.h @@ -108,6 +108,12 @@ struct operand { unsigned long val, orig_val, *ptr; }; +struct fetch_cache { + u8 data[15]; + unsigned long start; + unsigned long end; +}; + struct decode_cache { u8 twobyte; u8 b; @@ -130,6 +136,7 @@ struct decode_cache { u8 use_modrm_ea; unsigned long modrm_ea; unsigned long modrm_val; + struct fetch_cache fetch; }; struct x86_emulate_ctxt {