[PATCH] KVM: arm64: Disable OS double lock visibility by default and ignore VMM writes

Shameer Kolothum shameerali.kolothum.thodi at huawei.com
Thu Aug 8 05:57:11 PDT 2024


KVM exposes the OS double lock feature bit to Guests but returns
RAZ/WI on Guest OSDLR_EL1 access. Make sure we are hiding OS double
lock from Guests now. However we can't hide DoubleLock if the reported
DebugVer is < 8.2. So report a minimum DebugVer of 8.2 to Guests.

All this may break migration from the older kernels. Take care of
that by ignoring VMM writes for these values.

Signed-off-by: Shameer Kolothum <shameerali.kolothum.thodi at huawei.com>
---
Note:
 - I am not very sure on reporting DebugVer a min of 8.2. Hopefully this is
   fine. Please let me know.
   
Thanks,
Shameer
---  
 arch/arm64/kvm/sys_regs.c | 36 ++++++++++++++++++++++++++++++++----
 1 file changed, 32 insertions(+), 4 deletions(-)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index c90324060436..06e57d7730d8 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -1704,13 +1704,14 @@ static u64 read_sanitised_id_aa64pfr0_el1(struct kvm_vcpu *vcpu,
 	return val;
 }
 
-#define ID_REG_LIMIT_FIELD_ENUM(val, reg, field, limit)			       \
+#define ID_REG_LIMIT_FIELD_ENUM(val, reg, field, min_val, max_val)	       \
 ({									       \
 	u64 __f_val = FIELD_GET(reg##_##field##_MASK, val);		       \
+	(__f_val) = max_t(u64, __f_val, SYS_FIELD_VALUE(reg, field, min_val)); \
 	(val) &= ~reg##_##field##_MASK;					       \
 	(val) |= FIELD_PREP(reg##_##field##_MASK,			       \
 			    min(__f_val,				       \
-				(u64)SYS_FIELD_VALUE(reg, field, limit)));     \
+				(u64)SYS_FIELD_VALUE(reg, field, max_val)));   \
 	(val);								       \
 })
 
@@ -1719,7 +1720,7 @@ static u64 read_sanitised_id_aa64dfr0_el1(struct kvm_vcpu *vcpu,
 {
 	u64 val = read_sanitised_ftr_reg(SYS_ID_AA64DFR0_EL1);
 
-	val = ID_REG_LIMIT_FIELD_ENUM(val, ID_AA64DFR0_EL1, DebugVer, V8P8);
+	val = ID_REG_LIMIT_FIELD_ENUM(val, ID_AA64DFR0_EL1, DebugVer, V8P2, V8P8);
 
 	/*
 	 * Only initialize the PMU version if the vCPU was configured with one.
@@ -1732,6 +1733,10 @@ static u64 read_sanitised_id_aa64dfr0_el1(struct kvm_vcpu *vcpu,
 	/* Hide SPE from guests */
 	val &= ~ID_AA64DFR0_EL1_PMSVer_MASK;
 
+	/* Hide DoubleLock from guests */
+	val &= ~ID_AA64DFR0_EL1_DoubleLock_MASK;
+	val |= SYS_FIELD_PREP_ENUM(ID_AA64DFR0_EL1, DoubleLock, NI);
+
 	return val;
 }
 
@@ -1739,6 +1744,7 @@ static int set_id_aa64dfr0_el1(struct kvm_vcpu *vcpu,
 			       const struct sys_reg_desc *rd,
 			       u64 val)
 {
+	u64 hw_val = read_sanitised_ftr_reg(SYS_ID_AA64DFR0_EL1);
 	u8 debugver = SYS_FIELD_GET(ID_AA64DFR0_EL1, DebugVer, val);
 	u8 pmuver = SYS_FIELD_GET(ID_AA64DFR0_EL1, PMUVer, val);
 
@@ -1765,6 +1771,28 @@ static int set_id_aa64dfr0_el1(struct kvm_vcpu *vcpu,
 	 */
 	if (debugver < ID_AA64DFR0_EL1_DebugVer_IMP)
 		return -EINVAL;
+	else if (debugver < ID_AA64DFR0_EL1_DebugVer_V8P2) {
+		/*
+		 * KVM now reports a minimum DebugVer 8.2 to Guests. In order to keep
+		 * the migration working from old kernels, check and ignore the VMM
+		 * write.
+		 */
+		if ((hw_val & ID_AA64DFR0_EL1_DebugVer_MASK) ==
+		    (val & ID_AA64DFR0_EL1_DebugVer_MASK)) {
+			val &= ~ID_AA64DFR0_EL1_DebugVer_MASK;
+			val |= SYS_FIELD_PREP_ENUM(ID_AA64DFR0_EL1, DebugVer, V8P2);
+		}
+	}
+	/*
+	 * KVM used to expose OS double lock feature bit to Guests but returned
+	 * RAZ/WI on Guest OSDLR_EL1 access. We are hiding OS double lock now.
+	 * But for migration from old kernels to work ignore the VMM write.
+	 */
+	if ((hw_val & ID_AA64DFR0_EL1_DoubleLock_MASK) ==
+	    (val & ID_AA64DFR0_EL1_DoubleLock_MASK)) {
+		val &= ~ID_AA64DFR0_EL1_DoubleLock_MASK;
+		val |= SYS_FIELD_PREP_ENUM(ID_AA64DFR0_EL1, DoubleLock, NI);
+	}
 
 	return set_id_reg(vcpu, rd, val);
 }
@@ -1779,7 +1807,7 @@ static u64 read_sanitised_id_dfr0_el1(struct kvm_vcpu *vcpu,
 	if (kvm_vcpu_has_pmu(vcpu))
 		val |= SYS_FIELD_PREP(ID_DFR0_EL1, PerfMon, perfmon);
 
-	val = ID_REG_LIMIT_FIELD_ENUM(val, ID_DFR0_EL1, CopDbg, Debugv8p8);
+	val = ID_REG_LIMIT_FIELD_ENUM(val, ID_DFR0_EL1, CopDbg, NI, Debugv8p8);
 
 	return val;
 }
-- 
2.45.2




More information about the linux-arm-kernel mailing list