aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kvm
diff options
context:
space:
mode:
authorPaolo Bonzini <pbonzini@redhat.com>2014-06-19 05:37:06 -0400
committerPaolo Bonzini <pbonzini@redhat.com>2014-07-11 03:14:04 -0400
commit719d5a9b2487e0562f178f61e323c3dc18a8b200 (patch)
tree677713d985ffab18b25867d48ddc52a6c9bf4164 /arch/x86/kvm
parent17052f16a51af6d8f4b7eee0631af675ac204f65 (diff)
KVM: x86: ensure emulator fetches do not span multiple pages
When the CS base is not page-aligned, the linear address of the code could get close to the page boundary (e.g. 0x...ffe) even if the EIP value is not. So we need to first linearize the address, and only then compute the number of valid bytes that can be fetched. This happens relatively often when executing real mode code. Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Diffstat (limited to 'arch/x86/kvm')
-rw-r--r--arch/x86/kvm/emulate.c13
1 files changed, 7 insertions, 6 deletions
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index c16314807756..6a1d60956d63 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -711,14 +711,18 @@ static int segmented_read_std(struct x86_emulate_ctxt *ctxt,
711static int __do_insn_fetch_bytes(struct x86_emulate_ctxt *ctxt, int op_size) 711static int __do_insn_fetch_bytes(struct x86_emulate_ctxt *ctxt, int op_size)
712{ 712{
713 int rc; 713 int rc;
714 int size; 714 unsigned size;
715 unsigned long linear; 715 unsigned long linear;
716 int cur_size = ctxt->fetch.end - ctxt->fetch.data; 716 int cur_size = ctxt->fetch.end - ctxt->fetch.data;
717 struct segmented_address addr = { .seg = VCPU_SREG_CS, 717 struct segmented_address addr = { .seg = VCPU_SREG_CS,
718 .ea = ctxt->eip + cur_size }; 718 .ea = ctxt->eip + cur_size };
719 719
720 size = min(15UL ^ cur_size, 720 size = 15UL ^ cur_size;
721 PAGE_SIZE - offset_in_page(addr.ea)); 721 rc = __linearize(ctxt, addr, size, false, true, &linear);
722 if (unlikely(rc != X86EMUL_CONTINUE))
723 return rc;
724
725 size = min_t(unsigned, size, PAGE_SIZE - offset_in_page(linear));
722 726
723 /* 727 /*
724 * One instruction can only straddle two pages, 728 * One instruction can only straddle two pages,
@@ -728,9 +732,6 @@ static int __do_insn_fetch_bytes(struct x86_emulate_ctxt *ctxt, int op_size)
728 */ 732 */
729 if (unlikely(size < op_size)) 733 if (unlikely(size < op_size))
730 return X86EMUL_UNHANDLEABLE; 734 return X86EMUL_UNHANDLEABLE;
731 rc = __linearize(ctxt, addr, size, false, true, &linear);
732 if (unlikely(rc != X86EMUL_CONTINUE))
733 return rc;
734 rc = ctxt->ops->fetch(ctxt, linear, ctxt->fetch.end, 735 rc = ctxt->ops->fetch(ctxt, linear, ctxt->fetch.end,
735 size, &ctxt->exception); 736 size, &ctxt->exception);
736 if (unlikely(rc != X86EMUL_CONTINUE)) 737 if (unlikely(rc != X86EMUL_CONTINUE))