Merge pull request #2810 from kumpera/fix_hazard_free
[mono.git] / mono / mini / mini-arm-tls.h
1 #ifndef __MONO_MINI_ARM_TLS_H__
2 #define __MONO_MINI_ARM_TLS_H__
3
4 /* Fast inlined tls getters/setters */
5
6 int mono_fast_get_tls_key (int);
7 void mono_fast_set_tls_key (int, int);
8 int mono_fast_get_tls_key2 (int);
9 void mono_fast_set_tls_key2 (int, int);
10
11 /* Fallback tls getters/setters */
12
13 int mono_fallback_get_tls_key (int);
14 void mono_fallback_set_tls_key (int, int);
15
16 /* End of thunks */
17
18 void mono_fast_get_tls_key_end (void);
19 void mono_fast_set_tls_key_end (void);
20 void mono_fast_get_tls_key2_end (void);
21 void mono_fast_set_tls_key2_end (void);
22
23 #if defined(__linux__) && defined(HAVE_KW_THREAD) && defined(__ARM_EABI__)
24 void* __aeabi_read_tp (void);
25 #endif
26
27 /* Structure that maps a possible  tls implementation to the corresponding thunks */
28 typedef struct {
29         guint32 *expected_code;
30         int expected_code_length;
31         gboolean check_kernel_helper;
32         gpointer get_tls_thunk;
33         gpointer get_tls_thunk_end;
34         gpointer set_tls_thunk;
35         gpointer set_tls_thunk_end;
36 } MonoTlsImplementation;
37
38
39 static MonoTlsImplementation known_tls_implementations [] = {
40 #if defined(HAVE_KW_THREAD) && defined(__linux__) && defined(__ARM_EABI__)
41         { (guint32[]) {0x0f70ee1d, 0xbf004770}, 8, FALSE, mono_fast_get_tls_key, mono_fast_get_tls_key_end, mono_fast_set_tls_key, mono_fast_set_tls_key_end },
42         { (guint32[]) {0xe3e00a0f, 0xe240f01f}, 8, TRUE, mono_fast_get_tls_key, mono_fast_get_tls_key_end, mono_fast_set_tls_key, mono_fast_set_tls_key_end }
43 #elif defined(TARGET_IOS)
44         { (guint32[]) {0x1f70ee1d, 0x0103f021, 0x0020f851, 0xbf004770}, 16, FALSE, mono_fast_get_tls_key, mono_fast_get_tls_key_end, mono_fast_set_tls_key, mono_fast_set_tls_key_end }
45 #elif defined(TARGET_ANDROID)
46         { (guint32[]) {0xe2403003, 0xe353003c, 0xe92d4010, 0xe1a04000, 0x9a000001, 0xe3a00000, 0xe8bd8010, 0xe3e00a0f, 0xe240101f, 0xe12fff31, 0xe7900104, 0xe8bd8010}, 48, TRUE, mono_fast_get_tls_key, mono_fast_get_tls_key_end, mono_fast_set_tls_key, mono_fast_set_tls_key_end}, /* 1.5 */
47         { (guint32[]) {0xe2402003, 0xe1a03000, 0xe352003c, 0x8a000002, 0xee1d0f70, 0xe7900103, 0xe12fff1e}, 28, FALSE, mono_fast_get_tls_key, mono_fast_get_tls_key_end, mono_fast_set_tls_key, mono_fast_set_tls_key_end}, /* 4.2 */
48         { (guint32[]) {0xe2403007, 0xe3530084, 0x8a000002, 0xee1d1f70, 0xe7910100, 0xe12fff1e, 0xe3a00000, 0xe12fff1e}, 32, FALSE, mono_fast_get_tls_key, mono_fast_get_tls_key_end, mono_fast_set_tls_key, mono_fast_set_tls_key_end}, /* 4.4 */
49         { (guint32[]) {0x2b8c1fc3, 0xee1dd804, 0xf8511f70, 0x47700020, 0x47702000}, 20, FALSE, mono_fast_get_tls_key, mono_fast_get_tls_key_end, mono_fast_set_tls_key, mono_fast_set_tls_key_end}, /* 5.0 */
50         { (guint32[]) {0xb5104b0f, 0xda114298, 0xf020490e, 0xee1d4000, 0x00c24f70, 0xf8514479, 0x68631030, 0xd50707cc, 0x6e54441a, 0xd103428c, 0xbd106e90}, 44, FALSE, mono_fast_get_tls_key2, mono_fast_get_tls_key2_end, mono_fast_set_tls_key2, mono_fast_set_tls_key2_end} /* 6.0 */
51 #endif
52 };
53
54 static gboolean
55 known_kernel_helper (void)
56 {
57 #ifdef __linux__
58         const guint32* kuser_get_tls = (void*)0xffff0fe0; /* linux kernel user helper on arm */
59         guint32 expected [] = {0xee1d0f70, 0xe12fff1e};
60
61         /* Expecting mrc + bx lr in the kuser_get_tls kernel helper */
62         return memcmp (kuser_get_tls, expected, 8) == 0;
63 #else
64         g_error ("Trying to check linux kernel helper on non linux platform"); 
65         return FALSE;
66 #endif
67 }
68
69 static void
70 dump_code (guint32 *ptr)
71 {
72         char current_impl [256];
73         char hex [16];
74         int i;
75         guint32 page_mask = ~((guint32)mono_pagesize () - 1);
76
77         current_impl [0] = 0;
78         for (i = 0; i < 16; i++) {
79                 /* Don't risk page fault since we don't know where the code ends */
80                 if (((guint32)&ptr [i] & page_mask) != ((guint32)ptr & page_mask))
81                         break;
82                 sprintf (hex, "0x%x ", ptr [i]);
83                 strcat (current_impl, hex);
84         }
85
86         g_warning (current_impl);
87 }
88
89 static MonoTlsImplementation
90 mono_arm_get_tls_implementation (void)
91 {
92 #ifdef MONO_CROSS_COMPILE
93         g_assert_not_reached ();
94 #else
95         /* Discard thumb bit */
96 #if defined(__linux__) && defined(HAVE_KW_THREAD) && defined(__ARM_EABI__)
97         guint32* check_addr = (guint32*) ((guint32)__aeabi_read_tp & 0xfffffffe);
98 #else
99         guint32* check_addr = (guint32*) ((guint32)pthread_getspecific & 0xfffffffe);
100 #endif
101         int i;
102
103         if (!mini_get_debug_options ()->arm_use_fallback_tls) {
104                 for (i = 0; i < sizeof (known_tls_implementations) / sizeof (MonoTlsImplementation); i++) {
105                         if (memcmp (check_addr, known_tls_implementations [i].expected_code, known_tls_implementations [i].expected_code_length) == 0) {
106                                 if ((known_tls_implementations [i].check_kernel_helper && known_kernel_helper ()) ||
107                                                 !known_tls_implementations [i].check_kernel_helper)
108                                         return known_tls_implementations [i];
109                         }
110                 }
111         }
112
113         g_warning ("No fast tls on device. Using fallbacks. Current implementation : ");
114         dump_code (check_addr);
115
116         return (MonoTlsImplementation) { NULL, 0, FALSE, mono_fallback_get_tls_key, NULL, mono_fallback_set_tls_key, NULL };
117 #endif
118 }
119 #endif