diff mbox series

[RFC,v3,03/16] KVM: arm64: Hide SPE from guests

Message ID 20201027172705.15181-4-alexandru.elisei@arm.com (mailing list archive)
State New, archived
Headers show
Series KVM: arm64: Add Statistical Profiling Extension (SPE) support | expand

Commit Message

Alexandru Elisei Oct. 27, 2020, 5:26 p.m. UTC
When SPE is not implemented, accesses to the SPE registers cause an
undefined exception. KVM advertises the presence of SPE in the
ID_AA64DFR0_EL1 register, but configures MDCR_EL2 to trap accesses to the
registers and injects an undefined exception when that happens.

The architecture doesn't allow trapping access to the PMBIDR_EL1 register,
which means the guest will be able to read it even if SPE is not advertised
in the ID register. However, since it's usually better for a read to
unexpectedly succeed than to cause an exception, let's stop advertising the
presence of SPE to guests to better match how KVM emulates the
architecture.

Signed-off-by: Alexandru Elisei <alexandru.elisei@arm.com>
---
 arch/arm64/kvm/sys_regs.c | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)
diff mbox series

Patch

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index d9117bc56237..aa776c006a2a 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -244,6 +244,12 @@  static bool access_vm_reg(struct kvm_vcpu *vcpu,
 	return true;
 }
 
+static unsigned int spe_visibility(const struct kvm_vcpu *vcpu,
+				   const struct sys_reg_desc *r)
+{
+	return REG_HIDDEN_GUEST | REG_HIDDEN_USER;
+}
+
 static bool access_actlr(struct kvm_vcpu *vcpu,
 			 struct sys_reg_params *p,
 			 const struct sys_reg_desc *r)
@@ -1143,6 +1149,8 @@  static u64 read_id_reg(const struct kvm_vcpu *vcpu,
 		val = cpuid_feature_cap_perfmon_field(val,
 						ID_AA64DFR0_PMUVER_SHIFT,
 						ID_AA64DFR0_PMUVER_8_1);
+		/* Don't advertise SPE to guests */
+		val &= ~(0xfUL << ID_AA64DFR0_PMSVER_SHIFT);
 	} else if (id == SYS_ID_DFR0_EL1) {
 		/* Limit guests to PMUv3 for ARMv8.1 */
 		val = cpuid_feature_cap_perfmon_field(val,
@@ -1590,6 +1598,17 @@  static const struct sys_reg_desc sys_reg_descs[] = {
 	{ SYS_DESC(SYS_FAR_EL1), access_vm_reg, reset_unknown, FAR_EL1 },
 	{ SYS_DESC(SYS_PAR_EL1), NULL, reset_unknown, PAR_EL1 },
 
+	{ SYS_DESC(SYS_PMSCR_EL1), .visibility = spe_visibility },
+	{ SYS_DESC(SYS_PMSICR_EL1), .visibility = spe_visibility },
+	{ SYS_DESC(SYS_PMSIRR_EL1), .visibility = spe_visibility },
+	{ SYS_DESC(SYS_PMSFCR_EL1), .visibility = spe_visibility },
+	{ SYS_DESC(SYS_PMSEVFR_EL1), .visibility = spe_visibility },
+	{ SYS_DESC(SYS_PMSLATFR_EL1), .visibility = spe_visibility },
+	{ SYS_DESC(SYS_PMSIDR_EL1), .visibility = spe_visibility },
+	{ SYS_DESC(SYS_PMBLIMITR_EL1), .visibility = spe_visibility },
+	{ SYS_DESC(SYS_PMBPTR_EL1), .visibility = spe_visibility },
+	{ SYS_DESC(SYS_PMBSR_EL1), .visibility = spe_visibility },
+
 	{ SYS_DESC(SYS_PMINTENSET_EL1), access_pminten, reset_unknown, PMINTENSET_EL1 },
 	{ SYS_DESC(SYS_PMINTENCLR_EL1), access_pminten, reset_unknown, PMINTENSET_EL1 },