Re: [PATCH v3 5/8] KVM: nSVM: Always use NextRIP as vmcb02's NextRIP after first L2 VMRUN

From: Yosry Ahmed

Date: Wed Mar 04 2026 - 12:36:53 EST


On Tue, Feb 24, 2026 at 5:00 PM Yosry Ahmed <yosry@xxxxxxxxxx> wrote:
>
> For guests with NRIPS disabled, L1 does not provide NextRIP when running
> an L2 with an injected soft interrupt, instead it advances the current RIP
> before running it. KVM uses the current RIP as the NextRIP in vmcb02 to
> emulate a CPU without NRIPS.
>
> However, after L2 runs the first time, NextRIP will be updated by the
> CPU and/or KVM, and the current RIP is no longer the correct value to
> use in vmcb02. Hence, after save/restore, use the current RIP if and
> only if a nested run is pending, otherwise use NextRIP.
>
> Fixes: cc440cdad5b7 ("KVM: nSVM: implement KVM_GET_NESTED_STATE and KVM_SET_NESTED_STATE")
> CC: stable@xxxxxxxxxxxxxxx
> Signed-off-by: Yosry Ahmed <yosry@xxxxxxxxxx>
> ---
> arch/x86/kvm/svm/nested.c | 25 ++++++++++++++++---------
> 1 file changed, 16 insertions(+), 9 deletions(-)
>
> diff --git a/arch/x86/kvm/svm/nested.c b/arch/x86/kvm/svm/nested.c
> index 9909ff237e5ca..f3ed1bdbe76c9 100644
> --- a/arch/x86/kvm/svm/nested.c
> +++ b/arch/x86/kvm/svm/nested.c
> @@ -845,17 +845,24 @@ static void nested_vmcb02_prepare_control(struct vcpu_svm *svm,
> vmcb02->control.event_inj_err = svm->nested.ctl.event_inj_err;
>
> /*
> - * next_rip is consumed on VMRUN as the return address pushed on the
> + * NextRIP is consumed on VMRUN as the return address pushed on the
> * stack for injected soft exceptions/interrupts. If nrips is exposed
> - * to L1, take it verbatim from vmcb12. If nrips is supported in
> - * hardware but not exposed to L1, stuff the actual L2 RIP to emulate
> - * what a nrips=0 CPU would do (L1 is responsible for advancing RIP
> - * prior to injecting the event).
> + * to L1, take it verbatim from vmcb12.
> + *
> + * If nrips is supported in hardware but not exposed to L1, stuff the
> + * actual L2 RIP to emulate what a nrips=0 CPU would do (L1 is
> + * responsible for advancing RIP prior to injecting the event). This is
> + * only the case for the first L2 run after VMRUN. After that (e.g.
> + * during save/restore), NextRIP is updated by the CPU and/or KVM, and
> + * the value of the L2 RIP from vmcb12 should not be used.
> */
> - if (guest_cpu_cap_has(vcpu, X86_FEATURE_NRIPS))
> - vmcb02->control.next_rip = svm->nested.ctl.next_rip;
> - else if (boot_cpu_has(X86_FEATURE_NRIPS))
> - vmcb02->control.next_rip = vmcb12_rip;
> + if (boot_cpu_has(X86_FEATURE_NRIPS)) {
> + if (guest_cpu_cap_has(vcpu, X86_FEATURE_NRIPS) ||
> + !svm->nested.nested_run_pending)
> + vmcb02->control.next_rip = svm->nested.ctl.next_rip;
> + else
> + vmcb02->control.next_rip = vmcb12_rip;
> + }

This should probably also apply to soft_int_next_rip below the context
lines. Otherwise after patch 7 we keep it uninitialized if the guest
doesn't have NRIPs and !nested_run_pending.

>
> svm->nmi_l1_to_l2 = is_evtinj_nmi(vmcb02->control.event_inj);
> if (is_evtinj_soft(vmcb02->control.event_inj)) {
> --
> 2.53.0.414.gf7e9f6c205-goog
>