Merge branch kvm-arm64/nv-fp-elision into kvmarm-master/next

* kvm-arm64/nv-fp-elision:
  : .
  : Significantly reduce the overhead of the context switch between L1 and
  : L2 guests by eliding the save/restore of the FP/SIMD/SVE registers, as
  : this state is shared between the two guests, and therefore can be left
  : live.
  : .
  KVM: arm64: nv: Don't save/restore FP register during a nested ERET or exception
  KVM: arm64: nv: Track L2 to L1 exception emulation

Signed-off-by: Marc Zyngier <maz@kernel.org>
This commit is contained in:
Marc Zyngier 2026-06-12 09:03:57 +01:00
commit d1f0ed520b
3 changed files with 32 additions and 1 deletions

View File

@ -1112,7 +1112,8 @@ struct kvm_vcpu_arch {
#define IN_NESTED_ERET __vcpu_single_flag(sflags, BIT(7))
/* SError pending for nested guest */
#define NESTED_SERROR_PENDING __vcpu_single_flag(sflags, BIT(8))
/* KVM is currently emulating an L2 to L1 exception */
#define IN_NESTED_EXCEPTION __vcpu_single_flag(sflags, BIT(9))
/* Pointer to the vcpu's SVE FFR for sve_{save,load}_state() */
#define vcpu_sve_pffr(vcpu) (kern_hyp_va((vcpu)->arch.sve_state) + \

View File

@ -2862,6 +2862,8 @@ static int kvm_inject_nested(struct kvm_vcpu *vcpu, u64 esr_el2,
preempt_disable();
vcpu_set_flag(vcpu, IN_NESTED_EXCEPTION);
/*
* We may have an exception or PC update in the EL0/EL1 context.
* Commit it before entering EL2.
@ -2884,6 +2886,8 @@ static int kvm_inject_nested(struct kvm_vcpu *vcpu, u64 esr_el2,
__kvm_adjust_pc(vcpu);
kvm_arch_vcpu_load(vcpu, smp_processor_id());
vcpu_clear_flag(vcpu, IN_NESTED_EXCEPTION);
preempt_enable();
if (kvm_vcpu_has_pmu(vcpu))

View File

@ -28,6 +28,20 @@ void kvm_arch_vcpu_load_fp(struct kvm_vcpu *vcpu)
if (!system_supports_fpsimd())
return;
/*
* Avoid needless save/restore of the guest's common
* FPSIMD/SVE/SME regs during transitions between L1/L2.
*
* These transitions only happens in a non-preemptible context
* where the host regs have already been saved and unbound. The
* live registers are either free or owned by the guest.
*/
if (vcpu_get_flag(vcpu, IN_NESTED_ERET) ||
vcpu_get_flag(vcpu, IN_NESTED_EXCEPTION)) {
WARN_ON_ONCE(host_owns_fp_regs());
return;
}
/*
* Ensure that any host FPSIMD/SVE/SME state is saved and unbound such
* that the host kernel is responsible for restoring this state upon
@ -102,6 +116,18 @@ void kvm_arch_vcpu_put_fp(struct kvm_vcpu *vcpu)
{
unsigned long flags;
/*
* See comment in kvm_arch_vcpu_load_fp(). Note that we also rely on
* the guest's max VL to have been set by fpsimd_lazy_switch_to_host()
* so that any intervening kernel-mode SIMD (NEON or otherwise)
* operation sees the full guest state that needs saving.
*/
if (vcpu_get_flag(vcpu, IN_NESTED_ERET) ||
vcpu_get_flag(vcpu, IN_NESTED_EXCEPTION)) {
WARN_ON_ONCE(host_owns_fp_regs());
return;
}
local_irq_save(flags);
if (guest_owns_fp_regs()) {