On Mon, Aug 24, 2026 at 5:40 AM Tina Zhang <[email protected]> wrote:
>
> Add get_intercept_linear_addr() to compute the linear address for
> intercepts that report one, and pass the result through
> x86_instruction_info.
>
> Handle INVLPG as the initial user.  INVLPG's memory operand is decoded
> with NoAccess, and thus src_val does not contain the operand address.
> Compute the address from the decoded segment base and effective address
> in the emulator, where the operand state is available.
>
> This allows intercept handlers to use the linear address directly
> without duplicating the emulator's address calculation.
>
> Signed-off-by: Tina Zhang <[email protected]>
> ---
>  arch/x86/kvm/emulate.c     | 29 +++++++++++++++++++++--------
>  arch/x86/kvm/kvm_emulate.h |  1 +
>  2 files changed, 22 insertions(+), 8 deletions(-)
>
> diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
> index 8071b372d233..a0e57b64cadd 100644
> --- a/arch/x86/kvm/emulate.c
> +++ b/arch/x86/kvm/emulate.c
> @@ -410,6 +410,26 @@ static int em_salc(struct x86_emulate_ctxt *ctxt)
>         _fault ? X86EMUL_UNHANDLEABLE : X86EMUL_CONTINUE; \
>  })
>
> +static unsigned long seg_base(struct x86_emulate_ctxt *ctxt, int seg)
> +{
> +       if (ctxt->mode == X86EMUL_MODE_PROT64 && seg < VCPU_SREG_FS)
> +               return 0;
> +
> +       return ctxt->ops->get_cached_segment_base(ctxt, seg);
> +}
> +
> +static u64 get_intercept_linear_addr(struct x86_emulate_ctxt *ctxt,
> +                                    enum x86_intercept intercept)
> +{
> +       u64 la;
> +
> +       if (intercept != x86_intercept_invlpg)
> +               return 0;
> +
> +       la = seg_base(ctxt, ctxt->src.addr.mem.seg) + ctxt->src.addr.mem.ea;
> +       return ctxt->mode == X86EMUL_MODE_PROT64 ? la : (u32)la;
> +}

The linear address calculation here is replicated from __linearize().
Perhaps something like:

static u64 get_invlpg_linear_addr(struct x86_emulate_ctxt *ctxt)
{
        unsigned int max_size;
        ulong linear;

        if (intercept != x86_intercept_invlpg)
                return 0;

        __linearize(ctxt, ctxt->src.addr.mem, &max_size, 1,
ctxt->mode, &linear, X86EMUL_F_INVLPG);
        return linear;
}



>  static int emulator_check_intercept(struct x86_emulate_ctxt *ctxt,
>                                     enum x86_intercept intercept,
>                                     enum x86_intercept_stage stage)
> @@ -427,6 +447,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,
> +               .intercept_linear_addr = get_intercept_linear_addr(ctxt, 
> intercept),

Maybe:
+               .invlpg_linear_addr = get_invlpg_linear_addr(ctxt, intercept),

>                 .rip        = ctxt->eip,
>                 .next_rip   = ctxt->_eip,
>         };
> @@ -520,14 +541,6 @@ static u32 desc_limit_scaled(struct desc_struct *desc)
>         return desc->g ? (limit << 12) | 0xfff : limit;
>  }
>
> -static unsigned long seg_base(struct x86_emulate_ctxt *ctxt, int seg)
> -{
> -       if (ctxt->mode == X86EMUL_MODE_PROT64 && seg < VCPU_SREG_FS)
> -               return 0;
> -
> -       return ctxt->ops->get_cached_segment_base(ctxt, seg);
> -}
> -
>  static int emulate_exception(struct x86_emulate_ctxt *ctxt, int vec,
>                              u32 error, bool valid)
>  {
> diff --git a/arch/x86/kvm/kvm_emulate.h b/arch/x86/kvm/kvm_emulate.h
> index 3e375af15c03..9eda648a1314 100644
> --- a/arch/x86/kvm/kvm_emulate.h
> +++ b/arch/x86/kvm/kvm_emulate.h
> @@ -51,6 +51,7 @@ struct x86_instruction_info {
>         u8  src_type;           /* type of source operand               */
>         u8  dst_type;           /* type of destination operand          */
>         u8  ad_bytes;           /* size of src/dst address              */
> +       u64 intercept_linear_addr;      /* arch-reported linear address, if 
> any */

+       u64 invlpg_linear_addr;      /* linear address, if invlpg */

>         u64 rip;                /* rip of the instruction               */
>         u64 next_rip;           /* rip following the instruction        */
>  };
>
> base-commit: 1b731e5ded480bd1e5546aed35584238661ce72e
> --
> 2.43.7
>

I don't really like special-casing INVLPG, but I don't see an easy alternative.

Reply via email to