[RFC PATCH v7 14/28] KVM: arm64: Add SPE VCPU device attribute to initialize SPE
Lorenzo Stoakes (ARM)
ljs at kernel.org
Thu Oct 29 11:03:09 PDT 2026
On Thu, Sep 03, 2026 at 05:06:09PM +0100, Alexandru Elisei wrote:
> diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
> index 8ffa3e89d38c..c695aae484d3 100644
> --- a/arch/arm64/include/uapi/asm/kvm.h
> +++ b/arch/arm64/include/uapi/asm/kvm.h
> @@ -449,6 +449,7 @@ enum {
> #define KVM_ARM_VCPU_SPE_CTRL 3
> #define KVM_ARM_VCPU_SPE_IRQ 0
> #define KVM_ARM_VCPU_SPE_ID 1
> +#define KVM_ARM_VCPU_SPE_INIT 2
>
> /* KVM_IRQ_LINE irq field index values */
> #define KVM_ARM_IRQ_VCPU2_SHIFT 28
> diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
> index 132df44c3088..c9a026c61ce7 100644
> --- a/arch/arm64/kvm/arm.c
> +++ b/arch/arm64/kvm/arm.c
> @@ -1026,6 +1026,12 @@ int kvm_arch_vcpu_run_pid_change(struct kvm_vcpu *vcpu)
> return ret;
> }
>
> + if (vcpu_has_spe(vcpu)) {
> + ret = kvm_spe_vcpu_first_run_init(vcpu);
> + if (ret)
> + return ret;
> + }
> +
So, staring at patch 18 made me think about ordering again, which seems to be
_super_ sensitive in KVM :)
The next patch in the series (15) makes PMSVer depend on the SPE instance having
been assigned via KVM_ARM_VCPU_SPE_ID.
But you can still KVM_RUN before KVM_ARM_VCPU_SPE_INIT, which means this will
return -EINVAL:
int kvm_spe_vcpu_first_run_init(struct kvm_vcpu *vcpu)
{
...
if (!kvm_vcpu_spe_initialized(vcpu))
return -EINVAL;
...
}
And this is quite far down the function:
int kvm_arch_vcpu_run_pid_change(struct kvm_vcpu *vcpu)
{
struct kvm *kvm = vcpu->kvm;
int ret;
if (!kvm_vcpu_initialized(vcpu))
return -ENOEXEC;
if (!kvm_arm_vcpu_is_finalized(vcpu))
return -EPERM;
if (likely(vcpu_has_run_once(vcpu)))
return 0;
...
ret = kvm_vcpu_finalize_sys_regs(vcpu);
if (ret)
return ret;
...
/*
* This needs to happen after any restriction has been applied
* to the feature set.
*/
kvm_calculate_traps(vcpu);
...
if (vcpu_has_spe(vcpu)) {
ret = kvm_spe_vcpu_first_run_init(vcpu);
if (ret)
return ret;
}
...
}
patch 18 made me think of this as kvm_calculate_traps() does the FGU
initialisation (which derives from SPE state), and once done sets
KVM_ARCH_FLAG_FGU_INITIALIZED, meaning this state is incorrectly setup.
This is a real problem as HAS_RAN_ONCE isn't set on that failed path,
userland can finish the SPE setup, set KVM_ARCH_FLAG_FGU_INITIALIZED, and
that state is never recomputed.
Also kvm_vcpu_finalize_sys_regs() calls kvm_spe_finalize_idregs() (via
kvm_vm_finalize_sys_regs()) which writes PMSVer in the first place.
So it seems you should put this check _before_ these, e.g.:
int kvm_arch_vcpu_run_pid_change(struct kvm_vcpu *vcpu)
{
struct kvm *kvm = vcpu->kvm;
int ret;
if (!kvm_vcpu_initialized(vcpu))
return -ENOEXEC;
if (!kvm_arm_vcpu_is_finalized(vcpu))
return -EPERM;
if (likely(vcpu_has_run_once(vcpu)))
return 0;
...
>>>>
if (vcpu_has_spe(vcpu)) {
ret = kvm_spe_vcpu_first_run_init(vcpu);
if (ret)
return ret;
}
>>>
ret = kvm_vcpu_finalize_sys_regs(vcpu);
if (ret)
return ret;
...
/*
* This needs to happen after any restriction has been applied
* to the feature set.
*/
kvm_calculate_traps(vcpu);
...
}
--
Cheers, Lorenzo
More information about the linux-arm-kernel
mailing list