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