diff options
Diffstat (limited to 'arch/arm/include/asm/tls.h')
-rw-r--r-- | arch/arm/include/asm/tls.h | 64 |
1 files changed, 64 insertions, 0 deletions
diff --git a/arch/arm/include/asm/tls.h b/arch/arm/include/asm/tls.h index 83259b873333..5f833f7adba1 100644 --- a/arch/arm/include/asm/tls.h +++ b/arch/arm/include/asm/tls.h | |||
@@ -1,6 +1,9 @@ | |||
1 | #ifndef __ASMARM_TLS_H | 1 | #ifndef __ASMARM_TLS_H |
2 | #define __ASMARM_TLS_H | 2 | #define __ASMARM_TLS_H |
3 | 3 | ||
4 | #include <linux/compiler.h> | ||
5 | #include <asm/thread_info.h> | ||
6 | |||
4 | #ifdef __ASSEMBLY__ | 7 | #ifdef __ASSEMBLY__ |
5 | #include <asm/asm-offsets.h> | 8 | #include <asm/asm-offsets.h> |
6 | .macro switch_tls_none, base, tp, tpuser, tmp1, tmp2 | 9 | .macro switch_tls_none, base, tp, tpuser, tmp1, tmp2 |
@@ -50,6 +53,49 @@ | |||
50 | #endif | 53 | #endif |
51 | 54 | ||
52 | #ifndef __ASSEMBLY__ | 55 | #ifndef __ASSEMBLY__ |
56 | |||
57 | static inline void set_tls(unsigned long val) | ||
58 | { | ||
59 | struct thread_info *thread; | ||
60 | |||
61 | thread = current_thread_info(); | ||
62 | |||
63 | thread->tp_value[0] = val; | ||
64 | |||
65 | /* | ||
66 | * This code runs with preemption enabled and therefore must | ||
67 | * be reentrant with respect to switch_tls. | ||
68 | * | ||
69 | * We need to ensure ordering between the shadow state and the | ||
70 | * hardware state, so that we don't corrupt the hardware state | ||
71 | * with a stale shadow state during context switch. | ||
72 | * | ||
73 | * If we're preempted here, switch_tls will load TPIDRURO from | ||
74 | * thread_info upon resuming execution and the following mcr | ||
75 | * is merely redundant. | ||
76 | */ | ||
77 | barrier(); | ||
78 | |||
79 | if (!tls_emu) { | ||
80 | if (has_tls_reg) { | ||
81 | asm("mcr p15, 0, %0, c13, c0, 3" | ||
82 | : : "r" (val)); | ||
83 | } else { | ||
84 | #ifdef CONFIG_KUSER_HELPERS | ||
85 | /* | ||
86 | * User space must never try to access this | ||
87 | * directly. Expect your app to break | ||
88 | * eventually if you do so. The user helper | ||
89 | * at 0xffff0fe0 must be used instead. (see | ||
90 | * entry-armv.S for details) | ||
91 | */ | ||
92 | *((unsigned int *)0xffff0ff0) = val; | ||
93 | #endif | ||
94 | } | ||
95 | |||
96 | } | ||
97 | } | ||
98 | |||
53 | static inline unsigned long get_tpuser(void) | 99 | static inline unsigned long get_tpuser(void) |
54 | { | 100 | { |
55 | unsigned long reg = 0; | 101 | unsigned long reg = 0; |
@@ -59,5 +105,23 @@ static inline unsigned long get_tpuser(void) | |||
59 | 105 | ||
60 | return reg; | 106 | return reg; |
61 | } | 107 | } |
108 | |||
109 | static inline void set_tpuser(unsigned long val) | ||
110 | { | ||
111 | /* Since TPIDRURW is fully context-switched (unlike TPIDRURO), | ||
112 | * we need not update thread_info. | ||
113 | */ | ||
114 | if (has_tls_reg && !tls_emu) { | ||
115 | asm("mcr p15, 0, %0, c13, c0, 2" | ||
116 | : : "r" (val)); | ||
117 | } | ||
118 | } | ||
119 | |||
120 | static inline void flush_tls(void) | ||
121 | { | ||
122 | set_tls(0); | ||
123 | set_tpuser(0); | ||
124 | } | ||
125 | |||
62 | #endif | 126 | #endif |
63 | #endif /* __ASMARM_TLS_H */ | 127 | #endif /* __ASMARM_TLS_H */ |