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 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 #pragma ident "%Z%%M% %I% %E% SMI"
27
28 #include <sys/types.h>
29 #include <sys/systm.h>
30 #include <sys/errno.h>
31 #include <sys/cpuvar.h>
32 #include <sys/archsystm.h>
33 #include <sys/proc.h>
34 #include <sys/brand.h>
35 #include <sys/lx_brand.h>
36 #include <sys/lx_ldt.h>
37
38 long
39 lx_get_thread_area(struct ldt_info *inf)
40 {
41 struct lx_lwp_data *jlwp = ttolxlwp(curthread);
42 struct ldt_info ldt_inf;
43 user_desc_t *dscrp;
44 int entry;
45
46 if (fuword32(&inf->entry_number, (uint32_t *)&entry))
47 return (set_errno(EFAULT));
48
49 if (entry < GDT_TLSMIN || entry > GDT_TLSMAX)
50 return (set_errno(EINVAL));
51
52 dscrp = jlwp->br_tls + entry - GDT_TLSMIN;
53
54 /*
55 * convert the solaris ldt to the linux format expected by the
56 * caller
57 */
58 DESC_TO_LDT_INFO(dscrp, &ldt_inf);
59 ldt_inf.entry_number = entry;
60
61 if (copyout(&ldt_inf, inf, sizeof (struct ldt_info)))
62 return (set_errno(EFAULT));
63
64 return (0);
65 }
66
67 long
68 lx_set_thread_area(struct ldt_info *inf)
69 {
70 struct lx_lwp_data *jlwp = ttolxlwp(curthread);
71 struct ldt_info ldt_inf;
72 user_desc_t *dscrp;
73 int entry;
74 int i;
75
76 if (copyin(inf, &ldt_inf, sizeof (ldt_inf)))
77 return (set_errno(EFAULT));
78
79 entry = ldt_inf.entry_number;
80 if (entry == -1) {
81 /*
82 * find an empty entry in the tls for this thread
83 */
84 for (i = 0, dscrp = jlwp->br_tls;
85 i < LX_TLSNUM; i++, dscrp++)
86 if (((unsigned long *)dscrp)[0] == 0 &&
87 ((unsigned long *)dscrp)[1] == 0)
88 break;
89
90 if (i < LX_TLSNUM) {
91 /*
92 * found one
93 */
94 entry = i + GDT_TLSMIN;
95 if (suword32(&inf->entry_number, entry))
96 return (set_errno(EFAULT));
97 } else {
98 return (set_errno(ESRCH));
99 }
100 }
101
102 if (entry < GDT_TLSMIN || entry > GDT_TLSMAX)
103 return (set_errno(EINVAL));
104
105 /*
106 * convert the linux ldt info to standard intel descriptor
107 */
108 dscrp = jlwp->br_tls + entry - GDT_TLSMIN;
109
110 if (LDT_INFO_EMPTY(&ldt_inf)) {
111 ((unsigned long *)dscrp)[0] = 0;
112 ((unsigned long *)dscrp)[1] = 0;
113 } else {
114 LDT_INFO_TO_DESC(&ldt_inf, dscrp);
115 }
116
117 /*
118 * update the gdt with the new descriptor
119 */
120 kpreempt_disable();
121
122 for (i = 0, dscrp = jlwp->br_tls; i < LX_TLSNUM; i++, dscrp++)
123 lx_set_gdt(GDT_TLSMIN + i, dscrp);
124
125 kpreempt_enable();
126
127 return (0);
128 }