ARM: 7445/1: mm: update CONTEXTIDR register to contain PID of current process
authorWill Deacon <will.deacon@arm.com>
Fri, 6 Jul 2012 14:43:03 +0000 (15:43 +0100)
committerRussell King <rmk+kernel@arm.linux.org.uk>
Mon, 9 Jul 2012 16:41:10 +0000 (17:41 +0100)
This patch introduces a new Kconfig option which, when enabled, causes
the kernel to write the PID of the current task into the PROCID field
of the CONTEXTIDR on context switch. This is useful when analysing
hardware trace, since writes to this register can be configured to emit
an event into the trace stream.

The thread notifier for writing the PID is deliberately kept separate
from the ASID-writing code so that we can support newer processors using
LPAE, where the ASID is stored in TTBR0. As such, the switch_mm code is
updated to perform a read-modify-write sequence to ensure that we don't
clobber the PID on CPUs using the classic 2-level page tables.

Signed-off-by: Will Deacon <will.deacon@arm.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
arch/arm/Kconfig.debug
arch/arm/mm/context.c
arch/arm/mm/proc-v6.S
arch/arm/mm/proc-v7-2level.S

index 01a134141216a1a02f5fec43defa8768ad72fa26..521e15bc6401b8cd1246141260c74180ff9b1f6a 100644 (file)
@@ -369,4 +369,13 @@ config ARM_KPROBES_TEST
        help
          Perform tests of kprobes API and instruction set simulation.
 
+config PID_IN_CONTEXTIDR
+       bool "Write the current PID to the CONTEXTIDR register"
+       depends on CPU_COPY_V6
+       help
+         Enabling this option causes the kernel to write the current PID to
+         the PROCID field of the CONTEXTIDR register, at the expense of some
+         additional instructions during context switch. Say Y here only if you
+         are planning to use hardware trace tools with this kernel.
+
 endmenu
index 806cc4f63516fd4bfddecad4ec93be51a830f49a..119bc52ab93ed7675d4528a779e97270d308c70e 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/percpu.h>
 
 #include <asm/mmu_context.h>
+#include <asm/thread_notify.h>
 #include <asm/tlbflush.h>
 
 static DEFINE_RAW_SPINLOCK(cpu_asid_lock);
@@ -48,6 +49,40 @@ void cpu_set_reserved_ttbr0(void)
 }
 #endif
 
+#ifdef CONFIG_PID_IN_CONTEXTIDR
+static int contextidr_notifier(struct notifier_block *unused, unsigned long cmd,
+                              void *t)
+{
+       u32 contextidr;
+       pid_t pid;
+       struct thread_info *thread = t;
+
+       if (cmd != THREAD_NOTIFY_SWITCH)
+               return NOTIFY_DONE;
+
+       pid = task_pid_nr(thread->task) << ASID_BITS;
+       asm volatile(
+       "       mrc     p15, 0, %0, c13, c0, 1\n"
+       "       bfi     %1, %0, #0, %2\n"
+       "       mcr     p15, 0, %1, c13, c0, 1\n"
+       : "=r" (contextidr), "+r" (pid)
+       : "I" (ASID_BITS));
+       isb();
+
+       return NOTIFY_OK;
+}
+
+static struct notifier_block contextidr_notifier_block = {
+       .notifier_call = contextidr_notifier,
+};
+
+static int __init contextidr_notifier_init(void)
+{
+       return thread_register_notifier(&contextidr_notifier_block);
+}
+arch_initcall(contextidr_notifier_init);
+#endif
+
 /*
  * We fork()ed a process, and we need a new context for the child
  * to run in.
index 5900cd520e8456a9563b387f14f606d081ccaa56..86b8b480634fbc652dbf11dd9d9abaec84fa5e00 100644 (file)
@@ -107,6 +107,12 @@ ENTRY(cpu_v6_switch_mm)
        mcr     p15, 0, r2, c7, c5, 6           @ flush BTAC/BTB
        mcr     p15, 0, r2, c7, c10, 4          @ drain write buffer
        mcr     p15, 0, r0, c2, c0, 0           @ set TTB 0
+#ifdef CONFIG_PID_IN_CONTEXTIDR
+       mrc     p15, 0, r2, c13, c0, 1          @ read current context ID
+       bic     r2, r2, #0xff                   @ extract the PID
+       and     r1, r1, #0xff
+       orr     r1, r1, r2                      @ insert into new context ID
+#endif
        mcr     p15, 0, r1, c13, c0, 1          @ set context ID
 #endif
        mov     pc, lr
index 42ac069c8012bfad83345f62fa814de139614178..fd045e706390dc0ddafb0560d2be66b1568cd69f 100644 (file)
@@ -46,6 +46,11 @@ ENTRY(cpu_v7_switch_mm)
 #ifdef CONFIG_ARM_ERRATA_430973
        mcr     p15, 0, r2, c7, c5, 6           @ flush BTAC/BTB
 #endif
+#ifdef CONFIG_PID_IN_CONTEXTIDR
+       mrc     p15, 0, r2, c13, c0, 1          @ read current context ID
+       lsr     r2, r2, #8                      @ extract the PID
+       bfi     r1, r2, #8, #24                 @ insert into new context ID
+#endif
 #ifdef CONFIG_ARM_ERRATA_754322
        dsb
 #endif