aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/include/asm
diff options
context:
space:
mode:
authorAndré Hentschel <nerv@dawncrow.de>2013-06-18 18:23:26 -0400
committerRussell King <rmk+kernel@arm.linux.org.uk>2013-06-24 10:21:59 -0400
commita4780adeefd042482f624f5e0d577bf9cdcbb760 (patch)
treeead0e79b4f797a26cc30fc1596ada6fd6da5daf6 /arch/arm/include/asm
parent4a1b573346ee0d64d95beb78d49a5bbb574e6c6a (diff)
ARM: 7735/2: Preserve the user r/w register TPIDRURW on context switch and fork
Since commit 6a1c53124aa1 the user writeable TLS register was zeroed to prevent it from being used as a covert channel between two tasks. There are more and more applications coming to Windows RT, Wine could support them, but mostly they expect to have the thread environment block (TEB) in TPIDRURW. This patch preserves that register per thread instead of clearing it. Unlike the TPIDRURO, which is already switched, the TPIDRURW can be updated from userspace so needs careful treatment in the case that we modify TPIDRURW and call fork(). To avoid this we must always read TPIDRURW in copy_thread. Signed-off-by: André Hentschel <nerv@dawncrow.de> Signed-off-by: Will Deacon <will.deacon@arm.com> Signed-off-by: Jonathan Austin <jonathan.austin@arm.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm/include/asm')
-rw-r--r--arch/arm/include/asm/thread_info.h2
-rw-r--r--arch/arm/include/asm/tls.h40
2 files changed, 28 insertions, 14 deletions
diff --git a/arch/arm/include/asm/thread_info.h b/arch/arm/include/asm/thread_info.h
index 1995d1a84060..214d4158089a 100644
--- a/arch/arm/include/asm/thread_info.h
+++ b/arch/arm/include/asm/thread_info.h
@@ -58,7 +58,7 @@ struct thread_info {
58 struct cpu_context_save cpu_context; /* cpu context */ 58 struct cpu_context_save cpu_context; /* cpu context */
59 __u32 syscall; /* syscall number */ 59 __u32 syscall; /* syscall number */
60 __u8 used_cp[16]; /* thread used copro */ 60 __u8 used_cp[16]; /* thread used copro */
61 unsigned long tp_value; 61 unsigned long tp_value[2]; /* TLS registers */
62#ifdef CONFIG_CRUNCH 62#ifdef CONFIG_CRUNCH
63 struct crunch_state crunchstate; 63 struct crunch_state crunchstate;
64#endif 64#endif
diff --git a/arch/arm/include/asm/tls.h b/arch/arm/include/asm/tls.h
index 73409e6c0251..83259b873333 100644
--- a/arch/arm/include/asm/tls.h
+++ b/arch/arm/include/asm/tls.h
@@ -2,27 +2,30 @@
2#define __ASMARM_TLS_H 2#define __ASMARM_TLS_H
3 3
4#ifdef __ASSEMBLY__ 4#ifdef __ASSEMBLY__
5 .macro set_tls_none, tp, tmp1, tmp2 5#include <asm/asm-offsets.h>
6 .macro switch_tls_none, base, tp, tpuser, tmp1, tmp2
6 .endm 7 .endm
7 8
8 .macro set_tls_v6k, tp, tmp1, tmp2 9 .macro switch_tls_v6k, base, tp, tpuser, tmp1, tmp2
10 mrc p15, 0, \tmp2, c13, c0, 2 @ get the user r/w register
9 mcr p15, 0, \tp, c13, c0, 3 @ set TLS register 11 mcr p15, 0, \tp, c13, c0, 3 @ set TLS register
10 mov \tmp1, #0 12 mcr p15, 0, \tpuser, c13, c0, 2 @ and the user r/w register
11 mcr p15, 0, \tmp1, c13, c0, 2 @ clear user r/w TLS register 13 str \tmp2, [\base, #TI_TP_VALUE + 4] @ save it
12 .endm 14 .endm
13 15
14 .macro set_tls_v6, tp, tmp1, tmp2 16 .macro switch_tls_v6, base, tp, tpuser, tmp1, tmp2
15 ldr \tmp1, =elf_hwcap 17 ldr \tmp1, =elf_hwcap
16 ldr \tmp1, [\tmp1, #0] 18 ldr \tmp1, [\tmp1, #0]
17 mov \tmp2, #0xffff0fff 19 mov \tmp2, #0xffff0fff
18 tst \tmp1, #HWCAP_TLS @ hardware TLS available? 20 tst \tmp1, #HWCAP_TLS @ hardware TLS available?
19 mcrne p15, 0, \tp, c13, c0, 3 @ yes, set TLS register
20 movne \tmp1, #0
21 mcrne p15, 0, \tmp1, c13, c0, 2 @ clear user r/w TLS register
22 streq \tp, [\tmp2, #-15] @ set TLS value at 0xffff0ff0 21 streq \tp, [\tmp2, #-15] @ set TLS value at 0xffff0ff0
22 mrcne p15, 0, \tmp2, c13, c0, 2 @ get the user r/w register
23 mcrne p15, 0, \tp, c13, c0, 3 @ yes, set TLS register
24 mcrne p15, 0, \tpuser, c13, c0, 2 @ set user r/w register
25 strne \tmp2, [\base, #TI_TP_VALUE + 4] @ save it
23 .endm 26 .endm
24 27
25 .macro set_tls_software, tp, tmp1, tmp2 28 .macro switch_tls_software, base, tp, tpuser, tmp1, tmp2
26 mov \tmp1, #0xffff0fff 29 mov \tmp1, #0xffff0fff
27 str \tp, [\tmp1, #-15] @ set TLS value at 0xffff0ff0 30 str \tp, [\tmp1, #-15] @ set TLS value at 0xffff0ff0
28 .endm 31 .endm
@@ -31,19 +34,30 @@
31#ifdef CONFIG_TLS_REG_EMUL 34#ifdef CONFIG_TLS_REG_EMUL
32#define tls_emu 1 35#define tls_emu 1
33#define has_tls_reg 1 36#define has_tls_reg 1
34#define set_tls set_tls_none 37#define switch_tls switch_tls_none
35#elif defined(CONFIG_CPU_V6) 38#elif defined(CONFIG_CPU_V6)
36#define tls_emu 0 39#define tls_emu 0
37#define has_tls_reg (elf_hwcap & HWCAP_TLS) 40#define has_tls_reg (elf_hwcap & HWCAP_TLS)
38#define set_tls set_tls_v6 41#define switch_tls switch_tls_v6
39#elif defined(CONFIG_CPU_32v6K) 42#elif defined(CONFIG_CPU_32v6K)
40#define tls_emu 0 43#define tls_emu 0
41#define has_tls_reg 1 44#define has_tls_reg 1
42#define set_tls set_tls_v6k 45#define switch_tls switch_tls_v6k
43#else 46#else
44#define tls_emu 0 47#define tls_emu 0
45#define has_tls_reg 0 48#define has_tls_reg 0
46#define set_tls set_tls_software 49#define switch_tls switch_tls_software
47#endif 50#endif
48 51
52#ifndef __ASSEMBLY__
53static inline unsigned long get_tpuser(void)
54{
55 unsigned long reg = 0;
56
57 if (has_tls_reg && !tls_emu)
58 __asm__("mrc p15, 0, %0, c13, c0, 2" : "=r" (reg));
59
60 return reg;
61}
62#endif
49#endif /* __ASMARM_TLS_H */ 63#endif /* __ASMARM_TLS_H */