On Sat, Sep 12, 2026 at 11:44 PM Tina Zhang <[email protected]> wrote:
>
> When the x86 emulator encounters an instruction intercepted by L1,
> svm_check_intercept() synthesizes a nested VM-Exit without fresh hardware
> DecodeAssist state.  Populate the architectural EXITINFO1 field when
> DecodeAssists is exposed to L1.
>
> Provide the GPR number for MOV CR/DR, the interrupt vector for INTn, and
> the linear address for INVLPG.  Leave EXITINFO1 clear for CLTS, LMSW,
> SMSW, selective CR0 writes, and INVLPGA; the INVLPGA address remains in
> guest rAX.  Leave EXITINFO1 unchanged when DecodeAssists is not exposed,
> and leave unrelated intercepts unchanged.
>
> Signed-off-by: Tina Zhang <[email protected]>
> ---
>  arch/x86/kvm/svm/svm.c | 32 +++++++++++++++++++++++++++++++-
>  1 file changed, 31 insertions(+), 1 deletion(-)
>
> diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
> index ea647938a2a6..6834e1101bb6 100644
> --- a/arch/x86/kvm/svm/svm.c
> +++ b/arch/x86/kvm/svm/svm.c
> @@ -4837,6 +4837,7 @@ static int svm_check_intercept(struct kvm_vcpu *vcpu,
>         int vmexit, ret = X86EMUL_CONTINUE;
>         struct __x86_intercept icpt_info;
>         struct vmcb *vmcb = svm->vmcb;
> +       bool decode_assists;
>
>         if (info->intercept >= ARRAY_SIZE(x86_intercept_map))
>                 goto out;
> @@ -4846,14 +4847,26 @@ static int svm_check_intercept(struct kvm_vcpu *vcpu,
>         if (stage != icpt_info.stage)
>                 goto out;
>
> +       decode_assists = guest_cpu_cap_has(vcpu, X86_FEATURE_DECODEASSISTS);
> +
>         switch (icpt_info.exit_code) {
>         case SVM_EXIT_READ_CR0:
>                 if (info->intercept == x86_intercept_cr_read)
>                         icpt_info.exit_code += info->modrm_reg;
> +
> +               if (decode_assists)
> +                       vmcb->control.exit_info_1 =
> +                               info->intercept == x86_intercept_cr_read ?
> +                               BIT_ULL(63) | (info->modrm_rm & 0xf) : 0;

Nit: CR_VALID | (info->modrm_rm & SVM_EXITINFO_REG_MASK)

>                 break;
>         case SVM_EXIT_WRITE_CR0: {
>                 unsigned long cr0, val;
>
> +               if (decode_assists)
> +                       vmcb->control.exit_info_1 =
> +                               info->intercept == x86_intercept_cr_write ?
> +                               BIT_ULL(63) | (info->modrm_rm & 0xf) : 0;

Same nit.

> +
>                 /*
>                  * Adjust the exit code accordingly if a CR other than CR0 is
>                  * being written, and skip straight to the common handling as
> @@ -4891,13 +4904,30 @@ static int svm_check_intercept(struct kvm_vcpu *vcpu,
>                  */
>                 cr0 = vcpu->arch.cr0 & ~SVM_CR0_SELECTIVE_MASK;
>                 val = info->src_val  & ~SVM_CR0_SELECTIVE_MASK;
> -               if (cr0 ^ val)
> +               if (cr0 ^ val) {
>                         icpt_info.exit_code = SVM_EXIT_CR0_SEL_WRITE;
> +                       if (decode_assists)
> +                               vmcb->control.exit_info_1 = 0;
> +               }

I don't think clearing EXITINFO1 here is correct. The APM says:

> MOV-to-CR0 Special Case. If the instruction is MOV-to-CR, the GPR number is 
> provided. If the instruction is LMSW or CLTS, no additional information is 
> provided and bit 63 is not set.

The Decode Assists depend on the instruction opcode, not on the intercept.

>                 break;
>         }
>         case SVM_EXIT_READ_DR0:
>         case SVM_EXIT_WRITE_DR0:
>                 icpt_info.exit_code += info->modrm_reg;
> +               if (decode_assists)
> +                       vmcb->control.exit_info_1 = info->modrm_rm & 0xf;

Nit: SVM_EXITINFO_REG_MASK

> +               break;
> +       case SVM_EXIT_SWINT:
> +               if (decode_assists)
> +                       vmcb->control.exit_info_1 = info->src_val & 0xff;
> +               break;
> +       case SVM_EXIT_INVLPG:
> +               if (decode_assists)
> +                       vmcb->control.exit_info_1 = info->invlpg_linear_addr;
> +               break;
> +       case SVM_EXIT_INVLPGA:
> +               if (decode_assists)
> +                       vmcb->control.exit_info_1 = 0;
>                 break;
>         case SVM_EXIT_MSR:
>                 if (info->intercept == x86_intercept_wrmsr)
> --
> 2.43.7
>

Reply via email to