This is an automated email from the ASF dual-hosted git repository.
acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git
The following commit(s) were added to refs/heads/master by this push:
new baeedc5009f arch/arm64: Synchronize the TTBR0 write before the TLB
invalidation.
baeedc5009f is described below
commit baeedc5009fad5d19885c39c0a360b21fb126a4e
Author: Marco Casaroli <[email protected]>
AuthorDate: Thu Oct 8 00:23:47 2026 +0200
arch/arm64: Synchronize the TTBR0 write before the TLB invalidation.
mmu_write_ttbr0() writes TTBR0_EL1 and then invalidates the TLB. A write
to TTBR0_EL1 takes effect only at the next context synchronization event,
so until the ISB at the end of the invalidation, a table walk can still
use the old table. The instruction fetches of the invalidation sequence
itself do such walks. An entry that they cache after the TLBI completes
stays valid: walk cache entries are not tagged with the table base, and
the kernel and every process use ASID 0.
A kernel build then translates a user address of the new process through
a level 0 entry of the old table, and gets a level 1 translation fault.
Under QEMU with HVF on Apple silicon this happens on every boot of
qemu-armv8a:knsh: up_addrenv_va_to_pa() fails for the first user buffer,
and virtio gets a descriptor with address 0. TCG has no walk caches, so
it does not show the problem.
Add an ISB after the write, as the Arm ARM sequence for a TTBR change
without an ASID change requires: write, ISB, TLBI, DSB, ISB.
Assisted-by: Claude Code:claude-opus-5-5
Signed-off-by: Marco Casaroli <[email protected]>
---
arch/arm64/src/common/arm64_mmu.h | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/arch/arm64/src/common/arm64_mmu.h
b/arch/arm64/src/common/arm64_mmu.h
index 68862f4fc6c..f910f660b65 100644
--- a/arch/arm64/src/common/arm64_mmu.h
+++ b/arch/arm64/src/common/arm64_mmu.h
@@ -456,6 +456,12 @@ static inline void mmu_invalidate_tlbs(void)
static inline void mmu_write_ttbr0(uintptr_t reg)
{
write_sysreg(reg, ttbr0_el1);
+
+ /* Until this ISB, walks can still use the old table and cache its
+ * entries after the TLB invalidation below.
+ */
+
+ UP_ISB();
mmu_invalidate_tlbs();
}