diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index 390400a54a9c..ea188a338afb 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -705,51 +705,51 @@ static int segmented_read_std(struct x86_emulate_ctxt *ctxt, } /* - * Fetch the next byte of the instruction being emulated which is pointed to - * by ctxt->_eip, then increment ctxt->_eip. - * - * Also prefetch the remaining bytes of the instruction without crossing page + * Prefetch the remaining bytes of the instruction without crossing page * boundary if they are not in fetch_cache yet. */ -static int do_insn_fetch_byte(struct x86_emulate_ctxt *ctxt, u8 *dest) +static int do_insn_fetch_bytes(struct x86_emulate_ctxt *ctxt) { struct fetch_cache *fc = &ctxt->fetch; int rc; int size, cur_size; + unsigned long linear; - if (ctxt->_eip == fc->end) { - unsigned long linear; - struct segmented_address addr = { .seg = VCPU_SREG_CS, - .ea = ctxt->_eip }; - cur_size = fc->end - fc->start; - size = min(15UL - cur_size, - PAGE_SIZE - offset_in_page(ctxt->_eip)); - rc = __linearize(ctxt, addr, size, false, true, &linear); - if (unlikely(rc != X86EMUL_CONTINUE)) - return rc; - rc = ctxt->ops->fetch(ctxt, linear, fc->data + cur_size, - size, &ctxt->exception); - if (unlikely(rc != X86EMUL_CONTINUE)) - return rc; - fc->end += size; - } - *dest = fc->data[ctxt->_eip - fc->start]; - ctxt->_eip++; + struct segmented_address addr = { .seg = VCPU_SREG_CS, + .ea = fc->end }; + cur_size = fc->end - fc->start; + size = min(15UL - cur_size, + PAGE_SIZE - offset_in_page(fc->end)); + if (unlikely(size == 0)) + return X86EMUL_UNHANDLEABLE; + rc = __linearize(ctxt, addr, size, false, true, &linear); + if (unlikely(rc != X86EMUL_CONTINUE)) + return rc; + rc = ctxt->ops->fetch(ctxt, linear, fc->data + cur_size, + size, &ctxt->exception); + if (unlikely(rc != X86EMUL_CONTINUE)) + return rc; + fc->end += size; return X86EMUL_CONTINUE; } static int do_insn_fetch(struct x86_emulate_ctxt *ctxt, - void *dest, unsigned size) + void *__dest, unsigned size) { int rc; + struct fetch_cache *fc = &ctxt->fetch; + u8 *dest = __dest; + u8 *src = &fc->data[ctxt->_eip - fc->start]; - /* x86 instructions are limited to 15 bytes. */ - if (unlikely(ctxt->_eip + size - ctxt->eip > 15)) - return X86EMUL_UNHANDLEABLE; while (size--) { - rc = do_insn_fetch_byte(ctxt, dest++); - if (rc != X86EMUL_CONTINUE) - return rc; + if (unlikely(ctxt->_eip == fc->end)) { + rc = do_insn_fetch_bytes(ctxt); + if (rc != X86EMUL_CONTINUE) + return rc; + } + *dest++ = *src++; + ctxt->_eip++; + continue; } return X86EMUL_CONTINUE; } @@ -4227,6 +4227,11 @@ int x86_decode_insn(struct x86_emulate_ctxt *ctxt, void *insn, int insn_len) ctxt->opcode_len = 1; if (insn_len > 0) memcpy(ctxt->fetch.data, insn, insn_len); + else { + rc = do_insn_fetch_bytes(ctxt); + if (rc != X86EMUL_CONTINUE) + return rc; + } switch (mode) { case X86EMUL_MODE_REAL: