I encountered a problem about replacing the active TTBR0_EL2 register. It seems that the new data loading does not use the new page table, or the instruction execution is messed up. In short, Data Abort is triggered, and ISS indicates that the error details are at translation level 1.
I compared the process of modifying the page table base address in the Linux kernel and found that the Linux kernel added an `isb` instruction between modifying ttbr and TLB refresh. So I added it and found that everything worked fine. I read the ARM manual and some online information, but I didn't figure out why.
isb`
dsb`
Configuration: MMU on, dcache off, icache off
```asm; linux/arch/arm64/mm/proc.S .macro __idmap_cpu_set_reserved_ttbr1, tmp1, tmp2 adrp \tmp1, reserved_pg_dir phys_to_ttbr \tmp2, \tmp1 offset_ttbr1 \tmp2, \tmp1 msr ttbr1_el1, \tmp2 isb tlbi vmalle1 dsb nsh isb .endm```
BTW, do you think break-before-make is necessary for me? (Now I run in EL2 low address, and I try to change TTBR0_EL2 to a whole new page table)
It depends on what you're trying to achieve.
The advantage of break-before-make (BBM) is predictability. TLBs are not permitted to cache invalid translations (ones that result in a Translation Fault). BBM therefore lets you ensure that the old and new translation can't be the TLB at the same time (which would be a bad thing).
But you don't always need that. For example, if you're doing a task switch, the different tasks would be typically be ASID (or ASID+VMID) tagged. It's perfectly valid to have the same translation in the TLBs if they're tagged with different ASIDs. That assumes that you can atomically switch the TTBR and ASID, which in AArch64 you can.