Processors that implement the ARMv8-A architecture are typically used in systems running a complex operating system with many applications or tasks that run concurrently. When an application starts, the operating system allocates it a set of translation table entries that map both the code and data that is used by the application to physical memory. Each application therefore has its own unique translation tables residing in physical memory. These tables can be modified later by the kernel, for example, to map in extra memory space, and are removed when the application is no longer running.
Normally, it is likely that there are multiple tasks present in the memory system. The kernel scheduler periodically transfers execution from one task to another. This is called a context switch and requires the kernel to save all Execution state that is associated with the process and to restore the state of the process to be run next. The kernel also switches translation table entries to those of the next process to be run. The memory of the tasks that are not currently running is protected from the task that is running.
Exactly what has to be saved and restored varies between different operating systems, but typically a process context switch includes saving or restoring some or all of the following elements:
- General-purpose registers (X0 - X30).
- Advanced SIMD and floating-point registers (V0 - V31).
- Some status registers.
- TTBR0_EL1 and TTBR0.
- Thread Process ID (TPIDxxx) Registers.
- Address Space ID (ASID).
For EL0 and EL1, there are two translation tables. TTBR0_EL1 provides translations for the bottom of the virtual address space, which is typically application space and TTBR1_EL1 covers the top of the virtual address space, typically kernel space. This split means that the OS mappings do not have to be replicated in the translation tables of each task.
Translation table entries contain a non-global (nG) bit. If the nG bit is set for a particular page, it is associated with a specific task or application. If the bit is marked as 0, then the entry is global and applies to all tasks.
For non-global entries, when the TLB is updated and the entry is marked as non-global, a value is stored in the TLB entry in addition to the normal translation information. This value is called the Address Space ID, which is a number that is assigned by the OS to each individual task.
Subsequent TLB look-ups only match on that entry if the current ASID matches with the ASID stored in the entry. This enables multiple valid TLB entries to be present for a particular page that is marked as non-global, but with different ASID values. In other words, it is not necessary to clean or invalidate the TLBs when context switching takes place.
This ASID value can be specified as either an 8-bit or 16-bit value, which is controlled by the TCR_EL1.AS bit. The current ASID value is specified in either TTBR0_EL1 or TTBR1_EL1. TCR_EL1 controls which TTBR holds the ASID, but typically, it is TTBR0_EL1, as this corresponds to application space.
Having the current value of the ASID stored in the translation table register means that both the translation tables and the ASID can be atomically modified in a single instruction. This simplifies the process of changing the table and ASID when compared with the ARMv7-A architecture.
Additionally, the ARMv8-A architecture provides Thread ID registers for use by operating system software. These have no hardware significance and are typically used by threading libraries as a base pointer to per-thread data. This is often referred to as Thread Local Storage (TLS). For example, the Pthreads library uses this feature and includes the following registers:
- User Read and Write Thread ID Register (TPIDR_EL0).
- User Read-Only Thread ID Register (TPIDRRO_EL0).
- Thread ID Register, privileged accesses only (TPIDR_EL1).