|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [RFC v1 4/7] x86/hvm: Support a fast path during emulation
Information to complete the instruction may be provided by the processor
during a VMEXIT. Add a fast path during emulation to use this
information and avoid going through the full x86 emulator. Plumbing the
fast path through the emulator ensures consistent behaviour.
Signed-off-by: Ross Lagerwall <ross.lagerwall@xxxxxxxxxx>
---
xen/arch/x86/hvm/emulate.c | 160 ++++++++++++++++++-------
xen/arch/x86/include/asm/hvm/emulate.h | 3 +
2 files changed, 123 insertions(+), 40 deletions(-)
diff --git a/xen/arch/x86/hvm/emulate.c b/xen/arch/x86/hvm/emulate.c
index a96d7814f91c..c9553cd28238 100644
--- a/xen/arch/x86/hvm/emulate.c
+++ b/xen/arch/x86/hvm/emulate.c
@@ -2724,6 +2724,52 @@ static const struct x86_emulate_ops hvm_emulate_ops = {
.vmfunc = hvmemul_vmfunc,
};
+static int hvm_emulate_insn_len(struct hvm_emulate_ctxt *hvmemul_ctxt)
+{
+ struct x86_emulate_state *state;
+ unsigned long emul_len;
+ unsigned int instr_opcode, instr_modrm;
+ unsigned int modrm_rm, modrm_reg;
+ int modrm_mod;
+
+ state = x86_decode_insn(&hvmemul_ctxt->ctxt, hvmemul_insn_fetch);
+ if ( IS_ERR_OR_NULL(state) )
+ return X86EMUL_EXCEPTION;
+
+ emul_len = x86_insn_length(state, &hvmemul_ctxt->ctxt);
+ modrm_mod = x86_insn_modrm(state, &modrm_rm, &modrm_reg);
+ x86_emulate_free_state(state);
+
+ /* Extract components from instr_enc. */
+ instr_modrm = hvmemul_ctxt->insn & 0xff;
+ instr_opcode = hvmemul_ctxt->insn >> 8;
+
+ if ( instr_opcode == hvmemul_ctxt->ctxt.opcode )
+ {
+ if ( !instr_modrm )
+ {
+ hvmemul_ctxt->insn_len = emul_len;
+ return X86EMUL_OKAY;
+ }
+
+ if ( modrm_mod == MASK_EXTR(instr_modrm, 0300) && /* octal-ok */
+ (modrm_reg & 7) == MASK_EXTR(instr_modrm, 0070) && /* octal-ok */
+ (modrm_rm & 7) == MASK_EXTR(instr_modrm, 0007) ) /* octal-ok */
+ {
+ hvmemul_ctxt->insn_len = emul_len;
+ return X86EMUL_OKAY;
+ }
+ }
+
+ printk(XENLOG_G_WARNING
+ "Insn mismatch: Expected opcode %#x, modrm %#x, got emul_len %lu\n",
+ instr_opcode, instr_modrm, emul_len);
+ hvm_dump_emulation_state(XENLOG_G_WARNING, "Insn len",
+ hvmemul_ctxt, X86EMUL_UNHANDLEABLE);
+
+ return X86EMUL_EXCEPTION;
+}
+
/*
* Note that passing VIO_no_completion into this function serves as kind
* of (but not fully) an "auto select completion" indicator. When there's
@@ -2733,63 +2779,97 @@ static int _hvm_emulate_one(struct hvm_emulate_ctxt
*hvmemul_ctxt,
const struct x86_emulate_ops *ops,
enum vio_completion completion)
{
- const struct cpu_user_regs *regs = hvmemul_ctxt->ctxt.regs;
+ struct cpu_user_regs *regs = hvmemul_ctxt->ctxt.regs;
struct vcpu *curr = current;
uint32_t new_intr_shadow;
struct hvm_vcpu_io *hvio = &curr->arch.hvm.hvm_io;
int rc;
- /*
- * Enable caching if it's currently disabled, but leave the cache
- * untouched if it's already enabled, for re-execution to consume
- * entries populated by an earlier pass.
- */
- if ( hvio->cache->num_ents > hvio->cache->max_ents )
+ if ( hvmemul_ctxt->insn )
{
- ASSERT(curr->io.req.state == STATE_IOREQ_NONE);
- hvio->cache->num_ents = 0;
+ hvm_emulate_init_per_insn(hvmemul_ctxt, NULL, 0);
+ if ( !hvmemul_ctxt->insn_len )
+ {
+ rc = hvm_emulate_insn_len(hvmemul_ctxt);
+ if ( rc == X86EMUL_EXCEPTION )
+ {
+ x86_emul_hw_exception(X86_EXC_GP, 0, &hvmemul_ctxt->ctxt);
+ goto complete_insn;
+ }
+ }
+
+ switch ( hvmemul_ctxt->insn )
+ {
+ default:
+ ASSERT_UNREACHABLE();
+ rc = X86EMUL_UNHANDLEABLE;
+ break;
+ }
+
+ if ( rc == X86EMUL_OKAY )
+ {
+ regs->rip += hvmemul_ctxt->insn_len;
+ hvmemul_ctxt->ctxt.singlestep = regs->eflags & X86_EFLAGS_TF;
+ x86_emulate_complete(&hvmemul_ctxt->ctxt, rc);
+ }
}
else
- ASSERT(curr->io.req.state == STATE_IORESP_READY);
+ {
+ /* No fast path. Go through full emulator */
+ /*
+ * Enable caching if it's currently disabled, but leave the cache
+ * untouched if it's already enabled, for re-execution to consume
+ * entries populated by an earlier pass.
+ */
+ if ( hvio->cache->num_ents > hvio->cache->max_ents )
+ {
+ ASSERT(curr->io.req.state == STATE_IOREQ_NONE);
+ hvio->cache->num_ents = 0;
+ }
+ else
+ ASSERT(curr->io.req.state == STATE_IORESP_READY);
- hvm_emulate_init_per_insn(hvmemul_ctxt, hvio->mmio_insn,
- hvio->mmio_insn_bytes);
+ hvm_emulate_init_per_insn(hvmemul_ctxt, hvio->mmio_insn,
+ hvio->mmio_insn_bytes);
- hvio->mmio_retry = 0;
+ hvio->mmio_retry = 0;
- rc = x86_emulate(&hvmemul_ctxt->ctxt, ops);
- if ( rc == X86EMUL_OKAY && hvio->mmio_retry )
- rc = X86EMUL_RETRY;
+ rc = x86_emulate(&hvmemul_ctxt->ctxt, ops);
+ if ( rc == X86EMUL_OKAY && hvio->mmio_retry )
+ rc = X86EMUL_RETRY;
- if ( !ioreq_needs_completion(&curr->io.req) )
- completion = VIO_no_completion;
- else if ( completion == VIO_no_completion )
- completion = (curr->io.req.type != IOREQ_TYPE_PIO ||
- hvmemul_ctxt->is_mem_access) ? VIO_mmio_completion
- : VIO_pio_completion;
+ if ( !ioreq_needs_completion(&curr->io.req) )
+ completion = VIO_no_completion;
+ else if ( completion == VIO_no_completion )
+ completion = (curr->io.req.type != IOREQ_TYPE_PIO ||
+ hvmemul_ctxt->is_mem_access) ? VIO_mmio_completion
+ : VIO_pio_completion;
- switch ( curr->io.completion = completion )
- {
- case VIO_no_completion:
- case VIO_pio_completion:
- hvio->mmio_cache_count = 0;
- hvio->mmio_insn_bytes = 0;
- hvio->mmio_access = (struct npfec){};
- hvmemul_cache_disable(curr);
- break;
+ switch ( curr->io.completion = completion )
+ {
+ case VIO_no_completion:
+ case VIO_pio_completion:
+ hvio->mmio_cache_count = 0;
+ hvio->mmio_insn_bytes = 0;
+ hvio->mmio_access = (struct npfec){};
+ hvmemul_cache_disable(curr);
+ break;
- case VIO_mmio_completion:
- case VIO_realmode_completion:
- BUILD_BUG_ON(sizeof(hvio->mmio_insn) < sizeof(hvmemul_ctxt->insn_buf));
- hvio->mmio_insn_bytes = hvmemul_ctxt->insn_buf_bytes;
- memcpy(hvio->mmio_insn, hvmemul_ctxt->insn_buf, hvio->mmio_insn_bytes);
- break;
+ case VIO_mmio_completion:
+ case VIO_realmode_completion:
+ BUILD_BUG_ON(sizeof(hvio->mmio_insn) <
sizeof(hvmemul_ctxt->insn_buf));
+ hvio->mmio_insn_bytes = hvmemul_ctxt->insn_buf_bytes;
+ memcpy(hvio->mmio_insn, hvmemul_ctxt->insn_buf,
hvio->mmio_insn_bytes);
+ break;
- default:
- ASSERT_UNREACHABLE();
- return X86EMUL_UNHANDLEABLE;
+ default:
+ ASSERT_UNREACHABLE();
+ return X86EMUL_UNHANDLEABLE;
+ }
}
+ complete_insn:
+
if ( hvmemul_ctxt->ctxt.retire.singlestep )
hvm_inject_hw_exception(X86_EXC_DB, X86_EVENT_NO_EC);
diff --git a/xen/arch/x86/include/asm/hvm/emulate.h
b/xen/arch/x86/include/asm/hvm/emulate.h
index 084e2bd90588..1e626f8af8f2 100644
--- a/xen/arch/x86/include/asm/hvm/emulate.h
+++ b/xen/arch/x86/include/asm/hvm/emulate.h
@@ -53,6 +53,9 @@ struct hvm_emulate_ctxt {
bool is_mem_access;
bool set_context;
+
+ unsigned int insn;
+ unsigned int insn_len;
};
enum emul_kind {
--
2.53.0
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |