]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
KVM: arm64: Validate FGT register descriptions against RES0 masks
authorMarc Zyngier <maz@kernel.org>
Sun, 9 Feb 2025 14:19:05 +0000 (14:19 +0000)
committerMarc Zyngier <maz@kernel.org>
Sat, 10 May 2025 10:04:35 +0000 (11:04 +0100)
In order to point out to the unsuspecting KVM hacker that they
are missing something somewhere, validate that the known FGT bits
do not intersect with the corresponding RES0 mask, as computed at
boot time.

THis check is also performed at boot time, ensuring that there is
no runtime overhead.

Signed-off-by: Marc Zyngier <maz@kernel.org>
arch/arm64/include/asm/kvm_host.h
arch/arm64/kvm/config.c
arch/arm64/kvm/sys_regs.c

index 9386f15cdc2523db8e0af198010da61400eaba95..59bfb049ce9873cb16174bd79d9a460765862920 100644 (file)
@@ -1611,5 +1611,6 @@ void kvm_set_vm_id_reg(struct kvm *kvm, u32 reg, u64 val);
        (kvm_has_feat((k), ID_AA64MMFR3_EL1, S1POE, IMP))
 
 void compute_fgu(struct kvm *kvm, enum fgt_group_id fgt);
+void check_feature_map(void);
 
 #endif /* __ARM64_KVM_HOST_H__ */
index 9a29d298aae76932b60ea92a12c662491f15cd52..0c44a3d85872aecc1b3b58f383fcab53f9537392 100644 (file)
@@ -494,6 +494,35 @@ static const struct reg_bits_to_feat_map hafgrtr_feat_map[] = {
                   FEAT_AMUv1),
 };
 
+static void __init check_feat_map(const struct reg_bits_to_feat_map *map,
+                                 int map_size, u64 res0, const char *str)
+{
+       u64 mask = 0;
+
+       for (int i = 0; i < map_size; i++)
+               mask |= map[i].bits;
+
+       if (mask != ~res0)
+               kvm_err("Undefined %s behaviour, bits %016llx\n",
+                       str, mask ^ ~res0);
+}
+
+void __init check_feature_map(void)
+{
+       check_feat_map(hfgrtr_feat_map, ARRAY_SIZE(hfgrtr_feat_map),
+                      hfgrtr_masks.res0, hfgrtr_masks.str);
+       check_feat_map(hfgwtr_feat_map, ARRAY_SIZE(hfgwtr_feat_map),
+                      hfgwtr_masks.res0, hfgwtr_masks.str);
+       check_feat_map(hfgitr_feat_map, ARRAY_SIZE(hfgitr_feat_map),
+                      hfgitr_masks.res0, hfgitr_masks.str);
+       check_feat_map(hdfgrtr_feat_map, ARRAY_SIZE(hdfgrtr_feat_map),
+                      hdfgrtr_masks.res0, hdfgrtr_masks.str);
+       check_feat_map(hdfgwtr_feat_map, ARRAY_SIZE(hdfgwtr_feat_map),
+                      hdfgwtr_masks.res0, hdfgwtr_masks.str);
+       check_feat_map(hafgrtr_feat_map, ARRAY_SIZE(hafgrtr_feat_map),
+                      hafgrtr_masks.res0, hafgrtr_masks.str);
+}
+
 static bool idreg_feat_match(struct kvm *kvm, const struct reg_bits_to_feat_map *map)
 {
        u64 regval = kvm->arch.id_regs[map->regidx];
index b3e53a899c1fef94b86d82a517d4124b23669cb7..f24d1a7d9a8f40037f28c87d0a745436fbe08ecc 100644 (file)
@@ -5208,6 +5208,8 @@ int __init kvm_sys_reg_table_init(void)
 
        ret = populate_nv_trap_config();
 
+       check_feature_map();
+
        for (i = 0; !ret && i < ARRAY_SIZE(sys_reg_descs); i++)
                ret = populate_sysreg_config(sys_reg_descs + i, i);