1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22/*
23 * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27#include <stdio.h>
28#include <strings.h>
29#include <sys/types.h>
30#include <dlfcn.h>
31#include <libc_int.h>
32#include <_rtld.h>
33#include <_elf.h>
34#include <msg.h>
35#include <debug.h>
36
37#define	TLSBLOCKCNT	16	/* number of blocks of tmi_bits to allocate */
38				/* at a time. */
39typedef struct {
40	uint_t	*tmi_bits;
41	ulong_t	tmi_lowfree;
42	ulong_t	tmi_cnt;
43} Tlsmodid;
44
45static Tlsmodid	tmid = {0, 0, 0};
46
47static ulong_t
48tls_getmodid()
49{
50	ulong_t	ndx, cnt;
51
52	if (tmid.tmi_bits == 0) {
53		if ((tmid.tmi_bits =
54		    calloc(TLSBLOCKCNT, sizeof (uint_t))) == NULL)
55			return ((ulong_t)-1);
56		tmid.tmi_bits[0] = 1;
57		tmid.tmi_lowfree = 1;
58		tmid.tmi_cnt = TLSBLOCKCNT;
59		return (0);
60	}
61
62	for (cnt = tmid.tmi_lowfree / (sizeof (uint_t) * 8);
63	    cnt < tmid.tmi_cnt; cnt++) {
64		uint_t	bits;
65
66		/*
67		 * If all bits are assigned - move on.
68		 */
69		if ((tmid.tmi_bits[cnt] ^ ~((uint_t)0)) == 0)
70			continue;
71
72		for (ndx = 0, bits = 1; bits; bits = bits << 1, ndx++) {
73			if ((tmid.tmi_bits[cnt] & bits) == 0) {
74				tmid.tmi_bits[cnt] |= bits;
75				ndx = (cnt * (sizeof (uint_t)) * 8) + ndx;
76				tmid.tmi_lowfree = ndx + 1;
77				return (ndx);
78			}
79		}
80	}
81
82	/*
83	 * All bits taken - must allocate a new block
84	 */
85	if ((tmid.tmi_bits = realloc(tmid.tmi_bits,
86	    ((tmid.tmi_cnt * sizeof (uint_t)) +
87	    (TLSBLOCKCNT * sizeof (uint_t))))) == NULL)
88		return ((ulong_t)-1);
89
90	/*
91	 * Clear out the tail of the new allocation.
92	 */
93	bzero(&(tmid.tmi_bits[tmid.tmi_cnt]), TLSBLOCKCNT * sizeof (uint_t));
94	tmid.tmi_bits[tmid.tmi_cnt] = 1;
95	ndx = (tmid.tmi_cnt * sizeof (uint_t)) * 8;
96	tmid.tmi_lowfree = ndx + 1;
97	tmid.tmi_cnt += TLSBLOCKCNT;
98
99	return (ndx);
100}
101
102void
103tls_freemodid(ulong_t modid)
104{
105	ulong_t	i;
106	uint_t	j;
107
108	i = modid / (sizeof (uint_t) * 8);
109	/* LINTED */
110	j = modid % (sizeof (uint_t) * 8);
111	j = ~(1 << j);
112	tmid.tmi_bits[i] &= j;
113	if (modid < tmid.tmi_lowfree)
114		tmid.tmi_lowfree = modid;
115}
116
117void
118tls_modaddrem(Rt_map *lmp, uint_t flag)
119{
120	Lm_list		*lml = LIST(lmp);
121	TLS_modinfo	tmi;
122	Phdr		*tlsphdr;
123	int		(*fptr)(TLS_modinfo *);
124
125	if (flag & TM_FLG_MODADD) {
126		fptr = lml->lm_lcs[CI_TLS_MODADD].lc_un.lc_func;
127	} else if (FLAGS1(lmp) & FL1_RT_TLSADD) {
128		fptr = lml->lm_lcs[CI_TLS_MODREM].lc_un.lc_func;
129	} else {
130		return;
131	}
132
133	tlsphdr = PTTLS(lmp);
134
135	bzero(&tmi, sizeof (tmi));
136	tmi.tm_modname = PATHNAME(lmp);
137	tmi.tm_modid = TLSMODID(lmp);
138	tmi.tm_tlsblock = (void *)(tlsphdr->p_vaddr);
139
140	if (!(FLAGS(lmp) & FLG_RT_FIXED))
141		tmi.tm_tlsblock = (void *)((uintptr_t)tmi.tm_tlsblock +
142		    ADDR(lmp));
143
144	tmi.tm_filesz = tlsphdr->p_filesz;
145	tmi.tm_memsz = tlsphdr->p_memsz;
146	tmi.tm_flags = 0;
147	tmi.tm_stattlsoffset = 0;
148
149	DBG_CALL(Dbg_tls_modactivity(LIST(lmp), &tmi, flag));
150	(void) (*fptr)(&tmi);
151
152	/*
153	 * Tag that this link-map has registered its TLS, and, if this object
154	 * is being removed, free up the module id.
155	 */
156	FLAGS1(lmp) |= FL1_RT_TLSADD;
157
158	if (flag & TM_FLG_MODREM)
159		tls_freemodid(TLSMODID(lmp));
160}
161
162static ulong_t	tls_static_size = 0;	/* static TLS buffer size */
163static ulong_t	tls_static_resv = 512;	/* (extra) static TLS reservation */
164
165/*
166 * Track any static TLS use, retain the TLS header, and assign a TLS module
167 * identifier.
168 */
169int
170tls_assign(Lm_list *lml, Rt_map *lmp, Phdr *phdr)
171{
172	ulong_t	memsz = S_ROUND(phdr->p_memsz, M_TLSSTATALIGN);
173	ulong_t	filesz = phdr->p_filesz;
174	ulong_t	resv = tls_static_resv;
175
176	/*
177	 * If this object explicitly references static TLS, then there are some
178	 * limitations.
179	 */
180	if (FLAGS1(lmp) & FL1_RT_TLSSTAT) {
181		/*
182		 * Static TLS is only available to objects on the primary
183		 * link-map list.
184		 */
185		if (((lml->lm_flags & LML_FLG_BASELM) == 0) ||
186		    ((rtld_flags2 & RT_FL2_NOPLM) != 0)) {
187			eprintf(lml, ERR_FATAL, MSG_INTL(MSG_TLS_STATBASE),
188			    NAME(lmp));
189			return (0);
190		}
191
192		/*
193		 * All TLS blocks that are processed before thread
194		 * initialization, are registered with libc.  This
195		 * initialization is carried out through a handshake with libc
196		 * prior to executing any user code (ie. before the first .init
197		 * sections are called).  As part of this initialization, a
198		 * small backup TLS reservation is added (tls_static_resv).
199		 * Only explicit static TLS references that can be satisfied by
200		 * this TLS backup reservation can be satisfied.
201		 */
202		if (rtld_flags2 & RT_FL2_PLMSETUP) {
203			/*
204			 * Initialized static TLS can not be satisfied from the
205			 * TLS backup reservation.
206			 */
207			if (filesz) {
208				eprintf(lml, ERR_FATAL,
209				    MSG_INTL(MSG_TLS_STATINIT), NAME(lmp));
210				return (0);
211			}
212
213			/*
214			 * Make sure the backup reservation is sufficient.
215			 */
216			if (memsz > tls_static_resv) {
217				eprintf(lml, ERR_FATAL,
218				    MSG_INTL(MSG_TLS_STATSIZE), NAME(lmp),
219				    EC_XWORD(memsz), EC_XWORD(tls_static_resv));
220				return (0);
221			}
222
223			tls_static_resv -= memsz;
224		}
225	}
226
227	/*
228	 * If we haven't yet initialized threads, or this static reservation can
229	 * be satisfied from the TLS backup reservation, determine the total
230	 * static TLS size, and assign this object a static TLS offset.
231	 */
232	if (((rtld_flags2 & RT_FL2_PLMSETUP) == 0) ||
233	    (FLAGS1(lmp) & FL1_RT_TLSSTAT)) {
234		tls_static_size += memsz;
235		TLSSTATOFF(lmp) = tls_static_size;
236	}
237
238	/*
239	 * Retain the PT_TLS header, obtain a new module identifier, and
240	 * indicate that this link-map list contains a new TLS object.
241	 */
242	PTTLS(lmp) = phdr;
243	TLSMODID(lmp) = tls_getmodid();
244
245	/*
246	 * Now that we have a TLS module id, generate any static TLS reservation
247	 * diagnostic.
248	 */
249	if (resv != tls_static_resv)
250		DBG_CALL(Dbg_tls_static_resv(lmp, memsz, tls_static_resv));
251
252	return (++lml->lm_tls);
253}
254
255int
256tls_statmod(Lm_list *lml, Rt_map *lmp)
257{
258	uint_t		tlsmodndx, tlsmodcnt = lml->lm_tls;
259	TLS_modinfo	**tlsmodlist, *tlsbuflist;
260	Phdr		*tlsphdr;
261	int		(*fptr)(TLS_modinfo **, ulong_t);
262
263	fptr = lml->lm_lcs[CI_TLS_STATMOD].lc_un.lc_func;
264
265	/*
266	 * Allocate a buffer to report the TLS modules, the buffer consists of:
267	 *
268	 *	TLS_modinfo *	ptrs[tlsmodcnt + 1]
269	 *	TLS_modinfo	bufs[tlsmodcnt]
270	 *
271	 * The ptrs are initialized to the bufs - except the last one which
272	 * null terminates the array.
273	 *
274	 * Note, even if no TLS has yet been observed, we still supply a
275	 * TLS buffer with a single null entry.  This allows us to initialize
276	 * the backup TLS reservation.
277	 */
278	if ((tlsmodlist = calloc((sizeof (TLS_modinfo *) * (tlsmodcnt + 1)) +
279	    (sizeof (TLS_modinfo) * tlsmodcnt), 1)) == NULL)
280		return (0);
281
282	lml->lm_tls = 0;
283
284	/*
285	 * If we don't have any TLS modules - report that and return.
286	 */
287	if (tlsmodcnt == 0) {
288		if (fptr != NULL)
289			(void) (*fptr)(tlsmodlist, tls_static_resv);
290		DBG_CALL(Dbg_tls_static_block(&lml_main, 0, 0,
291		    tls_static_resv));
292		return (1);
293	}
294
295	/*
296	 * Initialize the TLS buffer.
297	 */
298	tlsbuflist = (TLS_modinfo *)((uintptr_t)tlsmodlist +
299	    ((tlsmodcnt + 1) * sizeof (TLS_modinfo *)));
300
301	for (tlsmodndx = 0; tlsmodndx < tlsmodcnt; tlsmodndx++)
302		tlsmodlist[tlsmodndx] = &tlsbuflist[tlsmodndx];
303
304	/*
305	 * Account for the initial dtv ptr in the TLSSIZE calculation.
306	 */
307	tlsmodndx = 0;
308	for (lmp = lml->lm_head; lmp; lmp = NEXT_RT_MAP(lmp)) {
309		if (THIS_IS_NOT_ELF(lmp) ||
310		    (PTTLS(lmp) == 0) || (PTTLS(lmp)->p_memsz == 0))
311			continue;
312
313		tlsphdr = PTTLS(lmp);
314
315		tlsmodlist[tlsmodndx]->tm_modname = PATHNAME(lmp);
316		tlsmodlist[tlsmodndx]->tm_modid = TLSMODID(lmp);
317		tlsmodlist[tlsmodndx]->tm_tlsblock = (void *)(tlsphdr->p_vaddr);
318
319		if (!(FLAGS(lmp) & FLG_RT_FIXED)) {
320			tlsmodlist[tlsmodndx]->tm_tlsblock = (void *)
321			    ((uintptr_t)tlsmodlist[tlsmodndx]->tm_tlsblock +
322			    ADDR(lmp));
323		}
324		tlsmodlist[tlsmodndx]->tm_filesz = tlsphdr->p_filesz;
325		tlsmodlist[tlsmodndx]->tm_memsz = tlsphdr->p_memsz;
326		tlsmodlist[tlsmodndx]->tm_flags = TM_FLG_STATICTLS;
327		tlsmodlist[tlsmodndx]->tm_stattlsoffset = TLSSTATOFF(lmp);
328		tlsmodndx++;
329	}
330
331	DBG_CALL(Dbg_tls_static_block(&lml_main, (void *)tlsmodlist,
332	    tls_static_size, tls_static_resv));
333	(void) (*fptr)(tlsmodlist, (tls_static_size + tls_static_resv));
334
335	/*
336	 * We're done with the list - clean it up.
337	 */
338	free(tlsmodlist);
339	return (1);
340}
341