On 9/15/2026 2:23 AM, Jim Mattson wrote:
On Sat, Sep 12, 2026 at 11:44 PM Tina Zhang <[email protected]> wrote:

INVLPG's memory operand is decoded with NoAccess, and thus src_val does
not contain the operand address.  Intercept handlers therefore cannot
construct exit state that reports the linear address from the existing
x86_instruction_info fields.

Add get_invlpg_linear_addr() to compute the address through __linearize(),
using the same flags as em_invlpg(), and pass the result through
x86_instruction_info.

Signed-off-by: Tina Zhang <[email protected]>
---
  arch/x86/kvm/emulate.c     | 18 ++++++++++++++++++
  arch/x86/kvm/kvm_emulate.h |  1 +
  2 files changed, 19 insertions(+)

diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index 8071b372d233..1dfece6af81e 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -410,6 +410,9 @@ static int em_salc(struct x86_emulate_ctxt *ctxt)
         _fault ? X86EMUL_UNHANDLEABLE : X86EMUL_CONTINUE; \
  })

+static u64 get_invlpg_linear_addr(struct x86_emulate_ctxt *ctxt,
+                                 enum x86_intercept intercept);
+
Nit: I would move __linearize() rather than add a forward declaration,
but maybe it all unravels if you pull on that thread.

  static int emulator_check_intercept(struct x86_emulate_ctxt *ctxt,
                                     enum x86_intercept intercept,
                                     enum x86_intercept_stage stage)
@@ -427,6 +430,7 @@ static int emulator_check_intercept(struct x86_emulate_ctxt 
*ctxt,
                 .src_type   = ctxt->src.type,
                 .dst_type   = ctxt->dst.type,
                 .ad_bytes   = ctxt->ad_bytes,
+               .invlpg_linear_addr = get_invlpg_linear_addr(ctxt, intercept),
                 .rip        = ctxt->eip,
                 .next_rip   = ctxt->_eip,
         };
@@ -702,6 +706,20 @@ static __always_inline int __linearize(struct 
x86_emulate_ctxt *ctxt,
                 return emulate_gp(ctxt, 0);
  }

+static u64 get_invlpg_linear_addr(struct x86_emulate_ctxt *ctxt,
+                                 enum x86_intercept intercept)
+{
+       unsigned int max_size;
+       unsigned long linear = 0;
+
+       if (intercept != x86_intercept_invlpg)
+               return 0;
+
+       __linearize(ctxt, ctxt->src.addr.mem, &max_size, 1, ctxt->mode,
+                   &linear, X86EMUL_F_INVLPG);

What if __linearize() fails?

This was also my concern with using __linearize() in v5, which is why I initially calculated the address directly. I wasn't sure how to handle its failures when we only need the address for EXITINFO1.

Simply propagating the error seems questionable, since em_invlpg() itself skips the invalidation on failure and returns X86EMUL_CONTINUE.

Would either of these approaches make sense?
Option 1: Factor the address calculation out into a helper shared by
__linearize() and get_invlpg_linear_addr(), leaving the checks in
__linearize().

Option 2: Extend the existing flags argument to __linearize() with an option to calculate the address without performing access checks.

Both would avoid duplicating the address calculation or modifying
ctxt->exception just to obtain the address for EXITINFO1.

Do you have a preference, or another approach in mind?

Thanks,
Tina



Reply via email to