1 /*
2  * Copyright (C) 2017 Hangzhou C-SKY Microsystems co.,ltd.
3  *
4  * Licensed under the LGPL v2.1 or later, see the file COPYING.LIB
5  * in this tarball.
6  */
7 
8 #ifndef _TLS_H
9 #define _TLS_H 1
10 
11 #ifndef __ASSEMBLER__
12 
13 # include <stdbool.h>
14 # include <stddef.h>
15 # include <stdint.h>
16 
17 /* Type for the dtv.  */
18 typedef union dtv
19 {
20   size_t counter;
21   struct
22   {
23     void *val;
24     bool is_static;
25   } pointer;
26 } dtv_t;
27 
28 #ifdef __CSKYABIV2__
29 /* define r31 as thread pointer register? */
30 # define READ_THREAD_POINTER() \
31     ({ void *__result;                                \
32        __asm__ __volatile__ ("mov %0, r31"	          \
33                              : "=r" (__result));      \
34        __result; })
35 #else
36 # define READ_THREAD_POINTER() \
37     ({ register unsigned int __result __asm__("a0");                 \
38        __asm__ __volatile__ ("trap 3;"	    \
39                              : "=r" (__result) : : );      \
40        __result; })
41 #endif
42 
43 #else /* __ASSEMBLER__ */
44 # include <tcb-offsets.h>
45 # ifdef __CSKYABIV2__
46 /* define r31 as thread pointer register? */
47 # define READ_THREAD_POINTER() \
48        mov r0, r31;
49 # else
50 # define READ_THREAD_POINTER() \
51        trap 3;
52 # endif
53 #endif /* __ASSEMBLER__ */
54 
55 /* We require TLS support in the tools.  */
56 #define HAVE_TLS_SUPPORT                1
57 #define HAVE_TLS_MODEL_ATTRIBUTE        1
58 #define HAVE___THREAD                   1
59 
60 /* Signal that TLS support is available.  */
61 #define USE_TLS	1
62 
63 # ifndef __ASSEMBLER__
64 
65 /* Get system call information.  */
66 #  include <sysdep.h>
67 
68 /* The TP points to the start of the thread blocks.  */
69 # define TLS_DTV_AT_TP	1
70 
71 /* Get the thread descriptor definition.  */
72 # include <../../descr.h>
73 
74 typedef struct
75 {
76   dtv_t *dtv;
77   void *private;
78 } tcbhead_t;
79 
80 /* This is the size of the initial TCB.  */
81 #  define TLS_INIT_TCB_SIZE	     sizeof (tcbhead_t)
82 
83 /* Alignment requirements for the initial TCB.  */
84 #  define TLS_INIT_TCB_ALIGN     16
85 
86 /* This is the size of the TCB.  */
87 #  define TLS_TCB_SIZE		sizeof (tcbhead_t)
88 
89 /* Alignment requirements for the TCB.  */
90 #  define TLS_TCB_ALIGN	    16
91 
92 /* This is the size we need before TCB.  */
93 #  define TLS_PRE_TCB_SIZE	sizeof (struct pthread)
94 
95 /* The thread pointer (in hardware register $29) points to the end of
96    the TCB + 0x7000, as for PowerPC.  The pthread_descr structure is
97    immediately in front of the TCB.  */
98 # define TLS_TCB_OFFSET     0//0x7000
99 
100 /* Install the dtv pointer.  The pointer passed is to the element with
101    index -1 which contain the length.  */
102 #  define INSTALL_DTV(tcbp, dtvp) \
103   (((tcbhead_t *) (tcbp))->dtv = (dtvp) + 1)
104 
105 /* Install new dtv for current thread.  */
106 #  define INSTALL_NEW_DTV(dtv) \
107   (THREAD_DTV() = (dtv))
108 
109 /* Return dtv of given thread descriptor.  */
110 #  define GET_DTV(tcbp) \
111   (((tcbhead_t *) (tcbp))->dtv)
112 
113 /* Code to initially initialize the thread pointer.  This might need
114    special attention since 'errno' is not yet available and if the
115    operation can cause a failure 'errno' must not be touched.  */
116 # define TLS_INIT_TP(tcbp, secondcall) \
117   ({ INTERNAL_SYSCALL_DECL (err);                   \
118      long result_var;                           \
119      result_var = INTERNAL_SYSCALL (set_thread_area, err, 1,        \
120                     (char *) (tcbp) + TLS_TCB_OFFSET);  \
121      INTERNAL_SYSCALL_ERROR_P (result_var, err)             \
122        ? "unknown error" : NULL; })
123 
124 /* Return the address of the dtv for the current thread.  */
125 #  define THREAD_DTV() \
126   (((tcbhead_t *) (READ_THREAD_POINTER () - TLS_TCB_OFFSET))->dtv)
127 
128 /* Return the thread descriptor for the current thread.  */
129 #  undef THREAD_SELF
130 #  define THREAD_SELF \
131  ((struct pthread *) (READ_THREAD_POINTER ()                 \
132               - TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE))
133 
134 /* Magic for libthread_db to know how to do THREAD_SELF.  */
135 # define DB_THREAD_SELF \
136   CONST_THREAD_AREA (32, sizeof (struct pthread))
137 
138 /* Access to data in the thread descriptor is easy.  */
139 #define THREAD_GETMEM(descr, member) \
140   descr->member
141 #define THREAD_GETMEM_NC(descr, member, idx) \
142   descr->member[idx]
143 #define THREAD_SETMEM(descr, member, value) \
144   descr->member = (value)
145 #define THREAD_SETMEM_NC(descr, member, idx, value) \
146   descr->member[idx] = (value)
147 
148 /* Initializing the thread pointer will generate a SIGILL if the syscall
149    is not available.  */
150 #define TLS_INIT_TP_EXPENSIVE 1
151 
152 /* Get and set the global scope generation counter in struct pthread.  */
153 #define THREAD_GSCOPE_FLAG_UNUSED 0
154 #define THREAD_GSCOPE_FLAG_USED   1
155 #define THREAD_GSCOPE_FLAG_WAIT   2
156 #define THREAD_GSCOPE_RESET_FLAG() \
157   do									     \
158     { int __res								     \
159 	= atomic_exchange_rel (&THREAD_SELF->header.gscope_flag,	     \
160 			       THREAD_GSCOPE_FLAG_UNUSED);		     \
161       if (__res == THREAD_GSCOPE_FLAG_WAIT)				     \
162 	lll_futex_wake (&THREAD_SELF->header.gscope_flag, 1, LLL_PRIVATE);   \
163     }									     \
164   while (0)
165 #define THREAD_GSCOPE_SET_FLAG() \
166   do									     \
167     {									     \
168       THREAD_SELF->header.gscope_flag = THREAD_GSCOPE_FLAG_USED;	     \
169       atomic_write_barrier ();						     \
170     }									     \
171   while (0)
172 #define THREAD_GSCOPE_WAIT() \
173   GL(dl_wait_lookup_done) ()
174 
175 #endif /* __ASSEMBLER__ */
176 
177 #endif	/* tls.h */
178