Changeset 04803bf in mainline for kernel/generic/src/mm/as.c


Ignore:
Timestamp:
2011-03-21T22:00:17Z (15 years ago)
Author:
Jiri Svoboda <jiri@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
143932e3
Parents:
b50b5af2 (diff), 7308e84 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge mainline changes (needs fixes).

File:
1 edited

Legend:

Unmodified
Added
Removed
  • kernel/generic/src/mm/as.c

    rb50b5af2 r04803bf  
    11/*
    2  * Copyright (c) 2001-2006 Jakub Jermar
     2 * Copyright (c) 2010 Jakub Jermar
    33 * All rights reserved.
    44 *
     
    3333/**
    3434 * @file
    35  * @brief       Address space related functions.
     35 * @brief Address space related functions.
    3636 *
    3737 * This file contains address space manipulation functions.
     
    7171#include <memstr.h>
    7272#include <macros.h>
     73#include <bitops.h>
    7374#include <arch.h>
    7475#include <errno.h>
    7576#include <config.h>
    7677#include <align.h>
    77 #include <arch/types.h>
     78#include <typedefs.h>
    7879#include <syscall/copy.h>
    7980#include <arch/interrupt.h>
     
    8990as_operations_t *as_operations = NULL;
    9091
    91 /**
    92  * Slab for as_t objects.
     92/** Slab for as_t objects.
     93 *
    9394 */
    9495static slab_cache_t *as_slab;
    9596
    96 /**
    97  * This lock serializes access to the ASID subsystem.
    98  * It protects:
     97/** ASID subsystem lock.
     98 *
     99 * This lock protects:
    99100 * - inactive_as_with_asid_head list
    100101 * - as->asid for each as of the as_t type
    101102 * - asids_allocated counter
     103 *
    102104 */
    103105SPINLOCK_INITIALIZE(asidlock);
    104106
    105107/**
    106  * This list contains address spaces that are not active on any
    107  * processor and that have valid ASID.
     108 * Inactive address spaces (on all processors)
     109 * that have valid ASID.
    108110 */
    109111LIST_INITIALIZE(inactive_as_with_asid_head);
     
    112114as_t *AS_KERNEL = NULL;
    113115
    114 static int area_flags_to_page_flags(int);
    115 static as_area_t *find_area_and_lock(as_t *, uintptr_t);
    116 static bool check_area_conflicts(as_t *, uintptr_t, size_t, as_area_t *);
    117 static void sh_info_remove_reference(share_info_t *);
    118 
    119 static int as_constructor(void *obj, int flags)
     116NO_TRACE static int as_constructor(void *obj, unsigned int flags)
    120117{
    121118        as_t *as = (as_t *) obj;
    122         int rc;
    123 
     119       
    124120        link_initialize(&as->inactive_as_with_asid_link);
    125121        mutex_initialize(&as->lock, MUTEX_PASSIVE);
    126122       
    127         rc = as_constructor_arch(as, flags);
    128        
    129         return rc;
    130 }
    131 
    132 static int as_destructor(void *obj)
    133 {
    134         as_t *as = (as_t *) obj;
    135 
    136         return as_destructor_arch(as);
     123        return as_constructor_arch(as, flags);
     124}
     125
     126NO_TRACE static size_t as_destructor(void *obj)
     127{
     128        return as_destructor_arch((as_t *) obj);
    137129}
    138130
     
    141133{
    142134        as_arch_init();
    143 
     135       
    144136        as_slab = slab_cache_create("as_slab", sizeof(as_t), 0,
    145137            as_constructor, as_destructor, SLAB_CACHE_MAGDEFERRED);
     
    149141                panic("Cannot create kernel address space.");
    150142       
    151         /* Make sure the kernel address space
     143        /*
     144         * Make sure the kernel address space
    152145         * reference count never drops to zero.
    153146         */
    154         atomic_set(&AS_KERNEL->refcount, 1);
     147        as_hold(AS_KERNEL);
    155148}
    156149
    157150/** Create address space.
    158151 *
    159  * @param flags         Flags that influence the way in wich the address space
    160  *                      is created.
    161  */
    162 as_t *as_create(int flags)
    163 {
    164         as_t *as;
    165 
    166         as = (as_t *) slab_alloc(as_slab, 0);
     152 * @param flags Flags that influence the way in wich the address
     153 *              space is created.
     154 *
     155 */
     156as_t *as_create(unsigned int flags)
     157{
     158        as_t *as = (as_t *) slab_alloc(as_slab, 0);
    167159        (void) as_create_arch(as, 0);
    168160       
     
    176168        atomic_set(&as->refcount, 0);
    177169        as->cpu_refcount = 0;
     170       
    178171#ifdef AS_PAGE_TABLE
    179172        as->genarch.page_table = page_table_create(flags);
     
    192185 * We know that we don't hold any spinlock.
    193186 *
    194  * @param as            Address space to be destroyed.
     187 * @param as Address space to be destroyed.
     188 *
    195189 */
    196190void as_destroy(as_t *as)
    197191{
    198         ipl_t ipl;
    199         bool cond;
    200192        DEADLOCK_PROBE_INIT(p_asidlock);
    201 
     193       
     194        ASSERT(as != AS);
    202195        ASSERT(atomic_get(&as->refcount) == 0);
    203196       
    204197        /*
    205          * Since there is no reference to this area,
    206          * it is safe not to lock its mutex.
    207          */
    208 
     198         * Since there is no reference to this address space, it is safe not to
     199         * lock its mutex.
     200         */
     201       
    209202        /*
    210203         * We need to avoid deadlock between TLB shootdown and asidlock.
     
    215208         */
    216209        preemption_disable();
    217         ipl = interrupts_read();
     210        ipl_t ipl = interrupts_read();
     211       
    218212retry:
    219213        interrupts_disable();
     
    223217                goto retry;
    224218        }
    225         preemption_enable();    /* Interrupts disabled, enable preemption */
    226         if (as->asid != ASID_INVALID && as != AS_KERNEL) {
    227                 if (as != AS && as->cpu_refcount == 0)
     219       
     220        /* Interrupts disabled, enable preemption */
     221        preemption_enable();
     222       
     223        if ((as->asid != ASID_INVALID) && (as != AS_KERNEL)) {
     224                if (as->cpu_refcount == 0)
    228225                        list_remove(&as->inactive_as_with_asid_link);
     226               
    229227                asid_put(as->asid);
    230228        }
     229       
    231230        spinlock_unlock(&asidlock);
    232 
     231        interrupts_restore(ipl);
     232       
     233       
    233234        /*
    234235         * Destroy address space areas of the address space.
    235236         * The B+tree must be walked carefully because it is
    236237         * also being destroyed.
    237          */     
    238         for (cond = true; cond; ) {
    239                 btree_node_t *node;
    240 
     238         */
     239        bool cond = true;
     240        while (cond) {
    241241                ASSERT(!list_empty(&as->as_area_btree.leaf_head));
    242                 node = list_get_instance(as->as_area_btree.leaf_head.next,
     242               
     243                btree_node_t *node =
     244                    list_get_instance(as->as_area_btree.leaf_head.next,
    243245                    btree_node_t, leaf_link);
    244 
    245                 if ((cond = node->keys)) {
     246               
     247                if ((cond = node->keys))
    246248                        as_area_destroy(as, node->key[0]);
    247                 }
    248         }
    249 
     249        }
     250       
    250251        btree_destroy(&as->as_area_btree);
     252       
    251253#ifdef AS_PAGE_TABLE
    252254        page_table_destroy(as->genarch.page_table);
     
    254256        page_table_destroy(NULL);
    255257#endif
    256 
    257         interrupts_restore(ipl);
    258 
     258       
    259259        slab_free(as_slab, as);
    260260}
    261261
     262/** Hold a reference to an address space.
     263 *
     264 * Holding a reference to an address space prevents destruction
     265 * of that address space.
     266 *
     267 * @param as Address space to be held.
     268 *
     269 */
     270NO_TRACE void as_hold(as_t *as)
     271{
     272        atomic_inc(&as->refcount);
     273}
     274
     275/** Release a reference to an address space.
     276 *
     277 * The last one to release a reference to an address space
     278 * destroys the address space.
     279 *
     280 * @param asAddress space to be released.
     281 *
     282 */
     283NO_TRACE void as_release(as_t *as)
     284{
     285        if (atomic_predec(&as->refcount) == 0)
     286                as_destroy(as);
     287}
     288
     289/** Check area conflicts with other areas.
     290 *
     291 * @param as    Address space.
     292 * @param addr  Starting virtual address of the area being tested.
     293 * @param count Number of pages in the area being tested.
     294 * @param avoid Do not touch this area.
     295 *
     296 * @return True if there is no conflict, false otherwise.
     297 *
     298 */
     299NO_TRACE static bool check_area_conflicts(as_t *as, uintptr_t addr,
     300    size_t count, as_area_t *avoid)
     301{
     302        ASSERT((addr % PAGE_SIZE) == 0);
     303        ASSERT(mutex_locked(&as->lock));
     304       
     305        /*
     306         * We don't want any area to have conflicts with NULL page.
     307         */
     308        if (overlaps(addr, count << PAGE_WIDTH, (uintptr_t) NULL, PAGE_SIZE))
     309                return false;
     310       
     311        /*
     312         * The leaf node is found in O(log n), where n is proportional to
     313         * the number of address space areas belonging to as.
     314         * The check for conflicts is then attempted on the rightmost
     315         * record in the left neighbour, the leftmost record in the right
     316         * neighbour and all records in the leaf node itself.
     317         */
     318        btree_node_t *leaf;
     319        as_area_t *area =
     320            (as_area_t *) btree_search(&as->as_area_btree, addr, &leaf);
     321        if (area) {
     322                if (area != avoid)
     323                        return false;
     324        }
     325       
     326        /* First, check the two border cases. */
     327        btree_node_t *node =
     328            btree_leaf_node_left_neighbour(&as->as_area_btree, leaf);
     329        if (node) {
     330                area = (as_area_t *) node->value[node->keys - 1];
     331               
     332                if (area != avoid) {
     333                        mutex_lock(&area->lock);
     334                       
     335                        if (overlaps(addr, count << PAGE_WIDTH,
     336                            area->base, area->pages << PAGE_WIDTH)) {
     337                                mutex_unlock(&area->lock);
     338                                return false;
     339                        }
     340                       
     341                        mutex_unlock(&area->lock);
     342                }
     343        }
     344       
     345        node = btree_leaf_node_right_neighbour(&as->as_area_btree, leaf);
     346        if (node) {
     347                area = (as_area_t *) node->value[0];
     348               
     349                if (area != avoid) {
     350                        mutex_lock(&area->lock);
     351                       
     352                        if (overlaps(addr, count << PAGE_WIDTH,
     353                            area->base, area->pages << PAGE_WIDTH)) {
     354                                mutex_unlock(&area->lock);
     355                                return false;
     356                        }
     357                       
     358                        mutex_unlock(&area->lock);
     359                }
     360        }
     361       
     362        /* Second, check the leaf node. */
     363        btree_key_t i;
     364        for (i = 0; i < leaf->keys; i++) {
     365                area = (as_area_t *) leaf->value[i];
     366               
     367                if (area == avoid)
     368                        continue;
     369               
     370                mutex_lock(&area->lock);
     371               
     372                if (overlaps(addr, count << PAGE_WIDTH,
     373                    area->base, area->pages << PAGE_WIDTH)) {
     374                        mutex_unlock(&area->lock);
     375                        return false;
     376                }
     377               
     378                mutex_unlock(&area->lock);
     379        }
     380       
     381        /*
     382         * So far, the area does not conflict with other areas.
     383         * Check if it doesn't conflict with kernel address space.
     384         */
     385        if (!KERNEL_ADDRESS_SPACE_SHADOWED) {
     386                return !overlaps(addr, count << PAGE_WIDTH,
     387                    KERNEL_ADDRESS_SPACE_START,
     388                    KERNEL_ADDRESS_SPACE_END - KERNEL_ADDRESS_SPACE_START);
     389        }
     390       
     391        return true;
     392}
     393
    262394/** Create address space area of common attributes.
    263395 *
    264396 * The created address space area is added to the target address space.
    265397 *
    266  * @param as            Target address space.
    267  * @param flags         Flags of the area memory.
    268  * @param size          Size of area.
    269  * @param base          Base address of area.
    270  * @param attrs         Attributes of the area.
    271  * @param backend       Address space area backend. NULL if no backend is used.
    272  * @param backend_data  NULL or a pointer to an array holding two void *.
    273  *
    274  * @return              Address space area on success or NULL on failure.
    275  */
    276 as_area_t *
    277 as_area_create(as_t *as, int flags, size_t size, uintptr_t base, int attrs,
    278     mem_backend_t *backend, mem_backend_data_t *backend_data)
    279 {
    280         ipl_t ipl;
    281         as_area_t *a;
    282        
    283         if (base % PAGE_SIZE)
     398 * @param as           Target address space.
     399 * @param flags        Flags of the area memory.
     400 * @param size         Size of area.
     401 * @param base         Base address of area.
     402 * @param attrs        Attributes of the area.
     403 * @param backend      Address space area backend. NULL if no backend is used.
     404 * @param backend_data NULL or a pointer to an array holding two void *.
     405 *
     406 * @return Address space area on success or NULL on failure.
     407 *
     408 */
     409as_area_t *as_area_create(as_t *as, unsigned int flags, size_t size,
     410    uintptr_t base, unsigned int attrs, mem_backend_t *backend,
     411    mem_backend_data_t *backend_data)
     412{
     413        if ((base % PAGE_SIZE) != 0)
    284414                return NULL;
    285 
    286         if (!size)
     415       
     416        if (size == 0)
    287417                return NULL;
    288 
     418       
     419        size_t pages = SIZE2FRAMES(size);
     420       
    289421        /* Writeable executable areas are not supported. */
    290422        if ((flags & AS_AREA_EXEC) && (flags & AS_AREA_WRITE))
    291423                return NULL;
    292424       
    293         ipl = interrupts_disable();
    294425        mutex_lock(&as->lock);
    295426       
    296         if (!check_area_conflicts(as, base, size, NULL)) {
     427        if (!check_area_conflicts(as, base, pages, NULL)) {
    297428                mutex_unlock(&as->lock);
    298                 interrupts_restore(ipl);
    299429                return NULL;
    300430        }
    301431       
    302         a = (as_area_t *) malloc(sizeof(as_area_t), 0);
    303 
    304         mutex_initialize(&a->lock, MUTEX_PASSIVE);
    305        
    306         a->as = as;
    307         a->flags = flags;
    308         a->attributes = attrs;
    309         a->pages = SIZE2FRAMES(size);
    310         a->base = base;
    311         a->sh_info = NULL;
    312         a->backend = backend;
     432        as_area_t *area = (as_area_t *) malloc(sizeof(as_area_t), 0);
     433       
     434        mutex_initialize(&area->lock, MUTEX_PASSIVE);
     435       
     436        area->as = as;
     437        area->flags = flags;
     438        area->attributes = attrs;
     439        area->pages = pages;
     440        area->resident = 0;
     441        area->base = base;
     442        area->sh_info = NULL;
     443        area->backend = backend;
     444       
    313445        if (backend_data)
    314                 a->backend_data = *backend_data;
     446                area->backend_data = *backend_data;
    315447        else
    316                 memsetb(&a->backend_data, sizeof(a->backend_data), 0);
    317 
    318         btree_create(&a->used_space);
    319        
    320         btree_insert(&as->as_area_btree, base, (void *) a, NULL);
    321 
     448                memsetb(&area->backend_data, sizeof(area->backend_data), 0);
     449       
     450        btree_create(&area->used_space);
     451        btree_insert(&as->as_area_btree, base, (void *) area, NULL);
     452       
    322453        mutex_unlock(&as->lock);
    323         interrupts_restore(ipl);
    324 
    325         return a;
     454       
     455        return area;
     456}
     457
     458/** Find address space area and lock it.
     459 *
     460 * @param as Address space.
     461 * @param va Virtual address.
     462 *
     463 * @return Locked address space area containing va on success or
     464 *         NULL on failure.
     465 *
     466 */
     467NO_TRACE static as_area_t *find_area_and_lock(as_t *as, uintptr_t va)
     468{
     469        ASSERT(mutex_locked(&as->lock));
     470       
     471        btree_node_t *leaf;
     472        as_area_t *area = (as_area_t *) btree_search(&as->as_area_btree, va, &leaf);
     473        if (area) {
     474                /* va is the base address of an address space area */
     475                mutex_lock(&area->lock);
     476                return area;
     477        }
     478       
     479        /*
     480         * Search the leaf node and the righmost record of its left neighbour
     481         * to find out whether this is a miss or va belongs to an address
     482         * space area found there.
     483         */
     484       
     485        /* First, search the leaf node itself. */
     486        btree_key_t i;
     487       
     488        for (i = 0; i < leaf->keys; i++) {
     489                area = (as_area_t *) leaf->value[i];
     490               
     491                mutex_lock(&area->lock);
     492               
     493                if ((area->base <= va) &&
     494                    (va < area->base + (area->pages << PAGE_WIDTH)))
     495                        return area;
     496               
     497                mutex_unlock(&area->lock);
     498        }
     499       
     500        /*
     501         * Second, locate the left neighbour and test its last record.
     502         * Because of its position in the B+tree, it must have base < va.
     503         */
     504        btree_node_t *lnode = btree_leaf_node_left_neighbour(&as->as_area_btree, leaf);
     505        if (lnode) {
     506                area = (as_area_t *) lnode->value[lnode->keys - 1];
     507               
     508                mutex_lock(&area->lock);
     509               
     510                if (va < area->base + (area->pages << PAGE_WIDTH))
     511                        return area;
     512               
     513                mutex_unlock(&area->lock);
     514        }
     515       
     516        return NULL;
    326517}
    327518
    328519/** Find address space area and change it.
    329520 *
    330  * @param as            Address space.
    331  * @param address       Virtual address belonging to the area to be changed.
    332  *                      Must be page-aligned.
    333  * @param size          New size of the virtual memory block starting at
    334  *                      address.
    335  * @param flags         Flags influencing the remap operation. Currently unused.
    336  *
    337  * @return              Zero on success or a value from @ref errno.h otherwise.
    338  */
    339 int as_area_resize(as_t *as, uintptr_t address, size_t size, int flags)
    340 {
    341         as_area_t *area;
    342         ipl_t ipl;
    343         size_t pages;
    344        
    345         ipl = interrupts_disable();
     521 * @param as      Address space.
     522 * @param address Virtual address belonging to the area to be changed.
     523 *                Must be page-aligned.
     524 * @param size    New size of the virtual memory block starting at
     525 *                address.
     526 * @param flags   Flags influencing the remap operation. Currently unused.
     527 *
     528 * @return Zero on success or a value from @ref errno.h otherwise.
     529 *
     530 */
     531int as_area_resize(as_t *as, uintptr_t address, size_t size, unsigned int flags)
     532{
    346533        mutex_lock(&as->lock);
    347534       
     
    349536         * Locate the area.
    350537         */
    351         area = find_area_and_lock(as, address);
     538        as_area_t *area = find_area_and_lock(as, address);
    352539        if (!area) {
    353540                mutex_unlock(&as->lock);
    354                 interrupts_restore(ipl);
    355541                return ENOENT;
    356542        }
    357 
     543       
    358544        if (area->backend == &phys_backend) {
    359545                /*
     
    363549                mutex_unlock(&area->lock);
    364550                mutex_unlock(&as->lock);
    365                 interrupts_restore(ipl);
    366551                return ENOTSUP;
    367552        }
     553       
    368554        if (area->sh_info) {
    369555                /*
    370                  * Remapping of shared address space areas 
     556                 * Remapping of shared address space areas
    371557                 * is not supported.
    372558                 */
    373559                mutex_unlock(&area->lock);
    374560                mutex_unlock(&as->lock);
    375                 interrupts_restore(ipl);
    376561                return ENOTSUP;
    377562        }
    378 
    379         pages = SIZE2FRAMES((address - area->base) + size);
     563       
     564        size_t pages = SIZE2FRAMES((address - area->base) + size);
    380565        if (!pages) {
    381566                /*
     
    384569                mutex_unlock(&area->lock);
    385570                mutex_unlock(&as->lock);
    386                 interrupts_restore(ipl);
    387571                return EPERM;
    388572        }
    389573       
    390574        if (pages < area->pages) {
    391                 bool cond;
    392                 uintptr_t start_free = area->base + pages * PAGE_SIZE;
    393 
     575                uintptr_t start_free = area->base + (pages << PAGE_WIDTH);
     576               
    394577                /*
    395578                 * Shrinking the area.
    396579                 * No need to check for overlaps.
    397580                 */
    398 
     581               
     582                page_table_lock(as, false);
     583               
    399584                /*
    400585                 * Start TLB shootdown sequence.
    401586                 */
    402                 tlb_shootdown_start(TLB_INVL_PAGES, as->asid, area->base +
    403                     pages * PAGE_SIZE, area->pages - pages);
    404 
     587                ipl_t ipl = tlb_shootdown_start(TLB_INVL_PAGES, as->asid,
     588                    area->base + (pages << PAGE_WIDTH), area->pages - pages);
     589               
    405590                /*
    406591                 * Remove frames belonging to used space starting from
     
    409594                 * is also the right way to remove part of the used_space
    410595                 * B+tree leaf list.
    411                  */             
    412                 for (cond = true; cond;) {
    413                         btree_node_t *node;
    414                
     596                 */
     597                bool cond = true;
     598                while (cond) {
    415599                        ASSERT(!list_empty(&area->used_space.leaf_head));
    416                         node =
     600                       
     601                        btree_node_t *node =
    417602                            list_get_instance(area->used_space.leaf_head.prev,
    418603                            btree_node_t, leaf_link);
     604                       
    419605                        if ((cond = (bool) node->keys)) {
    420                                 uintptr_t b = node->key[node->keys - 1];
    421                                 size_t c =
     606                                uintptr_t ptr = node->key[node->keys - 1];
     607                                size_t size =
    422608                                    (size_t) node->value[node->keys - 1];
    423                                 unsigned int i = 0;
    424                        
    425                                 if (overlaps(b, c * PAGE_SIZE, area->base,
    426                                     pages * PAGE_SIZE)) {
     609                                size_t i = 0;
     610                               
     611                                if (overlaps(ptr, size << PAGE_WIDTH, area->base,
     612                                    pages << PAGE_WIDTH)) {
    427613                                       
    428                                         if (b + c * PAGE_SIZE <= start_free) {
     614                                        if (ptr + (size << PAGE_WIDTH) <= start_free) {
    429615                                                /*
    430616                                                 * The whole interval fits
     
    434620                                                break;
    435621                                        }
    436                
     622                                       
    437623                                        /*
    438624                                         * Part of the interval corresponding
     
    440626                                         * address space area.
    441627                                         */
    442                
    443                                         cond = false;   /* we are almost done */
    444                                         i = (start_free - b) >> PAGE_WIDTH;
     628                                       
     629                                        /* We are almost done */
     630                                        cond = false;
     631                                        i = (start_free - ptr) >> PAGE_WIDTH;
    445632                                        if (!used_space_remove(area, start_free,
    446                                             c - i))
    447                                                 panic("Cannot remove used "
    448                                                     "space.");
     633                                            size - i))
     634                                                panic("Cannot remove used space.");
    449635                                } else {
    450636                                        /*
     
    452638                                         * completely removed.
    453639                                         */
    454                                         if (!used_space_remove(area, b, c))
    455                                                 panic("Cannot remove used "
    456                                                     "space.");
     640                                        if (!used_space_remove(area, ptr, size))
     641                                                panic("Cannot remove used space.");
    457642                                }
    458                        
    459                                 for (; i < c; i++) {
    460                                         pte_t *pte;
    461                        
    462                                         page_table_lock(as, false);
    463                                         pte = page_mapping_find(as, b +
    464                                             i * PAGE_SIZE);
    465                                         ASSERT(pte && PTE_VALID(pte) &&
    466                                             PTE_PRESENT(pte));
    467                                         if (area->backend &&
    468                                             area->backend->frame_free) {
     643                               
     644                                for (; i < size; i++) {
     645                                        pte_t *pte = page_mapping_find(as, ptr +
     646                                            (i << PAGE_WIDTH));
     647                                       
     648                                        ASSERT(pte);
     649                                        ASSERT(PTE_VALID(pte));
     650                                        ASSERT(PTE_PRESENT(pte));
     651                                       
     652                                        if ((area->backend) &&
     653                                            (area->backend->frame_free)) {
    469654                                                area->backend->frame_free(area,
    470                                                     b + i * PAGE_SIZE,
     655                                                    ptr + (i << PAGE_WIDTH),
    471656                                                    PTE_GET_FRAME(pte));
    472657                                        }
    473                                         page_mapping_remove(as, b +
    474                                             i * PAGE_SIZE);
    475                                         page_table_unlock(as, false);
     658                                       
     659                                        page_mapping_remove(as, ptr +
     660                                            (i << PAGE_WIDTH));
    476661                                }
    477662                        }
    478663                }
    479 
     664               
    480665                /*
    481666                 * Finish TLB shootdown sequence.
    482667                 */
    483 
    484                 tlb_invalidate_pages(as->asid, area->base + pages * PAGE_SIZE,
     668               
     669                tlb_invalidate_pages(as->asid, area->base + (pages << PAGE_WIDTH),
    485670                    area->pages - pages);
     671               
    486672                /*
    487673                 * Invalidate software translation caches (e.g. TSB on sparc64).
    488674                 */
    489675                as_invalidate_translation_cache(as, area->base +
    490                     pages * PAGE_SIZE, area->pages - pages);
    491                 tlb_shootdown_finalize();
    492                
     676                    (pages << PAGE_WIDTH), area->pages - pages);
     677                tlb_shootdown_finalize(ipl);
     678               
     679                page_table_unlock(as, false);
    493680        } else {
    494681                /*
     
    496683                 * Check for overlaps with other address space areas.
    497684                 */
    498                 if (!check_area_conflicts(as, address, pages * PAGE_SIZE,
    499                     area)) {
     685                if (!check_area_conflicts(as, address, pages, area)) {
    500686                        mutex_unlock(&area->lock);
    501                         mutex_unlock(&as->lock);               
    502                         interrupts_restore(ipl);
     687                        mutex_unlock(&as->lock);
    503688                        return EADDRNOTAVAIL;
    504689                }
    505         } 
    506 
     690        }
     691       
    507692        area->pages = pages;
    508693       
    509694        mutex_unlock(&area->lock);
    510695        mutex_unlock(&as->lock);
    511         interrupts_restore(ipl);
    512 
     696       
    513697        return 0;
    514698}
    515699
     700/** Remove reference to address space area share info.
     701 *
     702 * If the reference count drops to 0, the sh_info is deallocated.
     703 *
     704 * @param sh_info Pointer to address space area share info.
     705 *
     706 */
     707NO_TRACE static void sh_info_remove_reference(share_info_t *sh_info)
     708{
     709        bool dealloc = false;
     710       
     711        mutex_lock(&sh_info->lock);
     712        ASSERT(sh_info->refcount);
     713       
     714        if (--sh_info->refcount == 0) {
     715                dealloc = true;
     716                link_t *cur;
     717               
     718                /*
     719                 * Now walk carefully the pagemap B+tree and free/remove
     720                 * reference from all frames found there.
     721                 */
     722                for (cur = sh_info->pagemap.leaf_head.next;
     723                    cur != &sh_info->pagemap.leaf_head; cur = cur->next) {
     724                        btree_node_t *node
     725                            = list_get_instance(cur, btree_node_t, leaf_link);
     726                        btree_key_t i;
     727                       
     728                        for (i = 0; i < node->keys; i++)
     729                                frame_free((uintptr_t) node->value[i]);
     730                }
     731               
     732        }
     733        mutex_unlock(&sh_info->lock);
     734       
     735        if (dealloc) {
     736                btree_destroy(&sh_info->pagemap);
     737                free(sh_info);
     738        }
     739}
     740
    516741/** Destroy address space area.
    517742 *
    518  * @param as            Address space.
    519  * @param address       Address within the area to be deleted.
    520  *
    521  * @return              Zero on success or a value from @ref errno.h on failure.
     743 * @param as      Address space.
     744 * @param address Address within the area to be deleted.
     745 *
     746 * @return Zero on success or a value from @ref errno.h on failure.
     747 *
    522748 */
    523749int as_area_destroy(as_t *as, uintptr_t address)
    524750{
    525         as_area_t *area;
    526         uintptr_t base;
    527         link_t *cur;
    528         ipl_t ipl;
    529 
    530         ipl = interrupts_disable();
    531751        mutex_lock(&as->lock);
    532 
    533         area = find_area_and_lock(as, address);
     752       
     753        as_area_t *area = find_area_and_lock(as, address);
    534754        if (!area) {
    535755                mutex_unlock(&as->lock);
    536                 interrupts_restore(ipl);
    537756                return ENOENT;
    538757        }
    539 
    540         base = area->base;
    541 
     758       
     759        uintptr_t base = area->base;
     760       
     761        page_table_lock(as, false);
     762       
    542763        /*
    543764         * Start TLB shootdown sequence.
    544765         */
    545         tlb_shootdown_start(TLB_INVL_PAGES, as->asid, area->base, area->pages);
    546 
     766        ipl_t ipl = tlb_shootdown_start(TLB_INVL_PAGES, as->asid, area->base,
     767            area->pages);
     768       
    547769        /*
    548770         * Visit only the pages mapped by used_space B+tree.
    549771         */
     772        link_t *cur;
    550773        for (cur = area->used_space.leaf_head.next;
    551774            cur != &area->used_space.leaf_head; cur = cur->next) {
    552775                btree_node_t *node;
    553                 unsigned int i;
     776                btree_key_t i;
    554777               
    555778                node = list_get_instance(cur, btree_node_t, leaf_link);
    556779                for (i = 0; i < node->keys; i++) {
    557                         uintptr_t b = node->key[i];
    558                         size_t j;
    559                         pte_t *pte;
    560                        
    561                         for (j = 0; j < (size_t) node->value[i]; j++) {
    562                                 page_table_lock(as, false);
    563                                 pte = page_mapping_find(as, b + j * PAGE_SIZE);
    564                                 ASSERT(pte && PTE_VALID(pte) &&
    565                                     PTE_PRESENT(pte));
    566                                 if (area->backend &&
    567                                     area->backend->frame_free) {
    568                                         area->backend->frame_free(area, b +
    569                                             j * PAGE_SIZE, PTE_GET_FRAME(pte));
     780                        uintptr_t ptr = node->key[i];
     781                        size_t size;
     782                       
     783                        for (size = 0; size < (size_t) node->value[i]; size++) {
     784                                pte_t *pte =
     785                                    page_mapping_find(as, ptr + (size << PAGE_WIDTH));
     786                               
     787                                ASSERT(pte);
     788                                ASSERT(PTE_VALID(pte));
     789                                ASSERT(PTE_PRESENT(pte));
     790                               
     791                                if ((area->backend) &&
     792                                    (area->backend->frame_free)) {
     793                                        area->backend->frame_free(area,
     794                                            ptr + (size << PAGE_WIDTH), PTE_GET_FRAME(pte));
    570795                                }
    571                                 page_mapping_remove(as, b + j * PAGE_SIZE);                             
    572                                 page_table_unlock(as, false);
     796                               
     797                                page_mapping_remove(as, ptr + (size << PAGE_WIDTH));
    573798                        }
    574799                }
    575800        }
    576 
     801       
    577802        /*
    578803         * Finish TLB shootdown sequence.
    579804         */
    580 
     805       
    581806        tlb_invalidate_pages(as->asid, area->base, area->pages);
     807       
    582808        /*
    583809         * Invalidate potential software translation caches (e.g. TSB on
     
    585811         */
    586812        as_invalidate_translation_cache(as, area->base, area->pages);
    587         tlb_shootdown_finalize();
     813        tlb_shootdown_finalize(ipl);
     814       
     815        page_table_unlock(as, false);
    588816       
    589817        btree_destroy(&area->used_space);
    590 
     818       
    591819        area->attributes |= AS_AREA_ATTR_PARTIAL;
    592820       
    593821        if (area->sh_info)
    594822                sh_info_remove_reference(area->sh_info);
    595                
     823       
    596824        mutex_unlock(&area->lock);
    597 
     825       
    598826        /*
    599827         * Remove the empty area from address space.
     
    604832       
    605833        mutex_unlock(&as->lock);
    606         interrupts_restore(ipl);
    607834        return 0;
    608835}
     
    615842 * sh_info of the source area. The process of duplicating the
    616843 * mapping is done through the backend share function.
    617  * 
    618  * @param src_as        Pointer to source address space.
    619  * @param src_base      Base address of the source address space area.
    620  * @param acc_size      Expected size of the source area.
    621  * @param dst_as        Pointer to destination address space.
    622  * @param dst_base      Target base address.
     844 *
     845 * @param src_as         Pointer to source address space.
     846 * @param src_base       Base address of the source address space area.
     847 * @param acc_size       Expected size of the source area.
     848 * @param dst_as         Pointer to destination address space.
     849 * @param dst_base       Target base address.
    623850 * @param dst_flags_mask Destination address space area flags mask.
    624851 *
    625  * @return              Zero on success or ENOENT if there is no such task or if
    626  *                      there is no such address space area, EPERM if there was
    627  *                      a problem in accepting the area or ENOMEM if there was a
    628  *                      problem in allocating destination address space area.
    629  *                      ENOTSUP is returned if the address space area backend
    630  *                      does not support sharing.
     852 * @return Zero on success.
     853 * @return ENOENT if there is no such task or such address space.
     854 * @return EPERM if there was a problem in accepting the area.
     855 * @return ENOMEM if there was a problem in allocating destination
     856 *         address space area.
     857 * @return ENOTSUP if the address space area backend does not support
     858 *         sharing.
     859 *
    631860 */
    632861int as_area_share(as_t *src_as, uintptr_t src_base, size_t acc_size,
    633     as_t *dst_as, uintptr_t dst_base, int dst_flags_mask)
    634 {
    635         ipl_t ipl;
    636         int src_flags;
    637         size_t src_size;
    638         as_area_t *src_area, *dst_area;
    639         share_info_t *sh_info;
    640         mem_backend_t *src_backend;
    641         mem_backend_data_t src_backend_data;
    642        
    643         ipl = interrupts_disable();
     862    as_t *dst_as, uintptr_t dst_base, unsigned int dst_flags_mask)
     863{
    644864        mutex_lock(&src_as->lock);
    645         src_area = find_area_and_lock(src_as, src_base);
     865        as_area_t *src_area = find_area_and_lock(src_as, src_base);
    646866        if (!src_area) {
    647867                /*
     
    649869                 */
    650870                mutex_unlock(&src_as->lock);
    651                 interrupts_restore(ipl);
    652871                return ENOENT;
    653872        }
    654 
    655         if (!src_area->backend || !src_area->backend->share) {
     873       
     874        if ((!src_area->backend) || (!src_area->backend->share)) {
    656875                /*
    657876                 * There is no backend or the backend does not
     
    660879                mutex_unlock(&src_area->lock);
    661880                mutex_unlock(&src_as->lock);
    662                 interrupts_restore(ipl);
    663881                return ENOTSUP;
    664882        }
    665883       
    666         src_size = src_area->pages * PAGE_SIZE;
    667         src_flags = src_area->flags;
    668         src_backend = src_area->backend;
    669         src_backend_data = src_area->backend_data;
    670 
     884        size_t src_size = src_area->pages << PAGE_WIDTH;
     885        unsigned int src_flags = src_area->flags;
     886        mem_backend_t *src_backend = src_area->backend;
     887        mem_backend_data_t src_backend_data = src_area->backend_data;
     888       
    671889        /* Share the cacheable flag from the original mapping */
    672890        if (src_flags & AS_AREA_CACHEABLE)
    673891                dst_flags_mask |= AS_AREA_CACHEABLE;
    674 
    675         if (src_size != acc_size ||
    676             (src_flags & dst_flags_mask) != dst_flags_mask) {
     892       
     893        if ((src_size != acc_size) ||
     894            ((src_flags & dst_flags_mask) != dst_flags_mask)) {
    677895                mutex_unlock(&src_area->lock);
    678896                mutex_unlock(&src_as->lock);
    679                 interrupts_restore(ipl);
    680897                return EPERM;
    681898        }
    682 
     899       
    683900        /*
    684901         * Now we are committed to sharing the area.
     
    686903         * Then it will be safe to unlock it.
    687904         */
    688         sh_info = src_area->sh_info;
     905        share_info_t *sh_info = src_area->sh_info;
    689906        if (!sh_info) {
    690907                sh_info = (share_info_t *) malloc(sizeof(share_info_t), 0);
     
    693910                btree_create(&sh_info->pagemap);
    694911                src_area->sh_info = sh_info;
     912               
    695913                /*
    696914                 * Call the backend to setup sharing.
     
    702920                mutex_unlock(&sh_info->lock);
    703921        }
    704 
     922       
    705923        mutex_unlock(&src_area->lock);
    706924        mutex_unlock(&src_as->lock);
    707 
     925       
    708926        /*
    709927         * Create copy of the source address space area.
     
    714932         * to support sharing in less privileged mode.
    715933         */
    716         dst_area = as_area_create(dst_as, dst_flags_mask, src_size, dst_base,
    717             AS_AREA_ATTR_PARTIAL, src_backend, &src_backend_data);
     934        as_area_t *dst_area = as_area_create(dst_as, dst_flags_mask, src_size,
     935            dst_base, AS_AREA_ATTR_PARTIAL, src_backend, &src_backend_data);
    718936        if (!dst_area) {
    719937                /*
     
    722940                sh_info_remove_reference(sh_info);
    723941               
    724                 interrupts_restore(ipl);
    725942                return ENOMEM;
    726943        }
    727 
     944       
    728945        /*
    729946         * Now the destination address space area has been
    730947         * fully initialized. Clear the AS_AREA_ATTR_PARTIAL
    731948         * attribute and set the sh_info.
    732          */     
    733         mutex_lock(&dst_as->lock);     
     949         */
     950        mutex_lock(&dst_as->lock);
    734951        mutex_lock(&dst_area->lock);
    735952        dst_area->attributes &= ~AS_AREA_ATTR_PARTIAL;
    736953        dst_area->sh_info = sh_info;
    737954        mutex_unlock(&dst_area->lock);
    738         mutex_unlock(&dst_as->lock);   
    739 
    740         interrupts_restore(ipl);
     955        mutex_unlock(&dst_as->lock);
    741956       
    742957        return 0;
     
    745960/** Check access mode for address space area.
    746961 *
    747  * The address space area must be locked prior to this call.
    748  *
    749  * @param area          Address space area.
    750  * @param access        Access mode.
    751  *
    752  * @return              False if access violates area's permissions, true
    753  *                      otherwise.
    754  */
    755 bool as_area_check_access(as_area_t *area, pf_access_t access)
    756 {
     962 * @param area   Address space area.
     963 * @param access Access mode.
     964 *
     965 * @return False if access violates area's permissions, true
     966 *         otherwise.
     967 *
     968 */
     969NO_TRACE bool as_area_check_access(as_area_t *area, pf_access_t access)
     970{
     971        ASSERT(mutex_locked(&area->lock));
     972       
    757973        int flagmap[] = {
    758974                [PF_ACCESS_READ] = AS_AREA_READ,
     
    760976                [PF_ACCESS_EXEC] = AS_AREA_EXEC
    761977        };
    762 
     978       
    763979        if (!(area->flags & flagmap[access]))
    764980                return false;
    765981       
    766982        return true;
     983}
     984
     985/** Convert address space area flags to page flags.
     986 *
     987 * @param aflags Flags of some address space area.
     988 *
     989 * @return Flags to be passed to page_mapping_insert().
     990 *
     991 */
     992NO_TRACE static unsigned int area_flags_to_page_flags(unsigned int aflags)
     993{
     994        unsigned int flags = PAGE_USER | PAGE_PRESENT;
     995       
     996        if (aflags & AS_AREA_READ)
     997                flags |= PAGE_READ;
     998               
     999        if (aflags & AS_AREA_WRITE)
     1000                flags |= PAGE_WRITE;
     1001       
     1002        if (aflags & AS_AREA_EXEC)
     1003                flags |= PAGE_EXEC;
     1004       
     1005        if (aflags & AS_AREA_CACHEABLE)
     1006                flags |= PAGE_CACHEABLE;
     1007       
     1008        return flags;
    7671009}
    7681010
     
    7811023 *
    7821024 */
    783 int as_area_change_flags(as_t *as, int flags, uintptr_t address)
    784 {
    785         as_area_t *area;
    786         uintptr_t base;
    787         link_t *cur;
    788         ipl_t ipl;
    789         int page_flags;
    790         uintptr_t *old_frame;
    791         size_t frame_idx;
    792         size_t used_pages;
    793        
     1025int as_area_change_flags(as_t *as, unsigned int flags, uintptr_t address)
     1026{
    7941027        /* Flags for the new memory mapping */
    795         page_flags = area_flags_to_page_flags(flags);
    796 
    797         ipl = interrupts_disable();
     1028        unsigned int page_flags = area_flags_to_page_flags(flags);
     1029       
    7981030        mutex_lock(&as->lock);
    799 
    800         area = find_area_and_lock(as, address);
     1031       
     1032        as_area_t *area = find_area_and_lock(as, address);
    8011033        if (!area) {
    8021034                mutex_unlock(&as->lock);
    803                 interrupts_restore(ipl);
    8041035                return ENOENT;
    8051036        }
    806 
     1037       
    8071038        if ((area->sh_info) || (area->backend != &anon_backend)) {
    8081039                /* Copying shared areas not supported yet */
     
    8101041                mutex_unlock(&area->lock);
    8111042                mutex_unlock(&as->lock);
    812                 interrupts_restore(ipl);
    8131043                return ENOTSUP;
    8141044        }
    815 
    816         base = area->base;
    817 
     1045       
    8181046        /*
    8191047         * Compute total number of used pages in the used_space B+tree
    8201048         */
    821         used_pages = 0;
    822 
     1049        size_t used_pages = 0;
     1050        link_t *cur;
     1051       
    8231052        for (cur = area->used_space.leaf_head.next;
    8241053            cur != &area->used_space.leaf_head; cur = cur->next) {
    825                 btree_node_t *node;
    826                 unsigned int i;
    827                
    828                 node = list_get_instance(cur, btree_node_t, leaf_link);
    829                 for (i = 0; i < node->keys; i++) {
     1054                btree_node_t *node
     1055                    = list_get_instance(cur, btree_node_t, leaf_link);
     1056                btree_key_t i;
     1057               
     1058                for (i = 0; i < node->keys; i++)
    8301059                        used_pages += (size_t) node->value[i];
    831                 }
    832         }
    833 
     1060        }
     1061       
    8341062        /* An array for storing frame numbers */
    835         old_frame = malloc(used_pages * sizeof(uintptr_t), 0);
    836 
     1063        uintptr_t *old_frame = malloc(used_pages * sizeof(uintptr_t), 0);
     1064       
     1065        page_table_lock(as, false);
     1066       
    8371067        /*
    8381068         * Start TLB shootdown sequence.
    8391069         */
    840         tlb_shootdown_start(TLB_INVL_PAGES, as->asid, area->base, area->pages);
    841 
     1070        ipl_t ipl = tlb_shootdown_start(TLB_INVL_PAGES, as->asid, area->base,
     1071            area->pages);
     1072       
    8421073        /*
    8431074         * Remove used pages from page tables and remember their frame
    8441075         * numbers.
    8451076         */
    846         frame_idx = 0;
    847 
     1077        size_t frame_idx = 0;
     1078       
    8481079        for (cur = area->used_space.leaf_head.next;
    8491080            cur != &area->used_space.leaf_head; cur = cur->next) {
    850                 btree_node_t *node;
    851                 unsigned int i;
    852                
    853                 node = list_get_instance(cur, btree_node_t, leaf_link);
     1081                btree_node_t *node
     1082                    = list_get_instance(cur, btree_node_t, leaf_link);
     1083                btree_key_t i;
     1084               
    8541085                for (i = 0; i < node->keys; i++) {
    855                         uintptr_t b = node->key[i];
    856                         size_t j;
    857                         pte_t *pte;
    858                        
    859                         for (j = 0; j < (size_t) node->value[i]; j++) {
    860                                 page_table_lock(as, false);
    861                                 pte = page_mapping_find(as, b + j * PAGE_SIZE);
    862                                 ASSERT(pte && PTE_VALID(pte) &&
    863                                     PTE_PRESENT(pte));
     1086                        uintptr_t ptr = node->key[i];
     1087                        size_t size;
     1088                       
     1089                        for (size = 0; size < (size_t) node->value[i]; size++) {
     1090                                pte_t *pte =
     1091                                    page_mapping_find(as, ptr + (size << PAGE_WIDTH));
     1092                               
     1093                                ASSERT(pte);
     1094                                ASSERT(PTE_VALID(pte));
     1095                                ASSERT(PTE_PRESENT(pte));
     1096                               
    8641097                                old_frame[frame_idx++] = PTE_GET_FRAME(pte);
    865 
     1098                               
    8661099                                /* Remove old mapping */
    867                                 page_mapping_remove(as, b + j * PAGE_SIZE);
    868                                 page_table_unlock(as, false);
     1100                                page_mapping_remove(as, ptr + (size << PAGE_WIDTH));
    8691101                        }
    8701102                }
    8711103        }
    872 
     1104       
    8731105        /*
    8741106         * Finish TLB shootdown sequence.
    8751107         */
    876 
     1108       
    8771109        tlb_invalidate_pages(as->asid, area->base, area->pages);
    8781110       
     
    8821114         */
    8831115        as_invalidate_translation_cache(as, area->base, area->pages);
    884         tlb_shootdown_finalize();
    885 
     1116        tlb_shootdown_finalize(ipl);
     1117       
     1118        page_table_unlock(as, false);
     1119       
    8861120        /*
    8871121         * Set the new flags.
    8881122         */
    8891123        area->flags = flags;
    890 
     1124       
    8911125        /*
    8921126         * Map pages back in with new flags. This step is kept separate
     
    8951129         */
    8961130        frame_idx = 0;
    897 
     1131       
    8981132        for (cur = area->used_space.leaf_head.next;
    8991133            cur != &area->used_space.leaf_head; cur = cur->next) {
    900                 btree_node_t *node;
    901                 unsigned int i;
    902                
    903                 node = list_get_instance(cur, btree_node_t, leaf_link);
     1134                btree_node_t *node
     1135                    = list_get_instance(cur, btree_node_t, leaf_link);
     1136                btree_key_t i;
     1137               
    9041138                for (i = 0; i < node->keys; i++) {
    905                         uintptr_t b = node->key[i];
    906                         size_t j;
    907                        
    908                         for (j = 0; j < (size_t) node->value[i]; j++) {
     1139                        uintptr_t ptr = node->key[i];
     1140                        size_t size;
     1141                       
     1142                        for (size = 0; size < (size_t) node->value[i]; size++) {
    9091143                                page_table_lock(as, false);
    910 
     1144                               
    9111145                                /* Insert the new mapping */
    912                                 page_mapping_insert(as, b + j * PAGE_SIZE,
     1146                                page_mapping_insert(as, ptr + (size << PAGE_WIDTH),
    9131147                                    old_frame[frame_idx++], page_flags);
    914 
     1148                               
    9151149                                page_table_unlock(as, false);
    9161150                        }
    9171151                }
    9181152        }
    919 
     1153       
    9201154        free(old_frame);
    921 
     1155       
    9221156        mutex_unlock(&area->lock);
    9231157        mutex_unlock(&as->lock);
    924         interrupts_restore(ipl);
    925 
     1158       
    9261159        return 0;
    9271160}
    928 
    9291161
    9301162/** Handle page fault within the current address space.
     
    9361168 * Interrupts are assumed disabled.
    9371169 *
    938  * @param page          Faulting page.
    939  * @param access        Access mode that caused the page fault (i.e.
    940  *                      read/write/exec).
    941  * @param istate        Pointer to the interrupted state.
    942  *
    943  * @return              AS_PF_FAULT on page fault, AS_PF_OK on success or
    944  *                      AS_PF_DEFER if the fault was caused by copy_to_uspace()
    945  *                      or copy_from_uspace().
     1170 * @param page   Faulting page.
     1171 * @param access Access mode that caused the page fault (i.e.
     1172 *               read/write/exec).
     1173 * @param istate Pointer to the interrupted state.
     1174 *
     1175 * @return AS_PF_FAULT on page fault.
     1176 * @return AS_PF_OK on success.
     1177 * @return AS_PF_DEFER if the fault was caused by copy_to_uspace()
     1178 *         or copy_from_uspace().
     1179 *
    9461180 */
    9471181int as_page_fault(uintptr_t page, pf_access_t access, istate_t *istate)
    9481182{
    949         pte_t *pte;
    950         as_area_t *area;
    951        
    9521183        if (!THREAD)
    9531184                return AS_PF_FAULT;
    954                
    955         ASSERT(AS);
    956 
     1185       
     1186        if (!AS)
     1187                return AS_PF_FAULT;
     1188       
    9571189        mutex_lock(&AS->lock);
    958         area = find_area_and_lock(AS, page);   
     1190        as_area_t *area = find_area_and_lock(AS, page);
    9591191        if (!area) {
    9601192                /*
     
    9651197                goto page_fault;
    9661198        }
    967 
     1199       
    9681200        if (area->attributes & AS_AREA_ATTR_PARTIAL) {
    9691201                /*
     
    9731205                mutex_unlock(&area->lock);
    9741206                mutex_unlock(&AS->lock);
    975                 goto page_fault;               
    976         }
    977 
    978         if (!area->backend || !area->backend->page_fault) {
     1207                goto page_fault;
     1208        }
     1209       
     1210        if ((!area->backend) || (!area->backend->page_fault)) {
    9791211                /*
    9801212                 * The address space area is not backed by any backend
     
    9831215                mutex_unlock(&area->lock);
    9841216                mutex_unlock(&AS->lock);
    985                 goto page_fault;               
    986         }
    987 
     1217                goto page_fault;
     1218        }
     1219       
    9881220        page_table_lock(AS, false);
    9891221       
     
    9921224         * we need to make sure the mapping has not been already inserted.
    9931225         */
     1226        pte_t *pte;
    9941227        if ((pte = page_mapping_find(AS, page))) {
    9951228                if (PTE_PRESENT(pte)) {
     
    10191252        mutex_unlock(&AS->lock);
    10201253        return AS_PF_OK;
    1021 
     1254       
    10221255page_fault:
    10231256        if (THREAD->in_copy_from_uspace) {
     
    10321265                return AS_PF_FAULT;
    10331266        }
    1034 
     1267       
    10351268        return AS_PF_DEFER;
    10361269}
     
    10441277 * When this function is enetered, no spinlocks may be held.
    10451278 *
    1046  * @param old           Old address space or NULL.
    1047  * @param new           New address space.
     1279 * @param old Old address space or NULL.
     1280 * @param new New address space.
     1281 *
    10481282 */
    10491283void as_switch(as_t *old_as, as_t *new_as)
     
    10511285        DEADLOCK_PROBE_INIT(p_asidlock);
    10521286        preemption_disable();
     1287       
    10531288retry:
    10541289        (void) interrupts_disable();
    10551290        if (!spinlock_trylock(&asidlock)) {
    1056                 /* 
     1291                /*
    10571292                 * Avoid deadlock with TLB shootdown.
    10581293                 * We can enable interrupts here because
     
    10651300        }
    10661301        preemption_enable();
    1067 
     1302       
    10681303        /*
    10691304         * First, take care of the old address space.
    1070          */     
     1305         */
    10711306        if (old_as) {
    10721307                ASSERT(old_as->cpu_refcount);
    1073                 if((--old_as->cpu_refcount == 0) && (old_as != AS_KERNEL)) {
     1308               
     1309                if ((--old_as->cpu_refcount == 0) && (old_as != AS_KERNEL)) {
    10741310                        /*
    10751311                         * The old address space is no longer active on
     
    10791315                         */
    10801316                        ASSERT(old_as->asid != ASID_INVALID);
     1317                       
    10811318                        list_append(&old_as->inactive_as_with_asid_link,
    10821319                            &inactive_as_with_asid_head);
    10831320                }
    1084 
     1321               
    10851322                /*
    10861323                 * Perform architecture-specific tasks when the address space
     
    10891326                as_deinstall_arch(old_as);
    10901327        }
    1091 
     1328       
    10921329        /*
    10931330         * Second, prepare the new address space.
     
    10991336                        new_as->asid = asid_get();
    11001337        }
     1338       
    11011339#ifdef AS_PAGE_TABLE
    11021340        SET_PTL0_ADDRESS(new_as->genarch.page_table);
     
    11081346         */
    11091347        as_install_arch(new_as);
    1110 
     1348       
    11111349        spinlock_unlock(&asidlock);
    11121350       
     
    11141352}
    11151353
    1116 /** Convert address space area flags to page flags.
    1117  *
    1118  * @param aflags        Flags of some address space area.
    1119  *
    1120  * @return              Flags to be passed to page_mapping_insert().
    1121  */
    1122 int area_flags_to_page_flags(int aflags)
    1123 {
    1124         int flags;
    1125 
    1126         flags = PAGE_USER | PAGE_PRESENT;
    1127        
    1128         if (aflags & AS_AREA_READ)
    1129                 flags |= PAGE_READ;
    1130                
    1131         if (aflags & AS_AREA_WRITE)
    1132                 flags |= PAGE_WRITE;
    1133        
    1134         if (aflags & AS_AREA_EXEC)
    1135                 flags |= PAGE_EXEC;
    1136        
    1137         if (aflags & AS_AREA_CACHEABLE)
    1138                 flags |= PAGE_CACHEABLE;
    1139                
    1140         return flags;
    1141 }
    1142 
    11431354/** Compute flags for virtual address translation subsytem.
    11441355 *
    1145  * The address space area must be locked.
    1146  * Interrupts must be disabled.
    1147  *
    1148  * @param a             Address space area.
    1149  *
    1150  * @return              Flags to be used in page_mapping_insert().
    1151  */
    1152 int as_area_get_flags(as_area_t *a)
    1153 {
    1154         return area_flags_to_page_flags(a->flags);
     1356 * @param area Address space area.
     1357 *
     1358 * @return Flags to be used in page_mapping_insert().
     1359 *
     1360 */
     1361NO_TRACE unsigned int as_area_get_flags(as_area_t *area)
     1362{
     1363        ASSERT(mutex_locked(&area->lock));
     1364       
     1365        return area_flags_to_page_flags(area->flags);
    11551366}
    11561367
     
    11601371 * table.
    11611372 *
    1162  * @param flags         Flags saying whether the page table is for the kernel
    1163  *                      address space.
    1164  *
    1165  * @return              First entry of the page table.
    1166  */
    1167 pte_t *page_table_create(int flags)
     1373 * @param flags Flags saying whether the page table is for the kernel
     1374 *              address space.
     1375 *
     1376 * @return First entry of the page table.
     1377 *
     1378 */
     1379NO_TRACE pte_t *page_table_create(unsigned int flags)
    11681380{
    11691381        ASSERT(as_operations);
     
    11771389 * Destroy page table in architecture specific way.
    11781390 *
    1179  * @param page_table    Physical address of PTL0.
    1180  */
    1181 void page_table_destroy(pte_t *page_table)
     1391 * @param page_table Physical address of PTL0.
     1392 *
     1393 */
     1394NO_TRACE void page_table_destroy(pte_t *page_table)
    11821395{
    11831396        ASSERT(as_operations);
     
    11911404 * This function should be called before any page_mapping_insert(),
    11921405 * page_mapping_remove() and page_mapping_find().
    1193  * 
     1406 *
    11941407 * Locking order is such that address space areas must be locked
    11951408 * prior to this call. Address space can be locked prior to this
    11961409 * call in which case the lock argument is false.
    11971410 *
    1198  * @param as            Address space.
    1199  * @param lock          If false, do not attempt to lock as->lock.
    1200  */
    1201 void page_table_lock(as_t *as, bool lock)
     1411 * @param as   Address space.
     1412 * @param lock If false, do not attempt to lock as->lock.
     1413 *
     1414 */
     1415NO_TRACE void page_table_lock(as_t *as, bool lock)
    12021416{
    12031417        ASSERT(as_operations);
     
    12091423/** Unlock page table.
    12101424 *
    1211  * @param as            Address space.
    1212  * @param unlock        If false, do not attempt to unlock as->lock.
    1213  */
    1214 void page_table_unlock(as_t *as, bool unlock)
     1425 * @param as     Address space.
     1426 * @param unlock If false, do not attempt to unlock as->lock.
     1427 *
     1428 */
     1429NO_TRACE void page_table_unlock(as_t *as, bool unlock)
    12151430{
    12161431        ASSERT(as_operations);
     
    12201435}
    12211436
    1222 
    1223 /** Find address space area and lock it.
    1224  *
    1225  * The address space must be locked and interrupts must be disabled.
    1226  *
    1227  * @param as            Address space.
    1228  * @param va            Virtual address.
    1229  *
    1230  * @return              Locked address space area containing va on success or
    1231  *                      NULL on failure.
    1232  */
    1233 as_area_t *find_area_and_lock(as_t *as, uintptr_t va)
    1234 {
    1235         as_area_t *a;
    1236         btree_node_t *leaf, *lnode;
    1237         unsigned int i;
    1238        
    1239         a = (as_area_t *) btree_search(&as->as_area_btree, va, &leaf);
    1240         if (a) {
    1241                 /* va is the base address of an address space area */
    1242                 mutex_lock(&a->lock);
    1243                 return a;
    1244         }
    1245        
    1246         /*
    1247          * Search the leaf node and the righmost record of its left neighbour
    1248          * to find out whether this is a miss or va belongs to an address
    1249          * space area found there.
    1250          */
    1251        
    1252         /* First, search the leaf node itself. */
    1253         for (i = 0; i < leaf->keys; i++) {
    1254                 a = (as_area_t *) leaf->value[i];
    1255                 mutex_lock(&a->lock);
    1256                 if ((a->base <= va) && (va < a->base + a->pages * PAGE_SIZE)) {
    1257                         return a;
    1258                 }
    1259                 mutex_unlock(&a->lock);
    1260         }
    1261 
    1262         /*
    1263          * Second, locate the left neighbour and test its last record.
    1264          * Because of its position in the B+tree, it must have base < va.
    1265          */
    1266         lnode = btree_leaf_node_left_neighbour(&as->as_area_btree, leaf);
    1267         if (lnode) {
    1268                 a = (as_area_t *) lnode->value[lnode->keys - 1];
    1269                 mutex_lock(&a->lock);
    1270                 if (va < a->base + a->pages * PAGE_SIZE) {
    1271                         return a;
    1272                 }
    1273                 mutex_unlock(&a->lock);
    1274         }
    1275 
    1276         return NULL;
    1277 }
    1278 
    1279 /** Check area conflicts with other areas.
    1280  *
    1281  * The address space must be locked and interrupts must be disabled.
    1282  *
    1283  * @param as            Address space.
    1284  * @param va            Starting virtual address of the area being tested.
    1285  * @param size          Size of the area being tested.
    1286  * @param avoid_area    Do not touch this area.
    1287  *
    1288  * @return              True if there is no conflict, false otherwise.
    1289  */
    1290 bool
    1291 check_area_conflicts(as_t *as, uintptr_t va, size_t size, as_area_t *avoid_area)
    1292 {
    1293         as_area_t *a;
    1294         btree_node_t *leaf, *node;
    1295         unsigned int i;
    1296        
    1297         /*
    1298          * We don't want any area to have conflicts with NULL page.
    1299          */
    1300         if (overlaps(va, size, NULL, PAGE_SIZE))
    1301                 return false;
    1302        
    1303         /*
    1304          * The leaf node is found in O(log n), where n is proportional to
    1305          * the number of address space areas belonging to as.
    1306          * The check for conflicts is then attempted on the rightmost
    1307          * record in the left neighbour, the leftmost record in the right
    1308          * neighbour and all records in the leaf node itself.
    1309          */
    1310        
    1311         if ((a = (as_area_t *) btree_search(&as->as_area_btree, va, &leaf))) {
    1312                 if (a != avoid_area)
    1313                         return false;
    1314         }
    1315        
    1316         /* First, check the two border cases. */
    1317         if ((node = btree_leaf_node_left_neighbour(&as->as_area_btree, leaf))) {
    1318                 a = (as_area_t *) node->value[node->keys - 1];
    1319                 mutex_lock(&a->lock);
    1320                 if (overlaps(va, size, a->base, a->pages * PAGE_SIZE)) {
    1321                         mutex_unlock(&a->lock);
    1322                         return false;
    1323                 }
    1324                 mutex_unlock(&a->lock);
    1325         }
    1326         node = btree_leaf_node_right_neighbour(&as->as_area_btree, leaf);
    1327         if (node) {
    1328                 a = (as_area_t *) node->value[0];
    1329                 mutex_lock(&a->lock);
    1330                 if (overlaps(va, size, a->base, a->pages * PAGE_SIZE)) {
    1331                         mutex_unlock(&a->lock);
    1332                         return false;
    1333                 }
    1334                 mutex_unlock(&a->lock);
    1335         }
    1336        
    1337         /* Second, check the leaf node. */
    1338         for (i = 0; i < leaf->keys; i++) {
    1339                 a = (as_area_t *) leaf->value[i];
    1340        
    1341                 if (a == avoid_area)
    1342                         continue;
    1343        
    1344                 mutex_lock(&a->lock);
    1345                 if (overlaps(va, size, a->base, a->pages * PAGE_SIZE)) {
    1346                         mutex_unlock(&a->lock);
    1347                         return false;
    1348                 }
    1349                 mutex_unlock(&a->lock);
    1350         }
    1351 
    1352         /*
    1353          * So far, the area does not conflict with other areas.
    1354          * Check if it doesn't conflict with kernel address space.
    1355          */     
    1356         if (!KERNEL_ADDRESS_SPACE_SHADOWED) {
    1357                 return !overlaps(va, size,
    1358                     KERNEL_ADDRESS_SPACE_START,
    1359                     KERNEL_ADDRESS_SPACE_END - KERNEL_ADDRESS_SPACE_START);
    1360         }
    1361 
    1362         return true;
     1437/** Test whether page tables are locked.
     1438 *
     1439 * @param as Address space where the page tables belong.
     1440 *
     1441 * @return True if the page tables belonging to the address soace
     1442 *         are locked, otherwise false.
     1443 */
     1444NO_TRACE bool page_table_locked(as_t *as)
     1445{
     1446        ASSERT(as_operations);
     1447        ASSERT(as_operations->page_table_locked);
     1448
     1449        return as_operations->page_table_locked(as);
    13631450}
    13641451
    13651452/** Return size of the address space area with given base.
    13661453 *
    1367  * @param base          Arbitrary address insede the address space area.
    1368  *
    1369  * @return              Size of the address space area in bytes or zero if it
    1370  *                      does not exist.
     1454 * @param base Arbitrary address inside the address space area.
     1455 *
     1456 * @return Size of the address space area in bytes or zero if it
     1457 *         does not exist.
     1458 *
    13711459 */
    13721460size_t as_area_get_size(uintptr_t base)
    13731461{
    1374         ipl_t ipl;
    1375         as_area_t *src_area;
    13761462        size_t size;
    1377 
    1378         ipl = interrupts_disable();
    1379         src_area = find_area_and_lock(AS, base);
     1463       
     1464        page_table_lock(AS, true);
     1465        as_area_t *src_area = find_area_and_lock(AS, base);
     1466       
    13801467        if (src_area) {
    1381                 size = src_area->pages * PAGE_SIZE;
     1468                size = src_area->pages << PAGE_WIDTH;
    13821469                mutex_unlock(&src_area->lock);
    1383         } else {
     1470        } else
    13841471                size = 0;
    1385         }
    1386         interrupts_restore(ipl);
     1472       
     1473        page_table_unlock(AS, true);
    13871474        return size;
    13881475}
     
    13921479 * The address space area must be already locked.
    13931480 *
    1394  * @param a             Address space area.
    1395  * @param page          First page to be marked.
    1396  * @param count         Number of page to be marked.
    1397  *
    1398  * @return              Zero on failure and non-zero on success.
    1399  */
    1400 int used_space_insert(as_area_t *a, uintptr_t page, size_t count)
    1401 {
    1402         btree_node_t *leaf, *node;
    1403         size_t pages;
    1404         unsigned int i;
    1405 
     1481 * @param area  Address space area.
     1482 * @param page  First page to be marked.
     1483 * @param count Number of page to be marked.
     1484 *
     1485 * @return False on failure or true on success.
     1486 *
     1487 */
     1488bool used_space_insert(as_area_t *area, uintptr_t page, size_t count)
     1489{
     1490        ASSERT(mutex_locked(&area->lock));
    14061491        ASSERT(page == ALIGN_DOWN(page, PAGE_SIZE));
    14071492        ASSERT(count);
    1408 
    1409         pages = (size_t) btree_search(&a->used_space, page, &leaf);
     1493       
     1494        btree_node_t *leaf;
     1495        size_t pages = (size_t) btree_search(&area->used_space, page, &leaf);
    14101496        if (pages) {
    14111497                /*
    14121498                 * We hit the beginning of some used space.
    14131499                 */
    1414                 return 0;
    1415         }
    1416 
     1500                return false;
     1501        }
     1502       
    14171503        if (!leaf->keys) {
    1418                 btree_insert(&a->used_space, page, (void *) count, leaf);
    1419                 return 1;
    1420         }
    1421 
    1422         node = btree_leaf_node_left_neighbour(&a->used_space, leaf);
     1504                btree_insert(&area->used_space, page, (void *) count, leaf);
     1505                goto success;
     1506        }
     1507       
     1508        btree_node_t *node = btree_leaf_node_left_neighbour(&area->used_space, leaf);
    14231509        if (node) {
    14241510                uintptr_t left_pg = node->key[node->keys - 1];
     
    14321518                 * the left neigbour and the first interval of the leaf.
    14331519                 */
    1434                  
     1520               
    14351521                if (page >= right_pg) {
    14361522                        /* Do nothing. */
    1437                 } else if (overlaps(page, count * PAGE_SIZE, left_pg,
    1438                     left_cnt * PAGE_SIZE)) {
     1523                } else if (overlaps(page, count << PAGE_WIDTH, left_pg,
     1524                    left_cnt << PAGE_WIDTH)) {
    14391525                        /* The interval intersects with the left interval. */
    1440                         return 0;
    1441                 } else if (overlaps(page, count * PAGE_SIZE, right_pg,
    1442                     right_cnt * PAGE_SIZE)) {
     1526                        return false;
     1527                } else if (overlaps(page, count << PAGE_WIDTH, right_pg,
     1528                    right_cnt << PAGE_WIDTH)) {
    14431529                        /* The interval intersects with the right interval. */
    1444                         return 0;                       
    1445                 } else if ((page == left_pg + left_cnt * PAGE_SIZE) &&
    1446                     (page + count * PAGE_SIZE == right_pg)) {
     1530                        return false;
     1531                } else if ((page == left_pg + (left_cnt << PAGE_WIDTH)) &&
     1532                    (page + (count << PAGE_WIDTH) == right_pg)) {
    14471533                        /*
    14481534                         * The interval can be added by merging the two already
     
    14501536                         */
    14511537                        node->value[node->keys - 1] += count + right_cnt;
    1452                         btree_remove(&a->used_space, right_pg, leaf);
    1453                         return 1;
    1454                 } else if (page == left_pg + left_cnt * PAGE_SIZE) {
    1455                         /* 
     1538                        btree_remove(&area->used_space, right_pg, leaf);
     1539                        goto success;
     1540                } else if (page == left_pg + (left_cnt << PAGE_WIDTH)) {
     1541                        /*
    14561542                         * The interval can be added by simply growing the left
    14571543                         * interval.
    14581544                         */
    14591545                        node->value[node->keys - 1] += count;
    1460                         return 1;
    1461                 } else if (page + count * PAGE_SIZE == right_pg) {
     1546                        goto success;
     1547                } else if (page + (count << PAGE_WIDTH) == right_pg) {
    14621548                        /*
    14631549                         * The interval can be addded by simply moving base of
     
    14671553                        leaf->value[0] += count;
    14681554                        leaf->key[0] = page;
    1469                         return 1;
     1555                        goto success;
    14701556                } else {
    14711557                        /*
     
    14731559                         * but cannot be merged with any of them.
    14741560                         */
    1475                         btree_insert(&a->used_space, page, (void *) count,
     1561                        btree_insert(&area->used_space, page, (void *) count,
    14761562                            leaf);
    1477                         return 1;
     1563                        goto success;
    14781564                }
    14791565        } else if (page < leaf->key[0]) {
    14801566                uintptr_t right_pg = leaf->key[0];
    14811567                size_t right_cnt = (size_t) leaf->value[0];
    1482        
     1568               
    14831569                /*
    14841570                 * Investigate the border case in which the left neighbour does
    14851571                 * not exist but the interval fits from the left.
    14861572                 */
    1487                  
    1488                 if (overlaps(page, count * PAGE_SIZE, right_pg,
    1489                     right_cnt * PAGE_SIZE)) {
     1573               
     1574                if (overlaps(page, count << PAGE_WIDTH, right_pg,
     1575                    right_cnt << PAGE_WIDTH)) {
    14901576                        /* The interval intersects with the right interval. */
    1491                         return 0;
    1492                 } else if (page + count * PAGE_SIZE == right_pg) {
     1577                        return false;
     1578                } else if (page + (count << PAGE_WIDTH) == right_pg) {
    14931579                        /*
    14941580                         * The interval can be added by moving the base of the
     
    14981584                        leaf->key[0] = page;
    14991585                        leaf->value[0] += count;
    1500                         return 1;
     1586                        goto success;
    15011587                } else {
    15021588                        /*
     
    15041590                         * It must be added individually.
    15051591                         */
    1506                         btree_insert(&a->used_space, page, (void *) count,
     1592                        btree_insert(&area->used_space, page, (void *) count,
    15071593                            leaf);
    1508                         return 1;
    1509                 }
    1510         }
    1511 
    1512         node = btree_leaf_node_right_neighbour(&a->used_space, leaf);
     1594                        goto success;
     1595                }
     1596        }
     1597       
     1598        node = btree_leaf_node_right_neighbour(&area->used_space, leaf);
    15131599        if (node) {
    15141600                uintptr_t left_pg = leaf->key[leaf->keys - 1];
     
    15221608                 * the right neigbour and the last interval of the leaf.
    15231609                 */
    1524 
     1610               
    15251611                if (page < left_pg) {
    15261612                        /* Do nothing. */
    1527                 } else if (overlaps(page, count * PAGE_SIZE, left_pg,
    1528                     left_cnt * PAGE_SIZE)) {
     1613                } else if (overlaps(page, count << PAGE_WIDTH, left_pg,
     1614                    left_cnt << PAGE_WIDTH)) {
    15291615                        /* The interval intersects with the left interval. */
    1530                         return 0;
    1531                 } else if (overlaps(page, count * PAGE_SIZE, right_pg,
    1532                     right_cnt * PAGE_SIZE)) {
     1616                        return false;
     1617                } else if (overlaps(page, count << PAGE_WIDTH, right_pg,
     1618                    right_cnt << PAGE_WIDTH)) {
    15331619                        /* The interval intersects with the right interval. */
    1534                         return 0;                       
    1535                 } else if ((page == left_pg + left_cnt * PAGE_SIZE) &&
    1536                     (page + count * PAGE_SIZE == right_pg)) {
     1620                        return false;
     1621                } else if ((page == left_pg + (left_cnt << PAGE_WIDTH)) &&
     1622                    (page + (count << PAGE_WIDTH) == right_pg)) {
    15371623                        /*
    15381624                         * The interval can be added by merging the two already
    15391625                         * present intervals.
    1540                          * */
     1626                         */
    15411627                        leaf->value[leaf->keys - 1] += count + right_cnt;
    1542                         btree_remove(&a->used_space, right_pg, node);
    1543                         return 1;
    1544                 } else if (page == left_pg + left_cnt * PAGE_SIZE) {
     1628                        btree_remove(&area->used_space, right_pg, node);
     1629                        goto success;
     1630                } else if (page == left_pg + (left_cnt << PAGE_WIDTH)) {
    15451631                        /*
    15461632                         * The interval can be added by simply growing the left
    15471633                         * interval.
    1548                          * */
    1549                         leaf->value[leaf->keys - 1] +=  count;
    1550                         return 1;
    1551                 } else if (page + count * PAGE_SIZE == right_pg) {
     1634                         */
     1635                        leaf->value[leaf->keys - 1] += count;
     1636                        goto success;
     1637                } else if (page + (count << PAGE_WIDTH) == right_pg) {
    15521638                        /*
    15531639                         * The interval can be addded by simply moving base of
     
    15571643                        node->value[0] += count;
    15581644                        node->key[0] = page;
    1559                         return 1;
     1645                        goto success;
    15601646                } else {
    15611647                        /*
     
    15631649                         * but cannot be merged with any of them.
    15641650                         */
    1565                         btree_insert(&a->used_space, page, (void *) count,
     1651                        btree_insert(&area->used_space, page, (void *) count,
    15661652                            leaf);
    1567                         return 1;
     1653                        goto success;
    15681654                }
    15691655        } else if (page >= leaf->key[leaf->keys - 1]) {
    15701656                uintptr_t left_pg = leaf->key[leaf->keys - 1];
    15711657                size_t left_cnt = (size_t) leaf->value[leaf->keys - 1];
    1572        
     1658               
    15731659                /*
    15741660                 * Investigate the border case in which the right neighbour
    15751661                 * does not exist but the interval fits from the right.
    15761662                 */
    1577                  
    1578                 if (overlaps(page, count * PAGE_SIZE, left_pg,
    1579                     left_cnt * PAGE_SIZE)) {
     1663               
     1664                if (overlaps(page, count << PAGE_WIDTH, left_pg,
     1665                    left_cnt << PAGE_WIDTH)) {
    15801666                        /* The interval intersects with the left interval. */
    1581                         return 0;
    1582                 } else if (left_pg + left_cnt * PAGE_SIZE == page) {
     1667                        return false;
     1668                } else if (left_pg + (left_cnt << PAGE_WIDTH) == page) {
    15831669                        /*
    15841670                         * The interval can be added by growing the left
     
    15861672                         */
    15871673                        leaf->value[leaf->keys - 1] += count;
    1588                         return 1;
     1674                        goto success;
    15891675                } else {
    15901676                        /*
     
    15921678                         * It must be added individually.
    15931679                         */
    1594                         btree_insert(&a->used_space, page, (void *) count,
     1680                        btree_insert(&area->used_space, page, (void *) count,
    15951681                            leaf);
    1596                         return 1;
     1682                        goto success;
    15971683                }
    15981684        }
     
    16031689         * were already resolved.
    16041690         */
     1691        btree_key_t i;
    16051692        for (i = 1; i < leaf->keys; i++) {
    16061693                if (page < leaf->key[i]) {
     
    16091696                        size_t left_cnt = (size_t) leaf->value[i - 1];
    16101697                        size_t right_cnt = (size_t) leaf->value[i];
    1611 
     1698                       
    16121699                        /*
    16131700                         * The interval fits between left_pg and right_pg.
    16141701                         */
    1615 
    1616                         if (overlaps(page, count * PAGE_SIZE, left_pg,
    1617                             left_cnt * PAGE_SIZE)) {
     1702                       
     1703                        if (overlaps(page, count << PAGE_WIDTH, left_pg,
     1704                            left_cnt << PAGE_WIDTH)) {
    16181705                                /*
    16191706                                 * The interval intersects with the left
    16201707                                 * interval.
    16211708                                 */
    1622                                 return 0;
    1623                         } else if (overlaps(page, count * PAGE_SIZE, right_pg,
    1624                             right_cnt * PAGE_SIZE)) {
     1709                                return false;
     1710                        } else if (overlaps(page, count << PAGE_WIDTH, right_pg,
     1711                            right_cnt << PAGE_WIDTH)) {
    16251712                                /*
    16261713                                 * The interval intersects with the right
    16271714                                 * interval.
    16281715                                 */
    1629                                 return 0;                       
    1630                         } else if ((page == left_pg + left_cnt * PAGE_SIZE) &&
    1631                             (page + count * PAGE_SIZE == right_pg)) {
     1716                                return false;
     1717                        } else if ((page == left_pg + (left_cnt << PAGE_WIDTH)) &&
     1718                            (page + (count << PAGE_WIDTH) == right_pg)) {
    16321719                                /*
    16331720                                 * The interval can be added by merging the two
     
    16351722                                 */
    16361723                                leaf->value[i - 1] += count + right_cnt;
    1637                                 btree_remove(&a->used_space, right_pg, leaf);
    1638                                 return 1;
    1639                         } else if (page == left_pg + left_cnt * PAGE_SIZE) {
     1724                                btree_remove(&area->used_space, right_pg, leaf);
     1725                                goto success;
     1726                        } else if (page == left_pg + (left_cnt << PAGE_WIDTH)) {
    16401727                                /*
    16411728                                 * The interval can be added by simply growing
     
    16431730                                 */
    16441731                                leaf->value[i - 1] += count;
    1645                                 return 1;
    1646                         } else if (page + count * PAGE_SIZE == right_pg) {
     1732                                goto success;
     1733                        } else if (page + (count << PAGE_WIDTH) == right_pg) {
    16471734                                /*
    1648                                 * The interval can be addded by simply moving
     1735                                * The interval can be addded by simply moving
    16491736                                 * base of the right interval down and
    16501737                                 * increasing its size accordingly.
    1651                                  */
     1738                                 */
    16521739                                leaf->value[i] += count;
    16531740                                leaf->key[i] = page;
    1654                                 return 1;
     1741                                goto success;
    16551742                        } else {
    16561743                                /*
     
    16591746                                 * them.
    16601747                                 */
    1661                                 btree_insert(&a->used_space, page,
     1748                                btree_insert(&area->used_space, page,
    16621749                                    (void *) count, leaf);
    1663                                 return 1;
     1750                                goto success;
    16641751                        }
    16651752                }
    16661753        }
    1667 
    1668         panic("Inconsistency detected while adding %" PRIs " pages of used "
    1669             "space at %p.", count, page);
     1754       
     1755        panic("Inconsistency detected while adding %zu pages of used "
     1756            "space at %p.", count, (void *) page);
     1757       
     1758success:
     1759        area->resident += count;
     1760        return true;
    16701761}
    16711762
     
    16741765 * The address space area must be already locked.
    16751766 *
    1676  * @param a             Address space area.
    1677  * @param page          First page to be marked.
    1678  * @param count         Number of page to be marked.
    1679  *
    1680  * @return              Zero on failure and non-zero on success.
    1681  */
    1682 int used_space_remove(as_area_t *a, uintptr_t page, size_t count)
    1683 {
    1684         btree_node_t *leaf, *node;
    1685         size_t pages;
    1686         unsigned int i;
    1687 
     1767 * @param area  Address space area.
     1768 * @param page  First page to be marked.
     1769 * @param count Number of page to be marked.
     1770 *
     1771 * @return False on failure or true on success.
     1772 *
     1773 */
     1774bool used_space_remove(as_area_t *area, uintptr_t page, size_t count)
     1775{
     1776        ASSERT(mutex_locked(&area->lock));
    16881777        ASSERT(page == ALIGN_DOWN(page, PAGE_SIZE));
    16891778        ASSERT(count);
    1690 
    1691         pages = (size_t) btree_search(&a->used_space, page, &leaf);
     1779       
     1780        btree_node_t *leaf;
     1781        size_t pages = (size_t) btree_search(&area->used_space, page, &leaf);
    16921782        if (pages) {
    16931783                /*
     
    16951785                 */
    16961786                if (count > pages) {
    1697                         return 0;
     1787                        return false;
    16981788                } else if (count == pages) {
    1699                         btree_remove(&a->used_space, page, leaf);
    1700                         return 1;
     1789                        btree_remove(&area->used_space, page, leaf);
     1790                        goto success;
    17011791                } else {
    17021792                        /*
     
    17041794                         * Decrease its size and relocate its start address.
    17051795                         */
     1796                        btree_key_t i;
    17061797                        for (i = 0; i < leaf->keys; i++) {
    17071798                                if (leaf->key[i] == page) {
    1708                                         leaf->key[i] += count * PAGE_SIZE;
     1799                                        leaf->key[i] += count << PAGE_WIDTH;
    17091800                                        leaf->value[i] -= count;
    1710                                         return 1;
     1801                                        goto success;
    17111802                                }
    17121803                        }
     1804                       
    17131805                        goto error;
    17141806                }
    17151807        }
    1716 
    1717         node = btree_leaf_node_left_neighbour(&a->used_space, leaf);
    1718         if (node && page < leaf->key[0]) {
     1808       
     1809        btree_node_t *node = btree_leaf_node_left_neighbour(&area->used_space, leaf);
     1810        if ((node) && (page < leaf->key[0])) {
    17191811                uintptr_t left_pg = node->key[node->keys - 1];
    17201812                size_t left_cnt = (size_t) node->value[node->keys - 1];
    1721 
    1722                 if (overlaps(left_pg, left_cnt * PAGE_SIZE, page,
    1723                     count * PAGE_SIZE)) {
    1724                         if (page + count * PAGE_SIZE ==
    1725                             left_pg + left_cnt * PAGE_SIZE) {
     1813               
     1814                if (overlaps(left_pg, left_cnt << PAGE_WIDTH, page,
     1815                    count << PAGE_WIDTH)) {
     1816                        if (page + (count << PAGE_WIDTH) ==
     1817                            left_pg + (left_cnt << PAGE_WIDTH)) {
    17261818                                /*
    17271819                                 * The interval is contained in the rightmost
     
    17311823                                 */
    17321824                                node->value[node->keys - 1] -= count;
    1733                                 return 1;
    1734                         } else if (page + count * PAGE_SIZE <
    1735                             left_pg + left_cnt*PAGE_SIZE) {
    1736                                 size_t new_cnt;
    1737                                
     1825                                goto success;
     1826                        } else if (page + (count << PAGE_WIDTH) <
     1827                            left_pg + (left_cnt << PAGE_WIDTH)) {
    17381828                                /*
    17391829                                 * The interval is contained in the rightmost
     
    17431833                                 * new interval.
    17441834                                 */
    1745                                 new_cnt = ((left_pg + left_cnt * PAGE_SIZE) -
    1746                                     (page + count*PAGE_SIZE)) >> PAGE_WIDTH;
     1835                                size_t new_cnt = ((left_pg + (left_cnt << PAGE_WIDTH)) -
     1836                                    (page + (count << PAGE_WIDTH))) >> PAGE_WIDTH;
    17471837                                node->value[node->keys - 1] -= count + new_cnt;
    1748                                 btree_insert(&a->used_space, page +
    1749                                     count * PAGE_SIZE, (void *) new_cnt, leaf);
    1750                                 return 1;
     1838                                btree_insert(&area->used_space, page +
     1839                                    (count << PAGE_WIDTH), (void *) new_cnt, leaf);
     1840                                goto success;
    17511841                        }
    17521842                }
    1753                 return 0;
    1754         } else if (page < leaf->key[0]) {
    1755                 return 0;
    1756         }
     1843               
     1844                return false;
     1845        } else if (page < leaf->key[0])
     1846                return false;
    17571847       
    17581848        if (page > leaf->key[leaf->keys - 1]) {
    17591849                uintptr_t left_pg = leaf->key[leaf->keys - 1];
    17601850                size_t left_cnt = (size_t) leaf->value[leaf->keys - 1];
    1761 
    1762                 if (overlaps(left_pg, left_cnt * PAGE_SIZE, page,
    1763                     count * PAGE_SIZE)) {
    1764                         if (page + count * PAGE_SIZE ==
    1765                             left_pg + left_cnt * PAGE_SIZE) {
     1851               
     1852                if (overlaps(left_pg, left_cnt << PAGE_WIDTH, page,
     1853                    count << PAGE_WIDTH)) {
     1854                        if (page + (count << PAGE_WIDTH) ==
     1855                            left_pg + (left_cnt << PAGE_WIDTH)) {
    17661856                                /*
    17671857                                 * The interval is contained in the rightmost
     
    17701860                                 */
    17711861                                leaf->value[leaf->keys - 1] -= count;
    1772                                 return 1;
    1773                         } else if (page + count * PAGE_SIZE < left_pg +
    1774                             left_cnt * PAGE_SIZE) {
    1775                                 size_t new_cnt;
    1776                                
     1862                                goto success;
     1863                        } else if (page + (count << PAGE_WIDTH) < left_pg +
     1864                            (left_cnt << PAGE_WIDTH)) {
    17771865                                /*
    17781866                                 * The interval is contained in the rightmost
     
    17821870                                 * interval.
    17831871                                 */
    1784                                 new_cnt = ((left_pg + left_cnt * PAGE_SIZE) -
    1785                                     (page + count * PAGE_SIZE)) >> PAGE_WIDTH;
     1872                                size_t new_cnt = ((left_pg + (left_cnt << PAGE_WIDTH)) -
     1873                                    (page + (count << PAGE_WIDTH))) >> PAGE_WIDTH;
    17861874                                leaf->value[leaf->keys - 1] -= count + new_cnt;
    1787                                 btree_insert(&a->used_space, page +
    1788                                     count * PAGE_SIZE, (void *) new_cnt, leaf);
    1789                                 return 1;
     1875                                btree_insert(&area->used_space, page +
     1876                                    (count << PAGE_WIDTH), (void *) new_cnt, leaf);
     1877                                goto success;
    17901878                        }
    17911879                }
    1792                 return 0;
    1793         }       
     1880               
     1881                return false;
     1882        }
    17941883       
    17951884        /*
    17961885         * The border cases have been already resolved.
    1797          * Now the interval can be only between intervals of the leaf.
    1798          */
     1886         * Now the interval can be only between intervals of the leaf.
     1887         */
     1888        btree_key_t i;
    17991889        for (i = 1; i < leaf->keys - 1; i++) {
    18001890                if (page < leaf->key[i]) {
    18011891                        uintptr_t left_pg = leaf->key[i - 1];
    18021892                        size_t left_cnt = (size_t) leaf->value[i - 1];
    1803 
     1893                       
    18041894                        /*
    18051895                         * Now the interval is between intervals corresponding
    18061896                         * to (i - 1) and i.
    18071897                         */
    1808                         if (overlaps(left_pg, left_cnt * PAGE_SIZE, page,
    1809                             count * PAGE_SIZE)) {
    1810                                 if (page + count * PAGE_SIZE ==
    1811                                     left_pg + left_cnt*PAGE_SIZE) {
     1898                        if (overlaps(left_pg, left_cnt << PAGE_WIDTH, page,
     1899                            count << PAGE_WIDTH)) {
     1900                                if (page + (count << PAGE_WIDTH) ==
     1901                                    left_pg + (left_cnt << PAGE_WIDTH)) {
    18121902                                        /*
    18131903                                         * The interval is contained in the
     
    18171907                                         */
    18181908                                        leaf->value[i - 1] -= count;
    1819                                         return 1;
    1820                                 } else if (page + count * PAGE_SIZE <
    1821                                     left_pg + left_cnt * PAGE_SIZE) {
    1822                                         size_t new_cnt;
    1823                                
     1909                                        goto success;
     1910                                } else if (page + (count << PAGE_WIDTH) <
     1911                                    left_pg + (left_cnt << PAGE_WIDTH)) {
    18241912                                        /*
    18251913                                         * The interval is contained in the
     
    18291917                                         * also inserting a new interval.
    18301918                                         */
    1831                                         new_cnt = ((left_pg +
    1832                                             left_cnt * PAGE_SIZE) -
    1833                                             (page + count * PAGE_SIZE)) >>
     1919                                        size_t new_cnt = ((left_pg +
     1920                                            (left_cnt << PAGE_WIDTH)) -
     1921                                            (page + (count << PAGE_WIDTH))) >>
    18341922                                            PAGE_WIDTH;
    18351923                                        leaf->value[i - 1] -= count + new_cnt;
    1836                                         btree_insert(&a->used_space, page +
    1837                                             count * PAGE_SIZE, (void *) new_cnt,
     1924                                        btree_insert(&area->used_space, page +
     1925                                            (count << PAGE_WIDTH), (void *) new_cnt,
    18381926                                            leaf);
    1839                                         return 1;
     1927                                        goto success;
    18401928                                }
    18411929                        }
    1842                         return 0;
    1843                 }
    1844         }
    1845 
     1930                       
     1931                        return false;
     1932                }
     1933        }
     1934       
    18461935error:
    1847         panic("Inconsistency detected while removing %" PRIs " pages of used "
    1848             "space from %p.", count, page);
    1849 }
    1850 
    1851 /** Remove reference to address space area share info.
    1852  *
    1853  * If the reference count drops to 0, the sh_info is deallocated.
    1854  *
    1855  * @param sh_info       Pointer to address space area share info.
    1856  */
    1857 void sh_info_remove_reference(share_info_t *sh_info)
    1858 {
    1859         bool dealloc = false;
    1860 
    1861         mutex_lock(&sh_info->lock);
    1862         ASSERT(sh_info->refcount);
    1863         if (--sh_info->refcount == 0) {
    1864                 dealloc = true;
    1865                 link_t *cur;
    1866                
    1867                 /*
    1868                  * Now walk carefully the pagemap B+tree and free/remove
    1869                  * reference from all frames found there.
    1870                  */
    1871                 for (cur = sh_info->pagemap.leaf_head.next;
    1872                     cur != &sh_info->pagemap.leaf_head; cur = cur->next) {
    1873                         btree_node_t *node;
    1874                         unsigned int i;
    1875                        
    1876                         node = list_get_instance(cur, btree_node_t, leaf_link);
    1877                         for (i = 0; i < node->keys; i++)
    1878                                 frame_free((uintptr_t) node->value[i]);
    1879                 }
    1880                
    1881         }
    1882         mutex_unlock(&sh_info->lock);
    1883        
    1884         if (dealloc) {
    1885                 btree_destroy(&sh_info->pagemap);
    1886                 free(sh_info);
    1887         }
     1936        panic("Inconsistency detected while removing %zu pages of used "
     1937            "space from %p.", count, (void *) page);
     1938       
     1939success:
     1940        area->resident -= count;
     1941        return true;
    18881942}
    18891943
     
    18931947
    18941948/** Wrapper for as_area_create(). */
    1895 unative_t sys_as_area_create(uintptr_t address, size_t size, int flags)
     1949sysarg_t sys_as_area_create(uintptr_t address, size_t size, unsigned int flags)
    18961950{
    18971951        if (as_area_create(AS, flags | AS_AREA_CACHEABLE, size, address,
    18981952            AS_AREA_ATTR_NONE, &anon_backend, NULL))
    1899                 return (unative_t) address;
     1953                return (sysarg_t) address;
    19001954        else
    1901                 return (unative_t) -1;
     1955                return (sysarg_t) -1;
    19021956}
    19031957
    19041958/** Wrapper for as_area_resize(). */
    1905 unative_t sys_as_area_resize(uintptr_t address, size_t size, int flags)
    1906 {
    1907         return (unative_t) as_area_resize(AS, address, size, 0);
     1959sysarg_t sys_as_area_resize(uintptr_t address, size_t size, unsigned int flags)
     1960{
     1961        return (sysarg_t) as_area_resize(AS, address, size, 0);
    19081962}
    19091963
    19101964/** Wrapper for as_area_change_flags(). */
    1911 unative_t sys_as_area_change_flags(uintptr_t address, int flags)
    1912 {
    1913         return (unative_t) as_area_change_flags(AS, flags, address);
     1965sysarg_t sys_as_area_change_flags(uintptr_t address, unsigned int flags)
     1966{
     1967        return (sysarg_t) as_area_change_flags(AS, flags, address);
    19141968}
    19151969
    19161970/** Wrapper for as_area_destroy(). */
    1917 unative_t sys_as_area_destroy(uintptr_t address)
    1918 {
    1919         return (unative_t) as_area_destroy(AS, address);
     1971sysarg_t sys_as_area_destroy(uintptr_t address)
     1972{
     1973        return (sysarg_t) as_area_destroy(AS, address);
     1974}
     1975
     1976/** Return pointer to unmapped address space area
     1977 *
     1978 * @param base Lowest address bound.
     1979 * @param size Requested size of the allocation.
     1980 *
     1981 * @return Pointer to the beginning of unmapped address space area.
     1982 *
     1983 */
     1984sysarg_t sys_as_get_unmapped_area(uintptr_t base, size_t size)
     1985{
     1986        if (size == 0)
     1987                return 0;
     1988       
     1989        /*
     1990         * Make sure we allocate from page-aligned
     1991         * address. Check for possible overflow in
     1992         * each step.
     1993         */
     1994       
     1995        size_t pages = SIZE2FRAMES(size);
     1996        uintptr_t ret = 0;
     1997       
     1998        /*
     1999         * Find the lowest unmapped address aligned on the sz
     2000         * boundary, not smaller than base and of the required size.
     2001         */
     2002       
     2003        mutex_lock(&AS->lock);
     2004       
     2005        /* First check the base address itself */
     2006        uintptr_t addr = ALIGN_UP(base, PAGE_SIZE);
     2007        if ((addr >= base) &&
     2008            (check_area_conflicts(AS, addr, pages, NULL)))
     2009                ret = addr;
     2010       
     2011        /* Eventually check the addresses behind each area */
     2012        link_t *cur;
     2013        for (cur = AS->as_area_btree.leaf_head.next;
     2014            (ret == 0) && (cur != &AS->as_area_btree.leaf_head);
     2015            cur = cur->next) {
     2016                btree_node_t *node =
     2017                    list_get_instance(cur, btree_node_t, leaf_link);
     2018               
     2019                btree_key_t i;
     2020                for (i = 0; (ret == 0) && (i < node->keys); i++) {
     2021                        as_area_t *area = (as_area_t *) node->value[i];
     2022                       
     2023                        mutex_lock(&area->lock);
     2024                       
     2025                        uintptr_t addr =
     2026                            ALIGN_UP(area->base + (area->pages << PAGE_WIDTH),
     2027                            PAGE_SIZE);
     2028                       
     2029                        if ((addr >= base) && (addr >= area->base) &&
     2030                            (check_area_conflicts(AS, addr, pages, area)))
     2031                                ret = addr;
     2032                       
     2033                        mutex_unlock(&area->lock);
     2034                }
     2035        }
     2036       
     2037        mutex_unlock(&AS->lock);
     2038       
     2039        return (sysarg_t) ret;
     2040}
     2041
     2042/** Get list of adress space areas.
     2043 *
     2044 * @param as    Address space.
     2045 * @param obuf  Place to save pointer to returned buffer.
     2046 * @param osize Place to save size of returned buffer.
     2047 *
     2048 */
     2049void as_get_area_info(as_t *as, as_area_info_t **obuf, size_t *osize)
     2050{
     2051        mutex_lock(&as->lock);
     2052       
     2053        /* First pass, count number of areas. */
     2054       
     2055        size_t area_cnt = 0;
     2056        link_t *cur;
     2057       
     2058        for (cur = as->as_area_btree.leaf_head.next;
     2059            cur != &as->as_area_btree.leaf_head; cur = cur->next) {
     2060                btree_node_t *node =
     2061                    list_get_instance(cur, btree_node_t, leaf_link);
     2062                area_cnt += node->keys;
     2063        }
     2064       
     2065        size_t isize = area_cnt * sizeof(as_area_info_t);
     2066        as_area_info_t *info = malloc(isize, 0);
     2067       
     2068        /* Second pass, record data. */
     2069       
     2070        size_t area_idx = 0;
     2071       
     2072        for (cur = as->as_area_btree.leaf_head.next;
     2073            cur != &as->as_area_btree.leaf_head; cur = cur->next) {
     2074                btree_node_t *node =
     2075                    list_get_instance(cur, btree_node_t, leaf_link);
     2076                btree_key_t i;
     2077               
     2078                for (i = 0; i < node->keys; i++) {
     2079                        as_area_t *area = node->value[i];
     2080                       
     2081                        ASSERT(area_idx < area_cnt);
     2082                        mutex_lock(&area->lock);
     2083                       
     2084                        info[area_idx].start_addr = area->base;
     2085                        info[area_idx].size = FRAMES2SIZE(area->pages);
     2086                        info[area_idx].flags = area->flags;
     2087                        ++area_idx;
     2088                       
     2089                        mutex_unlock(&area->lock);
     2090                }
     2091        }
     2092       
     2093        mutex_unlock(&as->lock);
     2094       
     2095        *obuf = info;
     2096        *osize = isize;
    19202097}
    19212098
    19222099/** Print out information about address space.
    19232100 *
    1924  * @param as            Address space.
     2101 * @param as Address space.
     2102 *
    19252103 */
    19262104void as_print(as_t *as)
    19272105{
    1928         ipl_t ipl;
    1929        
    1930         ipl = interrupts_disable();
    19312106        mutex_lock(&as->lock);
    19322107       
    1933         /* print out info about address space areas */
     2108        /* Print out info about address space areas */
    19342109        link_t *cur;
    19352110        for (cur = as->as_area_btree.leaf_head.next;
    19362111            cur != &as->as_area_btree.leaf_head; cur = cur->next) {
    1937                 btree_node_t *node;
    1938                
    1939                 node = list_get_instance(cur, btree_node_t, leaf_link);
    1940                
    1941                 unsigned int i;
     2112                btree_node_t *node
     2113                    = list_get_instance(cur, btree_node_t, leaf_link);
     2114                btree_key_t i;
     2115               
    19422116                for (i = 0; i < node->keys; i++) {
    19432117                        as_area_t *area = node->value[i];
    1944                
     2118                       
    19452119                        mutex_lock(&area->lock);
    1946                         printf("as_area: %p, base=%p, pages=%" PRIs
    1947                             " (%p - %p)\n", area, area->base, area->pages,
    1948                             area->base, area->base + FRAMES2SIZE(area->pages));
     2120                        printf("as_area: %p, base=%p, pages=%zu"
     2121                            " (%p - %p)\n", area, (void *) area->base,
     2122                            area->pages, (void *) area->base,
     2123                            (void *) (area->base + FRAMES2SIZE(area->pages)));
    19492124                        mutex_unlock(&area->lock);
    19502125                }
     
    19522127       
    19532128        mutex_unlock(&as->lock);
    1954         interrupts_restore(ipl);
    19552129}
    19562130
Note: See TracChangeset for help on using the changeset viewer.