KVM: x86 emulator: prefetch up to 15 bytes of the instruction executed
authorAvi Kivity <avi@qumranet.com>
Tue, 20 Nov 2007 11:15:52 +0000 (13:15 +0200)
committerAvi Kivity <avi@qumranet.com>
Wed, 30 Jan 2008 15:53:09 +0000 (17:53 +0200)
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 <avi@qumranet.com>
drivers/kvm/x86_emulate.c
drivers/kvm/x86_emulate.h

index 8e2162f..6e7f774 100644 (file)
@@ -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.
index a62bf14..4603b2b 100644 (file)
@@ -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 {