1 #ifndef __ASMARM_TLS_H 2 #define __ASMARM_TLS_H 3 4 #include <linux/compiler.h> 5 #include <asm/thread_info.h> 6 7 #ifdef __ASSEMBLY__ 8 #include <asm/asm-offsets.h> 9 .macro switch_tls_none, base, tp, tpuser, tmp1, tmp2 10 .endm 11 12 .macro switch_tls_v6k, base, tp, tpuser, tmp1, tmp2 13 mrc p15, 0, \tmp2, c13, c0, 2 @ get the user r/w register 14 mcr p15, 0, \tp, c13, c0, 3 @ set TLS register 15 mcr p15, 0, \tpuser, c13, c0, 2 @ and the user r/w register 16 str \tmp2, [\base, #TI_TP_VALUE + 4] @ save it 17 .endm 18 19 .macro switch_tls_v6, base, tp, tpuser, tmp1, tmp2 20 ldr \tmp1, =elf_hwcap 21 ldr \tmp1, [\tmp1, #0] 22 mov \tmp2, #0xffff0fff 23 tst \tmp1, #HWCAP_TLS @ hardware TLS available? 24 streq \tp, [\tmp2, #-15] @ set TLS value at 0xffff0ff0 25 mrcne p15, 0, \tmp2, c13, c0, 2 @ get the user r/w register 26 mcrne p15, 0, \tp, c13, c0, 3 @ yes, set TLS register 27 mcrne p15, 0, \tpuser, c13, c0, 2 @ set user r/w register 28 strne \tmp2, [\base, #TI_TP_VALUE + 4] @ save it 29 .endm 30 31 .macro switch_tls_software, base, tp, tpuser, tmp1, tmp2 32 mov \tmp1, #0xffff0fff 33 str \tp, [\tmp1, #-15] @ set TLS value at 0xffff0ff0 34 .endm 35 #endif 36 37 #ifdef CONFIG_TLS_REG_EMUL 38 #define tls_emu 1 39 #define has_tls_reg 1 40 #define switch_tls switch_tls_none 41 #elif defined(CONFIG_CPU_V6) 42 #define tls_emu 0 43 #define has_tls_reg (elf_hwcap & HWCAP_TLS) 44 #define switch_tls switch_tls_v6 45 #elif defined(CONFIG_CPU_32v6K) 46 #define tls_emu 0 47 #define has_tls_reg 1 48 #define switch_tls switch_tls_v6k 49 #else 50 #define tls_emu 0 51 #define has_tls_reg 0 52 #define switch_tls switch_tls_software 53 #endif 54 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 99 static inline unsigned long get_tpuser(void) 100 { 101 unsigned long reg = 0; 102 103 if (has_tls_reg && !tls_emu) 104 __asm__("mrc p15, 0, %0, c13, c0, 2" : "=r" (reg)); 105 106 return reg; 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 126 #endif 127 #endif /* __ASMARM_TLS_H */ 128