Add hidden or reserved ID registers, and remaining ID registers, which don't require special handling, to id_reg_desc_table. Add 'flags' field to id_reg_desc, which is used to indicates hiddden or reserved registers. Since now id_reg_desc_init() is called even for hidden/reserved registers, change it to not do anything for them. Signed-off-by: Reiji Watanabe <reijiw@xxxxxxxxxx> --- arch/arm64/kvm/sys_regs.c | 84 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 82 insertions(+), 2 deletions(-) diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index 9e090441057a..479208dedd79 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -331,6 +331,11 @@ struct id_reg_desc { /* Fields that are not validated by arm64_check_features. */ u64 ignore_mask; + /* Miscellaneous flags */ +#define ID_DESC_REG_UNALLOC (1UL << 0) +#define ID_DESC_REG_HIDDEN (1UL << 1) + u64 flags; + /* An optional initialization function of the id_reg_desc */ void (*init)(struct id_reg_desc *id_reg); @@ -376,8 +381,13 @@ struct id_reg_desc { static void id_reg_desc_init(struct id_reg_desc *id_reg) { u32 id = reg_to_encoding(&id_reg->reg_desc); - u64 val = read_sanitised_ftr_reg(id); + u64 val; + + if (id_reg->flags & (ID_DESC_REG_HIDDEN | ID_DESC_REG_UNALLOC)) + /* Nothing to do for a hidden/unalloc ID register */ + return; + val = read_sanitised_ftr_reg(id); id_reg->vcpu_limit_val = val; id_reg_desc_init_ftr(id_reg); @@ -4192,33 +4202,103 @@ static struct id_reg_desc mvfr1_el1_desc = { .validate = validate_mvfr1_el1, }; +#define ID_DESC_DEFAULT(name) \ + [IDREG_IDX(SYS_##name)] = &(struct id_reg_desc) { \ + .reg_desc = ID_SANITISED(name), \ + } + +#define ID_DESC_HIDDEN(name) \ + [IDREG_IDX(SYS_##name)] = &(struct id_reg_desc) { \ + .reg_desc = ID_HIDDEN(name), \ + .flags = ID_DESC_REG_HIDDEN, \ + } + +#define ID_DESC_UNALLOC(crm, op2) \ + [(crm - 1) << 3 | op2] = &(struct id_reg_desc) { \ + .reg_desc = ID_UNALLOCATED(crm, op2), \ + .flags = ID_DESC_REG_UNALLOC, \ + } + #define ID_DESC(id_reg_name, id_reg_desc) \ [IDREG_IDX(SYS_##id_reg_name)] = (id_reg_desc) -/* A table for ID registers's information. */ +/* + * A table for ID registers's information. + * All entries in the table except ID_DESC_HIDDEN and ID_DESC_UNALLOC + * must have corresponding entries in arm64_ftr_regs[] in + * arch/arm64/kernel/cpufeature.c because read_sanitised_ftr_reg() is + * called for each of the ID registers. + */ static struct id_reg_desc *id_reg_desc_table[KVM_ARM_ID_REG_MAX_NUM] = { /* CRm=1 */ + ID_DESC_DEFAULT(ID_PFR0_EL1), + ID_DESC_DEFAULT(ID_PFR1_EL1), ID_DESC(ID_DFR0_EL1, &id_dfr0_el1_desc), + ID_DESC_HIDDEN(ID_AFR0_EL1), ID_DESC(ID_MMFR0_EL1, &id_mmfr0_el1_desc), + ID_DESC_DEFAULT(ID_MMFR1_EL1), + ID_DESC_DEFAULT(ID_MMFR2_EL1), + ID_DESC_DEFAULT(ID_MMFR3_EL1), + + /* CRm=2 */ + ID_DESC_DEFAULT(ID_ISAR0_EL1), + ID_DESC_DEFAULT(ID_ISAR1_EL1), + ID_DESC_DEFAULT(ID_ISAR2_EL1), + ID_DESC_DEFAULT(ID_ISAR3_EL1), + ID_DESC_DEFAULT(ID_ISAR4_EL1), + ID_DESC_DEFAULT(ID_ISAR5_EL1), + ID_DESC_DEFAULT(ID_MMFR4_EL1), + ID_DESC_DEFAULT(ID_ISAR6_EL1), /* CRm=3 */ + ID_DESC_DEFAULT(MVFR0_EL1), ID_DESC(MVFR1_EL1, &mvfr1_el1_desc), + ID_DESC_DEFAULT(MVFR2_EL1), + ID_DESC_UNALLOC(3, 3), + ID_DESC_DEFAULT(ID_PFR2_EL1), ID_DESC(ID_DFR1_EL1, &id_dfr1_el1_desc), + ID_DESC_DEFAULT(ID_MMFR5_EL1), + ID_DESC_UNALLOC(3, 7), /* CRm=4 */ ID_DESC(ID_AA64PFR0_EL1, &id_aa64pfr0_el1_desc), ID_DESC(ID_AA64PFR1_EL1, &id_aa64pfr1_el1_desc), + ID_DESC_UNALLOC(4, 2), + ID_DESC_UNALLOC(4, 3), + ID_DESC_DEFAULT(ID_AA64ZFR0_EL1), + ID_DESC_UNALLOC(4, 5), + ID_DESC_UNALLOC(4, 6), + ID_DESC_UNALLOC(4, 7), /* CRm=5 */ ID_DESC(ID_AA64DFR0_EL1, &id_aa64dfr0_el1_desc), + ID_DESC_DEFAULT(ID_AA64DFR1_EL1), + ID_DESC_UNALLOC(5, 2), + ID_DESC_UNALLOC(5, 3), + ID_DESC_HIDDEN(ID_AA64AFR0_EL1), + ID_DESC_HIDDEN(ID_AA64AFR1_EL1), + ID_DESC_UNALLOC(5, 6), + ID_DESC_UNALLOC(5, 7), /* CRm=6 */ ID_DESC(ID_AA64ISAR0_EL1, &id_aa64isar0_el1_desc), ID_DESC(ID_AA64ISAR1_EL1, &id_aa64isar1_el1_desc), ID_DESC(ID_AA64ISAR2_EL1, &id_aa64isar2_el1_desc), + ID_DESC_UNALLOC(6, 3), + ID_DESC_UNALLOC(6, 4), + ID_DESC_UNALLOC(6, 5), + ID_DESC_UNALLOC(6, 6), + ID_DESC_UNALLOC(6, 7), /* CRm=7 */ ID_DESC(ID_AA64MMFR0_EL1, &id_aa64mmfr0_el1_desc), + ID_DESC_DEFAULT(ID_AA64MMFR1_EL1), + ID_DESC_DEFAULT(ID_AA64MMFR2_EL1), + ID_DESC_UNALLOC(7, 3), + ID_DESC_UNALLOC(7, 4), + ID_DESC_UNALLOC(7, 5), + ID_DESC_UNALLOC(7, 6), + ID_DESC_UNALLOC(7, 7), }; static inline struct id_reg_desc *get_id_reg_desc(u32 id) -- 2.36.0.rc0.470.gd361397f0d-goog