Subject: Re: [PATCH v10 17/30] KVM: arm64: Support SME identification registers for guests

From: Jean-Philippe Brucker <[email-masked]>
Date: Wed, 18 Mar 2026 17:27:48 +0000

On Fri, Mar 06, 2026 at 05:01:09PM +0000, Mark Brown wrote:
> The primary register for identifying SME is ID_AA64PFR1_EL1.SME.  This
> is hidden from guests unless SME is enabled by the VMM.
> When it is visible it is writable and can be used to control the
> availability of SME2.
> 
> There is also a new register ID_AA64SMFR0_EL1 which we make writable,
> forcing it to all bits 0 if SME is disabled.  This includes the field
> SMEver giving the SME version, userspace is responsible for ensuring
> the value is consistent with ID_AA64PFR1_EL1.SME.  It also includes
> FA64, a separately enableable extension which provides the full FPSIMD
> and SVE instruction set including FFR in streaming mode.  Userspace can
> control the availability of FA64 by writing to this field.  The other
> features enumerated there only add new instructions, there are no
> architectural controls for these.
> 
> There is a further identification register SMIDR_EL1 which provides a
> basic description of the SME microarchitecture, in a manner similar to
> MIDR_EL1 for the PE.  It also describes support for priority management
> and a basic affinity description for shared SME units, plus some RES0
> space.  We do not support priority management for guests so this is
> hidden from guests, along with any new fields.
> 
> As for MIDR_EL1 and REVIDR_EL1 we expose the implementer and revision
> information to guests with the raw value from the CPU we are running on,
> this may present issues for asymmetric systems or for migration as it
> does for the existing registers.
> 
> Signed-off-by: Mark Brown <[email-masked]>
...
> +#define IMPLEMENTATION_ID_FILTERED(reg, mask, reg_visibility) {	\
> +	SYS_DESC(SYS_##reg),				\
> +	.access = access_imp_id_reg,			\
> +	.get_user = get_id_reg,				\
> +	.set_user = set_imp_id_reg,			\
> +	.reset = reset_imp_id_reg,			\
> +	.visibility = reg_visibility,				\

nit: rogue backslash

> +	.val = mask,					\
> +	}
> +
>  static u64 reset_mdcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
>  {
>  	__vcpu_assign_sys_reg(vcpu, r->reg, vcpu->kvm->arch.nr_pmu_counters);
> @@ -3238,7 +3280,6 @@ static const struct sys_reg_desc sys_reg_descs[] = {
>  				       ID_AA64PFR1_EL1_MTE_frac |
>  				       ID_AA64PFR1_EL1_NMI |
>  				       ID_AA64PFR1_EL1_RNDR_trap |
> -				       ID_AA64PFR1_EL1_SME |
>  				       ID_AA64PFR1_EL1_RES0 |
>  				       ID_AA64PFR1_EL1_MPAM_frac |
>  				       ID_AA64PFR1_EL1_MTE)),
> @@ -3248,7 +3289,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
>  		    ID_AA64PFR2_EL1_MTESTOREONLY),
>  	ID_UNALLOCATED(4,3),
>  	ID_WRITABLE(ID_AA64ZFR0_EL1, ~ID_AA64ZFR0_EL1_RES0),
> -	ID_HIDDEN(ID_AA64SMFR0_EL1),
> +	ID_WRITABLE(ID_AA64SMFR0_EL1, ~ID_AA64SMFR0_EL1_RES0),
>  	ID_UNALLOCATED(4,6),
>  	ID_WRITABLE(ID_AA64FPFR0_EL1, ~ID_AA64FPFR0_EL1_RES0),
>  
> @@ -3454,6 +3495,13 @@ static const struct sys_reg_desc sys_reg_descs[] = {
>  	{ SYS_DESC(SYS_CCSIDR_EL1), access_ccsidr },
>  	{ SYS_DESC(SYS_CLIDR_EL1), access_clidr, reset_clidr, CLIDR_EL1,
>  	  .set_user = set_clidr, .val = ~CLIDR_EL1_RES0 },
> +	IMPLEMENTATION_ID_FILTERED(SMIDR_EL1,
> +				   (SMIDR_EL1_NSMC | SMIDR_EL1_HIP |
> +				    SMIDR_EL1_AFFINITY2 |
> +				    SMIDR_EL1_IMPLEMENTER |
> +				    SMIDR_EL1_REVISION | SMIDR_EL1_SH |
> +				    SMIDR_EL1_AFFINITY),
> +				   sme_visibility),

Shouldn't we sanitize the SMIDR value obtained in reset_imp_id_reg() and
add SMPS to this mask, if we're hiding everything from the guest?

Thanks,
Jean

>  	IMPLEMENTATION_ID(AIDR_EL1, GENMASK_ULL(63, 0)),
>  	{ SYS_DESC(SYS_CSSELR_EL1), access_csselr, reset_unknown, CSSELR_EL1 },
>  	ID_FILTERED(CTR_EL0, ctr_el0,
> 
> -- 
> 2.47.3
> 
>