cae36a52 |
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 | } |