[PATCH v2 4/6] KVM: arm64: Account for RES1 bits in DECLARE_FEAT_MAP() and co
Marc Zyngier
maz at kernel.org
Wed Jan 21 02:50:45 PST 2026
Hi Nathan,
Thanks for reporting this.
On Tue, 20 Jan 2026 21:15:58 +0000,
Nathan Chancellor <nathan at kernel.org> wrote:
>
> Hi Marc,
>
> On Wed, Dec 10, 2025 at 05:30:22PM +0000, Marc Zyngier wrote:
> > None of the registers we manage in the feature dependency infrastructure
> > so far has any RES1 bit. This is about to change, as VTCR_EL2 has
> > its bit 31 being RES1.
> >
> > In order to not fail the consistency checks by not describing a bit,
> > add RES1 bits to the set of immutable bits. This requires some extra
> > surgery for the FGT handling, as we now need to track RES1 bits there
> > as well.
> >
> > There are no RES1 FGT bits *yet*. Watch this space.
> >
> > Signed-off-by: Marc Zyngier <maz at kernel.org>
>
> After this change in -next as commit c259d763e6b0 ("KVM: arm64: Account
> for RES1 bits in DECLARE_FEAT_MAP() and co"), I am seeing several
> "undefined behavior" errors on my two arm64 boxes.
>
> $ journalctl -k -g '(Linux version|kvm)' --no-hostname -o cat
> Linux version 6.19.0-rc4-00014-gc259d763e6b0 (nathan at framework-amd-ryzen-maxplus-395) (aarch64-linux-gcc (GCC) 15.2.0, GNU ld (GNU Binutils) 2.45) #1 SMP PREEMPT_DYNAMIC Tue Jan 20 13:59:52 MST 2026
> kvm [1]: nv: 568 coarse grained trap handlers
> kvm [1]: Undefined hfgrtr_masks behaviour, bits fff7ffffffffffff
> kvm [1]: Undefined hfgwtr_masks behaviour, bits fff7baffe9db39fb
> kvm [1]: Undefined hfgitr_masks behaviour, bits dfffffffffffffff
> kvm [1]: Undefined hdfgrtr_masks behaviour, bits fffdfb3fffcffeff
> kvm [1]: Undefined hdfgwtr_masks behaviour, bits 73f7763bbfbffdbf
> kvm [1]: Undefined hafgrtr_masks behaviour, bits 0003fffffffe001f
> kvm [1]: Undefined hfgrtr2_masks behaviour, bits 0000000000007fff
> kvm [1]: Undefined hfgwtr2_masks behaviour, bits 0000000000007ffd
> kvm [1]: Undefined hfgitr2_masks behaviour, bits 0000000000000003
> kvm [1]: Undefined hdfgrtr2_masks behaviour, bits 0000000001dfffff
> kvm [1]: Undefined hdfgwtr2_masks behaviour, bits 0000000001f9ffbf
> kvm [1]: IPA Size Limit: 44 bits
> kvm [1]: vgic-v2 at c0e0000
> kvm [1]: GICv3 sysreg trapping enabled ([C], reduced performance)
> kvm [1]: GIC system register CPU interface enabled
> kvm [1]: vgic interrupt IRQ9
> kvm [1]: Hyp nVHE mode initialized successfully
Let me guess: Cortex-A72 or similarly ancient ARM-designed CPUs, as
hinted by the lack of GICv3 TDIR control? Then these do not have
FEAT_FGT.
The issue stems from the fact that as an optimisation, we skip the
parsing of the FGT trap table on such hardware, which also results in
the FGT masks of known bits not being updated. We then compute the
effective feature map, and discover that the two don't match.
It was harmless so far, as we were only dealing with RES0 bits, and
assuming that anything that wasn't a RES0 bit was a stateful bit. With
the introduction of RES1 handling, we've run out of luck. To be clear,
that's just a warning, not a functional issue.
At this point, I don't think the above "optimisation" is worth having.
This is only done *once*, at boot time, so the gain is extremely
small. I'd like the checks to be effective irrespective of the HW the
kernel runs on, which is consistent with what we do for other tables
describing the architectural state.
Anyway, I came up with the following hack, which performs the checks,
but avoid inserting the FGT information in the sysreg xarray if the HW
doesn't support it, as a memory saving measure. Please let me know if
that helps (it does on my old boxes).
Thanks,
M.
diff --git a/arch/arm64/kvm/emulate-nested.c b/arch/arm64/kvm/emulate-nested.c
index 88336336efc9f..fa8fa09de67dc 100644
--- a/arch/arm64/kvm/emulate-nested.c
+++ b/arch/arm64/kvm/emulate-nested.c
@@ -2284,9 +2284,6 @@ int __init populate_nv_trap_config(void)
kvm_info("nv: %ld coarse grained trap handlers\n",
ARRAY_SIZE(encoding_to_cgt));
- if (!cpus_have_final_cap(ARM64_HAS_FGT))
- goto check_mcb;
-
for (int i = 0; i < ARRAY_SIZE(encoding_to_fgt); i++) {
const struct encoding_to_trap_config *fgt = &encoding_to_fgt[i];
union trap_config tc;
@@ -2306,6 +2303,15 @@ int __init populate_nv_trap_config(void)
}
tc.val |= fgt->tc.val;
+
+ if (!aggregate_fgt(tc)) {
+ ret = -EINVAL;
+ print_nv_trap_error(fgt, "FGT bit is reserved", ret);
+ }
+
+ if (!cpus_have_final_cap(ARM64_HAS_FGT))
+ continue;
+
prev = xa_store(&sr_forward_xa, enc,
xa_mk_value(tc.val), GFP_KERNEL);
@@ -2313,11 +2319,6 @@ int __init populate_nv_trap_config(void)
ret = xa_err(prev);
print_nv_trap_error(fgt, "Failed FGT insertion", ret);
}
-
- if (!aggregate_fgt(tc)) {
- ret = -EINVAL;
- print_nv_trap_error(fgt, "FGT bit is reserved", ret);
- }
}
}
@@ -2333,7 +2334,6 @@ int __init populate_nv_trap_config(void)
kvm_info("nv: %ld fine grained trap handlers\n",
ARRAY_SIZE(encoding_to_fgt));
-check_mcb:
for (int id = __MULTIPLE_CONTROL_BITS__; id < __COMPLEX_CONDITIONS__; id++) {
const enum cgt_group_id *cgids;
--
Without deviation from the norm, progress is not possible.
More information about the linux-arm-kernel
mailing list