I have a quick question about TLBs and ASIDs in ARMv8-A.
From what I understand (from ARM's programmer guide and Architecture Reference Manual) :
- Page/block descriptors (leaf MMU table entries) do not contain an ASID identifier, only a nG (non-global) bit, which says the ASID should be used for this page.
- The actual ASID value that is matched against the register value resides in the TLB. It is set when a page walk occurs and the corresponding entry is added to the TLB (with the current ASID, so that subsequent TLB lookups will check that the new ASID matches).
Say I want to use ASIDs to avoid updating tables when context switching. Each process has a resident ASID value. Process 1 some data at vaddr a1
, process 2 at vaddr a2
. I context switch from 1 to 2. During execution the TLB entry corresponding to a1
gets ejected (for some reason). Process 2 accesses a1
, a TLB miss occurs, and a page walk happens, succeeds and stores process 1's entry using ASID2 value, giving process 2 access to process 1's data.
What am I not understanding? Shouldn't the ASID mechanic provide security between process 1 and 2 while avoiding updating tables?
Optional question: if all my programs have .text
section at the same virtual address (at least, all programs have the same entry point address), do I need to update tables every time I context switch or can I have several entries matching the same vaddr, using different ASIDs?
It seems I had a misconception about ASIDs. I got the answer thanks to @artlessnoise's comment.
In the case I was describing, I missed the fact that we have to map process 2's pages at some point.
So what we actually do is this:
- Update tables: add process 2's pages, and remove any page process 2 must not see (including, in my example, page at address a1
)
- Change the ASID so any cached value with an old ASID cannot be used in TLB
- Start process 2. If process 1's corresponding page is still cached in TLB, it is ignored (since ASIDs mismatch). In both cases, a page walk happens, with the updated table containing only process-2-accessible pages.
So the (main) security is provided by the tables present when process 2 is running. And additional security in the TLB only is provided by the ASID mechanic, allowing us to not flush the TLB at every context switch.
EDIT: Another (far-fetched) solution would be to disable page walks for non-cached pages (trigger a MMU fault instead), and to manually check (from the kernel) process permissions every time a process accesses a non-cached page. It seems horrible performance-wise (as well as design-wise).