Visitar URL original
arch/arm64: Synchronize the TTBR0 write before the TLB invalidation. by casaroli · Pull Request #20500 · apache/nuttx · GitHub
Skip to content

arch/arm64: Synchronize the TTBR0 write before the TLB invalidation. - #20500

Merged
acassis merged 1 commit into
apache:masterfrom
casaroli:arm64-ttbr0-isb
Oct 8, 2026
Merged

acassis merged 1 commit into
apache:masterfrom
casaroli:arm64-ttbr0-isb

Conversation

@casaroli

@casaroli casaroli commented Oct 7, 2026

Copy link
Copy Markdown
Contributor

Summary

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, because walk cache entries are not tagged with the table base, and the kernel and every process use ASID 0.

In a kernel build, a user address of the new process is then translated through a level 0 entry of the old table, and the translation fails at level 1.

This PR adds an ISB after the write. This gives the Arm ARM sequence for a TTBR change without an ASID change: write, ISB, TLBI, DSB, ISB.

Impact

arm64 builds with CONFIG_ARCH_ADDRENV only: mmu_write_ttbr0() is called only by up_addrenv_select(). The cost is one ISB per address environment switch.

Testing

QEMU 11.0.0 with HVF (-accel hvf -cpu host) on an Apple M4, so the guest runs on real Arm cores. qemu-armv8a:knsh with CONFIG_ARCH_CHIP_QEMU_WITH_HV, and its applications on a virtio-9p share in place of semihosting, which HVF does not have. This needs #20498 and #20499.

Before this PR, every boot (5 of 5) stops when the kernel loads /system/bin/init:

qemu-system-aarch64: virtio: bogus descriptor or out of resources

up_addrenv_va_to_pa() of the first user buffer (0xc0001000) returns 0, so the descriptor has address 0. A record of each call, read with gdb after the failure, shows PAR_EL1 = 0x80b, a stage 1 translation fault at level 1. The level 0 and level 1 entries in memory are valid at that time, and they were written and invalidated before the TTBR0 switch. One more TLBI just before the AT makes the same translation succeed. A gdb breakpoint hides the failure, because the exception synchronizes the context.

A broadcast TLBI (tlbi vmalle1is, dsb ish) in place of the local one does not help. The ISB after the TTBR0 write does: 5 of 5 boots reach NSH, and ostest with POSIX fork() (#19773) exits with status 0, with CONFIG_TESTING_OSTEST_RR_RUNS=2000. With the default of 10 runs, the round robin test fails on this fast host, because each run completes within one time slice.

Under TCG, ostest on the same image exits with status 0, as before. TCG has no walk caches, so it does not show the problem.

tools/checkpatch.sh -c -u -m -g passes.

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 <marco.casaroli@gmail.com>
@casaroli
casaroli requested a review from pussuw as a code owner October 7, 2026 22:46
@github-actions github-actions Bot added Arch: arm64 Issues related to ARM64 (64-bit) architecture Size: XS The size of the change in this PR is very small labels Oct 7, 2026
@github-actions

github-actions Bot commented Oct 7, 2026

Copy link
Copy Markdown

MemBrowse Memory Report

No memory changes detected for:

@acassis
acassis merged commit baeedc5 into apache:master Oct 8, 2026
25 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Arch: arm64 Issues related to ARM64 (64-bit) architecture Size: XS The size of the change in this PR is very small

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants