source: mainline/kernel/generic/src/mm/as.c@ fc47885

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since fc47885 was fc47885, checked in by Martin Decky <martin@…>, 15 years ago

keep track of the number of resident pages on-the-fly (do not traverse the B+ tree while reading sysinfo)
cstyle updates (mostly update of comments)

  • Property mode set to 100644
File size: 51.4 KB
RevLine 
[20d50a1]1/*
[0321109]2 * Copyright (c) 2010 Jakub Jermar
[20d50a1]3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
[cc73a8a1]29/** @addtogroup genericmm
[b45c443]30 * @{
31 */
32
[9179d0a]33/**
[b45c443]34 * @file
[da1bafb]35 * @brief Address space related functions.
[9179d0a]36 *
[20d50a1]37 * This file contains address space manipulation functions.
38 * Roughly speaking, this is a higher-level client of
39 * Virtual Address Translation (VAT) subsystem.
[9179d0a]40 *
41 * Functionality provided by this file allows one to
[cc73a8a1]42 * create address spaces and create, resize and share
[9179d0a]43 * address space areas.
44 *
45 * @see page.c
46 *
[20d50a1]47 */
48
49#include <mm/as.h>
[ef67bab]50#include <arch/mm/as.h>
[20d50a1]51#include <mm/page.h>
52#include <mm/frame.h>
[085d973]53#include <mm/slab.h>
[20d50a1]54#include <mm/tlb.h>
55#include <arch/mm/page.h>
56#include <genarch/mm/page_pt.h>
[2802767]57#include <genarch/mm/page_ht.h>
[4512d7e]58#include <mm/asid.h>
[20d50a1]59#include <arch/mm/asid.h>
[31d8e10]60#include <preemption.h>
[20d50a1]61#include <synch/spinlock.h>
[1068f6a]62#include <synch/mutex.h>
[5c9a08b]63#include <adt/list.h>
[252127e]64#include <adt/btree.h>
[df0103f7]65#include <proc/task.h>
[e3c762cd]66#include <proc/thread.h>
[20d50a1]67#include <arch/asm.h>
[df0103f7]68#include <panic.h>
[20d50a1]69#include <debug.h>
[df0103f7]70#include <print.h>
[20d50a1]71#include <memstr.h>
[5a7d9d1]72#include <macros.h>
[20d50a1]73#include <arch.h>
[df0103f7]74#include <errno.h>
75#include <config.h>
[25bf215]76#include <align.h>
[d99c1d2]77#include <typedefs.h>
[e3c762cd]78#include <syscall/copy.h>
79#include <arch/interrupt.h>
[20d50a1]80
[92778f2]81#ifdef CONFIG_VIRT_IDX_DCACHE
82#include <arch/mm/cache.h>
83#endif /* CONFIG_VIRT_IDX_DCACHE */
84
[cc73a8a1]85/**
86 * Each architecture decides what functions will be used to carry out
87 * address space operations such as creating or locking page tables.
88 */
[ef67bab]89as_operations_t *as_operations = NULL;
[20d50a1]90
[fc47885]91/** Slab for as_t objects.
[da1bafb]92 *
[57da95c]93 */
94static slab_cache_t *as_slab;
95
[fc47885]96/** ASID subsystem lock.
97 *
98 * This lock protects:
[879585a3]99 * - inactive_as_with_asid_head list
100 * - as->asid for each as of the as_t type
101 * - asids_allocated counter
[da1bafb]102 *
[6f4495f5]103 */
[879585a3]104SPINLOCK_INITIALIZE(asidlock);
[7e4e532]105
106/**
[fc47885]107 * Inactive address spaces (on all processors)
108 * that have valid ASID.
[7e4e532]109 */
110LIST_INITIALIZE(inactive_as_with_asid_head);
111
[071a8ae6]112/** Kernel address space. */
113as_t *AS_KERNEL = NULL;
114
[7a0359b]115NO_TRACE static int as_constructor(void *obj, unsigned int flags)
[29b2bbf]116{
117 as_t *as = (as_t *) obj;
[da1bafb]118
[29b2bbf]119 link_initialize(&as->inactive_as_with_asid_link);
[7f341820]120 mutex_initialize(&as->lock, MUTEX_PASSIVE);
[29b2bbf]121
[fc47885]122 return as_constructor_arch(as, flags);
[29b2bbf]123}
124
[7a0359b]125NO_TRACE static size_t as_destructor(void *obj)
[29b2bbf]126{
[fc47885]127 return as_destructor_arch((as_t *) obj);
[29b2bbf]128}
129
[ef67bab]130/** Initialize address space subsystem. */
131void as_init(void)
132{
133 as_arch_init();
[da1bafb]134
[29b2bbf]135 as_slab = slab_cache_create("as_slab", sizeof(as_t), 0,
[6f4495f5]136 as_constructor, as_destructor, SLAB_CACHE_MAGDEFERRED);
[57da95c]137
[8e1ea655]138 AS_KERNEL = as_create(FLAG_AS_KERNEL);
[125e944]139 if (!AS_KERNEL)
[f651e80]140 panic("Cannot create kernel address space.");
[125e944]141
[fc47885]142 /*
143 * Make sure the kernel address space
[76fca31]144 * reference count never drops to zero.
145 */
[6193351]146 as_hold(AS_KERNEL);
[ef67bab]147}
148
[071a8ae6]149/** Create address space.
150 *
[da1bafb]151 * @param flags Flags that influence the way in wich the address
152 * space is created.
153 *
[071a8ae6]154 */
[da1bafb]155as_t *as_create(unsigned int flags)
[20d50a1]156{
[da1bafb]157 as_t *as = (as_t *) slab_alloc(as_slab, 0);
[29b2bbf]158 (void) as_create_arch(as, 0);
159
[252127e]160 btree_create(&as->as_area_btree);
[bb68433]161
162 if (flags & FLAG_AS_KERNEL)
163 as->asid = ASID_KERNEL;
164 else
165 as->asid = ASID_INVALID;
166
[31d8e10]167 atomic_set(&as->refcount, 0);
[47800e0]168 as->cpu_refcount = 0;
[da1bafb]169
[b3f8fb7]170#ifdef AS_PAGE_TABLE
[80bcaed]171 as->genarch.page_table = page_table_create(flags);
[b3f8fb7]172#else
173 page_table_create(flags);
174#endif
[76fca31]175
[20d50a1]176 return as;
177}
178
[482826d]179/** Destroy adress space.
180 *
[6f4495f5]181 * When there are no tasks referencing this address space (i.e. its refcount is
182 * zero), the address space can be destroyed.
[31d8e10]183 *
184 * We know that we don't hold any spinlock.
[6745592]185 *
[da1bafb]186 * @param as Address space to be destroyed.
187 *
[482826d]188 */
189void as_destroy(as_t *as)
[5be1923]190{
[31d8e10]191 DEADLOCK_PROBE_INIT(p_asidlock);
[fc47885]192
[1624aae]193 ASSERT(as != AS);
[31d8e10]194 ASSERT(atomic_get(&as->refcount) == 0);
[482826d]195
196 /*
[663bb537]197 * Since there is no reference to this address space, it is safe not to
198 * lock its mutex.
[482826d]199 */
[fc47885]200
[31d8e10]201 /*
202 * We need to avoid deadlock between TLB shootdown and asidlock.
203 * We therefore try to take asid conditionally and if we don't succeed,
204 * we enable interrupts and try again. This is done while preemption is
205 * disabled to prevent nested context switches. We also depend on the
206 * fact that so far no spinlocks are held.
207 */
208 preemption_disable();
[da1bafb]209 ipl_t ipl = interrupts_read();
210
[31d8e10]211retry:
212 interrupts_disable();
213 if (!spinlock_trylock(&asidlock)) {
214 interrupts_enable();
215 DEADLOCK_PROBE(p_asidlock, DEADLOCK_THRESHOLD);
216 goto retry;
217 }
[da1bafb]218
219 /* Interrupts disabled, enable preemption */
220 preemption_enable();
221
222 if ((as->asid != ASID_INVALID) && (as != AS_KERNEL)) {
[1624aae]223 if (as->cpu_refcount == 0)
[31e8ddd]224 list_remove(&as->inactive_as_with_asid_link);
[da1bafb]225
[482826d]226 asid_put(as->asid);
227 }
[da1bafb]228
[879585a3]229 spinlock_unlock(&asidlock);
[fdaad75d]230 interrupts_restore(ipl);
[fc47885]231
[da1bafb]232
[482826d]233 /*
234 * Destroy address space areas of the address space.
[8440473]235 * The B+tree must be walked carefully because it is
[6f9a9bc]236 * also being destroyed.
[da1bafb]237 */
238 bool cond = true;
239 while (cond) {
[6f9a9bc]240 ASSERT(!list_empty(&as->as_area_btree.leaf_head));
[da1bafb]241
242 btree_node_t *node =
243 list_get_instance(as->as_area_btree.leaf_head.next,
[6f4495f5]244 btree_node_t, leaf_link);
[da1bafb]245
246 if ((cond = node->keys))
[6f9a9bc]247 as_area_destroy(as, node->key[0]);
[482826d]248 }
[da1bafb]249
[152b2b0]250 btree_destroy(&as->as_area_btree);
[da1bafb]251
[b3f8fb7]252#ifdef AS_PAGE_TABLE
[80bcaed]253 page_table_destroy(as->genarch.page_table);
[b3f8fb7]254#else
255 page_table_destroy(NULL);
256#endif
[da1bafb]257
[57da95c]258 slab_free(as_slab, as);
[5be1923]259}
260
[0321109]261/** Hold a reference to an address space.
262 *
[fc47885]263 * Holding a reference to an address space prevents destruction
264 * of that address space.
[0321109]265 *
[da1bafb]266 * @param as Address space to be held.
267 *
[0321109]268 */
[7a0359b]269NO_TRACE void as_hold(as_t *as)
[0321109]270{
271 atomic_inc(&as->refcount);
272}
273
274/** Release a reference to an address space.
275 *
[fc47885]276 * The last one to release a reference to an address space
277 * destroys the address space.
[0321109]278 *
[da1bafb]279 * @param asAddress space to be released.
280 *
[0321109]281 */
[7a0359b]282NO_TRACE void as_release(as_t *as)
[0321109]283{
284 if (atomic_predec(&as->refcount) == 0)
285 as_destroy(as);
286}
287
[e3ee9b9]288/** Check area conflicts with other areas.
289 *
290 * @param as Address space.
291 * @param va Starting virtual address of the area being tested.
292 * @param size Size of the area being tested.
293 * @param avoid_area Do not touch this area.
294 *
295 * @return True if there is no conflict, false otherwise.
296 *
297 */
[7a0359b]298NO_TRACE static bool check_area_conflicts(as_t *as, uintptr_t va, size_t size,
[e3ee9b9]299 as_area_t *avoid_area)
300{
301 ASSERT(mutex_locked(&as->lock));
302
303 /*
304 * We don't want any area to have conflicts with NULL page.
305 */
[0b4a67a]306 if (overlaps(va, size, (uintptr_t) NULL, PAGE_SIZE))
[e3ee9b9]307 return false;
308
309 /*
310 * The leaf node is found in O(log n), where n is proportional to
311 * the number of address space areas belonging to as.
312 * The check for conflicts is then attempted on the rightmost
313 * record in the left neighbour, the leftmost record in the right
314 * neighbour and all records in the leaf node itself.
315 */
316 btree_node_t *leaf;
317 as_area_t *area =
318 (as_area_t *) btree_search(&as->as_area_btree, va, &leaf);
319 if (area) {
320 if (area != avoid_area)
321 return false;
322 }
323
324 /* First, check the two border cases. */
325 btree_node_t *node =
326 btree_leaf_node_left_neighbour(&as->as_area_btree, leaf);
327 if (node) {
328 area = (as_area_t *) node->value[node->keys - 1];
329
330 mutex_lock(&area->lock);
331
332 if (overlaps(va, size, area->base, area->pages * PAGE_SIZE)) {
333 mutex_unlock(&area->lock);
334 return false;
335 }
336
337 mutex_unlock(&area->lock);
338 }
339
340 node = btree_leaf_node_right_neighbour(&as->as_area_btree, leaf);
341 if (node) {
342 area = (as_area_t *) node->value[0];
343
344 mutex_lock(&area->lock);
345
346 if (overlaps(va, size, area->base, area->pages * PAGE_SIZE)) {
347 mutex_unlock(&area->lock);
348 return false;
349 }
350
351 mutex_unlock(&area->lock);
352 }
353
354 /* Second, check the leaf node. */
355 btree_key_t i;
356 for (i = 0; i < leaf->keys; i++) {
357 area = (as_area_t *) leaf->value[i];
358
359 if (area == avoid_area)
360 continue;
361
362 mutex_lock(&area->lock);
363
364 if (overlaps(va, size, area->base, area->pages * PAGE_SIZE)) {
365 mutex_unlock(&area->lock);
366 return false;
367 }
368
369 mutex_unlock(&area->lock);
370 }
371
372 /*
373 * So far, the area does not conflict with other areas.
374 * Check if it doesn't conflict with kernel address space.
375 */
376 if (!KERNEL_ADDRESS_SPACE_SHADOWED) {
377 return !overlaps(va, size,
378 KERNEL_ADDRESS_SPACE_START,
379 KERNEL_ADDRESS_SPACE_END - KERNEL_ADDRESS_SPACE_START);
380 }
381
382 return true;
383}
384
[20d50a1]385/** Create address space area of common attributes.
386 *
387 * The created address space area is added to the target address space.
388 *
[da1bafb]389 * @param as Target address space.
390 * @param flags Flags of the area memory.
391 * @param size Size of area.
392 * @param base Base address of area.
393 * @param attrs Attributes of the area.
394 * @param backend Address space area backend. NULL if no backend is used.
395 * @param backend_data NULL or a pointer to an array holding two void *.
396 *
397 * @return Address space area on success or NULL on failure.
[20d50a1]398 *
399 */
[da1bafb]400as_area_t *as_area_create(as_t *as, unsigned int flags, size_t size,
401 uintptr_t base, unsigned int attrs, mem_backend_t *backend,
402 mem_backend_data_t *backend_data)
[20d50a1]403{
404 if (base % PAGE_SIZE)
[37e7d2b9]405 return NULL;
[da1bafb]406
[dbbeb26]407 if (!size)
408 return NULL;
[da1bafb]409
[37e7d2b9]410 /* Writeable executable areas are not supported. */
411 if ((flags & AS_AREA_EXEC) && (flags & AS_AREA_WRITE))
412 return NULL;
[20d50a1]413
[1068f6a]414 mutex_lock(&as->lock);
[20d50a1]415
[37e7d2b9]416 if (!check_area_conflicts(as, base, size, NULL)) {
[1068f6a]417 mutex_unlock(&as->lock);
[37e7d2b9]418 return NULL;
419 }
[20d50a1]420
[da1bafb]421 as_area_t *area = (as_area_t *) malloc(sizeof(as_area_t), 0);
422
423 mutex_initialize(&area->lock, MUTEX_PASSIVE);
424
425 area->as = as;
426 area->flags = flags;
427 area->attributes = attrs;
428 area->pages = SIZE2FRAMES(size);
[fc47885]429 area->resident = 0;
[da1bafb]430 area->base = base;
431 area->sh_info = NULL;
432 area->backend = backend;
433
[0ee077ee]434 if (backend_data)
[da1bafb]435 area->backend_data = *backend_data;
[0ee077ee]436 else
[da1bafb]437 memsetb(&area->backend_data, sizeof(area->backend_data), 0);
438
439 btree_create(&area->used_space);
440 btree_insert(&as->as_area_btree, base, (void *) area, NULL);
[bb68433]441
[1068f6a]442 mutex_unlock(&as->lock);
[da1bafb]443
444 return area;
[20d50a1]445}
446
[e3ee9b9]447/** Find address space area and lock it.
448 *
449 * @param as Address space.
450 * @param va Virtual address.
451 *
452 * @return Locked address space area containing va on success or
453 * NULL on failure.
454 *
455 */
[7a0359b]456NO_TRACE static as_area_t *find_area_and_lock(as_t *as, uintptr_t va)
[e3ee9b9]457{
458 ASSERT(mutex_locked(&as->lock));
459
460 btree_node_t *leaf;
461 as_area_t *area = (as_area_t *) btree_search(&as->as_area_btree, va, &leaf);
462 if (area) {
463 /* va is the base address of an address space area */
464 mutex_lock(&area->lock);
465 return area;
466 }
467
468 /*
469 * Search the leaf node and the righmost record of its left neighbour
470 * to find out whether this is a miss or va belongs to an address
471 * space area found there.
472 */
473
474 /* First, search the leaf node itself. */
475 btree_key_t i;
476
477 for (i = 0; i < leaf->keys; i++) {
478 area = (as_area_t *) leaf->value[i];
479
480 mutex_lock(&area->lock);
481
482 if ((area->base <= va) && (va < area->base + area->pages * PAGE_SIZE))
483 return area;
484
485 mutex_unlock(&area->lock);
486 }
487
488 /*
489 * Second, locate the left neighbour and test its last record.
490 * Because of its position in the B+tree, it must have base < va.
491 */
492 btree_node_t *lnode = btree_leaf_node_left_neighbour(&as->as_area_btree, leaf);
493 if (lnode) {
494 area = (as_area_t *) lnode->value[lnode->keys - 1];
495
496 mutex_lock(&area->lock);
497
498 if (va < area->base + area->pages * PAGE_SIZE)
499 return area;
500
501 mutex_unlock(&area->lock);
502 }
503
504 return NULL;
505}
506
[df0103f7]507/** Find address space area and change it.
508 *
[da1bafb]509 * @param as Address space.
510 * @param address Virtual address belonging to the area to be changed.
511 * Must be page-aligned.
512 * @param size New size of the virtual memory block starting at
513 * address.
514 * @param flags Flags influencing the remap operation. Currently unused.
515 *
516 * @return Zero on success or a value from @ref errno.h otherwise.
[df0103f7]517 *
[da1bafb]518 */
519int as_area_resize(as_t *as, uintptr_t address, size_t size, unsigned int flags)
[df0103f7]520{
[1068f6a]521 mutex_lock(&as->lock);
[df0103f7]522
523 /*
524 * Locate the area.
525 */
[da1bafb]526 as_area_t *area = find_area_and_lock(as, address);
[df0103f7]527 if (!area) {
[1068f6a]528 mutex_unlock(&as->lock);
[7242a78e]529 return ENOENT;
[df0103f7]530 }
[da1bafb]531
[0ee077ee]532 if (area->backend == &phys_backend) {
[df0103f7]533 /*
534 * Remapping of address space areas associated
535 * with memory mapped devices is not supported.
536 */
[1068f6a]537 mutex_unlock(&area->lock);
538 mutex_unlock(&as->lock);
[7242a78e]539 return ENOTSUP;
[df0103f7]540 }
[da1bafb]541
[8182031]542 if (area->sh_info) {
543 /*
[da1bafb]544 * Remapping of shared address space areas
[8182031]545 * is not supported.
546 */
547 mutex_unlock(&area->lock);
548 mutex_unlock(&as->lock);
549 return ENOTSUP;
550 }
[da1bafb]551
552 size_t pages = SIZE2FRAMES((address - area->base) + size);
[df0103f7]553 if (!pages) {
554 /*
555 * Zero size address space areas are not allowed.
556 */
[1068f6a]557 mutex_unlock(&area->lock);
558 mutex_unlock(&as->lock);
[7242a78e]559 return EPERM;
[df0103f7]560 }
561
562 if (pages < area->pages) {
[eeb2bde2]563 uintptr_t start_free = area->base + pages * PAGE_SIZE;
[da1bafb]564
[df0103f7]565 /*
566 * Shrinking the area.
567 * No need to check for overlaps.
568 */
[da1bafb]569
[c964521]570 page_table_lock(as, false);
[da1bafb]571
[5552d60]572 /*
573 * Start TLB shootdown sequence.
574 */
[402eda5]575 ipl_t ipl = tlb_shootdown_start(TLB_INVL_PAGES, as->asid,
576 area->base + pages * PAGE_SIZE, area->pages - pages);
[da1bafb]577
[56789125]578 /*
579 * Remove frames belonging to used space starting from
580 * the highest addresses downwards until an overlap with
581 * the resized address space area is found. Note that this
582 * is also the right way to remove part of the used_space
583 * B+tree leaf list.
[da1bafb]584 */
585 bool cond = true;
586 while (cond) {
[56789125]587 ASSERT(!list_empty(&area->used_space.leaf_head));
[da1bafb]588
589 btree_node_t *node =
[6f4495f5]590 list_get_instance(area->used_space.leaf_head.prev,
591 btree_node_t, leaf_link);
[da1bafb]592
[56789125]593 if ((cond = (bool) node->keys)) {
[da1bafb]594 uintptr_t ptr = node->key[node->keys - 1];
595 size_t size =
[98000fb]596 (size_t) node->value[node->keys - 1];
[da1bafb]597 size_t i = 0;
598
599 if (overlaps(ptr, size * PAGE_SIZE, area->base,
[4638401]600 pages * PAGE_SIZE)) {
[56789125]601
[da1bafb]602 if (ptr + size * PAGE_SIZE <= start_free) {
[56789125]603 /*
[6f4495f5]604 * The whole interval fits
605 * completely in the resized
606 * address space area.
[56789125]607 */
608 break;
609 }
[da1bafb]610
[56789125]611 /*
[6f4495f5]612 * Part of the interval corresponding
613 * to b and c overlaps with the resized
614 * address space area.
[56789125]615 */
[da1bafb]616
617 /* We are almost done */
618 cond = false;
619 i = (start_free - ptr) >> PAGE_WIDTH;
[6745592]620 if (!used_space_remove(area, start_free,
[da1bafb]621 size - i))
622 panic("Cannot remove used space.");
[56789125]623 } else {
624 /*
[6f4495f5]625 * The interval of used space can be
626 * completely removed.
[56789125]627 */
[da1bafb]628 if (!used_space_remove(area, ptr, size))
629 panic("Cannot remove used space.");
[56789125]630 }
[da1bafb]631
632 for (; i < size; i++) {
633 pte_t *pte = page_mapping_find(as, ptr +
[6f4495f5]634 i * PAGE_SIZE);
[da1bafb]635
636 ASSERT(pte);
637 ASSERT(PTE_VALID(pte));
638 ASSERT(PTE_PRESENT(pte));
639
640 if ((area->backend) &&
641 (area->backend->frame_free)) {
[0ee077ee]642 area->backend->frame_free(area,
[da1bafb]643 ptr + i * PAGE_SIZE,
[6f4495f5]644 PTE_GET_FRAME(pte));
[8182031]645 }
[da1bafb]646
647 page_mapping_remove(as, ptr +
[6f4495f5]648 i * PAGE_SIZE);
[56789125]649 }
[df0103f7]650 }
651 }
[da1bafb]652
[df0103f7]653 /*
[5552d60]654 * Finish TLB shootdown sequence.
[df0103f7]655 */
[da1bafb]656
[6f4495f5]657 tlb_invalidate_pages(as->asid, area->base + pages * PAGE_SIZE,
658 area->pages - pages);
[da1bafb]659
[f1d1f5d3]660 /*
661 * Invalidate software translation caches (e.g. TSB on sparc64).
662 */
[6f4495f5]663 as_invalidate_translation_cache(as, area->base +
664 pages * PAGE_SIZE, area->pages - pages);
[402eda5]665 tlb_shootdown_finalize(ipl);
[31d8e10]666
[da1bafb]667 page_table_unlock(as, false);
[df0103f7]668 } else {
669 /*
670 * Growing the area.
671 * Check for overlaps with other address space areas.
672 */
[6f4495f5]673 if (!check_area_conflicts(as, address, pages * PAGE_SIZE,
674 area)) {
[1068f6a]675 mutex_unlock(&area->lock);
[da1bafb]676 mutex_unlock(&as->lock);
[7242a78e]677 return EADDRNOTAVAIL;
[df0103f7]678 }
[da1bafb]679 }
680
[df0103f7]681 area->pages = pages;
682
[1068f6a]683 mutex_unlock(&area->lock);
684 mutex_unlock(&as->lock);
[da1bafb]685
[7242a78e]686 return 0;
687}
688
[e3ee9b9]689/** Remove reference to address space area share info.
690 *
691 * If the reference count drops to 0, the sh_info is deallocated.
692 *
693 * @param sh_info Pointer to address space area share info.
694 *
695 */
[7a0359b]696NO_TRACE static void sh_info_remove_reference(share_info_t *sh_info)
[e3ee9b9]697{
698 bool dealloc = false;
699
700 mutex_lock(&sh_info->lock);
701 ASSERT(sh_info->refcount);
702
703 if (--sh_info->refcount == 0) {
704 dealloc = true;
705 link_t *cur;
706
707 /*
708 * Now walk carefully the pagemap B+tree and free/remove
709 * reference from all frames found there.
710 */
711 for (cur = sh_info->pagemap.leaf_head.next;
712 cur != &sh_info->pagemap.leaf_head; cur = cur->next) {
713 btree_node_t *node
714 = list_get_instance(cur, btree_node_t, leaf_link);
715 btree_key_t i;
716
717 for (i = 0; i < node->keys; i++)
718 frame_free((uintptr_t) node->value[i]);
719 }
720
721 }
722 mutex_unlock(&sh_info->lock);
723
724 if (dealloc) {
725 btree_destroy(&sh_info->pagemap);
726 free(sh_info);
727 }
728}
729
[7242a78e]730/** Destroy address space area.
731 *
[da1bafb]732 * @param as Address space.
733 * @param address Address within the area to be deleted.
734 *
735 * @return Zero on success or a value from @ref errno.h on failure.
[7242a78e]736 *
737 */
[7f1c620]738int as_area_destroy(as_t *as, uintptr_t address)
[7242a78e]739{
[1068f6a]740 mutex_lock(&as->lock);
[da1bafb]741
742 as_area_t *area = find_area_and_lock(as, address);
[7242a78e]743 if (!area) {
[1068f6a]744 mutex_unlock(&as->lock);
[7242a78e]745 return ENOENT;
746 }
[da1bafb]747
748 uintptr_t base = area->base;
749
[c964521]750 page_table_lock(as, false);
[da1bafb]751
[5552d60]752 /*
753 * Start TLB shootdown sequence.
754 */
[402eda5]755 ipl_t ipl = tlb_shootdown_start(TLB_INVL_PAGES, as->asid, area->base,
756 area->pages);
[da1bafb]757
[567807b1]758 /*
759 * Visit only the pages mapped by used_space B+tree.
760 */
[da1bafb]761 link_t *cur;
[6f4495f5]762 for (cur = area->used_space.leaf_head.next;
763 cur != &area->used_space.leaf_head; cur = cur->next) {
[567807b1]764 btree_node_t *node;
[da1bafb]765 btree_key_t i;
[56789125]766
[f8d069e8]767 node = list_get_instance(cur, btree_node_t, leaf_link);
768 for (i = 0; i < node->keys; i++) {
[da1bafb]769 uintptr_t ptr = node->key[i];
770 size_t size;
[56789125]771
[da1bafb]772 for (size = 0; size < (size_t) node->value[i]; size++) {
773 pte_t *pte = page_mapping_find(as, ptr + size * PAGE_SIZE);
774
775 ASSERT(pte);
776 ASSERT(PTE_VALID(pte));
777 ASSERT(PTE_PRESENT(pte));
778
779 if ((area->backend) &&
780 (area->backend->frame_free)) {
781 area->backend->frame_free(area,
782 ptr + size * PAGE_SIZE, PTE_GET_FRAME(pte));
[56789125]783 }
[da1bafb]784
785 page_mapping_remove(as, ptr + size * PAGE_SIZE);
[7242a78e]786 }
787 }
788 }
[da1bafb]789
[7242a78e]790 /*
[5552d60]791 * Finish TLB shootdown sequence.
[7242a78e]792 */
[da1bafb]793
[f1d1f5d3]794 tlb_invalidate_pages(as->asid, area->base, area->pages);
[da1bafb]795
[f1d1f5d3]796 /*
[6f4495f5]797 * Invalidate potential software translation caches (e.g. TSB on
798 * sparc64).
[f1d1f5d3]799 */
800 as_invalidate_translation_cache(as, area->base, area->pages);
[402eda5]801 tlb_shootdown_finalize(ipl);
[da1bafb]802
[c964521]803 page_table_unlock(as, false);
[f1d1f5d3]804
[5552d60]805 btree_destroy(&area->used_space);
[da1bafb]806
[8d4f2ae]807 area->attributes |= AS_AREA_ATTR_PARTIAL;
[8182031]808
809 if (area->sh_info)
810 sh_info_remove_reference(area->sh_info);
[da1bafb]811
[1068f6a]812 mutex_unlock(&area->lock);
[da1bafb]813
[7242a78e]814 /*
815 * Remove the empty area from address space.
816 */
[f1d1f5d3]817 btree_remove(&as->as_area_btree, base, NULL);
[7242a78e]818
[8d4f2ae]819 free(area);
820
[f1d1f5d3]821 mutex_unlock(&as->lock);
[7242a78e]822 return 0;
[df0103f7]823}
824
[8d6bc2d5]825/** Share address space area with another or the same address space.
[df0103f7]826 *
[0ee077ee]827 * Address space area mapping is shared with a new address space area.
828 * If the source address space area has not been shared so far,
829 * a new sh_info is created. The new address space area simply gets the
830 * sh_info of the source area. The process of duplicating the
831 * mapping is done through the backend share function.
[da1bafb]832 *
833 * @param src_as Pointer to source address space.
834 * @param src_base Base address of the source address space area.
835 * @param acc_size Expected size of the source area.
836 * @param dst_as Pointer to destination address space.
837 * @param dst_base Target base address.
[fd4d8c0]838 * @param dst_flags_mask Destination address space area flags mask.
[df0103f7]839 *
[da1bafb]840 * @return Zero on success.
841 * @return ENOENT if there is no such task or such address space.
842 * @return EPERM if there was a problem in accepting the area.
843 * @return ENOMEM if there was a problem in allocating destination
844 * address space area.
845 * @return ENOTSUP if the address space area backend does not support
846 * sharing.
847 *
[df0103f7]848 */
[7f1c620]849int as_area_share(as_t *src_as, uintptr_t src_base, size_t acc_size,
[da1bafb]850 as_t *dst_as, uintptr_t dst_base, unsigned int dst_flags_mask)
[df0103f7]851{
[1068f6a]852 mutex_lock(&src_as->lock);
[da1bafb]853 as_area_t *src_area = find_area_and_lock(src_as, src_base);
[a9e8b39]854 if (!src_area) {
[6fa476f7]855 /*
856 * Could not find the source address space area.
857 */
[1068f6a]858 mutex_unlock(&src_as->lock);
[6fa476f7]859 return ENOENT;
860 }
[da1bafb]861
862 if ((!src_area->backend) || (!src_area->backend->share)) {
[8d6bc2d5]863 /*
[f47fd19]864 * There is no backend or the backend does not
[0ee077ee]865 * know how to share the area.
[8d6bc2d5]866 */
867 mutex_unlock(&src_area->lock);
868 mutex_unlock(&src_as->lock);
869 return ENOTSUP;
870 }
871
[da1bafb]872 size_t src_size = src_area->pages * PAGE_SIZE;
873 unsigned int src_flags = src_area->flags;
874 mem_backend_t *src_backend = src_area->backend;
875 mem_backend_data_t src_backend_data = src_area->backend_data;
876
[1ec1fd8]877 /* Share the cacheable flag from the original mapping */
878 if (src_flags & AS_AREA_CACHEABLE)
879 dst_flags_mask |= AS_AREA_CACHEABLE;
[da1bafb]880
881 if ((src_size != acc_size) ||
882 ((src_flags & dst_flags_mask) != dst_flags_mask)) {
[8d6bc2d5]883 mutex_unlock(&src_area->lock);
884 mutex_unlock(&src_as->lock);
[df0103f7]885 return EPERM;
886 }
[da1bafb]887
[8d6bc2d5]888 /*
889 * Now we are committed to sharing the area.
[8440473]890 * First, prepare the area for sharing.
[8d6bc2d5]891 * Then it will be safe to unlock it.
892 */
[da1bafb]893 share_info_t *sh_info = src_area->sh_info;
[8d6bc2d5]894 if (!sh_info) {
895 sh_info = (share_info_t *) malloc(sizeof(share_info_t), 0);
[08a19ba]896 mutex_initialize(&sh_info->lock, MUTEX_PASSIVE);
[8d6bc2d5]897 sh_info->refcount = 2;
898 btree_create(&sh_info->pagemap);
899 src_area->sh_info = sh_info;
[da1bafb]900
[c0697c4c]901 /*
902 * Call the backend to setup sharing.
903 */
904 src_area->backend->share(src_area);
[8d6bc2d5]905 } else {
906 mutex_lock(&sh_info->lock);
907 sh_info->refcount++;
908 mutex_unlock(&sh_info->lock);
909 }
[da1bafb]910
[8d6bc2d5]911 mutex_unlock(&src_area->lock);
912 mutex_unlock(&src_as->lock);
[da1bafb]913
[df0103f7]914 /*
[a9e8b39]915 * Create copy of the source address space area.
916 * The destination area is created with AS_AREA_ATTR_PARTIAL
917 * attribute set which prevents race condition with
918 * preliminary as_page_fault() calls.
[fd4d8c0]919 * The flags of the source area are masked against dst_flags_mask
920 * to support sharing in less privileged mode.
[df0103f7]921 */
[da1bafb]922 as_area_t *dst_area = as_area_create(dst_as, dst_flags_mask, src_size,
923 dst_base, AS_AREA_ATTR_PARTIAL, src_backend, &src_backend_data);
[a9e8b39]924 if (!dst_area) {
[df0103f7]925 /*
926 * Destination address space area could not be created.
927 */
[8d6bc2d5]928 sh_info_remove_reference(sh_info);
929
[df0103f7]930 return ENOMEM;
931 }
[da1bafb]932
[a9e8b39]933 /*
934 * Now the destination address space area has been
935 * fully initialized. Clear the AS_AREA_ATTR_PARTIAL
[8d6bc2d5]936 * attribute and set the sh_info.
[da1bafb]937 */
938 mutex_lock(&dst_as->lock);
[1068f6a]939 mutex_lock(&dst_area->lock);
[a9e8b39]940 dst_area->attributes &= ~AS_AREA_ATTR_PARTIAL;
[8d6bc2d5]941 dst_area->sh_info = sh_info;
[1068f6a]942 mutex_unlock(&dst_area->lock);
[da1bafb]943 mutex_unlock(&dst_as->lock);
944
[df0103f7]945 return 0;
946}
947
[fb84455]948/** Check access mode for address space area.
949 *
[da1bafb]950 * @param area Address space area.
951 * @param access Access mode.
952 *
953 * @return False if access violates area's permissions, true
954 * otherwise.
[fb84455]955 *
956 */
[97bdb4a]957NO_TRACE bool as_area_check_access(as_area_t *area, pf_access_t access)
[fb84455]958{
[fc47885]959 ASSERT(mutex_locked(&area->lock));
960
[fb84455]961 int flagmap[] = {
962 [PF_ACCESS_READ] = AS_AREA_READ,
963 [PF_ACCESS_WRITE] = AS_AREA_WRITE,
964 [PF_ACCESS_EXEC] = AS_AREA_EXEC
965 };
[da1bafb]966
[fb84455]967 if (!(area->flags & flagmap[access]))
968 return false;
969
970 return true;
971}
972
[e3ee9b9]973/** Convert address space area flags to page flags.
974 *
975 * @param aflags Flags of some address space area.
976 *
977 * @return Flags to be passed to page_mapping_insert().
978 *
979 */
[7a0359b]980NO_TRACE static unsigned int area_flags_to_page_flags(unsigned int aflags)
[e3ee9b9]981{
982 unsigned int flags = PAGE_USER | PAGE_PRESENT;
983
984 if (aflags & AS_AREA_READ)
985 flags |= PAGE_READ;
986
987 if (aflags & AS_AREA_WRITE)
988 flags |= PAGE_WRITE;
989
990 if (aflags & AS_AREA_EXEC)
991 flags |= PAGE_EXEC;
992
993 if (aflags & AS_AREA_CACHEABLE)
994 flags |= PAGE_CACHEABLE;
995
996 return flags;
997}
998
[6745592]999/** Change adress space area flags.
[c98e6ee]1000 *
1001 * The idea is to have the same data, but with a different access mode.
1002 * This is needed e.g. for writing code into memory and then executing it.
1003 * In order for this to work properly, this may copy the data
1004 * into private anonymous memory (unless it's already there).
1005 *
[76fca31]1006 * @param as Address space.
1007 * @param flags Flags of the area memory.
1008 * @param address Address within the area to be changed.
1009 *
1010 * @return Zero on success or a value from @ref errno.h on failure.
[c98e6ee]1011 *
1012 */
[da1bafb]1013int as_area_change_flags(as_t *as, unsigned int flags, uintptr_t address)
[c98e6ee]1014{
1015 /* Flags for the new memory mapping */
[da1bafb]1016 unsigned int page_flags = area_flags_to_page_flags(flags);
1017
[c98e6ee]1018 mutex_lock(&as->lock);
[da1bafb]1019
1020 as_area_t *area = find_area_and_lock(as, address);
[c98e6ee]1021 if (!area) {
1022 mutex_unlock(&as->lock);
1023 return ENOENT;
1024 }
[da1bafb]1025
[76fca31]1026 if ((area->sh_info) || (area->backend != &anon_backend)) {
[c98e6ee]1027 /* Copying shared areas not supported yet */
1028 /* Copying non-anonymous memory not supported yet */
1029 mutex_unlock(&area->lock);
1030 mutex_unlock(&as->lock);
1031 return ENOTSUP;
1032 }
[da1bafb]1033
[c98e6ee]1034 /*
1035 * Compute total number of used pages in the used_space B+tree
1036 */
[da1bafb]1037 size_t used_pages = 0;
1038 link_t *cur;
1039
[c98e6ee]1040 for (cur = area->used_space.leaf_head.next;
1041 cur != &area->used_space.leaf_head; cur = cur->next) {
[da1bafb]1042 btree_node_t *node
1043 = list_get_instance(cur, btree_node_t, leaf_link);
1044 btree_key_t i;
[c98e6ee]1045
[da1bafb]1046 for (i = 0; i < node->keys; i++)
[98000fb]1047 used_pages += (size_t) node->value[i];
[c98e6ee]1048 }
[da1bafb]1049
[c98e6ee]1050 /* An array for storing frame numbers */
[da1bafb]1051 uintptr_t *old_frame = malloc(used_pages * sizeof(uintptr_t), 0);
1052
[c964521]1053 page_table_lock(as, false);
[da1bafb]1054
[c98e6ee]1055 /*
1056 * Start TLB shootdown sequence.
1057 */
[402eda5]1058 ipl_t ipl = tlb_shootdown_start(TLB_INVL_PAGES, as->asid, area->base,
1059 area->pages);
[da1bafb]1060
[c98e6ee]1061 /*
1062 * Remove used pages from page tables and remember their frame
1063 * numbers.
1064 */
[da1bafb]1065 size_t frame_idx = 0;
1066
[c98e6ee]1067 for (cur = area->used_space.leaf_head.next;
1068 cur != &area->used_space.leaf_head; cur = cur->next) {
[da1bafb]1069 btree_node_t *node
1070 = list_get_instance(cur, btree_node_t, leaf_link);
1071 btree_key_t i;
[c98e6ee]1072
1073 for (i = 0; i < node->keys; i++) {
[da1bafb]1074 uintptr_t ptr = node->key[i];
1075 size_t size;
[c98e6ee]1076
[da1bafb]1077 for (size = 0; size < (size_t) node->value[i]; size++) {
1078 pte_t *pte = page_mapping_find(as, ptr + size * PAGE_SIZE);
1079
1080 ASSERT(pte);
1081 ASSERT(PTE_VALID(pte));
1082 ASSERT(PTE_PRESENT(pte));
1083
[c98e6ee]1084 old_frame[frame_idx++] = PTE_GET_FRAME(pte);
[da1bafb]1085
[c98e6ee]1086 /* Remove old mapping */
[da1bafb]1087 page_mapping_remove(as, ptr + size * PAGE_SIZE);
[c98e6ee]1088 }
1089 }
1090 }
[da1bafb]1091
[c98e6ee]1092 /*
1093 * Finish TLB shootdown sequence.
1094 */
[da1bafb]1095
[c98e6ee]1096 tlb_invalidate_pages(as->asid, area->base, area->pages);
[76fca31]1097
[c98e6ee]1098 /*
1099 * Invalidate potential software translation caches (e.g. TSB on
1100 * sparc64).
1101 */
1102 as_invalidate_translation_cache(as, area->base, area->pages);
[402eda5]1103 tlb_shootdown_finalize(ipl);
[da1bafb]1104
[c964521]1105 page_table_unlock(as, false);
[da1bafb]1106
[ae7f6fb]1107 /*
1108 * Set the new flags.
1109 */
1110 area->flags = flags;
[da1bafb]1111
[c98e6ee]1112 /*
1113 * Map pages back in with new flags. This step is kept separate
[6745592]1114 * so that the memory area could not be accesed with both the old and
1115 * the new flags at once.
[c98e6ee]1116 */
1117 frame_idx = 0;
[da1bafb]1118
[c98e6ee]1119 for (cur = area->used_space.leaf_head.next;
1120 cur != &area->used_space.leaf_head; cur = cur->next) {
[da1bafb]1121 btree_node_t *node
1122 = list_get_instance(cur, btree_node_t, leaf_link);
1123 btree_key_t i;
[c98e6ee]1124
1125 for (i = 0; i < node->keys; i++) {
[da1bafb]1126 uintptr_t ptr = node->key[i];
1127 size_t size;
[c98e6ee]1128
[da1bafb]1129 for (size = 0; size < (size_t) node->value[i]; size++) {
[c98e6ee]1130 page_table_lock(as, false);
[da1bafb]1131
[c98e6ee]1132 /* Insert the new mapping */
[da1bafb]1133 page_mapping_insert(as, ptr + size * PAGE_SIZE,
[c98e6ee]1134 old_frame[frame_idx++], page_flags);
[da1bafb]1135
[c98e6ee]1136 page_table_unlock(as, false);
1137 }
1138 }
1139 }
[da1bafb]1140
[c98e6ee]1141 free(old_frame);
[da1bafb]1142
[c98e6ee]1143 mutex_unlock(&area->lock);
1144 mutex_unlock(&as->lock);
[da1bafb]1145
[c98e6ee]1146 return 0;
1147}
1148
[20d50a1]1149/** Handle page fault within the current address space.
1150 *
[6745592]1151 * This is the high-level page fault handler. It decides whether the page fault
1152 * can be resolved by any backend and if so, it invokes the backend to resolve
1153 * the page fault.
[8182031]1154 *
[20d50a1]1155 * Interrupts are assumed disabled.
1156 *
[da1bafb]1157 * @param page Faulting page.
1158 * @param access Access mode that caused the page fault (i.e.
1159 * read/write/exec).
1160 * @param istate Pointer to the interrupted state.
1161 *
1162 * @return AS_PF_FAULT on page fault.
1163 * @return AS_PF_OK on success.
1164 * @return AS_PF_DEFER if the fault was caused by copy_to_uspace()
1165 * or copy_from_uspace().
[20d50a1]1166 *
1167 */
[7f1c620]1168int as_page_fault(uintptr_t page, pf_access_t access, istate_t *istate)
[20d50a1]1169{
[1068f6a]1170 if (!THREAD)
[8182031]1171 return AS_PF_FAULT;
[7af8c0e]1172
1173 if (!AS)
1174 return AS_PF_FAULT;
1175
[1068f6a]1176 mutex_lock(&AS->lock);
[da1bafb]1177 as_area_t *area = find_area_and_lock(AS, page);
[20d50a1]1178 if (!area) {
1179 /*
1180 * No area contained mapping for 'page'.
1181 * Signal page fault to low-level handler.
1182 */
[1068f6a]1183 mutex_unlock(&AS->lock);
[e3c762cd]1184 goto page_fault;
[20d50a1]1185 }
[da1bafb]1186
[a9e8b39]1187 if (area->attributes & AS_AREA_ATTR_PARTIAL) {
1188 /*
1189 * The address space area is not fully initialized.
1190 * Avoid possible race by returning error.
1191 */
[1068f6a]1192 mutex_unlock(&area->lock);
1193 mutex_unlock(&AS->lock);
[da1bafb]1194 goto page_fault;
[a9e8b39]1195 }
[da1bafb]1196
1197 if ((!area->backend) || (!area->backend->page_fault)) {
[8182031]1198 /*
1199 * The address space area is not backed by any backend
1200 * or the backend cannot handle page faults.
1201 */
1202 mutex_unlock(&area->lock);
1203 mutex_unlock(&AS->lock);
[da1bafb]1204 goto page_fault;
[8182031]1205 }
[da1bafb]1206
[2299914]1207 page_table_lock(AS, false);
1208
1209 /*
[6745592]1210 * To avoid race condition between two page faults on the same address,
1211 * we need to make sure the mapping has not been already inserted.
[2299914]1212 */
[da1bafb]1213 pte_t *pte;
[2299914]1214 if ((pte = page_mapping_find(AS, page))) {
1215 if (PTE_PRESENT(pte)) {
[fb84455]1216 if (((access == PF_ACCESS_READ) && PTE_READABLE(pte)) ||
[6f4495f5]1217 (access == PF_ACCESS_WRITE && PTE_WRITABLE(pte)) ||
1218 (access == PF_ACCESS_EXEC && PTE_EXECUTABLE(pte))) {
[fb84455]1219 page_table_unlock(AS, false);
1220 mutex_unlock(&area->lock);
1221 mutex_unlock(&AS->lock);
1222 return AS_PF_OK;
1223 }
[2299914]1224 }
1225 }
[20d50a1]1226
1227 /*
[8182031]1228 * Resort to the backend page fault handler.
[20d50a1]1229 */
[0ee077ee]1230 if (area->backend->page_fault(area, page, access) != AS_PF_OK) {
[8182031]1231 page_table_unlock(AS, false);
1232 mutex_unlock(&area->lock);
1233 mutex_unlock(&AS->lock);
1234 goto page_fault;
1235 }
[20d50a1]1236
[8182031]1237 page_table_unlock(AS, false);
[1068f6a]1238 mutex_unlock(&area->lock);
1239 mutex_unlock(&AS->lock);
[e3c762cd]1240 return AS_PF_OK;
[da1bafb]1241
[e3c762cd]1242page_fault:
1243 if (THREAD->in_copy_from_uspace) {
1244 THREAD->in_copy_from_uspace = false;
[6f4495f5]1245 istate_set_retaddr(istate,
1246 (uintptr_t) &memcpy_from_uspace_failover_address);
[e3c762cd]1247 } else if (THREAD->in_copy_to_uspace) {
1248 THREAD->in_copy_to_uspace = false;
[6f4495f5]1249 istate_set_retaddr(istate,
1250 (uintptr_t) &memcpy_to_uspace_failover_address);
[e3c762cd]1251 } else {
1252 return AS_PF_FAULT;
1253 }
[da1bafb]1254
[e3c762cd]1255 return AS_PF_DEFER;
[20d50a1]1256}
1257
[7e4e532]1258/** Switch address spaces.
[1068f6a]1259 *
1260 * Note that this function cannot sleep as it is essentially a part of
[879585a3]1261 * scheduling. Sleeping here would lead to deadlock on wakeup. Another
1262 * thing which is forbidden in this context is locking the address space.
[20d50a1]1263 *
[31d8e10]1264 * When this function is enetered, no spinlocks may be held.
1265 *
[da1bafb]1266 * @param old Old address space or NULL.
1267 * @param new New address space.
1268 *
[20d50a1]1269 */
[80bcaed]1270void as_switch(as_t *old_as, as_t *new_as)
[20d50a1]1271{
[31d8e10]1272 DEADLOCK_PROBE_INIT(p_asidlock);
1273 preemption_disable();
[da1bafb]1274
[31d8e10]1275retry:
1276 (void) interrupts_disable();
1277 if (!spinlock_trylock(&asidlock)) {
[da1bafb]1278 /*
[31d8e10]1279 * Avoid deadlock with TLB shootdown.
1280 * We can enable interrupts here because
1281 * preemption is disabled. We should not be
1282 * holding any other lock.
1283 */
1284 (void) interrupts_enable();
1285 DEADLOCK_PROBE(p_asidlock, DEADLOCK_THRESHOLD);
1286 goto retry;
1287 }
1288 preemption_enable();
[da1bafb]1289
[7e4e532]1290 /*
1291 * First, take care of the old address space.
[da1bafb]1292 */
[80bcaed]1293 if (old_as) {
1294 ASSERT(old_as->cpu_refcount);
[da1bafb]1295
1296 if ((--old_as->cpu_refcount == 0) && (old_as != AS_KERNEL)) {
[7e4e532]1297 /*
1298 * The old address space is no longer active on
1299 * any processor. It can be appended to the
1300 * list of inactive address spaces with assigned
1301 * ASID.
1302 */
[2057572]1303 ASSERT(old_as->asid != ASID_INVALID);
[da1bafb]1304
[2057572]1305 list_append(&old_as->inactive_as_with_asid_link,
1306 &inactive_as_with_asid_head);
[7e4e532]1307 }
[da1bafb]1308
[57da95c]1309 /*
1310 * Perform architecture-specific tasks when the address space
1311 * is being removed from the CPU.
1312 */
[80bcaed]1313 as_deinstall_arch(old_as);
[7e4e532]1314 }
[da1bafb]1315
[7e4e532]1316 /*
1317 * Second, prepare the new address space.
1318 */
[80bcaed]1319 if ((new_as->cpu_refcount++ == 0) && (new_as != AS_KERNEL)) {
[879585a3]1320 if (new_as->asid != ASID_INVALID)
[80bcaed]1321 list_remove(&new_as->inactive_as_with_asid_link);
[879585a3]1322 else
1323 new_as->asid = asid_get();
[7e4e532]1324 }
[da1bafb]1325
[80bcaed]1326#ifdef AS_PAGE_TABLE
1327 SET_PTL0_ADDRESS(new_as->genarch.page_table);
1328#endif
[7e4e532]1329
[20d50a1]1330 /*
1331 * Perform architecture-specific steps.
[4512d7e]1332 * (e.g. write ASID to hardware register etc.)
[20d50a1]1333 */
[80bcaed]1334 as_install_arch(new_as);
[da1bafb]1335
[879585a3]1336 spinlock_unlock(&asidlock);
[20d50a1]1337
[80bcaed]1338 AS = new_as;
[20d50a1]1339}
[6a3c9a7]1340
[df0103f7]1341/** Compute flags for virtual address translation subsytem.
1342 *
[da1bafb]1343 * @param area Address space area.
1344 *
1345 * @return Flags to be used in page_mapping_insert().
[df0103f7]1346 *
1347 */
[97bdb4a]1348NO_TRACE unsigned int as_area_get_flags(as_area_t *area)
[df0103f7]1349{
[1d432f9]1350 ASSERT(mutex_locked(&area->lock));
[fc47885]1351
[da1bafb]1352 return area_flags_to_page_flags(area->flags);
[df0103f7]1353}
1354
[ef67bab]1355/** Create page table.
1356 *
[6745592]1357 * Depending on architecture, create either address space private or global page
1358 * table.
[ef67bab]1359 *
[da1bafb]1360 * @param flags Flags saying whether the page table is for the kernel
1361 * address space.
1362 *
1363 * @return First entry of the page table.
[ef67bab]1364 *
1365 */
[97bdb4a]1366NO_TRACE pte_t *page_table_create(unsigned int flags)
[ef67bab]1367{
[bd1deed]1368 ASSERT(as_operations);
1369 ASSERT(as_operations->page_table_create);
1370
1371 return as_operations->page_table_create(flags);
[ef67bab]1372}
[d3e7ff4]1373
[482826d]1374/** Destroy page table.
1375 *
1376 * Destroy page table in architecture specific way.
1377 *
[da1bafb]1378 * @param page_table Physical address of PTL0.
1379 *
[482826d]1380 */
[97bdb4a]1381NO_TRACE void page_table_destroy(pte_t *page_table)
[482826d]1382{
[bd1deed]1383 ASSERT(as_operations);
1384 ASSERT(as_operations->page_table_destroy);
1385
1386 as_operations->page_table_destroy(page_table);
[482826d]1387}
1388
[2299914]1389/** Lock page table.
1390 *
1391 * This function should be called before any page_mapping_insert(),
1392 * page_mapping_remove() and page_mapping_find().
[da1bafb]1393 *
[2299914]1394 * Locking order is such that address space areas must be locked
1395 * prior to this call. Address space can be locked prior to this
1396 * call in which case the lock argument is false.
1397 *
[da1bafb]1398 * @param as Address space.
1399 * @param lock If false, do not attempt to lock as->lock.
1400 *
[2299914]1401 */
[97bdb4a]1402NO_TRACE void page_table_lock(as_t *as, bool lock)
[2299914]1403{
1404 ASSERT(as_operations);
1405 ASSERT(as_operations->page_table_lock);
[bd1deed]1406
[2299914]1407 as_operations->page_table_lock(as, lock);
1408}
1409
1410/** Unlock page table.
1411 *
[da1bafb]1412 * @param as Address space.
1413 * @param unlock If false, do not attempt to unlock as->lock.
1414 *
[2299914]1415 */
[97bdb4a]1416NO_TRACE void page_table_unlock(as_t *as, bool unlock)
[2299914]1417{
1418 ASSERT(as_operations);
1419 ASSERT(as_operations->page_table_unlock);
[bd1deed]1420
[2299914]1421 as_operations->page_table_unlock(as, unlock);
1422}
1423
[ada559c]1424/** Test whether page tables are locked.
1425 *
[e3ee9b9]1426 * @param as Address space where the page tables belong.
[ada559c]1427 *
[e3ee9b9]1428 * @return True if the page tables belonging to the address soace
1429 * are locked, otherwise false.
[ada559c]1430 */
[97bdb4a]1431NO_TRACE bool page_table_locked(as_t *as)
[ada559c]1432{
1433 ASSERT(as_operations);
1434 ASSERT(as_operations->page_table_locked);
1435
1436 return as_operations->page_table_locked(as);
1437}
1438
[b878df3]1439/** Return size of the address space area with given base.
1440 *
[1d432f9]1441 * @param base Arbitrary address inside the address space area.
[da1bafb]1442 *
1443 * @return Size of the address space area in bytes or zero if it
1444 * does not exist.
[b878df3]1445 *
1446 */
1447size_t as_area_get_size(uintptr_t base)
[7c23af9]1448{
1449 size_t size;
[da1bafb]1450
[1d432f9]1451 page_table_lock(AS, true);
[da1bafb]1452 as_area_t *src_area = find_area_and_lock(AS, base);
1453
[6745592]1454 if (src_area) {
[7c23af9]1455 size = src_area->pages * PAGE_SIZE;
[1068f6a]1456 mutex_unlock(&src_area->lock);
[da1bafb]1457 } else
[7c23af9]1458 size = 0;
[da1bafb]1459
[1d432f9]1460 page_table_unlock(AS, true);
[7c23af9]1461 return size;
1462}
1463
[25bf215]1464/** Mark portion of address space area as used.
1465 *
1466 * The address space area must be already locked.
1467 *
[da1bafb]1468 * @param area Address space area.
1469 * @param page First page to be marked.
1470 * @param count Number of page to be marked.
1471 *
[fc47885]1472 * @return False on failure or true on success.
[25bf215]1473 *
1474 */
[fc47885]1475bool used_space_insert(as_area_t *area, uintptr_t page, size_t count)
[25bf215]1476{
[1d432f9]1477 ASSERT(mutex_locked(&area->lock));
[25bf215]1478 ASSERT(page == ALIGN_DOWN(page, PAGE_SIZE));
1479 ASSERT(count);
[da1bafb]1480
1481 btree_node_t *leaf;
1482 size_t pages = (size_t) btree_search(&area->used_space, page, &leaf);
[25bf215]1483 if (pages) {
1484 /*
1485 * We hit the beginning of some used space.
1486 */
[fc47885]1487 return false;
[25bf215]1488 }
[da1bafb]1489
[a6cb8cb]1490 if (!leaf->keys) {
[da1bafb]1491 btree_insert(&area->used_space, page, (void *) count, leaf);
[fc47885]1492 goto success;
[a6cb8cb]1493 }
[da1bafb]1494
1495 btree_node_t *node = btree_leaf_node_left_neighbour(&area->used_space, leaf);
[25bf215]1496 if (node) {
[6f4495f5]1497 uintptr_t left_pg = node->key[node->keys - 1];
1498 uintptr_t right_pg = leaf->key[0];
[98000fb]1499 size_t left_cnt = (size_t) node->value[node->keys - 1];
1500 size_t right_cnt = (size_t) leaf->value[0];
[25bf215]1501
1502 /*
1503 * Examine the possibility that the interval fits
1504 * somewhere between the rightmost interval of
1505 * the left neigbour and the first interval of the leaf.
1506 */
[da1bafb]1507
[25bf215]1508 if (page >= right_pg) {
1509 /* Do nothing. */
[6f4495f5]1510 } else if (overlaps(page, count * PAGE_SIZE, left_pg,
1511 left_cnt * PAGE_SIZE)) {
[25bf215]1512 /* The interval intersects with the left interval. */
[fc47885]1513 return false;
[6f4495f5]1514 } else if (overlaps(page, count * PAGE_SIZE, right_pg,
1515 right_cnt * PAGE_SIZE)) {
[25bf215]1516 /* The interval intersects with the right interval. */
[fc47885]1517 return false;
[6f4495f5]1518 } else if ((page == left_pg + left_cnt * PAGE_SIZE) &&
1519 (page + count * PAGE_SIZE == right_pg)) {
1520 /*
1521 * The interval can be added by merging the two already
1522 * present intervals.
1523 */
[56789125]1524 node->value[node->keys - 1] += count + right_cnt;
[da1bafb]1525 btree_remove(&area->used_space, right_pg, leaf);
[fc47885]1526 goto success;
[6f4495f5]1527 } else if (page == left_pg + left_cnt * PAGE_SIZE) {
[da1bafb]1528 /*
[6f4495f5]1529 * The interval can be added by simply growing the left
1530 * interval.
1531 */
[56789125]1532 node->value[node->keys - 1] += count;
[fc47885]1533 goto success;
[6f4495f5]1534 } else if (page + count * PAGE_SIZE == right_pg) {
[25bf215]1535 /*
[6f4495f5]1536 * The interval can be addded by simply moving base of
1537 * the right interval down and increasing its size
1538 * accordingly.
[25bf215]1539 */
[56789125]1540 leaf->value[0] += count;
[25bf215]1541 leaf->key[0] = page;
[fc47885]1542 goto success;
[25bf215]1543 } else {
1544 /*
1545 * The interval is between both neigbouring intervals,
1546 * but cannot be merged with any of them.
1547 */
[da1bafb]1548 btree_insert(&area->used_space, page, (void *) count,
[6f4495f5]1549 leaf);
[fc47885]1550 goto success;
[25bf215]1551 }
1552 } else if (page < leaf->key[0]) {
[7f1c620]1553 uintptr_t right_pg = leaf->key[0];
[98000fb]1554 size_t right_cnt = (size_t) leaf->value[0];
[da1bafb]1555
[25bf215]1556 /*
[6f4495f5]1557 * Investigate the border case in which the left neighbour does
1558 * not exist but the interval fits from the left.
[25bf215]1559 */
[da1bafb]1560
[6f4495f5]1561 if (overlaps(page, count * PAGE_SIZE, right_pg,
1562 right_cnt * PAGE_SIZE)) {
[25bf215]1563 /* The interval intersects with the right interval. */
[fc47885]1564 return false;
[6f4495f5]1565 } else if (page + count * PAGE_SIZE == right_pg) {
[25bf215]1566 /*
[6f4495f5]1567 * The interval can be added by moving the base of the
1568 * right interval down and increasing its size
1569 * accordingly.
[25bf215]1570 */
1571 leaf->key[0] = page;
[56789125]1572 leaf->value[0] += count;
[fc47885]1573 goto success;
[25bf215]1574 } else {
1575 /*
1576 * The interval doesn't adjoin with the right interval.
1577 * It must be added individually.
1578 */
[da1bafb]1579 btree_insert(&area->used_space, page, (void *) count,
[6f4495f5]1580 leaf);
[fc47885]1581 goto success;
[25bf215]1582 }
1583 }
[da1bafb]1584
1585 node = btree_leaf_node_right_neighbour(&area->used_space, leaf);
[25bf215]1586 if (node) {
[6f4495f5]1587 uintptr_t left_pg = leaf->key[leaf->keys - 1];
1588 uintptr_t right_pg = node->key[0];
[98000fb]1589 size_t left_cnt = (size_t) leaf->value[leaf->keys - 1];
1590 size_t right_cnt = (size_t) node->value[0];
[25bf215]1591
1592 /*
1593 * Examine the possibility that the interval fits
1594 * somewhere between the leftmost interval of
1595 * the right neigbour and the last interval of the leaf.
1596 */
[da1bafb]1597
[25bf215]1598 if (page < left_pg) {
1599 /* Do nothing. */
[6f4495f5]1600 } else if (overlaps(page, count * PAGE_SIZE, left_pg,
1601 left_cnt * PAGE_SIZE)) {
[25bf215]1602 /* The interval intersects with the left interval. */
[fc47885]1603 return false;
[6f4495f5]1604 } else if (overlaps(page, count * PAGE_SIZE, right_pg,
1605 right_cnt * PAGE_SIZE)) {
[25bf215]1606 /* The interval intersects with the right interval. */
[fc47885]1607 return false;
[6f4495f5]1608 } else if ((page == left_pg + left_cnt * PAGE_SIZE) &&
1609 (page + count * PAGE_SIZE == right_pg)) {
1610 /*
1611 * The interval can be added by merging the two already
1612 * present intervals.
[da1bafb]1613 */
[56789125]1614 leaf->value[leaf->keys - 1] += count + right_cnt;
[da1bafb]1615 btree_remove(&area->used_space, right_pg, node);
[fc47885]1616 goto success;
[6f4495f5]1617 } else if (page == left_pg + left_cnt * PAGE_SIZE) {
1618 /*
1619 * The interval can be added by simply growing the left
1620 * interval.
[da1bafb]1621 */
[fc47885]1622 leaf->value[leaf->keys - 1] += count;
1623 goto success;
[6f4495f5]1624 } else if (page + count * PAGE_SIZE == right_pg) {
[25bf215]1625 /*
[6f4495f5]1626 * The interval can be addded by simply moving base of
1627 * the right interval down and increasing its size
1628 * accordingly.
[25bf215]1629 */
[56789125]1630 node->value[0] += count;
[25bf215]1631 node->key[0] = page;
[fc47885]1632 goto success;
[25bf215]1633 } else {
1634 /*
1635 * The interval is between both neigbouring intervals,
1636 * but cannot be merged with any of them.
1637 */
[da1bafb]1638 btree_insert(&area->used_space, page, (void *) count,
[6f4495f5]1639 leaf);
[fc47885]1640 goto success;
[25bf215]1641 }
1642 } else if (page >= leaf->key[leaf->keys - 1]) {
[7f1c620]1643 uintptr_t left_pg = leaf->key[leaf->keys - 1];
[98000fb]1644 size_t left_cnt = (size_t) leaf->value[leaf->keys - 1];
[da1bafb]1645
[25bf215]1646 /*
[6f4495f5]1647 * Investigate the border case in which the right neighbour
1648 * does not exist but the interval fits from the right.
[25bf215]1649 */
[da1bafb]1650
[6f4495f5]1651 if (overlaps(page, count * PAGE_SIZE, left_pg,
1652 left_cnt * PAGE_SIZE)) {
[56789125]1653 /* The interval intersects with the left interval. */
[fc47885]1654 return false;
[6f4495f5]1655 } else if (left_pg + left_cnt * PAGE_SIZE == page) {
1656 /*
1657 * The interval can be added by growing the left
1658 * interval.
1659 */
[56789125]1660 leaf->value[leaf->keys - 1] += count;
[fc47885]1661 goto success;
[25bf215]1662 } else {
1663 /*
1664 * The interval doesn't adjoin with the left interval.
1665 * It must be added individually.
1666 */
[da1bafb]1667 btree_insert(&area->used_space, page, (void *) count,
[6f4495f5]1668 leaf);
[fc47885]1669 goto success;
[25bf215]1670 }
1671 }
1672
1673 /*
[6f4495f5]1674 * Note that if the algorithm made it thus far, the interval can fit
1675 * only between two other intervals of the leaf. The two border cases
1676 * were already resolved.
[25bf215]1677 */
[da1bafb]1678 btree_key_t i;
[25bf215]1679 for (i = 1; i < leaf->keys; i++) {
1680 if (page < leaf->key[i]) {
[6f4495f5]1681 uintptr_t left_pg = leaf->key[i - 1];
1682 uintptr_t right_pg = leaf->key[i];
[98000fb]1683 size_t left_cnt = (size_t) leaf->value[i - 1];
1684 size_t right_cnt = (size_t) leaf->value[i];
[da1bafb]1685
[25bf215]1686 /*
1687 * The interval fits between left_pg and right_pg.
1688 */
[da1bafb]1689
[6f4495f5]1690 if (overlaps(page, count * PAGE_SIZE, left_pg,
1691 left_cnt * PAGE_SIZE)) {
1692 /*
1693 * The interval intersects with the left
1694 * interval.
1695 */
[fc47885]1696 return false;
[6f4495f5]1697 } else if (overlaps(page, count * PAGE_SIZE, right_pg,
1698 right_cnt * PAGE_SIZE)) {
1699 /*
1700 * The interval intersects with the right
1701 * interval.
1702 */
[fc47885]1703 return false;
[6f4495f5]1704 } else if ((page == left_pg + left_cnt * PAGE_SIZE) &&
1705 (page + count * PAGE_SIZE == right_pg)) {
1706 /*
1707 * The interval can be added by merging the two
1708 * already present intervals.
1709 */
[56789125]1710 leaf->value[i - 1] += count + right_cnt;
[da1bafb]1711 btree_remove(&area->used_space, right_pg, leaf);
[fc47885]1712 goto success;
[6f4495f5]1713 } else if (page == left_pg + left_cnt * PAGE_SIZE) {
1714 /*
1715 * The interval can be added by simply growing
1716 * the left interval.
1717 */
[56789125]1718 leaf->value[i - 1] += count;
[fc47885]1719 goto success;
[6f4495f5]1720 } else if (page + count * PAGE_SIZE == right_pg) {
[25bf215]1721 /*
[da1bafb]1722 * The interval can be addded by simply moving
[6f4495f5]1723 * base of the right interval down and
1724 * increasing its size accordingly.
[da1bafb]1725 */
[56789125]1726 leaf->value[i] += count;
[25bf215]1727 leaf->key[i] = page;
[fc47885]1728 goto success;
[25bf215]1729 } else {
1730 /*
[6f4495f5]1731 * The interval is between both neigbouring
1732 * intervals, but cannot be merged with any of
1733 * them.
[25bf215]1734 */
[da1bafb]1735 btree_insert(&area->used_space, page,
[6f4495f5]1736 (void *) count, leaf);
[fc47885]1737 goto success;
[25bf215]1738 }
1739 }
1740 }
[da1bafb]1741
[7e752b2]1742 panic("Inconsistency detected while adding %zu pages of used "
1743 "space at %p.", count, (void *) page);
[fc47885]1744
1745success:
1746 area->resident += count;
1747 return true;
[25bf215]1748}
1749
1750/** Mark portion of address space area as unused.
1751 *
1752 * The address space area must be already locked.
1753 *
[da1bafb]1754 * @param area Address space area.
1755 * @param page First page to be marked.
1756 * @param count Number of page to be marked.
1757 *
[fc47885]1758 * @return False on failure or true on success.
[25bf215]1759 *
1760 */
[fc47885]1761bool used_space_remove(as_area_t *area, uintptr_t page, size_t count)
[25bf215]1762{
[1d432f9]1763 ASSERT(mutex_locked(&area->lock));
[25bf215]1764 ASSERT(page == ALIGN_DOWN(page, PAGE_SIZE));
1765 ASSERT(count);
[da1bafb]1766
1767 btree_node_t *leaf;
1768 size_t pages = (size_t) btree_search(&area->used_space, page, &leaf);
[25bf215]1769 if (pages) {
1770 /*
1771 * We are lucky, page is the beginning of some interval.
1772 */
1773 if (count > pages) {
[fc47885]1774 return false;
[25bf215]1775 } else if (count == pages) {
[da1bafb]1776 btree_remove(&area->used_space, page, leaf);
[fc47885]1777 goto success;
[25bf215]1778 } else {
1779 /*
1780 * Find the respective interval.
1781 * Decrease its size and relocate its start address.
1782 */
[da1bafb]1783 btree_key_t i;
[25bf215]1784 for (i = 0; i < leaf->keys; i++) {
1785 if (leaf->key[i] == page) {
[6f4495f5]1786 leaf->key[i] += count * PAGE_SIZE;
[56789125]1787 leaf->value[i] -= count;
[fc47885]1788 goto success;
[25bf215]1789 }
1790 }
[fc47885]1791
[25bf215]1792 goto error;
1793 }
1794 }
[da1bafb]1795
1796 btree_node_t *node = btree_leaf_node_left_neighbour(&area->used_space, leaf);
1797 if ((node) && (page < leaf->key[0])) {
[7f1c620]1798 uintptr_t left_pg = node->key[node->keys - 1];
[98000fb]1799 size_t left_cnt = (size_t) node->value[node->keys - 1];
[da1bafb]1800
[6f4495f5]1801 if (overlaps(left_pg, left_cnt * PAGE_SIZE, page,
1802 count * PAGE_SIZE)) {
1803 if (page + count * PAGE_SIZE ==
1804 left_pg + left_cnt * PAGE_SIZE) {
[25bf215]1805 /*
[6f4495f5]1806 * The interval is contained in the rightmost
1807 * interval of the left neighbour and can be
1808 * removed by updating the size of the bigger
1809 * interval.
[25bf215]1810 */
[56789125]1811 node->value[node->keys - 1] -= count;
[fc47885]1812 goto success;
[6f4495f5]1813 } else if (page + count * PAGE_SIZE <
1814 left_pg + left_cnt*PAGE_SIZE) {
[25bf215]1815 /*
[6f4495f5]1816 * The interval is contained in the rightmost
1817 * interval of the left neighbour but its
1818 * removal requires both updating the size of
1819 * the original interval and also inserting a
1820 * new interval.
[25bf215]1821 */
[da1bafb]1822 size_t new_cnt = ((left_pg + left_cnt * PAGE_SIZE) -
[6f4495f5]1823 (page + count*PAGE_SIZE)) >> PAGE_WIDTH;
[56789125]1824 node->value[node->keys - 1] -= count + new_cnt;
[da1bafb]1825 btree_insert(&area->used_space, page +
[6f4495f5]1826 count * PAGE_SIZE, (void *) new_cnt, leaf);
[fc47885]1827 goto success;
[25bf215]1828 }
1829 }
[fc47885]1830
1831 return false;
[da1bafb]1832 } else if (page < leaf->key[0])
[fc47885]1833 return false;
[25bf215]1834
1835 if (page > leaf->key[leaf->keys - 1]) {
[7f1c620]1836 uintptr_t left_pg = leaf->key[leaf->keys - 1];
[98000fb]1837 size_t left_cnt = (size_t) leaf->value[leaf->keys - 1];
[da1bafb]1838
[6f4495f5]1839 if (overlaps(left_pg, left_cnt * PAGE_SIZE, page,
1840 count * PAGE_SIZE)) {
[da1bafb]1841 if (page + count * PAGE_SIZE ==
[6f4495f5]1842 left_pg + left_cnt * PAGE_SIZE) {
[25bf215]1843 /*
[6f4495f5]1844 * The interval is contained in the rightmost
1845 * interval of the leaf and can be removed by
1846 * updating the size of the bigger interval.
[25bf215]1847 */
[56789125]1848 leaf->value[leaf->keys - 1] -= count;
[fc47885]1849 goto success;
[6f4495f5]1850 } else if (page + count * PAGE_SIZE < left_pg +
1851 left_cnt * PAGE_SIZE) {
[25bf215]1852 /*
[6f4495f5]1853 * The interval is contained in the rightmost
1854 * interval of the leaf but its removal
1855 * requires both updating the size of the
1856 * original interval and also inserting a new
1857 * interval.
[25bf215]1858 */
[da1bafb]1859 size_t new_cnt = ((left_pg + left_cnt * PAGE_SIZE) -
[6f4495f5]1860 (page + count * PAGE_SIZE)) >> PAGE_WIDTH;
[56789125]1861 leaf->value[leaf->keys - 1] -= count + new_cnt;
[da1bafb]1862 btree_insert(&area->used_space, page +
[6f4495f5]1863 count * PAGE_SIZE, (void *) new_cnt, leaf);
[fc47885]1864 goto success;
[25bf215]1865 }
1866 }
[fc47885]1867
1868 return false;
[da1bafb]1869 }
[25bf215]1870
1871 /*
1872 * The border cases have been already resolved.
[fc47885]1873 * Now the interval can be only between intervals of the leaf.
[25bf215]1874 */
[da1bafb]1875 btree_key_t i;
[25bf215]1876 for (i = 1; i < leaf->keys - 1; i++) {
1877 if (page < leaf->key[i]) {
[7f1c620]1878 uintptr_t left_pg = leaf->key[i - 1];
[98000fb]1879 size_t left_cnt = (size_t) leaf->value[i - 1];
[da1bafb]1880
[25bf215]1881 /*
[6f4495f5]1882 * Now the interval is between intervals corresponding
1883 * to (i - 1) and i.
[25bf215]1884 */
[6f4495f5]1885 if (overlaps(left_pg, left_cnt * PAGE_SIZE, page,
1886 count * PAGE_SIZE)) {
1887 if (page + count * PAGE_SIZE ==
1888 left_pg + left_cnt*PAGE_SIZE) {
[25bf215]1889 /*
[6f4495f5]1890 * The interval is contained in the
1891 * interval (i - 1) of the leaf and can
1892 * be removed by updating the size of
1893 * the bigger interval.
[25bf215]1894 */
[56789125]1895 leaf->value[i - 1] -= count;
[fc47885]1896 goto success;
[6f4495f5]1897 } else if (page + count * PAGE_SIZE <
1898 left_pg + left_cnt * PAGE_SIZE) {
[25bf215]1899 /*
[6f4495f5]1900 * The interval is contained in the
1901 * interval (i - 1) of the leaf but its
1902 * removal requires both updating the
1903 * size of the original interval and
[25bf215]1904 * also inserting a new interval.
1905 */
[da1bafb]1906 size_t new_cnt = ((left_pg +
[6f4495f5]1907 left_cnt * PAGE_SIZE) -
1908 (page + count * PAGE_SIZE)) >>
1909 PAGE_WIDTH;
[56789125]1910 leaf->value[i - 1] -= count + new_cnt;
[da1bafb]1911 btree_insert(&area->used_space, page +
[6f4495f5]1912 count * PAGE_SIZE, (void *) new_cnt,
1913 leaf);
[fc47885]1914 goto success;
[25bf215]1915 }
1916 }
[fc47885]1917
1918 return false;
[25bf215]1919 }
1920 }
[da1bafb]1921
[25bf215]1922error:
[7e752b2]1923 panic("Inconsistency detected while removing %zu pages of used "
1924 "space from %p.", count, (void *) page);
[fc47885]1925
1926success:
1927 area->resident -= count;
1928 return true;
[25bf215]1929}
1930
[df0103f7]1931/*
1932 * Address space related syscalls.
1933 */
1934
1935/** Wrapper for as_area_create(). */
[96b02eb9]1936sysarg_t sys_as_area_create(uintptr_t address, size_t size, unsigned int flags)
[df0103f7]1937{
[6f4495f5]1938 if (as_area_create(AS, flags | AS_AREA_CACHEABLE, size, address,
1939 AS_AREA_ATTR_NONE, &anon_backend, NULL))
[96b02eb9]1940 return (sysarg_t) address;
[df0103f7]1941 else
[96b02eb9]1942 return (sysarg_t) -1;
[df0103f7]1943}
1944
[c6e314a]1945/** Wrapper for as_area_resize(). */
[96b02eb9]1946sysarg_t sys_as_area_resize(uintptr_t address, size_t size, unsigned int flags)
[df0103f7]1947{
[96b02eb9]1948 return (sysarg_t) as_area_resize(AS, address, size, 0);
[7242a78e]1949}
1950
[c98e6ee]1951/** Wrapper for as_area_change_flags(). */
[96b02eb9]1952sysarg_t sys_as_area_change_flags(uintptr_t address, unsigned int flags)
[c98e6ee]1953{
[96b02eb9]1954 return (sysarg_t) as_area_change_flags(AS, flags, address);
[c98e6ee]1955}
1956
[c6e314a]1957/** Wrapper for as_area_destroy(). */
[96b02eb9]1958sysarg_t sys_as_area_destroy(uintptr_t address)
[7242a78e]1959{
[96b02eb9]1960 return (sysarg_t) as_area_destroy(AS, address);
[df0103f7]1961}
[b45c443]1962
[336db295]1963/** Get list of adress space areas.
1964 *
[da1bafb]1965 * @param as Address space.
1966 * @param obuf Place to save pointer to returned buffer.
1967 * @param osize Place to save size of returned buffer.
1968 *
[336db295]1969 */
1970void as_get_area_info(as_t *as, as_area_info_t **obuf, size_t *osize)
1971{
1972 mutex_lock(&as->lock);
[da1bafb]1973
[336db295]1974 /* First pass, count number of areas. */
[da1bafb]1975
1976 size_t area_cnt = 0;
1977 link_t *cur;
1978
[336db295]1979 for (cur = as->as_area_btree.leaf_head.next;
1980 cur != &as->as_area_btree.leaf_head; cur = cur->next) {
[da1bafb]1981 btree_node_t *node =
1982 list_get_instance(cur, btree_node_t, leaf_link);
[336db295]1983 area_cnt += node->keys;
1984 }
[da1bafb]1985
1986 size_t isize = area_cnt * sizeof(as_area_info_t);
1987 as_area_info_t *info = malloc(isize, 0);
1988
[336db295]1989 /* Second pass, record data. */
[da1bafb]1990
1991 size_t area_idx = 0;
1992
[336db295]1993 for (cur = as->as_area_btree.leaf_head.next;
1994 cur != &as->as_area_btree.leaf_head; cur = cur->next) {
[da1bafb]1995 btree_node_t *node =
1996 list_get_instance(cur, btree_node_t, leaf_link);
1997 btree_key_t i;
1998
[336db295]1999 for (i = 0; i < node->keys; i++) {
2000 as_area_t *area = node->value[i];
[da1bafb]2001
[336db295]2002 ASSERT(area_idx < area_cnt);
2003 mutex_lock(&area->lock);
[da1bafb]2004
[336db295]2005 info[area_idx].start_addr = area->base;
2006 info[area_idx].size = FRAMES2SIZE(area->pages);
2007 info[area_idx].flags = area->flags;
2008 ++area_idx;
[da1bafb]2009
[336db295]2010 mutex_unlock(&area->lock);
2011 }
2012 }
[da1bafb]2013
[336db295]2014 mutex_unlock(&as->lock);
[da1bafb]2015
[336db295]2016 *obuf = info;
2017 *osize = isize;
2018}
2019
[64c2ad5]2020/** Print out information about address space.
2021 *
[da1bafb]2022 * @param as Address space.
2023 *
[64c2ad5]2024 */
2025void as_print(as_t *as)
2026{
2027 mutex_lock(&as->lock);
2028
2029 /* print out info about address space areas */
2030 link_t *cur;
[6f4495f5]2031 for (cur = as->as_area_btree.leaf_head.next;
2032 cur != &as->as_area_btree.leaf_head; cur = cur->next) {
[da1bafb]2033 btree_node_t *node
2034 = list_get_instance(cur, btree_node_t, leaf_link);
2035 btree_key_t i;
[64c2ad5]2036
2037 for (i = 0; i < node->keys; i++) {
[7ba7c6d]2038 as_area_t *area = node->value[i];
[da1bafb]2039
[64c2ad5]2040 mutex_lock(&area->lock);
[7e752b2]2041 printf("as_area: %p, base=%p, pages=%zu"
2042 " (%p - %p)\n", area, (void *) area->base,
2043 area->pages, (void *) area->base,
2044 (void *) (area->base + FRAMES2SIZE(area->pages)));
[64c2ad5]2045 mutex_unlock(&area->lock);
2046 }
2047 }
2048
2049 mutex_unlock(&as->lock);
2050}
2051
[cc73a8a1]2052/** @}
[b45c443]2053 */
Note: See TracBrowser for help on using the repository browser.