mirror of
https://github.com/apache/nuttx.git
synced 2026-10-10 07:40:27 +00:00
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 <marco.casaroli@gmail.com>
This commit is contained in:
parent
f3721d83d0
commit
baeedc5009
1 changed files with 6 additions and 0 deletions
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue