1 |
/* container.c - container class for physical memory server. |
/* container.c - container class for physical memory server. |
2 |
Copyright (C) 2003 Free Software Foundation, Inc. |
Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. |
3 |
Written by Marcus Brinkmann. |
Written by Neal H. Walfield <neal@gnu.org>. |
4 |
|
|
5 |
This file is part of the GNU Hurd. |
This file is part of the GNU Hurd. |
6 |
|
|
7 |
The GNU Hurd is free software; you can redistribute it and/or |
The GNU Hurd is free software; you can redistribute it and/or |
8 |
modify it under the terms of the GNU Lesser General Public |
modify it under the terms of the GNU General Public License as |
9 |
License as published by the Free Software Foundation; either |
published by the Free Software Foundation; either version 2, or (at |
10 |
version 2.1 of the License, or (at your option) any later version. |
your option) any later version. |
11 |
|
|
12 |
The GNU Hurd is distributed in the hope that it will be useful, |
The GNU Hurd is distributed in the hope that it will be useful, but |
13 |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
WITHOUT ANY WARRANTY; without even the implied warranty of |
14 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
15 |
Lesser General Public License for more details. |
General Public License for more details. |
16 |
|
|
17 |
You should have received a copy of the GNU Lesser General Public |
You should have received a copy of the GNU General Public License |
18 |
License along with the GNU C Library; if not, write to the Free |
along with the GNU Hurd; see the file COPYING. If not, write to |
19 |
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA |
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, |
20 |
02111-1307 USA. */ |
USA. */ |
21 |
|
|
22 |
#if HAVE_CONFIG_H |
#if HAVE_CONFIG_H |
23 |
#include <config.h> |
#include <config.h> |
24 |
#endif |
#endif |
25 |
|
|
26 |
#include <stdlib.h> |
#include <stdlib.h> |
27 |
|
#include <errno.h> |
28 |
|
#include <pthread.h> |
29 |
|
#include <compiler.h> |
30 |
#include <l4.h> |
#include <l4.h> |
31 |
|
|
32 |
#include <hurd/cap-server.h> |
#include <hurd/cap-server.h> |
33 |
|
#include <hurd/btree.h> |
34 |
|
|
35 |
#include "physmem.h" |
#include "physmem.h" |
36 |
#include "zalloc.h" |
#include "zalloc.h" |
37 |
|
|
38 |
|
#include "output.h" |
39 |
|
|
40 |
|
|
41 |
static void |
static struct hurd_cap_class container_class; |
42 |
container_reinit (hurd_cap_class_t cap_class, hurd_cap_obj_t obj) |
|
43 |
|
|
44 |
|
/* CTX->obj should be a memory control object, not a container. */ |
45 |
|
static error_t |
46 |
|
container_create (hurd_cap_rpc_context_t ctx) |
47 |
{ |
{ |
48 |
container_t container = hurd_cap_obj_to_user (container_t, obj); |
error_t err; |
49 |
l4_word_t nr_fpages; |
hurd_cap_obj_t obj; |
50 |
|
hurd_cap_handle_t handle; |
51 |
|
|
52 |
nr_fpages = container->nr_fpages; |
l4_msg_clear (ctx->msg); |
53 |
|
|
54 |
l4_unmap_fpages (nr_fpages, container->fpages); |
err = hurd_cap_class_alloc (&container_class, &obj); |
55 |
|
if (err) |
56 |
|
return err; |
57 |
|
hurd_cap_obj_unlock (obj); |
58 |
|
|
59 |
while (nr_fpages > 0) |
err = hurd_cap_bucket_inject (ctx->bucket, obj, ctx->sender, &handle); |
60 |
|
if (err) |
61 |
{ |
{ |
62 |
l4_fpage_t fpage = container->fpages[--nr_fpages]; |
hurd_cap_obj_drop (obj); |
63 |
zfree (l4_address (fpage), l4_size (fpage)); |
return err; |
64 |
} |
} |
65 |
|
|
66 |
|
/* The reply message consists of a single word, a capability handle |
67 |
|
which the client can use to refer to the container. */ |
68 |
|
|
69 |
|
l4_msg_append_word (ctx->msg, handle); |
70 |
|
|
71 |
|
debug ("Created handle %x\n", handle); |
72 |
|
|
73 |
|
return 0; |
74 |
} |
} |
75 |
|
|
76 |
|
static error_t |
77 |
error_t |
container_share (hurd_cap_rpc_context_t ctx) |
|
container_map (hurd_cap_rpc_context_t ctx) |
|
78 |
{ |
{ |
79 |
container_t container = hurd_cap_obj_to_user (container_t, ctx->obj); |
return EOPNOTSUPP; |
80 |
l4_word_t offset = l4_page_trunc (l4_msg_word (ctx->msg, 1)); |
} |
|
l4_word_t rights = l4_msg_word (ctx->msg, 1) & 0x7; |
|
|
l4_word_t size = l4_page_round (l4_msg_word (ctx->msg, 2)); |
|
|
l4_word_t vaddr = l4_page_trunc (l4_msg_word (ctx->msg, 3)); |
|
|
l4_word_t start; |
|
|
l4_word_t end; |
|
|
l4_word_t nr_fpages; |
|
|
#define MAX_MAP_ITEMS ((L4_NUM_MRS - 1) / 2) |
|
|
l4_fpage_t fpages[MAX_MAP_ITEMS]; |
|
|
l4_word_t i; |
|
81 |
|
|
82 |
/* FIXME FIXME FIXME */ |
static error_t |
83 |
if (offset > 0x8000000) |
container_allocate (hurd_cap_rpc_context_t ctx) |
84 |
|
{ |
85 |
|
error_t err; |
86 |
|
struct container *container = hurd_cap_obj_to_user (struct container *, |
87 |
|
ctx->obj); |
88 |
|
l4_word_t flags = l4_msg_word (ctx->msg, 1); |
89 |
|
uintptr_t start = l4_msg_word (ctx->msg, 2); |
90 |
|
size_t size = l4_msg_word (ctx->msg, 3); |
91 |
|
size_t amount; |
92 |
|
int i; |
93 |
|
|
94 |
|
/* We require at least three arguments (in addition to the cap id): |
95 |
|
the flags, the start and the size. */ |
96 |
|
if (l4_untyped_words (l4_msg_msg_tag (ctx->msg)) != 4) |
97 |
{ |
{ |
98 |
/* Allocation. */ |
debug ("incorrect number of arguments passed. require 4 but got %d\n", |
99 |
start = zalloc (size); |
l4_untyped_words (l4_msg_msg_tag (ctx->msg))); |
100 |
end = start + size - 1; |
l4_msg_clear (ctx->msg); |
101 |
|
return EINVAL; |
102 |
|
} |
103 |
|
|
104 |
|
/* Allocate the memory. */ |
105 |
|
l4_fpage_t fpages[L4_FPAGE_SPAN_MAX]; |
106 |
|
int nr_fpages = l4_fpage_span (0, size - 1, fpages); |
107 |
|
|
108 |
|
for (err = 0, amount = 0, i = 0; i < nr_fpages; i ++) |
109 |
|
{ |
110 |
|
/* FIXME: Check to make sure that the memory control object that |
111 |
|
this container refers to has enough memory to do each |
112 |
|
allocation. */ |
113 |
|
struct frame_entry *fe = frame_entry_alloc (); |
114 |
|
if (! fe) |
115 |
|
break; |
116 |
|
|
117 |
|
err = frame_entry_new (container, fe, start + l4_address (fpages[i]), |
118 |
|
l4_size (fpages[i])); |
119 |
|
if (err) |
120 |
|
{ |
121 |
|
frame_entry_dealloc (fe); |
122 |
|
break; |
123 |
|
} |
124 |
|
|
125 |
|
amount += l4_size (fpages[i]); |
126 |
|
|
127 |
|
/* XXX: Use the flags. |
128 |
|
frame->flags = flags; */ |
129 |
} |
} |
130 |
else |
|
131 |
|
l4_msg_clear (ctx->msg); |
132 |
|
l4_msg_append_word (ctx->msg, amount); |
133 |
|
|
134 |
|
return err; |
135 |
|
} |
136 |
|
|
137 |
|
static error_t |
138 |
|
container_deallocate (hurd_cap_rpc_context_t ctx) |
139 |
|
{ |
140 |
|
error_t err; |
141 |
|
struct container *container = hurd_cap_obj_to_user (struct container *, |
142 |
|
ctx->obj); |
143 |
|
uintptr_t start = l4_msg_word (ctx->msg, 1); |
144 |
|
size_t size = l4_msg_word (ctx->msg, 2); |
145 |
|
struct frame_entry *fe; |
146 |
|
|
147 |
|
/* We require at least two arguments (in addition to the cap id): |
148 |
|
the start and the size. */ |
149 |
|
if (l4_untyped_words (l4_msg_msg_tag (ctx->msg)) != 3) |
150 |
{ |
{ |
151 |
/* FIXME: Currently, we just trust that everything is all-right. */ |
debug ("incorrect number of arguments passed. require 3 but got %d\n", |
152 |
start = l4_address (container->fpages[0]) + offset; |
l4_untyped_words (l4_msg_msg_tag (ctx->msg))); |
153 |
end = start + size - 1; |
l4_msg_clear (ctx->msg); |
154 |
|
return EINVAL; |
155 |
} |
} |
156 |
|
|
157 |
l4_msg_clear (ctx->msg); |
l4_msg_clear (ctx->msg); |
|
nr_fpages = l4_fpage_xspan (start, end, vaddr, fpages, MAX_MAP_ITEMS); |
|
158 |
|
|
159 |
for (i = 0; i < nr_fpages; i++) |
fe = frame_entry_find (container, start, size); |
160 |
|
if (! fe) |
161 |
|
/* Nothing was allocated in this region. */ |
162 |
|
return 0; |
163 |
|
|
164 |
|
/* Find the first region which overlaps with this one. */ |
165 |
|
while (1) |
166 |
|
{ |
167 |
|
struct frame_entry *prev = hurd_btree_frame_entry_prev (fe); |
168 |
|
|
169 |
|
if (! prev |
170 |
|
|| ! overlap (prev->region.start, prev->region.size, start, size)) |
171 |
|
break; |
172 |
|
|
173 |
|
fe = prev; |
174 |
|
} |
175 |
|
|
176 |
|
for (;;) |
177 |
{ |
{ |
178 |
l4_map_item_t map_item; |
struct frame_entry *next = hurd_btree_frame_entry_next (fe); |
|
l4_fpage_t fpage; |
|
179 |
|
|
180 |
fpage = fpages[i]; |
if (start <= fe->region.start |
181 |
l4_set_rights (&fpage, rights); |
&& start + size <= fe->region.start + fe->region.size) |
182 |
map_item = l4_map_item (fpage, vaddr); |
/* Deallocate the entire frame entry. */ |
183 |
l4_msg_append_map_item (ctx->msg, map_item); |
{ |
184 |
vaddr += l4_size (fpage); |
frame_entry_drop (container, fe); |
185 |
|
frame_entry_dealloc (fe); |
186 |
|
} |
187 |
|
else |
188 |
|
/* We keep part of the region. */ |
189 |
|
{ |
190 |
|
int i; |
191 |
|
l4_fpage_t fpages[L4_FPAGE_SPAN_MAX]; |
192 |
|
int nr_fpages; |
193 |
|
|
194 |
|
/* Detach the frame entry from its container: frame entries |
195 |
|
in the same container cannot overlap and we are going to |
196 |
|
replace it with a set of smaller frame entries covering |
197 |
|
the physical memory which will not be deallocated. */ |
198 |
|
frame_entry_detach (container, fe); |
199 |
|
|
200 |
|
if (start >= fe->region.start) |
201 |
|
/* We keep part of the start of the region. */ |
202 |
|
{ |
203 |
|
nr_fpages = l4_fpage_span (0, start - fe->region.start, fpages); |
204 |
|
|
205 |
|
for (i = 0; i < nr_fpages; i ++) |
206 |
|
{ |
207 |
|
struct frame_entry *subfe = frame_entry_alloc (); |
208 |
|
assert (fe); |
209 |
|
|
210 |
|
err = frame_entry_use (container, subfe, |
211 |
|
start + l4_address (fpages[i]), |
212 |
|
l4_size (fpages[i]), |
213 |
|
fe->frame, l4_address (fpages[i])); |
214 |
|
assert_perror (err); |
215 |
|
} |
216 |
|
} |
217 |
|
|
218 |
|
if (start + size < fe->region.start + fe->region.size) |
219 |
|
/* We keep part of the end of the region. */ |
220 |
|
{ |
221 |
|
nr_fpages = l4_fpage_span (0, size - start, fpages); |
222 |
|
|
223 |
|
for (i = 0; i < nr_fpages; i ++) |
224 |
|
{ |
225 |
|
struct frame_entry *subfe = frame_entry_alloc (); |
226 |
|
assert (fe); |
227 |
|
|
228 |
|
err = frame_entry_use (container, subfe, |
229 |
|
start + l4_address (fpages[i]), |
230 |
|
l4_size (fpages[i]), |
231 |
|
fe->frame, l4_address (fpages[i])); |
232 |
|
assert_perror (err); |
233 |
|
} |
234 |
|
} |
235 |
|
|
236 |
|
frame_deref (fe->frame); |
237 |
|
frame_entry_dealloc (fe); |
238 |
|
} |
239 |
|
|
240 |
|
if (! next || ! overlap (next->region.start, next->region.size, |
241 |
|
start, size)) |
242 |
|
break; |
243 |
|
fe = next; |
244 |
} |
} |
245 |
|
|
246 |
return 0; |
return 0; |
247 |
} |
} |
248 |
|
|
249 |
|
static error_t |
250 |
|
container_map (hurd_cap_rpc_context_t ctx) |
251 |
|
{ |
252 |
|
struct container *container = hurd_cap_obj_to_user (struct container *, |
253 |
|
ctx->obj); |
254 |
|
uintptr_t index = l4_page_trunc (l4_msg_word (ctx->msg, 1)); |
255 |
|
l4_word_t rights = l4_msg_word (ctx->msg, 1) & 0x7; |
256 |
|
size_t size = l4_page_round (l4_msg_word (ctx->msg, 2)); |
257 |
|
uintptr_t vaddr = l4_page_trunc (l4_msg_word (ctx->msg, 3)); |
258 |
|
int nr_fpages; |
259 |
|
#define MAX_MAP_ITEMS ((L4_NUM_MRS - 1) / 2) |
260 |
|
int i; |
261 |
|
|
262 |
|
l4_msg_clear (ctx->msg); |
263 |
|
|
264 |
|
pthread_mutex_lock (&container->lock); |
265 |
|
|
266 |
|
for (i = 0; i < MAX_MAP_ITEMS && size > 0; ) |
267 |
|
{ |
268 |
|
l4_fpage_t fpages[MAX_MAP_ITEMS]; |
269 |
|
struct frame_entry *fe; |
270 |
|
|
271 |
|
/* Get the memory. */ |
272 |
|
fe = frame_entry_find (container, index, 1); |
273 |
|
if (! fe) |
274 |
|
{ |
275 |
|
pthread_mutex_unlock (&container->lock); |
276 |
|
return errno; |
277 |
|
} |
278 |
|
|
279 |
|
/* Allocate the memory (if needed). */ |
280 |
|
if (! fe->frame) |
281 |
|
{ |
282 |
|
fe->frame = frame_alloc (fe->region.size); |
283 |
|
if (! fe->frame) |
284 |
|
{ |
285 |
|
pthread_mutex_unlock (&container->lock); |
286 |
|
return errno; |
287 |
|
} |
288 |
|
|
289 |
|
frame_use (fe->frame, fe); |
290 |
|
} |
291 |
|
|
292 |
|
frame_memory_bind (fe->frame); |
293 |
|
fe->frame->may_be_mapped = true; |
294 |
|
|
295 |
|
/* This might only be a partial mapping of a memory. Subtract |
296 |
|
the desired index from where the memory actually starts and |
297 |
|
add that to the address of the physical memory block. */ |
298 |
|
l4_word_t mem |
299 |
|
= l4_address (fe->frame->memory) + index - fe->region.start; |
300 |
|
l4_word_t amount = fe->region.size - (index - fe->region.start); |
301 |
|
|
302 |
|
/* Does the user want all that we can give? */ |
303 |
|
if (amount > size) |
304 |
|
amount = size; |
305 |
|
|
306 |
|
/* Adjust the index and the size. */ |
307 |
|
size -= amount; |
308 |
|
index += amount; |
309 |
|
|
310 |
|
nr_fpages = l4_fpage_xspan (mem, mem + amount - 1, |
311 |
|
vaddr, &fpages[i], MAX_MAP_ITEMS - i); |
312 |
|
for (; i < MAX_MAP_ITEMS && amount > 0; i ++) |
313 |
|
{ |
314 |
|
l4_map_item_t map_item; |
315 |
|
|
316 |
|
assert (nr_fpages > 0); |
317 |
|
|
318 |
|
/* Set the desired permissions. */ |
319 |
|
l4_set_rights (&fpages[i], rights); |
320 |
|
|
321 |
|
/* Add the mad item to the message. */ |
322 |
|
map_item = l4_map_item (fpages[i], vaddr); |
323 |
|
l4_msg_append_map_item (ctx->msg, map_item); |
324 |
|
|
325 |
|
mem += l4_size (fpages[i]); |
326 |
|
vaddr += l4_size (fpages[i]); |
327 |
|
amount -= l4_size (fpages[i]); |
328 |
|
nr_fpages --; |
329 |
|
} |
330 |
|
|
331 |
|
assert (nr_fpages == 0); |
332 |
|
} |
333 |
|
|
334 |
|
pthread_mutex_unlock (&container->lock); |
335 |
|
|
336 |
|
return 0; |
337 |
|
} |
338 |
|
|
339 |
|
enum container_ops |
340 |
|
{ |
341 |
|
container_create_id = 130, |
342 |
|
container_share_id, |
343 |
|
container_allocate_id, |
344 |
|
container_deallocate_id, |
345 |
|
container_map_id |
346 |
|
}; |
347 |
|
|
348 |
error_t |
error_t |
349 |
container_demuxer (hurd_cap_rpc_context_t ctx) |
container_demuxer (hurd_cap_rpc_context_t ctx) |
350 |
{ |
{ |
351 |
error_t err = 0; |
error_t err = 0; |
352 |
|
|
353 |
|
debug ("Message %d from %x\n", l4_msg_label (ctx->msg), ctx->from); |
354 |
switch (l4_msg_label (ctx->msg)) |
switch (l4_msg_label (ctx->msg)) |
355 |
{ |
{ |
356 |
/* PHYSMEM_MAP */ |
case container_create_id: |
357 |
case 128: |
err = container_create (ctx); |
358 |
|
break; |
359 |
|
|
360 |
|
case container_share_id: |
361 |
|
err = container_share (ctx); |
362 |
|
break; |
363 |
|
|
364 |
|
case container_allocate_id: |
365 |
|
err = container_allocate (ctx); |
366 |
|
break; |
367 |
|
|
368 |
|
case container_deallocate_id: |
369 |
|
err = container_deallocate (ctx); |
370 |
|
break; |
371 |
|
|
372 |
|
case 128: /* The old container map implementation. */ |
373 |
|
case container_map_id: |
374 |
err = container_map (ctx); |
err = container_map (ctx); |
375 |
break; |
break; |
376 |
|
|
378 |
err = EOPNOTSUPP; |
err = EOPNOTSUPP; |
379 |
} |
} |
380 |
|
|
381 |
return err; |
/* If the stub returns EOPNOTSUPP then we clear the message buffer, |
382 |
} |
otherwise we assume that the message buffer contains a valid |
383 |
|
reply message and in which case we set the error code returned by |
384 |
|
the stub and have the demuxer succeed. */ |
385 |
|
if (EXPECT_FALSE (err == EOPNOTSUPP)) |
386 |
|
l4_msg_clear (ctx->msg); |
387 |
|
|
388 |
|
l4_set_msg_label (ctx->msg, err); |
389 |
|
|
390 |
|
debug ("Returning error %d\n", err); |
|
static struct hurd_cap_class container_class; |
|
391 |
|
|
392 |
/* Initialize the container class subsystem. */ |
return 0; |
|
error_t |
|
|
container_class_init () |
|
|
{ |
|
|
return hurd_cap_class_init (&container_class, container_t, |
|
|
NULL, NULL, container_reinit, NULL, |
|
|
container_demuxer); |
|
393 |
} |
} |
|
|
|
394 |
|
|
|
/* Allocate a new container object covering the NR_FPAGES fpages |
|
|
listed in FPAGES. The object returned is locked and has one |
|
|
reference. */ |
|
395 |
error_t |
error_t |
396 |
container_alloc (l4_word_t nr_fpages, l4_word_t *fpages, |
container_alloc (l4_word_t nr_fpages, l4_word_t *fpages, |
397 |
container_t *r_container) |
struct container **r_container) |
398 |
{ |
{ |
399 |
error_t err; |
error_t err; |
400 |
hurd_cap_obj_t obj; |
hurd_cap_obj_t obj; |
401 |
container_t container; |
struct container *container; |
402 |
|
l4_word_t start; |
403 |
|
int i; |
404 |
|
|
405 |
err = hurd_cap_class_alloc (&container_class, &obj); |
err = hurd_cap_class_alloc (&container_class, &obj); |
406 |
if (err) |
if (err) |
407 |
return err; |
return err; |
408 |
|
|
409 |
container = hurd_cap_obj_to_user (container_t, obj); |
container = hurd_cap_obj_to_user (struct container *, obj); |
410 |
assert (nr_fpages <= L4_FPAGE_SPAN_MAX); |
|
411 |
container->nr_fpages = nr_fpages; |
hurd_btree_frame_entry_tree_init (&container->frame_entries); |
412 |
memcpy (container->fpages, fpages, sizeof (l4_fpage_t) * nr_fpages); |
start = l4_address (fpages[0]); |
413 |
|
for (i = 0; i < nr_fpages; i ++) |
414 |
|
{ |
415 |
|
struct frame_entry *fe = frame_entry_alloc (); |
416 |
|
if (! fe) |
417 |
|
return ENOMEM; |
418 |
|
|
419 |
|
err = frame_entry_new (container, fe, |
420 |
|
l4_address (fpages[i]) - start, |
421 |
|
l4_size (fpages[i])); |
422 |
|
if (err) |
423 |
|
{ |
424 |
|
frame_entry_dealloc (fe); |
425 |
|
return err; |
426 |
|
} |
427 |
|
|
428 |
|
fe->frame = frame_alloc (l4_size (fpages[i])); |
429 |
|
if (! fe->frame) |
430 |
|
{ |
431 |
|
frame_entry_drop (container, fe); |
432 |
|
frame_entry_dealloc (fe); |
433 |
|
return ENOMEM; |
434 |
|
} |
435 |
|
|
436 |
|
frame_use (fe->frame, fe); |
437 |
|
|
438 |
|
fe->frame->memory = fpages[i]; |
439 |
|
} |
440 |
|
|
441 |
*r_container = container; |
*r_container = container; |
442 |
return 0; |
return 0; |
443 |
} |
} |
444 |
|
|
445 |
|
|
446 |
|
static void |
447 |
|
container_reinit (hurd_cap_class_t cap_class, hurd_cap_obj_t obj) |
448 |
|
{ |
449 |
|
struct container *container = hurd_cap_obj_to_user (struct container *, |
450 |
|
obj); |
451 |
|
struct frame_entry *fe, *next; |
452 |
|
|
453 |
|
/* We don't need to lock the container as we know we are the only |
454 |
|
ones who can now access it. */ |
455 |
|
for (fe = hurd_btree_frame_entry_first (&container->frame_entries); |
456 |
|
fe; fe = next) |
457 |
|
{ |
458 |
|
next = hurd_btree_frame_entry_next (fe); |
459 |
|
frame_entry_drop (container, fe); |
460 |
|
frame_entry_dealloc (fe); |
461 |
|
} |
462 |
|
hurd_btree_frame_entry_tree_init (&container->frame_entries); |
463 |
|
} |
464 |
|
|
465 |
|
|
466 |
|
/* Initialize the container class subsystem. */ |
467 |
|
error_t |
468 |
|
container_class_init () |
469 |
|
{ |
470 |
|
return hurd_cap_class_init (&container_class, struct container *, |
471 |
|
NULL, NULL, container_reinit, NULL, |
472 |
|
container_demuxer); |
473 |
|
} |
474 |
|
|