[PATCH 1/1 V2] Add Thread Support for the Context ID Register of ARM v6 & v7 Architectures

Will Deacon will.deacon at arm.com
Tue Jul 19 12:43:43 EDT 2011


On Tue, Jul 19, 2011 at 06:21:41AM +0100, Wolfgang BETZ wrote:
>     We don't use fake PIDs for anything. The only thing that can go wrong is
>     during task switch where we switch the mm and then switch the PID in your
>     thread notifier. Reading the context ID between these two points will give
>     you the PID of the previous task.
> 
> Well, don't we set the CONTEXTIDR also during mm switch (in cpu_switch_mm())?
> And in this occasion we will copy the value coming from mm->context.id, i.e.
> with a "PID" value which does not correspond to a thread identifier but to what
> is used for ASID rollover handling!?! I am afraid that this will/can confuse
> external tools.

Yes, but that's easy to fix. We just make switch_mm do read-modify-write of
the upper bits. It also doesn't require us to change the type signature of
that function (see patch below)

> Furthermore, I do not like the idea that we are sending out over the trace
> logic two times the CONTEXTIDR content for each context switch. Seems not to be
> a very clean solution to me :-\

Fair enough, but I think it's a lot better than changing the ASID handling
code.

>     I don't think this is a big problem since
>     we're in the middle of context switch anyway, so it's hard to define when
>     the thread switch has completed. You just have to be aware that the
>     current mm_struct / ASID may not correspond to the PID. One nice property is
>     that you can be sure the PID is correct once you've returned to userspace.
> 
> OK, once you return to user-space everything will be good, but the tools we are
> talking about here do not care (only) about user- or kernel-space, these want
> to trace both (simultaneously)!

I was just giving an example as to an easy way of knowing when the PID is in
sync with the ASID by looking at traces.

Will


So here's something I hacked up. I've compiled it but that's all. I'm also
not sure that the notifier belongs in mm/context.c and you may or may not want
an isb after updating the register.


diff --git a/arch/arm/mm/context.c b/arch/arm/mm/context.c
index b0ee9ba..59ab68a 100644
--- a/arch/arm/mm/context.c
+++ b/arch/arm/mm/context.c
@@ -14,6 +14,7 @@
 #include <linux/percpu.h>
 
 #include <asm/mmu_context.h>
+#include <asm/thread_notify.h>
 #include <asm/tlbflush.h>
 
 static DEFINE_SPINLOCK(cpu_asid_lock);
@@ -155,3 +156,43 @@ void __new_context(struct mm_struct *mm)
 	set_mm_context(mm, asid);
 	spin_unlock(&cpu_asid_lock);
 }
+
+#ifdef CONFIG_PID_IN_CONTEXTIDR
+static int contextidr_notifier(struct notifier_block *unused, unsigned long cmd,
+			       void *t)
+{
+	unsigned long flags;
+	u32 contextid;
+	struct thread_info *thread = t;
+
+	if (cmd != THREAD_NOTIFY_SWITCH)
+		return NOTIFY_DONE;
+
+	local_irq_save(flags);
+	asm volatile("mrc	p15, 0, %0, c15, c0, 1\n"
+		     "bic	%0, %0, #0xffffff00\n"
+		     "orr	%0, %0, %1, lsl #8\n"
+		     "mcr	p15, 0, %0, c15, c0, 1"
+		     : "=&r" (contextid)
+		     : "r" (task_tgid_vnr(thread->task)));
+	local_irq_restore(flags);
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block contextidr_notifier_block = {
+	.notifier_call = contextidr_notifier,
+};
+
+static int __init contextidr_init(void)
+{
+	unsigned int cpu_arch = cpu_architecture();
+
+	if (cpu_arch < CPU_ARCH_ARMv6)
+		return 0;
+
+	thread_register_notifier(&contextidr_notifier_block);
+	return 0;
+}
+arch_initcall(contextidr_init);
+#endif
diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S
index 089c0b5..3605c00 100644
--- a/arch/arm/mm/proc-v7.S
+++ b/arch/arm/mm/proc-v7.S
@@ -111,6 +111,12 @@ ENTRY(cpu_v7_switch_mm)
 #ifdef CONFIG_ARM_ERRATA_754322
 	dsb
 #endif
+#ifdef CONFIG_PID_IN_CONTEXTIDR
+	mrc	p15, 0, r2, c15, c0, 1
+	bic	r2, r2, #0xff
+	bfc	r1, #8, #24
+	orr	r1, r1, r2
+#endif
 	mcr	p15, 0, r2, c13, c0, 1		@ set reserved context ID
 	isb
 1:	mcr	p15, 0, r0, c2, c0, 0		@ set TTB 0




More information about the linux-arm-kernel mailing list