@@ -283,6 +283,9 @@ static u64 read_sanitised_id_aa64pfr0_el1(struct kvm_vcpu *vcpu,
val &= ~ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_AMU);
+ if (!system_supports_sve())
+ val &= ~ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_SVE);
+
return val;
}
@@ -291,6 +294,22 @@ static int set_id_aa64pfr0_el1(struct kvm_vcpu *vcpu,
u64 val)
{
u8 csv2, csv3;
+ int fp, simd;
+ bool has_sve = id_aa64pfr0_sve(val);
+
+ simd = cpuid_feature_extract_signed_field(val, ID_AA64PFR0_EL1_AdvSIMD_SHIFT);
+ fp = cpuid_feature_extract_signed_field(val, ID_AA64PFR0_EL1_FP_SHIFT);
+ /* AdvSIMD field must have the same value as FP field */
+ if (simd != fp)
+ return -EINVAL;
+
+ /* fp must be supported when sve is supported */
+ if (has_sve && (fp < 0))
+ return -EINVAL;
+
+ /* Check if there is a conflict with a request via KVM_ARM_VCPU_INIT */
+ if (vcpu_has_sve(vcpu) ^ has_sve)
+ return -EPERM;
/*
* Allow AA64PFR0_EL1.CSV2 to be set from userspace as long as
@@ -582,7 +601,7 @@ const struct sys_reg_desc id_reg_descs[KVM_ARM_ID_REG_NUM] = {
.get_user = get_id_reg,
.set_user = set_id_aa64pfr0_el1,
.reset = read_sanitised_id_aa64pfr0_el1,
- .val = ID_AA64PFR0_EL1_CSV2_MASK | ID_AA64PFR0_EL1_CSV3_MASK, },
+ .val = GENMASK(63, 0), },
ID_SANITISED(ID_AA64PFR1_EL1),
ID_UNALLOCATED(4, 2),
ID_UNALLOCATED(4, 3),
Return an error if userspace tries to set SVE field of the register to a value that conflicts with SVE configuration for the guest. SIMD/FP/SVE fields of the requested value are validated according to Arm ARM. Signed-off-by: Jing Zhang <jingzhangos@google.com> --- arch/arm64/kvm/id_regs.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-)