@@ -472,6 +472,7 @@ enum vcpu_sysreg {
/* FP/SIMD/SVE */
SVCR,
FPMR,
+ SMIDR_EL1, /* Streaming Mode Identification Register */
/* 32bit specific registers. */
DACR32_EL2, /* Domain Access Control Register */
@@ -882,6 +882,39 @@ static u64 reset_mpidr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
return mpidr;
}
+static u64 reset_smidr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
+{
+ u64 smidr = 0;
+
+ if (!system_supports_sme())
+ return smidr;
+
+ smidr = read_sysreg_s(SYS_SMIDR_EL1);
+
+ /*
+ * Mask out any priority or affinity information, or fields we
+ * don't know about.
+ */
+ smidr &= ~(SMIDR_EL1_SMPS_MASK | SMIDR_EL1_AFFINITY_MASK |
+ SMIDR_EL1_RES0);
+
+ vcpu_write_sys_reg(vcpu, smidr, SMIDR_EL1);
+
+ return smidr;
+}
+
+static bool access_smidr(struct kvm_vcpu *vcpu,
+ struct sys_reg_params *p,
+ const struct sys_reg_desc *r)
+{
+ if (p->is_write)
+ return write_to_read_only(vcpu, p, r);
+
+ p->regval = vcpu_read_sys_reg(vcpu, r->reg);
+
+ return true;
+}
+
static unsigned int pmu_visibility(const struct kvm_vcpu *vcpu,
const struct sys_reg_desc *r)
{
@@ -1576,7 +1609,9 @@ static u64 __kvm_read_sanitised_id_reg(const struct kvm_vcpu *vcpu,
if (!kvm_has_mte(vcpu->kvm))
val &= ~ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_MTE);
- val &= ~ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_SME);
+ if (!vcpu_has_sme(vcpu))
+ val &= ~ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_SME);
+
val &= ~ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_RNDR_trap);
val &= ~ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_NMI);
val &= ~ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_MTE_frac);
@@ -1676,6 +1711,10 @@ static unsigned int id_visibility(const struct kvm_vcpu *vcpu,
if (!vcpu_has_sve(vcpu))
return REG_RAZ;
break;
+ case SYS_ID_AA64SMFR0_EL1:
+ if (!vcpu_has_sme(vcpu))
+ return REG_RAZ;
+ break;
}
return 0;
@@ -2601,7 +2640,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
ID_WRITABLE(ID_AA64PFR2_EL1, ID_AA64PFR2_EL1_FPMR),
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),
@@ -2799,7 +2838,8 @@ static const struct sys_reg_desc sys_reg_descs[] = {
{ SYS_DESC(SYS_CLIDR_EL1), access_clidr, reset_clidr, CLIDR_EL1,
.set_user = set_clidr, .val = ~CLIDR_EL1_RES0 },
{ SYS_DESC(SYS_CCSIDR2_EL1), undef_access },
- { SYS_DESC(SYS_SMIDR_EL1), undef_access },
+ { SYS_DESC(SYS_SMIDR_EL1), .access = access_smidr, .reset = reset_smidr,
+ .reg = SMIDR_EL1, .visibility = sme_visibility },
{ SYS_DESC(SYS_CSSELR_EL1), access_csselr, reset_unknown, CSSELR_EL1 },
ID_FILTERED(CTR_EL0, ctr_el0,
CTR_EL0_DIC_MASK |
SME adds an identification register SMIDR_EL1 which provides a basic description of the SME implementation, describing the implementation in a manner similar to MIDR_EL1 for the PE as well as indicating support for priority management. Since we do not currently support SME priority control we mask out SMPS, indicating that priority management is not supported. We do the same for Affinity, indicating that there is no physical sharing, and unknown 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 <broonie@kernel.org> --- arch/arm64/include/asm/kvm_host.h | 1 + arch/arm64/kvm/sys_regs.c | 46 ++++++++++++++++++++++++++++++++++++--- 2 files changed, 44 insertions(+), 3 deletions(-)