On Fri, Sep 18, 2026 at 1:56 AM 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     | 23 +++++++++++++++++++++++
>  arch/x86/kvm/kvm_emulate.h |  1 +
>  2 files changed, 24 insertions(+)
>
> diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
> index c1b21282187f..2972a35b0ac0 100644
> --- a/arch/x86/kvm/emulate.c
> +++ b/arch/x86/kvm/emulate.c
> @@ -411,6 +411,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);
> +
>  static int emulator_check_intercept(struct x86_emulate_ctxt *ctxt,
>                                     enum x86_intercept intercept,
>                                     enum x86_intercept_stage stage)
> @@ -428,6 +431,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,
>         };
> @@ -684,6 +688,25 @@ 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;
> +
> +       /*
> +        * Use the same address calculation as em_invlpg() for the address
> +        * reported to L1.  Ignore address-check failures, as __linearize()
> +        * sets linear before reporting a failure.
> +        */

That comment misses the main point. Perhaps something like:

        /*
         * Ignore faults, just as em_invlpg() does. Calling __linearize()
         * exactly as em_invlpg() does guarantees agreement with
         * em_invlpg() on the linear address.
         */

> +       __linearize(ctxt, ctxt->src.addr.mem, &max_size, 1, ctxt->mode,
> +                   &linear, X86EMUL_F_INVLPG);
> +       return linear;
> +}
> +
>  static int linearize(struct x86_emulate_ctxt *ctxt,
>                      struct segmented_address addr,
>                      unsigned size, bool write,

Reply via email to