x86_emulate_insn() is too long and has many confusing goto statements. This patch is the first part of a work which tries to split it into a few meaningful functions: just encapsulates the switch statement for the one byte instruction emulation as emulate_onebyte_insn(). Note that goto done with rc set to X86EMUL_UNHANDLEABLE will result in returning EMULATION_FAILED which is defined as -1. Signed-off-by: Takuya Yoshikawa <yoshikawa.takuya@xxxxxxxxxxxxx> --- arch/x86/kvm/emulate.c | 179 +++++++++++++++++++++++++++--------------------- 1 files changed, 100 insertions(+), 79 deletions(-) diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index ad46239..18d7c07 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -2945,88 +2945,14 @@ static bool string_insn_completed(struct x86_emulate_ctxt *ctxt) return false; } -int -x86_emulate_insn(struct x86_emulate_ctxt *ctxt) +static int emulate_onebyte_insn(struct x86_emulate_ctxt *ctxt, + struct x86_emulate_ops *ops, + struct decode_cache *c, + bool *need_writeback) { - struct x86_emulate_ops *ops = ctxt->ops; - u64 msr_data; - struct decode_cache *c = &ctxt->decode; int rc = X86EMUL_CONTINUE; - int saved_dst_type = c->dst.type; int irq; /* Used for int 3, int, and into */ - ctxt->decode.mem_read.pos = 0; - - if (ctxt->mode == X86EMUL_MODE_PROT64 && (c->d & No64)) { - rc = emulate_ud(ctxt); - goto done; - } - - /* LOCK prefix is allowed only with some instructions */ - if (c->lock_prefix && (!(c->d & Lock) || c->dst.type != OP_MEM)) { - rc = emulate_ud(ctxt); - goto done; - } - - if ((c->d & SrcMask) == SrcMemFAddr && c->src.type != OP_MEM) { - rc = emulate_ud(ctxt); - goto done; - } - - /* Privileged instruction can be executed only in CPL=0 */ - if ((c->d & Priv) && ops->cpl(ctxt->vcpu)) { - rc = emulate_gp(ctxt, 0); - goto done; - } - - if (c->rep_prefix && (c->d & String)) { - /* All REP prefixes have the same first termination condition */ - if (address_mask(c, c->regs[VCPU_REGS_RCX]) == 0) { - ctxt->eip = c->eip; - goto done; - } - } - - if ((c->src.type == OP_MEM) && !(c->d & NoAccess)) { - rc = read_emulated(ctxt, ops, linear(ctxt, c->src.addr.mem), - c->src.valptr, c->src.bytes); - if (rc != X86EMUL_CONTINUE) - goto done; - c->src.orig_val64 = c->src.val64; - } - - if (c->src2.type == OP_MEM) { - rc = read_emulated(ctxt, ops, linear(ctxt, c->src2.addr.mem), - &c->src2.val, c->src2.bytes); - if (rc != X86EMUL_CONTINUE) - goto done; - } - - if ((c->d & DstMask) == ImplicitOps) - goto special_insn; - - - if ((c->dst.type == OP_MEM) && !(c->d & Mov)) { - /* optimisation - avoid slow emulated read if Mov */ - rc = read_emulated(ctxt, ops, linear(ctxt, c->dst.addr.mem), - &c->dst.val, c->dst.bytes); - if (rc != X86EMUL_CONTINUE) - goto done; - } - c->dst.orig_val = c->dst.val; - -special_insn: - - if (c->execute) { - rc = c->execute(ctxt); - if (rc != X86EMUL_CONTINUE) - goto done; - goto writeback; - } - - if (c->twobyte) - goto twobyte_insn; - switch (c->b) { case 0x00 ... 0x05: add: /* add */ @@ -3371,7 +3297,102 @@ special_insn: goto cannot_emulate; } - if (rc != X86EMUL_CONTINUE) + *need_writeback = (rc == X86EMUL_CONTINUE); + return rc; + +done: + *need_writeback = false; + return rc; + +cannot_emulate: + *need_writeback = false; + return X86EMUL_UNHANDLEABLE; +} + +int +x86_emulate_insn(struct x86_emulate_ctxt *ctxt) +{ + struct x86_emulate_ops *ops = ctxt->ops; + u64 msr_data; + struct decode_cache *c = &ctxt->decode; + int rc = X86EMUL_CONTINUE; + int saved_dst_type = c->dst.type; + bool need_writeback; + + ctxt->decode.mem_read.pos = 0; + + if (ctxt->mode == X86EMUL_MODE_PROT64 && (c->d & No64)) { + rc = emulate_ud(ctxt); + goto done; + } + + /* LOCK prefix is allowed only with some instructions */ + if (c->lock_prefix && (!(c->d & Lock) || c->dst.type != OP_MEM)) { + rc = emulate_ud(ctxt); + goto done; + } + + if ((c->d & SrcMask) == SrcMemFAddr && c->src.type != OP_MEM) { + rc = emulate_ud(ctxt); + goto done; + } + + /* Privileged instruction can be executed only in CPL=0 */ + if ((c->d & Priv) && ops->cpl(ctxt->vcpu)) { + rc = emulate_gp(ctxt, 0); + goto done; + } + + if (c->rep_prefix && (c->d & String)) { + /* All REP prefixes have the same first termination condition */ + if (address_mask(c, c->regs[VCPU_REGS_RCX]) == 0) { + ctxt->eip = c->eip; + goto done; + } + } + + if ((c->src.type == OP_MEM) && !(c->d & NoAccess)) { + rc = read_emulated(ctxt, ops, linear(ctxt, c->src.addr.mem), + c->src.valptr, c->src.bytes); + if (rc != X86EMUL_CONTINUE) + goto done; + c->src.orig_val64 = c->src.val64; + } + + if (c->src2.type == OP_MEM) { + rc = read_emulated(ctxt, ops, linear(ctxt, c->src2.addr.mem), + &c->src2.val, c->src2.bytes); + if (rc != X86EMUL_CONTINUE) + goto done; + } + + if ((c->d & DstMask) == ImplicitOps) + goto special_insn; + + + if ((c->dst.type == OP_MEM) && !(c->d & Mov)) { + /* optimisation - avoid slow emulated read if Mov */ + rc = read_emulated(ctxt, ops, linear(ctxt, c->dst.addr.mem), + &c->dst.val, c->dst.bytes); + if (rc != X86EMUL_CONTINUE) + goto done; + } + c->dst.orig_val = c->dst.val; + +special_insn: + + if (c->execute) { + rc = c->execute(ctxt); + if (rc != X86EMUL_CONTINUE) + goto done; + goto writeback; + } + + if (c->twobyte) + goto twobyte_insn; + + rc = emulate_onebyte_insn(ctxt, ops, c, &need_writeback); + if (!need_writeback) goto done; writeback: -- 1.7.1 -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html