On Mon, Aug 24, 2026 at 5:40 AM Tina Zhang <[email protected]> wrote:
>
> DecodeAssists provides instruction bytes for nested page faults and
> intercepted page faults caused by data accesses. When the feature is
> exposed to L1, copy fresh hardware-provided instruction bytes from VMCB02
> to VMCB12 for these exits.
>
> Clear the VMCB12 instruction-byte state before rebuilding it, and leave the
> length zero for instruction-fetch page faults, unrelated exits, and exits
> without fresh hardware bytes.
>
> Signed-off-by: Tina Zhang <[email protected]>
> ---
> arch/x86/kvm/svm/nested.c | 35 +++++++++++++++++++++++++++++++++++
> 1 file changed, 35 insertions(+)
>
> diff --git a/arch/x86/kvm/svm/nested.c b/arch/x86/kvm/svm/nested.c
> index 6770721d4e4c..2db0ec66e8dc 100644
> --- a/arch/x86/kvm/svm/nested.c
> +++ b/arch/x86/kvm/svm/nested.c
> @@ -42,6 +42,20 @@ static void nested_svm_clear_insn_bytes(struct vmcb *vmcb)
> sizeof(vmcb->control.insn_bytes));
> }
>
> +static void nested_svm_copy_insn_bytes(struct vmcb *to,
> + const struct vmcb *from)
> +{
> + u8 insn_len = from->control.insn_len;
> +
> + nested_svm_clear_insn_bytes(to);
It's not obvious to me that this clearing is necessary (except in the
case of the early return below). The APM does not say what happens to
the remaining bytes if there is a short read.
> + if (WARN_ON_ONCE(insn_len > sizeof(from->control.insn_bytes)))
> + return;
> +
> + to->control.insn_len = insn_len;
> + memcpy(to->control.insn_bytes, from->control.insn_bytes, insn_len);
> +}
> static bool nested_svm_vmexit_has_insn_bytes(const struct vmcb *vmcb)
> {
> u64 exit_code = vmcb->control.exit_code;
> @@ -67,6 +81,25 @@ static void nested_svm_clear_vmcb02_insn_bytes(struct
> vcpu_svm *svm)
> svm->nested.vmcb02_insn_bytes_fresh = false;
> }
>
> +static void nested_svm_update_vmcb12_insn_bytes(struct kvm_vcpu *vcpu,
> + struct vmcb *vmcb12,
> + const struct vmcb *vmcb02)
> +{
> + struct vcpu_svm *svm = to_svm(vcpu);
> +
> + nested_svm_clear_insn_bytes(vmcb12);
Clearing here is premature. If L1 does not have
X86_FEATURE_DECODEASSISTS, the "Guest Instruction Bytes" fields of
vmcs12 should not be touched.
Moreover, as I pointed out earlier, if L1 has
X86_FEATURE_DECODEASSISTS, and the VM-exit doesn't have instruction
bytes, you onlyhave to clear bits 7:0.
> + if (!guest_cpu_cap_has(vcpu, X86_FEATURE_DECODEASSISTS) ||
> + !nested_svm_vmexit_has_insn_bytes(vmcb02))
> + goto out;
> +
> + if (svm->nested.vmcb02_insn_bytes_fresh)
> + nested_svm_copy_insn_bytes(vmcb12, vmcb02);
> +
> +out:
> + svm->nested.vmcb02_insn_bytes_fresh = false;
> +}
> +
> static void nested_svm_inject_npf_exit(struct kvm_vcpu *vcpu,
> struct x86_exception *fault,
> bool from_hardware)
> @@ -1332,6 +1365,8 @@ static int nested_svm_vmexit_update_vmcb12(struct
> kvm_vcpu *vcpu)
> if (guest_cpu_cap_has(vcpu, X86_FEATURE_NRIPS))
> vmcb12->control.next_rip = vmcb02->control.next_rip;
>
> + nested_svm_update_vmcb12_insn_bytes(vcpu, vmcb12, vmcb02);
> +
> if (nested_vmcb12_has_lbrv(vcpu))
> svm_copy_lbrs(&vmcb12->save, &vmcb02->save);
>
> --
> 2.43.7
>