@@ -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;
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(+)