ARM: 6943/1: mm: use TTBR1 instead of reserved context ID
authorWill Deacon <will.deacon@arm.com>
Thu, 26 May 2011 10:23:43 +0000 (11:23 +0100)
committerRussell King <rmk+kernel@arm.linux.org.uk>
Thu, 26 May 2011 11:14:33 +0000 (12:14 +0100)
On ARMv7 CPUs that cache first level page table entries (like the
Cortex-A15), using a reserved ASID while changing the TTBR or flushing
the TLB is unsafe.

This is because the CPU may cache the first level entry as the result of
a speculative memory access while the reserved ASID is assigned. After
the process owning the page tables dies, the memory will be reallocated
and may be written with junk values which can be interpreted as global,
valid PTEs by the processor. This will result in the TLB being populated
with bogus global entries.

This patch avoids the use of a reserved context ID in the v7 switch_mm
and ASID rollover code by temporarily using the swapper_pg_dir pointed
at by TTBR1, which contains only global entries that are not tagged
with ASIDs.

Acked-by: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Will Deacon <will.deacon@arm.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
arch/arm/mm/context.c
arch/arm/mm/proc-v7.S

index b0ee9ba3cfab41a52853eca727466abff88ddf27..0d86298c7279b1367171a8b29e92b2c48fc61ed3 100644 (file)
@@ -24,9 +24,7 @@ DEFINE_PER_CPU(struct mm_struct *, current_mm);
 
 /*
  * We fork()ed a process, and we need a new context for the child
- * to run in.  We reserve version 0 for initial tasks so we will
- * always allocate an ASID. The ASID 0 is reserved for the TTBR
- * register changing sequence.
+ * to run in.
  */
 void __init_new_context(struct task_struct *tsk, struct mm_struct *mm)
 {
@@ -36,8 +34,11 @@ void __init_new_context(struct task_struct *tsk, struct mm_struct *mm)
 
 static void flush_context(void)
 {
-       /* set the reserved ASID before flushing the TLB */
-       asm("mcr        p15, 0, %0, c13, c0, 1\n" : : "r" (0));
+       u32 ttb;
+       /* Copy TTBR1 into TTBR0 */
+       asm volatile("mrc       p15, 0, %0, c2, c0, 1\n"
+                    "mcr       p15, 0, %0, c2, c0, 0"
+                    : "=r" (ttb));
        isb();
        local_flush_tlb_all();
        if (icache_is_vivt_asid_tagged()) {
index 3c3867850a3011d1e163d347a25ffbabc4aa4dc7..b3b566ec83d397c1074c1dcbee0d5e33542e7d9c 100644 (file)
@@ -108,18 +108,16 @@ ENTRY(cpu_v7_switch_mm)
 #ifdef CONFIG_ARM_ERRATA_430973
        mcr     p15, 0, r2, c7, c5, 6           @ flush BTAC/BTB
 #endif
-#ifdef CONFIG_ARM_ERRATA_754322
-       dsb
-#endif
-       mcr     p15, 0, r2, c13, c0, 1          @ set reserved context ID
-       isb
-1:     mcr     p15, 0, r0, c2, c0, 0           @ set TTB 0
+       mrc     p15, 0, r2, c2, c0, 1           @ load TTB 1
+       mcr     p15, 0, r2, c2, c0, 0           @ into TTB 0
        isb
 #ifdef CONFIG_ARM_ERRATA_754322
        dsb
 #endif
        mcr     p15, 0, r1, c13, c0, 1          @ set context ID
        isb
+       mcr     p15, 0, r0, c2, c0, 0           @ set TTB 0
+       isb
 #endif
        mov     pc, lr
 ENDPROC(cpu_v7_switch_mm)