0001
0002 #ifndef __ASMARM_TLS_H
0003 #define __ASMARM_TLS_H
0004
0005 #include <linux/compiler.h>
0006 #include <asm/thread_info.h>
0007
0008 #ifdef __ASSEMBLY__
0009 #include <asm/asm-offsets.h>
0010 .macro switch_tls_none, base, tp, tpuser, tmp1, tmp2
0011 .endm
0012
0013 .macro switch_tls_v6k, base, tp, tpuser, tmp1, tmp2
0014 mrc p15, 0, \tmp2, c13, c0, 2 @ get the user r/w register
0015 @ TLS register update is deferred until return to user space
0016 mcr p15, 0, \tpuser, c13, c0, 2 @ set the user r/w register
0017 str \tmp2, [\base, #TI_TP_VALUE + 4] @ save it
0018 .endm
0019
0020 .macro switch_tls_v6, base, tp, tpuser, tmp1, tmp2
0021 #ifdef CONFIG_SMP
0022 ALT_SMP(nop)
0023 ALT_UP_B(.L0_\@)
0024 .subsection 1
0025 #endif
0026 .L0_\@:
0027 ldr_va \tmp1, elf_hwcap
0028 mov \tmp2, #0xffff0fff
0029 tst \tmp1, #HWCAP_TLS @ hardware TLS available?
0030 streq \tp, [\tmp2, #-15] @ set TLS value at 0xffff0ff0
0031 beq .L2_\@
0032 mcr p15, 0, \tp, c13, c0, 3 @ yes, set TLS register
0033 #ifdef CONFIG_SMP
0034 b .L1_\@
0035 .previous
0036 #endif
0037 .L1_\@: switch_tls_v6k \base, \tp, \tpuser, \tmp1, \tmp2
0038 .L2_\@:
0039 .endm
0040
0041 .macro switch_tls_software, base, tp, tpuser, tmp1, tmp2
0042 mov \tmp1, #0xffff0fff
0043 str \tp, [\tmp1, #-15] @ set TLS value at 0xffff0ff0
0044 .endm
0045 #else
0046 #include <asm/smp_plat.h>
0047 #endif
0048
0049 #ifdef CONFIG_TLS_REG_EMUL
0050 #define tls_emu 1
0051 #define has_tls_reg 1
0052 #define defer_tls_reg_update 0
0053 #define switch_tls switch_tls_none
0054 #elif defined(CONFIG_CPU_V6)
0055 #define tls_emu 0
0056 #define has_tls_reg (elf_hwcap & HWCAP_TLS)
0057 #define defer_tls_reg_update is_smp()
0058 #define switch_tls switch_tls_v6
0059 #elif defined(CONFIG_CPU_32v6K)
0060 #define tls_emu 0
0061 #define has_tls_reg 1
0062 #define defer_tls_reg_update 1
0063 #define switch_tls switch_tls_v6k
0064 #else
0065 #define tls_emu 0
0066 #define has_tls_reg 0
0067 #define defer_tls_reg_update 0
0068 #define switch_tls switch_tls_software
0069 #endif
0070
0071 #ifndef __ASSEMBLY__
0072
0073 static inline void set_tls(unsigned long val)
0074 {
0075 struct thread_info *thread;
0076
0077 thread = current_thread_info();
0078
0079 thread->tp_value[0] = val;
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090
0091
0092
0093 barrier();
0094
0095 if (!tls_emu) {
0096 if (has_tls_reg && !defer_tls_reg_update) {
0097 asm("mcr p15, 0, %0, c13, c0, 3"
0098 : : "r" (val));
0099 } else if (!has_tls_reg) {
0100 #ifdef CONFIG_KUSER_HELPERS
0101
0102
0103
0104
0105
0106
0107
0108 *((unsigned int *)0xffff0ff0) = val;
0109 #endif
0110 }
0111
0112 }
0113 }
0114
0115 static inline unsigned long get_tpuser(void)
0116 {
0117 unsigned long reg = 0;
0118
0119 if (has_tls_reg && !tls_emu)
0120 __asm__("mrc p15, 0, %0, c13, c0, 2" : "=r" (reg));
0121
0122 return reg;
0123 }
0124
0125 static inline void set_tpuser(unsigned long val)
0126 {
0127
0128
0129
0130 if (has_tls_reg && !tls_emu) {
0131 asm("mcr p15, 0, %0, c13, c0, 2"
0132 : : "r" (val));
0133 }
0134 }
0135
0136 static inline void flush_tls(void)
0137 {
0138 set_tls(0);
0139 set_tpuser(0);
0140 }
0141
0142 #endif
0143 #endif