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@xxxxxxxxxx> --- arch/arm64/kvm/sys_regs.c | 54 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) 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; -- 2.36.0.rc0.470.gd361397f0d-goog