Greg Kroah-Hartman | b244131 | 2017-11-01 15:07:57 +0100 | [diff] [blame] | 1 | /* SPDX-License-Identifier: GPL-2.0 */ |
Tony Lindgren | f159f4e | 2010-07-05 14:53:10 +0100 | [diff] [blame] | 2 | #ifndef __ASMARM_TLS_H |
| 3 | #define __ASMARM_TLS_H |
| 4 | |
Nathan Lynch | fbfb872 | 2014-09-11 02:49:08 +0100 | [diff] [blame] | 5 | #include <linux/compiler.h> |
| 6 | #include <asm/thread_info.h> |
| 7 | |
Tony Lindgren | f159f4e | 2010-07-05 14:53:10 +0100 | [diff] [blame] | 8 | #ifdef __ASSEMBLY__ |
André Hentschel | a4780ad | 2013-06-18 23:23:26 +0100 | [diff] [blame] | 9 | #include <asm/asm-offsets.h> |
| 10 | .macro switch_tls_none, base, tp, tpuser, tmp1, tmp2 |
Tony Lindgren | f159f4e | 2010-07-05 14:53:10 +0100 | [diff] [blame] | 11 | .endm |
| 12 | |
André Hentschel | a4780ad | 2013-06-18 23:23:26 +0100 | [diff] [blame] | 13 | .macro switch_tls_v6k, base, tp, tpuser, tmp1, tmp2 |
| 14 | mrc p15, 0, \tmp2, c13, c0, 2 @ get the user r/w register |
Tony Lindgren | f159f4e | 2010-07-05 14:53:10 +0100 | [diff] [blame] | 15 | mcr p15, 0, \tp, c13, c0, 3 @ set TLS register |
André Hentschel | a4780ad | 2013-06-18 23:23:26 +0100 | [diff] [blame] | 16 | mcr p15, 0, \tpuser, c13, c0, 2 @ and the user r/w register |
| 17 | str \tmp2, [\base, #TI_TP_VALUE + 4] @ save it |
Tony Lindgren | f159f4e | 2010-07-05 14:53:10 +0100 | [diff] [blame] | 18 | .endm |
| 19 | |
André Hentschel | a4780ad | 2013-06-18 23:23:26 +0100 | [diff] [blame] | 20 | .macro switch_tls_v6, base, tp, tpuser, tmp1, tmp2 |
Tony Lindgren | f159f4e | 2010-07-05 14:53:10 +0100 | [diff] [blame] | 21 | ldr \tmp1, =elf_hwcap |
| 22 | ldr \tmp1, [\tmp1, #0] |
| 23 | mov \tmp2, #0xffff0fff |
| 24 | tst \tmp1, #HWCAP_TLS @ hardware TLS available? |
Tony Lindgren | f159f4e | 2010-07-05 14:53:10 +0100 | [diff] [blame] | 25 | streq \tp, [\tmp2, #-15] @ set TLS value at 0xffff0ff0 |
André Hentschel | a4780ad | 2013-06-18 23:23:26 +0100 | [diff] [blame] | 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 |
Tony Lindgren | f159f4e | 2010-07-05 14:53:10 +0100 | [diff] [blame] | 30 | .endm |
| 31 | |
André Hentschel | a4780ad | 2013-06-18 23:23:26 +0100 | [diff] [blame] | 32 | .macro switch_tls_software, base, tp, tpuser, tmp1, tmp2 |
Tony Lindgren | f159f4e | 2010-07-05 14:53:10 +0100 | [diff] [blame] | 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 |
André Hentschel | a4780ad | 2013-06-18 23:23:26 +0100 | [diff] [blame] | 41 | #define switch_tls switch_tls_none |
Russell King | 37bc618 | 2011-01-17 16:38:56 +0000 | [diff] [blame] | 42 | #elif defined(CONFIG_CPU_V6) |
Tony Lindgren | f159f4e | 2010-07-05 14:53:10 +0100 | [diff] [blame] | 43 | #define tls_emu 0 |
| 44 | #define has_tls_reg (elf_hwcap & HWCAP_TLS) |
André Hentschel | a4780ad | 2013-06-18 23:23:26 +0100 | [diff] [blame] | 45 | #define switch_tls switch_tls_v6 |
Russell King | 37bc618 | 2011-01-17 16:38:56 +0000 | [diff] [blame] | 46 | #elif defined(CONFIG_CPU_32v6K) |
| 47 | #define tls_emu 0 |
| 48 | #define has_tls_reg 1 |
André Hentschel | a4780ad | 2013-06-18 23:23:26 +0100 | [diff] [blame] | 49 | #define switch_tls switch_tls_v6k |
Tony Lindgren | f159f4e | 2010-07-05 14:53:10 +0100 | [diff] [blame] | 50 | #else |
| 51 | #define tls_emu 0 |
| 52 | #define has_tls_reg 0 |
André Hentschel | a4780ad | 2013-06-18 23:23:26 +0100 | [diff] [blame] | 53 | #define switch_tls switch_tls_software |
Tony Lindgren | f159f4e | 2010-07-05 14:53:10 +0100 | [diff] [blame] | 54 | #endif |
| 55 | |
André Hentschel | a4780ad | 2013-06-18 23:23:26 +0100 | [diff] [blame] | 56 | #ifndef __ASSEMBLY__ |
Nathan Lynch | fbfb872 | 2014-09-11 02:49:08 +0100 | [diff] [blame] | 57 | |
| 58 | static inline void set_tls(unsigned long val) |
| 59 | { |
| 60 | struct thread_info *thread; |
| 61 | |
| 62 | thread = current_thread_info(); |
| 63 | |
| 64 | thread->tp_value[0] = val; |
| 65 | |
| 66 | /* |
| 67 | * This code runs with preemption enabled and therefore must |
| 68 | * be reentrant with respect to switch_tls. |
| 69 | * |
| 70 | * We need to ensure ordering between the shadow state and the |
| 71 | * hardware state, so that we don't corrupt the hardware state |
| 72 | * with a stale shadow state during context switch. |
| 73 | * |
| 74 | * If we're preempted here, switch_tls will load TPIDRURO from |
| 75 | * thread_info upon resuming execution and the following mcr |
| 76 | * is merely redundant. |
| 77 | */ |
| 78 | barrier(); |
| 79 | |
| 80 | if (!tls_emu) { |
| 81 | if (has_tls_reg) { |
| 82 | asm("mcr p15, 0, %0, c13, c0, 3" |
| 83 | : : "r" (val)); |
| 84 | } else { |
Nathan Lynch | 9cc6d9e | 2014-09-29 19:11:36 +0100 | [diff] [blame] | 85 | #ifdef CONFIG_KUSER_HELPERS |
Nathan Lynch | fbfb872 | 2014-09-11 02:49:08 +0100 | [diff] [blame] | 86 | /* |
| 87 | * User space must never try to access this |
| 88 | * directly. Expect your app to break |
| 89 | * eventually if you do so. The user helper |
| 90 | * at 0xffff0fe0 must be used instead. (see |
| 91 | * entry-armv.S for details) |
| 92 | */ |
| 93 | *((unsigned int *)0xffff0ff0) = val; |
Nathan Lynch | 9cc6d9e | 2014-09-29 19:11:36 +0100 | [diff] [blame] | 94 | #endif |
Nathan Lynch | fbfb872 | 2014-09-11 02:49:08 +0100 | [diff] [blame] | 95 | } |
| 96 | |
| 97 | } |
| 98 | } |
| 99 | |
André Hentschel | a4780ad | 2013-06-18 23:23:26 +0100 | [diff] [blame] | 100 | static inline unsigned long get_tpuser(void) |
| 101 | { |
| 102 | unsigned long reg = 0; |
| 103 | |
| 104 | if (has_tls_reg && !tls_emu) |
| 105 | __asm__("mrc p15, 0, %0, c13, c0, 2" : "=r" (reg)); |
| 106 | |
| 107 | return reg; |
| 108 | } |
Nathan Lynch | fbfb872 | 2014-09-11 02:49:08 +0100 | [diff] [blame] | 109 | |
| 110 | static inline void set_tpuser(unsigned long val) |
| 111 | { |
| 112 | /* Since TPIDRURW is fully context-switched (unlike TPIDRURO), |
| 113 | * we need not update thread_info. |
| 114 | */ |
| 115 | if (has_tls_reg && !tls_emu) { |
| 116 | asm("mcr p15, 0, %0, c13, c0, 2" |
| 117 | : : "r" (val)); |
| 118 | } |
| 119 | } |
| 120 | |
| 121 | static inline void flush_tls(void) |
| 122 | { |
| 123 | set_tls(0); |
| 124 | set_tpuser(0); |
| 125 | } |
| 126 | |
André Hentschel | a4780ad | 2013-06-18 23:23:26 +0100 | [diff] [blame] | 127 | #endif |
Tony Lindgren | f159f4e | 2010-07-05 14:53:10 +0100 | [diff] [blame] | 128 | #endif /* __ASMARM_TLS_H */ |