[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[RFC v1 4/7] x86/hvm: Support a fast path during emulation


  • To: xen-devel@xxxxxxxxxxxxxxxxxxxx
  • From: Ross Lagerwall <ross.lagerwall@xxxxxxxxxx>
  • Date: Mon, 18 May 2026 14:14:01 +0100
  • Arc-authentication-results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=citrix.com; dmarc=pass action=none header.from=citrix.com; dkim=pass header.d=citrix.com; arc=none
  • Arc-message-signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=E01jp2Z6iewjF/MH52l40+JkT5jeEYpzfDYIumrs0IU=; b=GmPxPmJYcPiUyvgSKXypjGxedEU1SZdONU3G4BAKk1GPaHRzIf136TGiYJYM8Edn9Sf3RZLe3/qR/+Yuvj0QdpPPsCouz6ivFaokujG9Eg7i/haZYqPhX2xS5N131GTupEh8w1lLWz6bqyu3aw6FfZ6cfnalTuzKEXb2mARyxNpeHenFNA1/rmggHDglL1ujQ6z2jIWMa52YJIrP4rkFsesB4KYaSsmoF4gQ2mjWUu3D1TfsC0Q8UDBm8c4uXP59QJZ4OHBwJ+/1fQQW1HoNd+xmZ6JRVX5cpi6qx7QcYtuj+r+Zxkd8bKh7c9H9LehS0W3Ce2dchXSZ4Yza1F3+dA==
  • Arc-seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=GuZlb7uKpvo9maczxH5N2NRCmDsTD9umaTmUdvS5IkGAFvhCQekVHSkTnsCcGuXGUF7380MpWvtVyprRSq/YRP/03NCOFmoSFc1hQ3YNYYCApnGOFQxyOCu9j8QReHyJjNOXPtgl9ygm3yMSgbbKGf3h+0bV+vee1jgqUVemoIiOCfotAFpn4nfbIMadR8oc/vFsp7LQGrU6XxcNRwySkZT6uPWh1FSpx3NBayikA9pfGprJmQa5GFWtsBiSE6t/6MtfOzbKd9iE8huHKhFtGdSNaD55/rlUjjUkozizHhyS/8+CPCqQQI6dNlVeUfvPyI4vv6Yvlf9KU8x/pkM3vQ==
  • Authentication-results: eu.smtp.expurgate.cloud; dkim=pass header.s=selector1 header.d=citrix.com header.i="@citrix.com" header.h="From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck"
  • Authentication-results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=citrix.com;
  • Cc: Ross Lagerwall <ross.lagerwall@xxxxxxxxxx>, Jan Beulich <jbeulich@xxxxxxxx>, Andrew Cooper <andrew.cooper3@xxxxxxxxxx>, Roger Pau Monné <roger.pau@xxxxxxxxxx>, Teddy Astie <teddy.astie@xxxxxxxxxx>
  • Delivery-date: Mon, 18 May 2026 13:14:33 +0000
  • List-id: Xen developer discussion <xen-devel.lists.xenproject.org>

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




 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.