Rev 1238 | Rev 1248 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 1238 | Rev 1239 | ||
---|---|---|---|
Line 124... | Line 124... | ||
124 | /** Create address space area of common attributes. |
124 | /** Create address space area of common attributes. |
125 | * |
125 | * |
126 | * The created address space area is added to the target address space. |
126 | * The created address space area is added to the target address space. |
127 | * |
127 | * |
128 | * @param as Target address space. |
128 | * @param as Target address space. |
129 | * @param flags Flags of the area. |
129 | * @param flags Flags of the area memory. |
130 | * @param size Size of area. |
130 | * @param size Size of area. |
131 | * @param base Base address of area. |
131 | * @param base Base address of area. |
- | 132 | * @param attrs Attributes of the area. |
|
132 | * |
133 | * |
133 | * @return Address space area on success or NULL on failure. |
134 | * @return Address space area on success or NULL on failure. |
134 | */ |
135 | */ |
135 | as_area_t *as_area_create(as_t *as, int flags, size_t size, __address base) |
136 | as_area_t *as_area_create(as_t *as, int flags, size_t size, __address base, int attrs) |
136 | { |
137 | { |
137 | ipl_t ipl; |
138 | ipl_t ipl; |
138 | as_area_t *a; |
139 | as_area_t *a; |
139 | 140 | ||
140 | if (base % PAGE_SIZE) |
141 | if (base % PAGE_SIZE) |
Line 159... | Line 160... | ||
159 | a = (as_area_t *) malloc(sizeof(as_area_t), 0); |
160 | a = (as_area_t *) malloc(sizeof(as_area_t), 0); |
160 | 161 | ||
161 | spinlock_initialize(&a->lock, "as_area_lock"); |
162 | spinlock_initialize(&a->lock, "as_area_lock"); |
162 | 163 | ||
163 | a->flags = flags; |
164 | a->flags = flags; |
- | 165 | a->attributes = attrs; |
|
164 | a->pages = SIZE2FRAMES(size); |
166 | a->pages = SIZE2FRAMES(size); |
165 | a->base = base; |
167 | a->base = base; |
166 | 168 | ||
167 | btree_insert(&as->as_area_btree, base, (void *) a, NULL); |
169 | btree_insert(&as->as_area_btree, base, (void *) a, NULL); |
168 | 170 | ||
Line 287... | Line 289... | ||
287 | * source area. Moreover, any existing mapping |
289 | * source area. Moreover, any existing mapping |
288 | * is copied as well, providing thus a mechanism |
290 | * is copied as well, providing thus a mechanism |
289 | * for sharing group of pages. The source address |
291 | * for sharing group of pages. The source address |
290 | * space area and any associated mapping is preserved. |
292 | * space area and any associated mapping is preserved. |
291 | * |
293 | * |
292 | * @param id Task ID of the accepting task. |
294 | * @param dst_id Task ID of the accepting task. |
293 | * @param base Base address of the source address space area. |
295 | * @param src_base Base address of the source address space area. |
294 | * |
296 | * |
295 | * @return 0 on success or ENOENT if there is no such task or |
297 | * @return 0 on success or ENOENT if there is no such task or |
296 | * if there is no such address space area, |
298 | * if there is no such address space area, |
297 | * EPERM if there was a problem in accepting the area or |
299 | * EPERM if there was a problem in accepting the area or |
298 | * ENOMEM if there was a problem in allocating destination |
300 | * ENOMEM if there was a problem in allocating destination |
299 | * address space area. |
301 | * address space area. |
300 | */ |
302 | */ |
301 | int as_area_send(task_id_t id, __address base) |
303 | int as_area_send(task_id_t dst_id, __address src_base) |
302 | { |
304 | { |
303 | ipl_t ipl; |
305 | ipl_t ipl; |
304 | task_t *t; |
306 | task_t *t; |
305 | count_t i; |
307 | count_t i; |
306 | as_t *as; |
308 | as_t *dst_as; |
307 | __address dst_base; |
309 | __address dst_base; |
308 | int flags; |
310 | int src_flags; |
309 | size_t size; |
311 | size_t src_size; |
310 | as_area_t *area; |
312 | as_area_t *src_area, *dst_area; |
311 | 313 | ||
312 | ipl = interrupts_disable(); |
314 | ipl = interrupts_disable(); |
313 | spinlock_lock(&tasks_lock); |
315 | spinlock_lock(&tasks_lock); |
314 | 316 | ||
315 | t = task_find_by_id(id); |
317 | t = task_find_by_id(dst_id); |
316 | if (!NULL) { |
318 | if (!NULL) { |
317 | spinlock_unlock(&tasks_lock); |
319 | spinlock_unlock(&tasks_lock); |
318 | interrupts_restore(ipl); |
320 | interrupts_restore(ipl); |
319 | return ENOENT; |
321 | return ENOENT; |
320 | } |
322 | } |
321 | 323 | ||
322 | spinlock_lock(&t->lock); |
324 | spinlock_lock(&t->lock); |
323 | spinlock_unlock(&tasks_lock); |
325 | spinlock_unlock(&tasks_lock); |
324 | 326 | ||
325 | as = t->as; |
327 | dst_as = t->as; |
326 | dst_base = (__address) t->accept_arg.base; |
328 | dst_base = (__address) t->accept_arg.base; |
327 | 329 | ||
328 | if (as == AS) { |
330 | if (dst_as == AS) { |
329 | /* |
331 | /* |
330 | * The two tasks share the entire address space. |
332 | * The two tasks share the entire address space. |
331 | * Return error since there is no point in continuing. |
333 | * Return error since there is no point in continuing. |
332 | */ |
334 | */ |
333 | spinlock_unlock(&t->lock); |
335 | spinlock_unlock(&t->lock); |
334 | interrupts_restore(ipl); |
336 | interrupts_restore(ipl); |
335 | return EPERM; |
337 | return EPERM; |
336 | } |
338 | } |
337 | 339 | ||
338 | spinlock_lock(&AS->lock); |
340 | spinlock_lock(&AS->lock); |
339 | area = find_area_and_lock(AS, base); |
341 | src_area = find_area_and_lock(AS, src_base); |
340 | if (!area) { |
342 | if (!src_area) { |
341 | /* |
343 | /* |
342 | * Could not find the source address space area. |
344 | * Could not find the source address space area. |
343 | */ |
345 | */ |
344 | spinlock_unlock(&t->lock); |
346 | spinlock_unlock(&t->lock); |
345 | spinlock_unlock(&AS->lock); |
347 | spinlock_unlock(&AS->lock); |
346 | interrupts_restore(ipl); |
348 | interrupts_restore(ipl); |
347 | return ENOENT; |
349 | return ENOENT; |
348 | } |
350 | } |
349 | size = area->pages * PAGE_SIZE; |
351 | src_size = src_area->pages * PAGE_SIZE; |
350 | flags = area->flags; |
352 | src_flags = src_area->flags; |
351 | spinlock_unlock(&area->lock); |
353 | spinlock_unlock(&src_area->lock); |
352 | spinlock_unlock(&AS->lock); |
354 | spinlock_unlock(&AS->lock); |
353 | 355 | ||
354 | if ((t->accept_arg.task_id != TASK->taskid) || (t->accept_arg.size != size) || |
356 | if ((t->accept_arg.task_id != TASK->taskid) || (t->accept_arg.size != src_size) || |
355 | (t->accept_arg.flags != flags)) { |
357 | (t->accept_arg.flags != src_flags)) { |
356 | /* |
358 | /* |
357 | * Discrepancy in either task ID, size or flags. |
359 | * Discrepancy in either task ID, size or flags. |
358 | */ |
360 | */ |
359 | spinlock_unlock(&t->lock); |
361 | spinlock_unlock(&t->lock); |
360 | interrupts_restore(ipl); |
362 | interrupts_restore(ipl); |
361 | return EPERM; |
363 | return EPERM; |
362 | } |
364 | } |
363 | 365 | ||
364 | /* |
366 | /* |
365 | * Create copy of the address space area. |
367 | * Create copy of the source address space area. |
- | 368 | * The destination area is created with AS_AREA_ATTR_PARTIAL |
|
- | 369 | * attribute set which prevents race condition with |
|
- | 370 | * preliminary as_page_fault() calls. |
|
366 | */ |
371 | */ |
367 | if (!as_area_create(as, flags, size, dst_base)) { |
372 | dst_area = as_area_create(dst_as, src_flags, src_size, dst_base, AS_AREA_ATTR_PARTIAL); |
- | 373 | if (!dst_area) { |
|
368 | /* |
374 | /* |
369 | * Destination address space area could not be created. |
375 | * Destination address space area could not be created. |
370 | */ |
376 | */ |
371 | spinlock_unlock(&t->lock); |
377 | spinlock_unlock(&t->lock); |
372 | interrupts_restore(ipl); |
378 | interrupts_restore(ipl); |
373 | return ENOMEM; |
379 | return ENOMEM; |
374 | } |
380 | } |
375 | 381 | ||
376 | /* |
- | |
377 | * NOTE: we have just introduced a race condition. |
- | |
378 | * The destination task can try to attempt the newly |
- | |
379 | * created area before its mapping is copied from |
- | |
380 | * the source address space area. In result, frames |
- | |
381 | * can get lost. |
- | |
382 | * |
- | |
383 | * Currently, this race is not solved, but one of the |
- | |
384 | * possible solutions would be to sleep in as_page_fault() |
- | |
385 | * when this situation is detected. |
- | |
386 | */ |
- | |
387 | - | ||
388 | memsetb((__address) &t->accept_arg, sizeof(as_area_acptsnd_arg_t), 0); |
382 | memsetb((__address) &t->accept_arg, sizeof(as_area_acptsnd_arg_t), 0); |
389 | spinlock_unlock(&t->lock); |
383 | spinlock_unlock(&t->lock); |
390 | 384 | ||
391 | /* |
385 | /* |
392 | * Avoid deadlock by first locking the address space with lower address. |
386 | * Avoid deadlock by first locking the address space with lower address. |
393 | */ |
387 | */ |
394 | if (as < AS) { |
388 | if (dst_as < AS) { |
395 | spinlock_lock(&as->lock); |
389 | spinlock_lock(&dst_as->lock); |
396 | spinlock_lock(&AS->lock); |
390 | spinlock_lock(&AS->lock); |
397 | } else { |
391 | } else { |
398 | spinlock_lock(&AS->lock); |
392 | spinlock_lock(&AS->lock); |
399 | spinlock_lock(&as->lock); |
393 | spinlock_lock(&dst_as->lock); |
400 | } |
394 | } |
401 | 395 | ||
402 | for (i = 0; i < SIZE2FRAMES(size); i++) { |
396 | for (i = 0; i < SIZE2FRAMES(src_size); i++) { |
403 | pte_t *pte; |
397 | pte_t *pte; |
404 | __address frame; |
398 | __address frame; |
405 | 399 | ||
406 | page_table_lock(AS, false); |
400 | page_table_lock(AS, false); |
407 | pte = page_mapping_find(AS, base + i*PAGE_SIZE); |
401 | pte = page_mapping_find(AS, src_base + i*PAGE_SIZE); |
408 | if (pte && PTE_VALID(pte)) { |
402 | if (pte && PTE_VALID(pte)) { |
409 | ASSERT(PTE_PRESENT(pte)); |
403 | ASSERT(PTE_PRESENT(pte)); |
410 | frame = PTE_GET_FRAME(pte); |
404 | frame = PTE_GET_FRAME(pte); |
411 | if (!(flags & AS_AREA_DEVICE)) |
405 | if (!(src_flags & AS_AREA_DEVICE)) |
412 | frame_reference_add(ADDR2PFN(frame)); |
406 | frame_reference_add(ADDR2PFN(frame)); |
413 | page_table_unlock(AS, false); |
407 | page_table_unlock(AS, false); |
414 | } else { |
408 | } else { |
415 | page_table_unlock(AS, false); |
409 | page_table_unlock(AS, false); |
416 | continue; |
410 | continue; |
417 | } |
411 | } |
418 | 412 | ||
419 | page_table_lock(as, false); |
413 | page_table_lock(dst_as, false); |
420 | page_mapping_insert(as, dst_base + i*PAGE_SIZE, frame, area_flags_to_page_flags(flags)); |
414 | page_mapping_insert(dst_as, dst_base + i*PAGE_SIZE, frame, area_flags_to_page_flags(src_flags)); |
421 | page_table_unlock(as, false); |
415 | page_table_unlock(dst_as, false); |
422 | } |
416 | } |
- | 417 | ||
- | 418 | /* |
|
- | 419 | * Now the destination address space area has been |
|
- | 420 | * fully initialized. Clear the AS_AREA_ATTR_PARTIAL |
|
- | 421 | * attribute. |
|
- | 422 | */ |
|
- | 423 | spinlock_lock(&dst_area->lock); |
|
- | 424 | dst_area->attributes &= ~AS_AREA_ATTR_PARTIAL; |
|
- | 425 | spinlock_unlock(&dst_area->lock); |
|
423 | 426 | ||
424 | spinlock_unlock(&AS->lock); |
427 | spinlock_unlock(&AS->lock); |
425 | spinlock_unlock(&as->lock); |
428 | spinlock_unlock(&dst_as->lock); |
426 | interrupts_restore(ipl); |
429 | interrupts_restore(ipl); |
427 | 430 | ||
428 | return 0; |
431 | return 0; |
429 | } |
432 | } |
430 | 433 | ||
Line 484... | Line 487... | ||
484 | */ |
487 | */ |
485 | spinlock_unlock(&AS->lock); |
488 | spinlock_unlock(&AS->lock); |
486 | return 0; |
489 | return 0; |
487 | } |
490 | } |
488 | 491 | ||
- | 492 | if (area->attributes & AS_AREA_ATTR_PARTIAL) { |
|
- | 493 | /* |
|
- | 494 | * The address space area is not fully initialized. |
|
- | 495 | * Avoid possible race by returning error. |
|
- | 496 | */ |
|
- | 497 | spinlock_unlock(&area->lock); |
|
- | 498 | spinlock_unlock(&AS->lock); |
|
- | 499 | return 0; |
|
- | 500 | } |
|
- | 501 | ||
489 | ASSERT(!(area->flags & AS_AREA_DEVICE)); |
502 | ASSERT(!(area->flags & AS_AREA_DEVICE)); |
490 | 503 | ||
491 | page_table_lock(AS, false); |
504 | page_table_lock(AS, false); |
492 | 505 | ||
493 | /* |
506 | /* |
Line 837... | Line 850... | ||
837 | */ |
850 | */ |
838 | 851 | ||
839 | /** Wrapper for as_area_create(). */ |
852 | /** Wrapper for as_area_create(). */ |
840 | __native sys_as_area_create(__address address, size_t size, int flags) |
853 | __native sys_as_area_create(__address address, size_t size, int flags) |
841 | { |
854 | { |
842 | if (as_area_create(AS, flags, size, address)) |
855 | if (as_area_create(AS, flags, size, address, AS_AREA_ATTR_NONE)) |
843 | return (__native) address; |
856 | return (__native) address; |
844 | else |
857 | else |
845 | return (__native) -1; |
858 | return (__native) -1; |
846 | } |
859 | } |
847 | 860 |