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();
 }
 

Reply via email to