Re: [PATCH v2 4/6] KVM: arm64: Account for RES1 bits in DECLARE_FEAT_MAP() and co
From: Marc Zyngier <maz@kernel.org>
Date: 2026-01-21 10:50:58
Also in:
kvm, kvmarm
Subsystem:
arm64 port (aarch64 architecture), kernel virtual machine for arm64 (kvm/arm64), the rest · Maintainers:
Catalin Marinas, Will Deacon, Marc Zyngier, Oliver Upton, Linus Torvalds
Hi Nathan, Thanks for reporting this. On Tue, 20 Jan 2026 21:15:58 +0000, Nathan Chancellor [off-list ref] wrote:
Hi Marc, On Wed, Dec 10, 2025 at 05:30:22PM +0000, Marc Zyngier wrote:quoted
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@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@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@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.