diff mbox series

[v7,04/38] KVM: arm64: Generate id_reg_desc's ftr_bits at KVM init when needed

Message ID 20220419065544.3616948-5-reijiw@google.com (mailing list archive)
State New, archived
Headers show
Series KVM: arm64: Make CPU ID registers writable by userspace | expand

Commit Message

Reiji Watanabe April 19, 2022, 6:55 a.m. UTC
Most of entries in ftr_bits[] of id_reg_desc will be UNSIGNED+LOWER_SAFE.
Use that as the default arm64_ftr_bits for any entries that are not
statically defined in ftr_bits[] so that we don't have to statically
define every single UNSIGNED+LOWER_SAFE entry.

Signed-off-by: Reiji Watanabe <reijiw@google.com>
---
 arch/arm64/kvm/sys_regs.c | 54 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 54 insertions(+)
diff mbox series

Patch

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 30adc19e4619..b19e14a1206a 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -35,6 +35,7 @@ 
 
 static u64 read_id_reg_with_encoding(const struct kvm_vcpu *vcpu, u32 id);
 static inline struct id_reg_desc *get_id_reg_desc(u32 id);
+static void id_reg_desc_init_ftr(struct id_reg_desc *idr);
 
 /*
  * All of this file is extremely similar to the ARM coproc.c, but the
@@ -325,6 +326,8 @@  struct id_reg_desc {
 	 * Used to validate the ID register values with arm64_check_features().
 	 * The last item in the array must be terminated by an item whose
 	 * width field is zero as that is expected by arm64_check_features().
+	 * Entries that are not statically defined will be generated as
+	 * UNSIGNED+LOWER_SAFE entries during KVM's initialization.
 	 */
 	struct arm64_ftr_bits	ftr_bits[FTR_FIELDS_NUM];
 };
@@ -335,6 +338,9 @@  static void id_reg_desc_init(struct id_reg_desc *id_reg)
 	u64 val = read_sanitised_ftr_reg(id);
 
 	id_reg->vcpu_limit_val = val;
+
+	id_reg_desc_init_ftr(id_reg);
+
 	if (id_reg->init)
 		id_reg->init(id_reg);
 
@@ -3173,6 +3179,54 @@  static inline struct id_reg_desc *get_id_reg_desc(u32 id)
 	return id_reg_desc_table[IDREG_IDX(id)];
 }
 
+void kvm_ftr_bits_set_default(u8 shift, struct arm64_ftr_bits *ftrp)
+{
+	ftrp->sign = FTR_UNSIGNED;
+	ftrp->type = FTR_LOWER_SAFE;
+	ftrp->shift = shift;
+	ftrp->width = ARM64_FEATURE_FIELD_BITS;
+	ftrp->safe_val = 0;
+}
+
+/*
+ * Check to see if the id_reg's ftr_bits have statically defined entries
+ * for all fields of the ID register, and generate the default ones
+ * (FTR_UNSIGNED+FTR_LOWER_SAFE) for any missing fields.
+ */
+static void id_reg_desc_init_ftr(struct id_reg_desc *idr)
+{
+	struct arm64_ftr_bits *ftrp = idr->ftr_bits;
+	int index = 0;
+	int shift;
+	u64 ftr_mask;
+	u64 mask = 0;
+
+	/* Create a mask for fields that are statically defined */
+	for (index = 0; ftrp->width != 0; index++, ftrp++) {
+		ftr_mask = arm64_ftr_mask(ftrp);
+		WARN_ON_ONCE(mask & ftr_mask);
+		mask |= ftr_mask;
+	}
+
+	if (mask == -1UL)
+		/* All fields are statically defined */
+		return;
+
+	/* The 'index' indicates the first unused index of ftr_bits */
+	for (shift = 0; shift < 64; shift += ARM64_FEATURE_FIELD_BITS) {
+		/* Check if there is an existing ftrp for the field */
+		ftr_mask = ARM64_FEATURE_FIELD_MASK << shift;
+		if (mask & ftr_mask)
+			continue;
+
+		/* Generate the default arm64_ftr_bits for the field */
+		kvm_ftr_bits_set_default(shift, &idr->ftr_bits[index++]);
+		mask |= ftr_mask;
+	}
+
+	WARN_ON((mask != -1UL) || (index != (FTR_FIELDS_NUM - 1)));
+}
+
 static void id_reg_desc_init_all(void)
 {
 	int i;