37 |
|
|
38 |
/* Initialized by the machine-specific startup-code. */ |
/* Initialized by the machine-specific startup-code. */ |
39 |
extern struct hurd_startup_data *__hurd_startup_data; |
extern struct hurd_startup_data *__hurd_startup_data; |
|
|
|
|
/* We don't want to start mapping things at 0 as then we don't catch |
|
|
NULL pointer dereferences. Reserving about 16k makes sense. */ |
|
|
#define VIRTUAL_MEMORY_START 0x4000 |
|
|
|
|
|
struct as as; |
|
40 |
|
|
41 |
void |
void |
42 |
map_init (void) |
map_system_init (void) |
43 |
{ |
{ |
44 |
|
error_t err; |
45 |
int i; |
int i; |
46 |
struct map *map; |
struct map *map; |
47 |
|
|
48 |
pthread_mutex_init (&as.lock, NULL); |
pthread_mutex_init (&as.lock, NULL); |
49 |
hurd_btree_map_tree_init (&as.mappings); |
hurd_btree_map_tree_init (&as.mappings); |
50 |
|
|
51 |
/* Add the startup code. */ |
/* Reserve the virtual memory where the startup code lies. */ |
52 |
map = map_alloc (); |
map = map_alloc (); |
53 |
assert (map); |
assert (map); |
54 |
|
err = map_init (map, (uintptr_t) HURD_STARTUP_ADDR, HURD_STARTUP_SIZE, |
55 |
|
NULL, 0, NULL); |
56 |
|
assert_perror (err); |
57 |
|
|
58 |
map->store = NULL; |
/* The UTCB. */ |
59 |
map->store_offset = (uintptr_t) HURD_STARTUP_ADDR; |
map = map_alloc (); |
60 |
map->vm.start = (uintptr_t) HURD_STARTUP_ADDR; |
assert (map); |
61 |
map->vm.size = HURD_STARTUP_SIZE; |
err = map_init (map, l4_address (__hurd_startup_data->utcb_area), |
62 |
|
l4_size (__hurd_startup_data->utcb_area), |
63 |
|
NULL, 0, NULL); |
64 |
|
assert_perror (err); |
65 |
|
|
66 |
|
/* And the kip. */ |
67 |
|
map = map_alloc (); |
68 |
|
assert (map); |
69 |
|
err = map_init (map, (uintptr_t) l4_kip (), l4_kip_area_size (), |
70 |
|
NULL, 0, NULL); |
71 |
|
assert_perror (err); |
72 |
|
|
73 |
/* Add the program code, data segment, etc which can be found in the |
/* Add the program code, data segment, etc which can be found in the |
74 |
start up data. */ |
start up data. */ |
82 |
/* XXX: Wrong, wrong, wrong. Right now we just make sure we |
/* XXX: Wrong, wrong, wrong. Right now we just make sure we |
83 |
know about the virtual address region the mapping uses and |
know about the virtual address region the mapping uses and |
84 |
assume that there won't be any page faults. */ |
assume that there won't be any page faults. */ |
|
map->store = NULL; |
|
85 |
// lookup store (mapv->cont.server, mapv->cont.cap_handle) add |
// lookup store (mapv->cont.server, mapv->cont.cap_handle) add |
86 |
// these frames to it (but we would need to copy them to the |
// these memory to it (but we would need to copy them to the |
87 |
// default container. |
// default container. |
88 |
map->store_offset = mapv->offset & ~0x7; |
err = map_init (map, (l4_word_t) mapv->vaddr, mapv->size, |
89 |
map->vm.start = (l4_word_t) mapv->vaddr; |
NULL, mapv->offset & ~0x7, 0); |
90 |
map->vm.size = mapv->size; |
assert_perror (err); |
91 |
|
|
92 |
/* FIXME: Do something with the access rights (in the lower |
/* FIXME: Do something with the access rights (in the lower |
93 |
three bits of offset). */ |
three bits of offset). */ |
|
|
|
|
map_insert (map); |
|
94 |
} |
} |
95 |
} |
} |
96 |
|
|
97 |
bool map_spare_integrate; |
bool map_spare_integrate; |
98 |
struct map map_spare; |
struct map map_spare; |
99 |
struct frame frame_spare; |
struct hurd_memory memory_spare; |
100 |
|
|
101 |
/* This is the allocation_buffer call back for the map slab. If this |
/* This is the allocation_buffer call back for the map slab. If this |
102 |
is called then someone has called map_alloc and hence map_lock is |
is called then someone has called map_alloc and hence map_lock is |
103 |
locked. */ |
locked. */ |
104 |
error_t |
error_t |
105 |
mem_slab_allocate_buffer (void *hook, size_t size, void **ptr) |
core_slab_allocate_buffer (void *hook, size_t size, void **ptr) |
106 |
{ |
{ |
107 |
error_t err; |
error_t err; |
108 |
int i; |
int i; |
110 |
|
|
111 |
assert ((size & (size - 1)) == 0); |
assert ((size & (size - 1)) == 0); |
112 |
|
|
113 |
/* Find an unused offset. */ |
/* Find an unused virtual memory address. */ |
114 |
if (EXPECT_FALSE (! mm_init_done)) |
if (EXPECT_FALSE (! mm_init_done)) |
115 |
{ |
{ |
116 |
/* We are not yet initialized. Initialize the mapping database. */ |
/* We are not yet initialized. Initialize the mapping database. */ |
167 |
if (! vaddr_free) |
if (! vaddr_free) |
168 |
continue; |
continue; |
169 |
|
|
170 |
/* We may have already allocated a map structure which |
/* We may have already allocated a map structure which the |
171 |
search would not find. This may do some extra work but |
above search would not find. */ |
172 |
that's life. */ |
map = map_find_first (vaddr, size); |
|
map = map_find (vaddr, size); |
|
173 |
if (map) |
if (map) |
174 |
{ |
{ |
175 |
vaddr_free = false; |
vaddr_free = false; |
180 |
while (! vaddr_free); |
while (! vaddr_free); |
181 |
} |
} |
182 |
else |
else |
183 |
vaddr = map_find_free (size, size); |
vaddr = as_find_free (size, size); |
184 |
|
|
185 |
/* Save the mapping in the spare map. We cannot call map_alloc as |
/* Save the mapping in the spare map. We cannot call map_alloc as |
186 |
it is likely (indirectly) invoking us because its slab is out of |
it is likely (indirectly) invoking us because its slab is out of |
192 |
/* We allocate and map the data ourselves even in the case where the |
/* We allocate and map the data ourselves even in the case where the |
193 |
pager is already up: clearly we are going to use the memory as |
pager is already up: clearly we are going to use the memory as |
194 |
soon as we return. */ |
soon as we return. */ |
195 |
err = frame_alloc_into (&frame_spare, vaddr, size); |
err = memory_alloc_into (&memory_spare, size); |
196 |
if (err) |
if (err) |
197 |
{ |
{ |
198 |
debug ("frame_alloc_into failed! %d\n", err); |
debug ("memory_alloc_into failed! %d\n", err); |
199 |
return err; |
return err; |
200 |
} |
} |
201 |
|
|
202 |
map_spare.store = &swap_store; |
map_spare.store = &core_store; |
203 |
map_spare.store_offset = frame_spare.dc_start; |
map_spare.store_offset = memory_spare.cont_start; |
204 |
map_spare.vm.start = vaddr; |
map_spare.vm.start = vaddr; |
205 |
map_spare.vm.size = size; |
map_spare.vm.size = size; |
206 |
map_spare_integrate = true; |
map_spare_integrate = true; |
207 |
|
|
208 |
err = frame_map (&frame_spare, 0, size, vaddr); |
err = hurd_memory_map (&memory_spare, 0, size, vaddr); |
209 |
if (err) |
if (err) |
210 |
/* Hmm, failure. Nevertheless we managed to allocate the memory. |
/* Hmm, failure. Nevertheless we managed to allocate the memory. |
211 |
Let's just ignore it and assume that whatever went wrong will |
Let's just ignore it and assume that whatever went wrong will |
212 |
go away when the memory is eventually faulted in. */ |
go away when the memory is eventually faulted in. */ |
213 |
debug ("frame_map failed! %d\n", err); |
debug ("hurd_memory_map failed! %d\n", err); |
214 |
|
|
215 |
*ptr = (void *) vaddr; |
*ptr = (void *) vaddr; |
216 |
return 0; |
return 0; |
217 |
} |
} |
218 |
|
|
219 |
error_t |
error_t |
220 |
mem_slab_deallocate_buffer (void *hook, void *buffer, size_t size) |
core_slab_deallocate_buffer (void *hook, void *buffer, size_t size) |
221 |
{ |
{ |
222 |
error_t err = hurd_vm_deallocate ((uintptr_t) buffer, size); |
error_t err = hurd_vm_release ((uintptr_t) buffer, size); |
223 |
assert_perror (err); |
assert_perror (err); |
224 |
return 0; |
return 0; |
225 |
} |
} |
226 |
|
|
227 |
struct hurd_slab_space map_slab |
struct hurd_slab_space map_slab |
228 |
= HURD_SLAB_SPACE_INITIALIZER (struct map, |
= HURD_SLAB_SPACE_INITIALIZER (struct map, |
229 |
mem_slab_allocate_buffer, |
core_slab_allocate_buffer, |
230 |
mem_slab_deallocate_buffer, |
core_slab_deallocate_buffer, |
231 |
NULL, NULL, NULL); |
NULL, NULL, NULL); |
232 |
|
|
233 |
struct map * |
struct map * |
246 |
another one for the caller. */ |
another one for the caller. */ |
247 |
if (EXPECT_FALSE (map_spare_integrate)) |
if (EXPECT_FALSE (map_spare_integrate)) |
248 |
{ |
{ |
249 |
struct frame frame, *f; |
struct hurd_memory memory, *f; |
250 |
|
|
251 |
memcpy (map, &map_spare, sizeof (struct map)); |
memcpy (map, &map_spare, sizeof (struct map)); |
252 |
map_insert (map); |
map_insert (map); |
253 |
|
|
254 |
/* We can't allocate it using frame_alloc() as that might call |
/* We can't allocate it using memory_alloc() as that might call |
255 |
the slab's buffer allocation routine and overwrite |
the slab's buffer allocation routine and overwrite |
256 |
FRAME_SPARE. Copy it here, then allocate it and only then |
MEMORY_SPARE. Copy it here, then allocate it and only then |
257 |
copy over. */ |
copy over. */ |
258 |
memcpy (&frame, &frame_spare, sizeof (struct frame)); |
memcpy (&memory, &memory_spare, sizeof (struct hurd_memory)); |
259 |
map_spare_integrate = false; |
map_spare_integrate = false; |
260 |
|
|
261 |
err = hurd_slab_alloc (&frame_slab, (void *) &f); |
err = hurd_slab_alloc (&memory_slab, (void *) &f); |
262 |
assert_perror (err); |
assert_perror (err); |
263 |
|
|
264 |
memcpy (f, &frame, sizeof (struct frame)); |
memcpy (f, &memory, sizeof (struct hurd_memory)); |
265 |
frame_insert (&swap_store, map->store_offset, f); |
hurd_store_cache (&core_store, map->store_offset, f); |
266 |
|
|
267 |
goto start; |
goto start; |
268 |
} |
} |
270 |
return map; |
return map; |
271 |
} |
} |
272 |
|
|
273 |
|
error_t |
274 |
|
map_init (struct map *map, uintptr_t vm_addr, size_t size, |
275 |
|
hurd_store_t *store, size_t store_offset, |
276 |
|
uintptr_t *vm_used_addr) |
277 |
|
{ |
278 |
|
if (vm_addr == 0) |
279 |
|
vm_addr = as_find_free (size, getpagesize ()); |
280 |
|
else |
281 |
|
{ |
282 |
|
struct map *map = map_find_first (vm_addr, size); |
283 |
|
if (map) |
284 |
|
return EEXIST; |
285 |
|
} |
286 |
|
|
287 |
|
map->vm.start = vm_addr; |
288 |
|
map->vm.size = size; |
289 |
|
map->store = store; |
290 |
|
map->store_offset = store_offset; |
291 |
|
|
292 |
|
if (vm_used_addr) |
293 |
|
*vm_used_addr = vm_addr; |
294 |
|
|
295 |
|
map_insert (map); |
296 |
|
|
297 |
|
return 0; |
298 |
|
} |
299 |
|
|
300 |
void |
void |
301 |
map_insert (struct map *map) |
map_insert (struct map *map) |
302 |
{ |
{ |
312 |
} |
} |
313 |
|
|
314 |
void |
void |
315 |
map_dealloc (struct map *map) |
map_free (struct map *map) |
316 |
{ |
{ |
317 |
map_detach (map); |
map_detach (map); |
318 |
hurd_slab_dealloc (&map_slab, (void *) map); |
hurd_slab_dealloc (&map_slab, (void *) map); |
319 |
} |
} |
320 |
|
|
321 |
struct map * |
struct map * |
322 |
map_find (uintptr_t address, size_t size) |
map_find_first (uintptr_t address, size_t size) |
323 |
{ |
{ |
324 |
struct region region = { address, size }; |
struct region region = { address, size }; |
325 |
struct map *map = hurd_btree_map_find (&as.mappings, ®ion); |
struct map *map = hurd_btree_map_find (&as.mappings, ®ion); |
329 |
|
|
330 |
for (;;) |
for (;;) |
331 |
{ |
{ |
332 |
struct map *prev = hurd_btree_map_prev (map); |
if (map->vm.start <= address) |
333 |
|
return map; |
334 |
|
|
335 |
|
struct map *prev = hurd_btree_map_prev (map); |
336 |
if (prev && overlap (address, size, prev->vm.start, prev->vm.size)) |
if (prev && overlap (address, size, prev->vm.start, prev->vm.size)) |
337 |
map = prev; |
map = prev; |
338 |
else |
else |
339 |
return map; |
return map; |
340 |
} |
} |
341 |
} |
} |
|
|
|
|
/* Find a free region of the virtual address space for a region of |
|
|
size SIZE with alignment ALIGN. Must be called with the map lock. |
|
|
The lock msut not be dropped until the virtual address is entered |
|
|
into the mapping database (and this function should not be called |
|
|
again until that has happened). */ |
|
|
uintptr_t |
|
|
map_find_free (size_t size, size_t align) |
|
|
{ |
|
|
/* Start the probe at the lowest address aligned address after |
|
|
VIRTUAL_MEMORY_START. FIXME: We should use a hint. But then, we |
|
|
shouldn't use linked lists either. */ |
|
|
l4_word_t start = (VIRTUAL_MEMORY_START + align - 1) & ~(align - 1); |
|
|
bool ok; |
|
|
struct map *map; |
|
|
|
|
|
do |
|
|
{ |
|
|
/* The proposed start is free unless proven not to be. */ |
|
|
ok = true; |
|
|
|
|
|
/* Iterate over all of the maps and see if any intersect. If |
|
|
none do, then we have a good address. */ |
|
|
for (map = hurd_btree_map_first (&as.mappings); map; |
|
|
map = hurd_btree_map_next (map)) |
|
|
if (overlap (start, size, map->vm.start, map->vm.size)) |
|
|
{ |
|
|
ok = false; |
|
|
/* Use the next aligned virtual address after MAP. */ |
|
|
/* FIXME: We need to check that we don't overflow. */ |
|
|
start = (map->vm.start + map->vm.size + align - 1) & ~(align - 1); |
|
|
break; |
|
|
} |
|
|
} |
|
|
while (! ok); |
|
|
|
|
|
return start; |
|
|
} |
|
|
|
|
|
/* Find a free region in a container for a region of size SIZE with |
|
|
alignment ALIGN. Must be called with the map lock. The lock must |
|
|
not be dropped until the virtual address is entered into the |
|
|
mapping database (and this function should not be called again |
|
|
until that has happened). */ |
|
|
uintptr_t |
|
|
store_find_free (struct store *store, size_t size, size_t align) |
|
|
{ |
|
|
/* FIXME: Optimize this search! */ |
|
|
l4_word_t offset = 0; |
|
|
bool ok; |
|
|
struct frame *frame; |
|
|
|
|
|
assert (! map_spare_integrate); |
|
|
|
|
|
do |
|
|
{ |
|
|
/* The proposed offset is free unless proven not to be. */ |
|
|
ok = true; |
|
|
|
|
|
for (frame = hurd_btree_frame_first (&store->frames); frame; |
|
|
frame = hurd_btree_frame_next (frame)) |
|
|
if (overlap (offset, size, frame->dc_start, frame->store.size)) |
|
|
{ |
|
|
ok = false; |
|
|
/* FIXME: Check for overflow. */ |
|
|
offset = (frame->dc_start + frame->store.size + align - 1) |
|
|
& ~(align - 1); |
|
|
break; |
|
|
} |
|
|
} |
|
|
while (! ok); |
|
|
|
|
|
debug ("Sought range covering %x bytes with alignment %x. Using %x\n", |
|
|
size, align, offset); |
|
|
|
|
|
return offset; |
|
|
} |
|