ARM: 8148/1: flush TLS and thumbee register state during exec
[platform/adaptation/renesas_rcar/renesas_kernel.git] / arch / arm / include / asm / tls.h
index 83259b8..36172ad 100644 (file)
@@ -1,6 +1,9 @@
 #ifndef __ASMARM_TLS_H
 #define __ASMARM_TLS_H
 
+#include <linux/compiler.h>
+#include <asm/thread_info.h>
+
 #ifdef __ASSEMBLY__
 #include <asm/asm-offsets.h>
        .macro switch_tls_none, base, tp, tpuser, tmp1, tmp2
 #endif
 
 #ifndef __ASSEMBLY__
+
+static inline void set_tls(unsigned long val)
+{
+       struct thread_info *thread;
+
+       thread = current_thread_info();
+
+       thread->tp_value[0] = val;
+
+       /*
+        * This code runs with preemption enabled and therefore must
+        * be reentrant with respect to switch_tls.
+        *
+        * We need to ensure ordering between the shadow state and the
+        * hardware state, so that we don't corrupt the hardware state
+        * with a stale shadow state during context switch.
+        *
+        * If we're preempted here, switch_tls will load TPIDRURO from
+        * thread_info upon resuming execution and the following mcr
+        * is merely redundant.
+        */
+       barrier();
+
+       if (!tls_emu) {
+               if (has_tls_reg) {
+                       asm("mcr p15, 0, %0, c13, c0, 3"
+                           : : "r" (val));
+               } else {
+                       /*
+                        * 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 int *)0xffff0ff0) = val;
+               }
+
+       }
+}
+
 static inline unsigned long get_tpuser(void)
 {
        unsigned long reg = 0;
@@ -59,5 +103,23 @@ static inline unsigned long get_tpuser(void)
 
        return reg;
 }
+
+static inline void set_tpuser(unsigned long val)
+{
+       /* Since TPIDRURW is fully context-switched (unlike TPIDRURO),
+        * we need not update thread_info.
+        */
+       if (has_tls_reg && !tls_emu) {
+               asm("mcr p15, 0, %0, c13, c0, 2"
+                   : : "r" (val));
+       }
+}
+
+static inline void flush_tls(void)
+{
+       set_tls(0);
+       set_tpuser(0);
+}
+
 #endif
 #endif /* __ASMARM_TLS_H */