[PATCH] ARM: 2651/3: kernel helpers for NPTL support
[linux-2.6.git] / arch / arm / kernel / traps.c
index 0078aeb..3a001fe 100644 (file)
@@ -450,13 +450,17 @@ asmlinkage int arm_syscall(int no, struct pt_regs *regs)
 
        case NR(set_tls):
                thread->tp_value = regs->ARM_r0;
+#ifdef CONFIG_HAS_TLS_REG
+               asm ("mcr p15, 0, %0, c13, c0, 3" : : "r" (regs->ARM_r0) );
+#else
                /*
-                * Our user accessible TLS ptr is located at 0xffff0ffc.
-                * On SMP read access to this address must raise a fault
-                * and be emulated from the data abort handler.
-                * m
+                * User space must never try to access this directly.
+                * Expect your app to break eventually if you do so.
+                * The user helper at 0xffff0fe0 must be used instead.
+                * (see entry-armv.S for details)
                 */
-               *((unsigned long *)0xffff0ffc) = thread->tp_value;
+               *((unsigned int *)0xffff0ff0) = regs->ARM_r0;
+#endif
                return 0;
 
        default:
@@ -493,6 +497,41 @@ asmlinkage int arm_syscall(int no, struct pt_regs *regs)
        return 0;
 }
 
+#if defined(CONFIG_CPU_32v6) && !defined(CONFIG_HAS_TLS_REG)
+
+/*
+ * We might be running on an ARMv6+ processor which should have the TLS
+ * register, but for some reason we can't use it and have to emulate it.
+ */
+
+static int get_tp_trap(struct pt_regs *regs, unsigned int instr)
+{
+       int reg = (instr >> 12) & 15;
+       if (reg == 15)
+               return 1;
+       regs->uregs[reg] = current_thread_info()->tp_value;
+       regs->ARM_pc += 4;
+       return 0;
+}
+
+static struct undef_hook arm_mrc_hook = {
+       .instr_mask     = 0x0fff0fff,
+       .instr_val      = 0x0e1d0f70,
+       .cpsr_mask      = PSR_T_BIT,
+       .cpsr_val       = 0,
+       .fn             = get_tp_trap,
+};
+
+static int __init arm_mrc_hook_init(void)
+{
+       register_undef_hook(&arm_mrc_hook);
+       return 0;
+}
+
+late_initcall(arm_mrc_hook_init);
+
+#endif
+
 void __bad_xchg(volatile void *ptr, int size)
 {
        printk("xchg: bad data size: pc 0x%p, ptr 0x%p, size %d\n",
@@ -580,14 +619,17 @@ void __init trap_init(void)
 {
        extern char __stubs_start[], __stubs_end[];
        extern char __vectors_start[], __vectors_end[];
+       extern char __kuser_helper_start[], __kuser_helper_end[];
+       int kuser_sz = __kuser_helper_end - __kuser_helper_start;
 
        /*
-        * Copy the vectors and stubs (in entry-armv.S) into the
-        * vector page, mapped at 0xffff0000, and ensure these are
-        * visible to the instruction stream.
+        * Copy the vectors, stubs and kuser helpers (in entry-armv.S)
+        * into the vector page, mapped at 0xffff0000, and ensure these
+        * are visible to the instruction stream.
         */
        memcpy((void *)0xffff0000, __vectors_start, __vectors_end - __vectors_start);
        memcpy((void *)0xffff0200, __stubs_start, __stubs_end - __stubs_start);
+       memcpy((void *)0xffff1000 - kuser_sz, __kuser_helper_start, kuser_sz);
        flush_icache_range(0xffff0000, 0xffff0000 + PAGE_SIZE);
        modify_domain(DOMAIN_USER, DOMAIN_CLIENT);
 }