add linux_emul base, reorganize docs
[openbsd_emul.git] / linux_emul_base / tls.c
1 #include <u.h>
2 #include <libc.h>
3 #include <ureg.h>
4 #include "dat.h"
5 #include "fns.h"
6 #include "linux.h"
7
8 enum {
9 Index,
10 Type,
11 Flags,
12 DPL,
13 Base,
14 Limit,
15 Nfields,
16 };
17
18 static int
19 descempty(struct linux_user_desc *info)
20 {
21 return info->base_addr==0 && info->limit==0 &&
22 info->contents==0 && info->read_exec_only==1 &&
23 info->seg_32bit==0 && info->limit_in_pages==0 &&
24 info->seg_not_present==1 && info->useable==0;
25 }
26
27 int sys_set_thread_area(void *pinfo)
28 {
29 struct linux_user_desc *info = pinfo;
30 char buf[1024];
31 char *p, *e, *f[Nfields];
32 int n, fd, idx, err;
33
34 trace("sys_set_thread_area(%p)", pinfo);
35
36 err = -ENOSYS;
37 if((fd = open("/dev/gdt", ORDWR)) < 0)
38 goto out;
39
40 idx = info->entry_number;
41 if(idx == -1){
42 err = -ESRCH;
43 if((n = read(fd, buf, sizeof(buf)-1)) <= 0)
44 goto out;
45 buf[n] = 0;
46 p = buf;
47 while(e = strchr(p, '\n')){
48 *e = 0;
49 if(getfields(p, f, nelem(f), 1, " ") != nelem(f))
50 goto out;
51 idx = strtoul(f[Index], nil, 16);
52 if(idx >= 8*sizeof(current->tlsmask))
53 break;
54 if((current->tlsmask & (1<<idx)) == 0)
55 goto found;
56 p = e+1;
57 }
58 goto out;
59 }
60
61 found:
62 err = -EINVAL;
63 if(idx < 0 || idx >= 8*sizeof(current->tlsmask))
64 goto out;
65
66 buf[0] = 0;
67 if(!info->seg_not_present)
68 strcat(buf, "P");
69 if(info->limit_in_pages)
70 strcat(buf, "G");
71 if(info->useable)
72 strcat(buf, "U");
73 if(info->contents & 2){
74 /* code segment */
75 if(info->contents & 1)
76 strcat(buf, "C");
77 if(info->seg_32bit)
78 strcat(buf, "D");
79 if(!info->read_exec_only)
80 strcat(buf, "R");
81 if(buf[0] == 0)
82 strcat(buf, "-");
83
84 if(fprint(fd, "%x code %s 3 %lux %lux\n",
85 idx, buf, (ulong)info->base_addr, (ulong)info->limit) < 0)
86 goto out;
87 } else {
88 /* data segment */
89 if(info->contents & 1)
90 strcat(buf, "E");
91 if(info->seg_32bit)
92 strcat(buf, "B");
93 if(!info->read_exec_only)
94 strcat(buf, "W");
95 if(buf[0] == 0)
96 strcat(buf, "-");
97
98 if(fprint(fd, "%x data %s 3 %lux %lux\n",
99 idx, buf, (ulong)info->base_addr, (ulong)info->limit) < 0)
100 goto out;
101 }
102
103 err = 0;
104 info->entry_number = idx;
105 if(!descempty(info)){
106 current->tlsmask |= 1<<idx;
107 } else {
108 current->tlsmask &= ~(1<<idx);
109 }
110
111 out:
112 if(fd >= 0)
113 close(fd);
114 return err;
115 }
116
117 int sys_get_thread_area(void *pinfo)
118 {
119 struct linux_user_desc *info = pinfo;
120 int err, n, fd, idx;
121 char buf[1024];
122 char *p, *e, *f[Nfields];
123
124 trace("sys_get_thread_area(%p)", pinfo);
125
126 err = -ENOSYS;
127 if((fd = open("/dev/gdt", OREAD)) < 0)
128 goto out;
129
130 err = -EINVAL;
131 if((n = read(fd, buf, sizeof(buf)-1)) <= 0)
132 goto out;
133 buf[n] = 0;
134 p = buf;
135 while(e = strchr(p, '\n')){
136 *e = 0;
137 if(getfields(p, f, nelem(f), 1, " ") != nelem(f))
138 goto out;
139 idx = strtoul(f[Index], nil, 16);
140 if(idx >= 8*sizeof(current->tlsmask))
141 break;
142 if(idx == info->entry_number)
143 goto found;
144 p = e+1;
145 }
146 goto out;
147
148 found:
149 info->contents = 0;
150 if(strcmp(f[Type], "code") == 0)
151 info->contents |= 2;
152 info->seg_not_present = 1;
153 info->limit_in_pages = 0;
154 info->seg_32bit = 0;
155 info->read_exec_only = 1;
156 info->useable = 0;
157 for(p = f[Flags]; *p; p++){
158 switch(*p){
159 case 'P':
160 info->seg_not_present = 0;
161 break;
162 case 'G':
163 info->limit_in_pages = 1;
164 break;
165 case 'B':
166 case 'D':
167 info->seg_32bit = 1;
168 break;
169 case 'W':
170 case 'R':
171 info->read_exec_only = 0;
172 break;
173 case 'U':
174 info->useable = 1;
175 break;
176 case 'E':
177 case 'C':
178 info->contents |= 1;
179 break;
180 }
181 }
182
183 info->base_addr = strtoul(f[Base], nil, 16);
184 info->limit = strtoul(f[Limit], nil, 16);
185
186 err = 0;
187
188 out:
189 if(fd >= 0)
190 close(fd);
191 return err;
192 }
193
194 static void
195 cleardesc(struct linux_user_desc *info)
196 {
197 info->base_addr=0;
198 info->limit=0;
199 info->contents=0;
200 info->read_exec_only=1;
201 info->seg_32bit=0;
202 info->limit_in_pages=0;
203 info->seg_not_present=1;
204 info->useable=0;
205 }
206
207 void inittls(void)
208 {
209 struct linux_user_desc info;
210 int i;
211
212 for(i=0; i<8*sizeof(current->tlsmask); i++){
213 if((current->tlsmask & (1 << i)) == 0)
214 continue;
215 cleardesc(&info);
216 info.entry_number = i;
217 sys_set_thread_area(&info);
218 }
219 current->tlsmask = 0;
220 }
221
222 void clonetls(Uproc *new)
223 {
224 new->tlsmask = current->tlsmask;
225 }
226
227 int sys_modify_ldt(int func, void *data, int count)
228 {
229 trace("sys_modify_ldt(%d, %p, %x)", func, data, count);
230
231 return -ENOSYS;
232 }