aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorAvi Kivity <avi@redhat.com>2010-04-11 06:05:15 -0400
committerAvi Kivity <avi@redhat.com>2010-05-17 05:17:33 -0400
commit2fb53ad811e238d5dec8716b99986c3f234e3337 (patch)
treeae8c407943348d07e980ee8e7e1f311596d7658f /arch
parent4496f974825e2ee317c3cc94e41ec2db7eb73af8 (diff)
KVM: x86 emulator: Don't overwrite decode cache
Currently if we an instruction spans a page boundary, when we fetch the second half we overwrite the first half. This prevents us from tracing the full instruction opcodes. Fix by appending the second half to the first. Signed-off-by: Avi Kivity <avi@redhat.com> Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Diffstat (limited to 'arch')
-rw-r--r--arch/x86/kvm/emulate.c19
1 files changed, 10 insertions, 9 deletions
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index 64c9854f0458..083b269a83ea 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -646,21 +646,22 @@ static unsigned long ss_base(struct x86_emulate_ctxt *ctxt)
646 646
647static int do_fetch_insn_byte(struct x86_emulate_ctxt *ctxt, 647static int do_fetch_insn_byte(struct x86_emulate_ctxt *ctxt,
648 struct x86_emulate_ops *ops, 648 struct x86_emulate_ops *ops,
649 unsigned long linear, u8 *dest) 649 unsigned long eip, u8 *dest)
650{ 650{
651 struct fetch_cache *fc = &ctxt->decode.fetch; 651 struct fetch_cache *fc = &ctxt->decode.fetch;
652 int rc; 652 int rc;
653 int size; 653 int size, cur_size;
654 654
655 if (linear < fc->start || linear >= fc->end) { 655 if (eip == fc->end) {
656 size = min(15UL, PAGE_SIZE - offset_in_page(linear)); 656 cur_size = fc->end - fc->start;
657 rc = ops->fetch(linear, fc->data, size, ctxt->vcpu, NULL); 657 size = min(15UL - cur_size, PAGE_SIZE - offset_in_page(eip));
658 rc = ops->fetch(ctxt->cs_base + eip, fc->data + cur_size,
659 size, ctxt->vcpu, NULL);
658 if (rc != X86EMUL_CONTINUE) 660 if (rc != X86EMUL_CONTINUE)
659 return rc; 661 return rc;
660 fc->start = linear; 662 fc->end += size;
661 fc->end = linear + size;
662 } 663 }
663 *dest = fc->data[linear - fc->start]; 664 *dest = fc->data[eip - fc->start];
664 return X86EMUL_CONTINUE; 665 return X86EMUL_CONTINUE;
665} 666}
666 667
@@ -673,7 +674,6 @@ static int do_insn_fetch(struct x86_emulate_ctxt *ctxt,
673 /* x86 instructions are limited to 15 bytes. */ 674 /* x86 instructions are limited to 15 bytes. */
674 if (eip + size - ctxt->eip > 15) 675 if (eip + size - ctxt->eip > 15)
675 return X86EMUL_UNHANDLEABLE; 676 return X86EMUL_UNHANDLEABLE;
676 eip += ctxt->cs_base;
677 while (size--) { 677 while (size--) {
678 rc = do_fetch_insn_byte(ctxt, ops, eip++, dest++); 678 rc = do_fetch_insn_byte(ctxt, ops, eip++, dest++);
679 if (rc != X86EMUL_CONTINUE) 679 if (rc != X86EMUL_CONTINUE)
@@ -935,6 +935,7 @@ x86_decode_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
935 /* Shadow copy of register state. Committed on successful emulation. */ 935 /* Shadow copy of register state. Committed on successful emulation. */
936 memset(c, 0, sizeof(struct decode_cache)); 936 memset(c, 0, sizeof(struct decode_cache));
937 c->eip = ctxt->eip; 937 c->eip = ctxt->eip;
938 c->fetch.start = c->fetch.end = c->eip;
938 ctxt->cs_base = seg_base(ctxt, VCPU_SREG_CS); 939 ctxt->cs_base = seg_base(ctxt, VCPU_SREG_CS);
939 memcpy(c->regs, ctxt->vcpu->arch.regs, sizeof c->regs); 940 memcpy(c->regs, ctxt->vcpu->arch.regs, sizeof c->regs);
940 941