Hello,
I got a little problem in ARMv8's MMU.
Obviously, when we access the kernel virtual address in application such as :
unsigned long *p = 0xffffffff28008000; unsigned long x = *p; *p = 1;
The application will be killed by kernel and then reports "segment fault".
But What the actual action does by MMU in ARMv8? When does it find the permission fault?
In the first time it gets the VA? OR when MMU obtains the value from the TTBR1_EL1? OR at the time when MMU translates the table and gets some descriptor which determines the permission?
Different OSs might take slightly different approaches. But...The architecture gives a kernel developer a few different ways to handle this.
One approach would be to disable access to the entirety of kernel space from user space. There is a pair of top-level controls, called TCR_ELx.E0PDx, which can disable EL0 access to either half of the virtual address space.
Arm A-profile Architecture Registers
For example, setting TCR_EL1.E0PD1 causes any unprivileged access to trigger a translation fault. The MMU doesn't need to a TLB look-up/table walk to do this. If the control is set, all the MMU has to do is look which half of the address space is being accessed and where the access came from.
Another more software approach is to unmap most of kernel space before entering EL0 (and potentially setting TCR_ELn.EPDn). Again, any attempt to access (most) kernel mappings will then fault. If EPDn is set, then again the MMU doesn't require a table walk to make this determination. BUT when you next re-enter the kernel, the kernel will need to restore its mappings.Or, you could do it per-page using permissions. Each valid page has a set of permissions associated with it (e.g. read-able, executable). For the EL0/1 (and EL0/2) translation regimes you can specify different user (EL0) and privileged (EL1) permissions. To perform a permission check the MMU first has to have the translation. When you access the page it will check the TLB for a cached permission, if there's none there the MMU performs a table walk. Once it has the translation it compares the configured permission to the attempted access, faulting if necessary.
Thanks for your answer.
In my circumstance, I just use Linux OS. And I made a module to check what TCR_EL1's value is. I found that in my processor, the TCR_EL1.E0PD1 ==0 and TCR_EL1.EPDn==0. And in my test_module, I Set the page table descriptor (translated from TTBR1_EL1) 's AP filed to be 0b01 (means allow user rw).
But after all of things done, I still get "segment fault" when access kernel virtual address in user application.
So, I still have this question.
In that case, you need to check the ESR_EL1 value being reported when the MMU faults the access. The syndrome will tell you why access was blocked.
Besides the check of ESR_EL1 as from Martin, another thought is to make sure that your AP bits on the right page table entry for this virtual address. there are some unused kernel VA holes . fffffe0000000000 - ffffffffffffffff (2TB ) guard region. and your VA is under this region.
more info: www.kernel.org/.../memory.rst