[PATCH] KVM: arm64: Don't livelock when AT can't resolve a fault IPA
Ard Biesheuvel
ardb at kernel.org
Mon Nov 2 10:23:09 PST 2026
On Mon, 2 Nov 2026, at 17:52, Marc Zyngier wrote:
> On Mon, 02 Nov 2026 15:57:51 +0000,
> Fuad Tabba <fuad.tabba at linux.dev> wrote:
>>
>> Hi Will,
>>
>> On Mon, 02 Nov 2026 14:17:10 +0000, Will Deacon <will at kernel.org> wrote:
>> > On Mon, Nov 02, 2026 at 02:09:25PM +0000, Marc Zyngier wrote:
>> > > On Mon, 02 Nov 2026 13:59:12 +0000,
>> > > Will Deacon <will at kernel.org> wrote:
>> [...]
>> > > > > diff --git a/arch/arm64/kvm/hyp/include/hyp/switch.h b/arch/arm64/kvm/hyp/include/hyp/switch.h
>> [...]
>> > > > > static inline bool kvm_hyp_handle_memory_fault(struct kvm_vcpu *vcpu,
>> > > > > u64 *exit_code)
>> > > > > {
>> > > > > - if (!__populate_fault_info(vcpu))
>> > > > > + if (!__populate_fault_info(vcpu)) {
>> > > >
>> > > > Presumably we need a barrier (DSB?) here, to ensure that the TLBI happens
>> > > > after the AT instruction?
>>
>> I don't think the TLBI requires a barrier before it, because it
>> doesn't matter if the AT's walk allocates entries after the TLBI.
>> Anything it allocates matches memory, and the stage-2 descriptor the
>> AT faulted on has AF clear, so that descriptor can't be cached:
>>
>> R_XCLRD: Translation table entries that generate a Translation
>> fault, an Address size fault, or an Access flag fault are never cached
>> in a TLB.
>>
>> The stale entries the guest keeps hitting were already there before
>> the TLBI, and the dsb(nsh) and isb after it are what complete it
>> against them.
>>
>> [... your other reply ... ]
>> > > Alternatively, VMALLE1 or even VAE1 should be enough to get rid of the
>> > > S1 TLB.
>> >
>> > Ah, sorry, VMALLE1 is what I meant to ask about. I basically haven't
>> > understood the need to invalidate the stage-2.
>>
>> The guest's walk can also go through a stage-2 entry for its
>> page-table page, cached before the aging cleared that page's AF, and
>> nothing requires the AT to use that entry:
>>
>> R_NPZWX: When an address translation instruction is executed, it is
>> IMPLEMENTATION DEFINED whether the result can be returned from a TLB,
>> or a translation table walk occurs.
>>
>> So if my reading is correct, on a CPU whose AT walks memory instead,
>> the AT keeps failing while the guest's walk goes through the stale
>> entry, and the guest takes the same permission fault again. VMALLE1
>> and VAE1 only cover stage 1, so they'd leave that loop in place.
>
> If we assume that the TLB covers VA->PA (which is a very likely case),
> TLBI VAE1 should nuke the permission fault that brought the vcpu to
> EL2, and instead walk the page tables, getting the access fault.
>
> The only case I can imagine where invalidating S2 would matter is if
> you are running under NV, because there is an independent S2 TLB (the
> shadow S2), and then VMALLS12E1 makes total sense.
>
> Ard, was this solely observed under NV? Or did you see it on a non NV
> guest as well?
>
No it happens with guests running at EL1 too.
My experiments seem to indicate that on this uarch, the AT instruction
does not hit in the TLB, and so it can fail on AF==0 for an IPA that
is covered by a S2-only TLB entry (with AF==1 and XN==1 due to lazy exec).
So after the VAAE1, the S1 walk happily produces the same translation
we just invalidated, without taking a S1PTW fault, and the guest faults
again on the I-fetch that took us to hyp the first time around.
More information about the linux-arm-kernel
mailing list