1
2#ifndef __ASMARM_TLS_H
3#define __ASMARM_TLS_H
4
5#include <linux/compiler.h>
6#include <asm/thread_info.h>
7
8#ifdef __ASSEMBLY__
9#include <asm/asm-offsets.h>
10 .macro switch_tls_none, base, tp, tpuser, tmp1, tmp2
11 .endm
12
13 .macro switch_tls_v6k, base, tp, tpuser, tmp1, tmp2
14 mrc p15, 0, \tmp2, c13, c0, 2 @ get the user r/w register
15 @ TLS register update is deferred until return to user space
16 mcr p15, 0, \tpuser, c13, c0, 2 @ set the user r/w register
17 str \tmp2, [\base, #TI_TP_VALUE + 4] @ save it
18 .endm
19
20 .macro switch_tls_v6, base, tp, tpuser, tmp1, tmp2
21 ldr \tmp1, =elf_hwcap
22 ldr \tmp1, [\tmp1, #0]
23 mov \tmp2, #0xffff0fff
24 tst \tmp1, #HWCAP_TLS @ hardware TLS available?
25 streq \tp, [\tmp2, #-15] @ set TLS value at 0xffff0ff0
26 mrcne p15, 0, \tmp2, c13, c0, 2 @ get the user r/w register
27 mcrne p15, 0, \tp, c13, c0, 3 @ yes, set TLS register
28 mcrne p15, 0, \tpuser, c13, c0, 2 @ set user r/w register
29 strne \tmp2, [\base, #TI_TP_VALUE + 4] @ save it
30 .endm
31
32 .macro switch_tls_software, base, tp, tpuser, tmp1, tmp2
33 mov \tmp1, #0xffff0fff
34 str \tp, [\tmp1, #-15] @ set TLS value at 0xffff0ff0
35 .endm
36#endif
37
38#ifdef CONFIG_TLS_REG_EMUL
39#define tls_emu 1
40#define has_tls_reg 1
41#define defer_tls_reg_update 0
42#define switch_tls switch_tls_none
43#elif defined(CONFIG_CPU_V6)
44#define tls_emu 0
45#define has_tls_reg (elf_hwcap & HWCAP_TLS)
46#define defer_tls_reg_update 0
47#define switch_tls switch_tls_v6
48#elif defined(CONFIG_CPU_32v6K)
49#define tls_emu 0
50#define has_tls_reg 1
51#define defer_tls_reg_update 1
52#define switch_tls switch_tls_v6k
53#else
54#define tls_emu 0
55#define has_tls_reg 0
56#define defer_tls_reg_update 0
57#define switch_tls switch_tls_software
58#endif
59
60#ifndef __ASSEMBLY__
61
62static inline void set_tls(unsigned long val)
63{
64 struct thread_info *thread;
65
66 thread = current_thread_info();
67
68 thread->tp_value[0] = val;
69
70
71
72
73
74
75
76
77
78
79
80
81
82 barrier();
83
84 if (!tls_emu && !defer_tls_reg_update) {
85 if (has_tls_reg) {
86 asm("mcr p15, 0, %0, c13, c0, 3"
87 : : "r" (val));
88 } else {
89#ifdef CONFIG_KUSER_HELPERS
90
91
92
93
94
95
96
97 *((unsigned int *)0xffff0ff0) = val;
98#endif
99 }
100
101 }
102}
103
104static inline unsigned long get_tpuser(void)
105{
106 unsigned long reg = 0;
107
108 if (has_tls_reg && !tls_emu)
109 __asm__("mrc p15, 0, %0, c13, c0, 2" : "=r" (reg));
110
111 return reg;
112}
113
114static inline void set_tpuser(unsigned long val)
115{
116
117
118
119 if (has_tls_reg && !tls_emu) {
120 asm("mcr p15, 0, %0, c13, c0, 2"
121 : : "r" (val));
122 }
123}
124
125static inline void flush_tls(void)
126{
127 set_tls(0);
128 set_tpuser(0);
129}
130
131#endif
132#endif
133