Ignore:
File:
1 edited

Legend:

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

    re3ee9b9 r402eda5  
    116116as_t *AS_KERNEL = NULL;
    117117
     118static unsigned int area_flags_to_page_flags(unsigned int);
     119static as_area_t *find_area_and_lock(as_t *, uintptr_t);
     120static bool check_area_conflicts(as_t *, uintptr_t, size_t, as_area_t *);
     121static void sh_info_remove_reference(share_info_t *);
     122
    118123static int as_constructor(void *obj, unsigned int flags)
    119124{
     
    291296        if (atomic_predec(&as->refcount) == 0)
    292297                as_destroy(as);
    293 }
    294 
    295 /** Check area conflicts with other areas.
    296  *
    297  * @param as         Address space.
    298  * @param va         Starting virtual address of the area being tested.
    299  * @param size       Size of the area being tested.
    300  * @param avoid_area Do not touch this area.
    301  *
    302  * @return True if there is no conflict, false otherwise.
    303  *
    304  */
    305 static bool check_area_conflicts(as_t *as, uintptr_t va, size_t size,
    306     as_area_t *avoid_area)
    307 {
    308         ASSERT(mutex_locked(&as->lock));
    309        
    310         /*
    311          * We don't want any area to have conflicts with NULL page.
    312          *
    313          */
    314         if (overlaps(va, size, NULL, PAGE_SIZE))
    315                 return false;
    316        
    317         /*
    318          * The leaf node is found in O(log n), where n is proportional to
    319          * the number of address space areas belonging to as.
    320          * The check for conflicts is then attempted on the rightmost
    321          * record in the left neighbour, the leftmost record in the right
    322          * neighbour and all records in the leaf node itself.
    323          *
    324          */
    325         btree_node_t *leaf;
    326         as_area_t *area =
    327             (as_area_t *) btree_search(&as->as_area_btree, va, &leaf);
    328         if (area) {
    329                 if (area != avoid_area)
    330                         return false;
    331         }
    332        
    333         /* First, check the two border cases. */
    334         btree_node_t *node =
    335             btree_leaf_node_left_neighbour(&as->as_area_btree, leaf);
    336         if (node) {
    337                 area = (as_area_t *) node->value[node->keys - 1];
    338                
    339                 mutex_lock(&area->lock);
    340                
    341                 if (overlaps(va, size, area->base, area->pages * PAGE_SIZE)) {
    342                         mutex_unlock(&area->lock);
    343                         return false;
    344                 }
    345                
    346                 mutex_unlock(&area->lock);
    347         }
    348        
    349         node = btree_leaf_node_right_neighbour(&as->as_area_btree, leaf);
    350         if (node) {
    351                 area = (as_area_t *) node->value[0];
    352                
    353                 mutex_lock(&area->lock);
    354                
    355                 if (overlaps(va, size, area->base, area->pages * PAGE_SIZE)) {
    356                         mutex_unlock(&area->lock);
    357                         return false;
    358                 }
    359                
    360                 mutex_unlock(&area->lock);
    361         }
    362        
    363         /* Second, check the leaf node. */
    364         btree_key_t i;
    365         for (i = 0; i < leaf->keys; i++) {
    366                 area = (as_area_t *) leaf->value[i];
    367                
    368                 if (area == avoid_area)
    369                         continue;
    370                
    371                 mutex_lock(&area->lock);
    372                
    373                 if (overlaps(va, size, area->base, area->pages * PAGE_SIZE)) {
    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          */
    386         if (!KERNEL_ADDRESS_SPACE_SHADOWED) {
    387                 return !overlaps(va, size,
    388                     KERNEL_ADDRESS_SPACE_START,
    389                     KERNEL_ADDRESS_SPACE_END - KERNEL_ADDRESS_SPACE_START);
    390         }
    391        
    392         return true;
    393298}
    394299
     
    452357       
    453358        return area;
    454 }
    455 
    456 /** Find address space area and lock it.
    457  *
    458  * @param as Address space.
    459  * @param va Virtual address.
    460  *
    461  * @return Locked address space area containing va on success or
    462  *         NULL on failure.
    463  *
    464  */
    465 static as_area_t *find_area_and_lock(as_t *as, uintptr_t va)
    466 {
    467         ASSERT(mutex_locked(&as->lock));
    468        
    469         btree_node_t *leaf;
    470         as_area_t *area = (as_area_t *) btree_search(&as->as_area_btree, va, &leaf);
    471         if (area) {
    472                 /* va is the base address of an address space area */
    473                 mutex_lock(&area->lock);
    474                 return area;
    475         }
    476        
    477         /*
    478          * Search the leaf node and the righmost record of its left neighbour
    479          * to find out whether this is a miss or va belongs to an address
    480          * space area found there.
    481          *
    482          */
    483        
    484         /* First, search the leaf node itself. */
    485         btree_key_t i;
    486        
    487         for (i = 0; i < leaf->keys; i++) {
    488                 area = (as_area_t *) leaf->value[i];
    489                
    490                 mutex_lock(&area->lock);
    491                
    492                 if ((area->base <= va) && (va < area->base + area->pages * PAGE_SIZE))
    493                         return area;
    494                
    495                 mutex_unlock(&area->lock);
    496         }
    497        
    498         /*
    499          * Second, locate the left neighbour and test its last record.
    500          * Because of its position in the B+tree, it must have base < va.
    501          *
    502          */
    503         btree_node_t *lnode = btree_leaf_node_left_neighbour(&as->as_area_btree, leaf);
    504         if (lnode) {
    505                 area = (as_area_t *) lnode->value[lnode->keys - 1];
    506                
    507                 mutex_lock(&area->lock);
    508                
    509                 if (va < area->base + area->pages * PAGE_SIZE)
    510                         return area;
    511                
    512                 mutex_unlock(&area->lock);
    513         }
    514        
    515         return NULL;
    516359}
    517360
     
    710553}
    711554
    712 /** Remove reference to address space area share info.
    713  *
    714  * If the reference count drops to 0, the sh_info is deallocated.
    715  *
    716  * @param sh_info Pointer to address space area share info.
    717  *
    718  */
    719 static void sh_info_remove_reference(share_info_t *sh_info)
    720 {
    721         bool dealloc = false;
    722        
    723         mutex_lock(&sh_info->lock);
    724         ASSERT(sh_info->refcount);
    725        
    726         if (--sh_info->refcount == 0) {
    727                 dealloc = true;
    728                 link_t *cur;
    729                
    730                 /*
    731                  * Now walk carefully the pagemap B+tree and free/remove
    732                  * reference from all frames found there.
    733                  */
    734                 for (cur = sh_info->pagemap.leaf_head.next;
    735                     cur != &sh_info->pagemap.leaf_head; cur = cur->next) {
    736                         btree_node_t *node
    737                             = list_get_instance(cur, btree_node_t, leaf_link);
    738                         btree_key_t i;
    739                        
    740                         for (i = 0; i < node->keys; i++)
    741                                 frame_free((uintptr_t) node->value[i]);
    742                 }
    743                
    744         }
    745         mutex_unlock(&sh_info->lock);
    746        
    747         if (dealloc) {
    748                 btree_destroy(&sh_info->pagemap);
    749                 free(sh_info);
    750         }
    751 }
    752 
    753555/** Destroy address space area.
    754556 *
     
    1003805}
    1004806
    1005 /** Convert address space area flags to page flags.
    1006  *
    1007  * @param aflags Flags of some address space area.
    1008  *
    1009  * @return Flags to be passed to page_mapping_insert().
    1010  *
    1011  */
    1012 static unsigned int area_flags_to_page_flags(unsigned int aflags)
    1013 {
    1014         unsigned int flags = PAGE_USER | PAGE_PRESENT;
    1015        
    1016         if (aflags & AS_AREA_READ)
    1017                 flags |= PAGE_READ;
    1018                
    1019         if (aflags & AS_AREA_WRITE)
    1020                 flags |= PAGE_WRITE;
    1021        
    1022         if (aflags & AS_AREA_EXEC)
    1023                 flags |= PAGE_EXEC;
    1024        
    1025         if (aflags & AS_AREA_CACHEABLE)
    1026                 flags |= PAGE_CACHEABLE;
    1027        
    1028         return flags;
    1029 }
    1030 
    1031807/** Change adress space area flags.
    1032808 *
     
    13851161}
    13861162
    1387 
     1163/** Convert address space area flags to page flags.
     1164 *
     1165 * @param aflags Flags of some address space area.
     1166 *
     1167 * @return Flags to be passed to page_mapping_insert().
     1168 *
     1169 */
     1170unsigned int area_flags_to_page_flags(unsigned int aflags)
     1171{
     1172        unsigned int flags = PAGE_USER | PAGE_PRESENT;
     1173       
     1174        if (aflags & AS_AREA_READ)
     1175                flags |= PAGE_READ;
     1176               
     1177        if (aflags & AS_AREA_WRITE)
     1178                flags |= PAGE_WRITE;
     1179       
     1180        if (aflags & AS_AREA_EXEC)
     1181                flags |= PAGE_EXEC;
     1182       
     1183        if (aflags & AS_AREA_CACHEABLE)
     1184                flags |= PAGE_CACHEABLE;
     1185       
     1186        return flags;
     1187}
    13881188
    13891189/** Compute flags for virtual address translation subsytem.
     
    14721272/** Test whether page tables are locked.
    14731273 *
    1474  * @param as Address space where the page tables belong.
    1475  *
    1476  * @return True if the page tables belonging to the address soace
    1477  *         are locked, otherwise false.
     1274 * @param as            Address space where the page tables belong.
     1275 *
     1276 * @return              True if the page tables belonging to the address soace
     1277 *                      are locked, otherwise false.
    14781278 */
    14791279bool page_table_locked(as_t *as)
     
    14831283
    14841284        return as_operations->page_table_locked(as);
     1285}
     1286
     1287
     1288/** Find address space area and lock it.
     1289 *
     1290 * @param as Address space.
     1291 * @param va Virtual address.
     1292 *
     1293 * @return Locked address space area containing va on success or
     1294 *         NULL on failure.
     1295 *
     1296 */
     1297as_area_t *find_area_and_lock(as_t *as, uintptr_t va)
     1298{
     1299        ASSERT(mutex_locked(&as->lock));
     1300
     1301        btree_node_t *leaf;
     1302        as_area_t *area = (as_area_t *) btree_search(&as->as_area_btree, va, &leaf);
     1303        if (area) {
     1304                /* va is the base address of an address space area */
     1305                mutex_lock(&area->lock);
     1306                return area;
     1307        }
     1308       
     1309        /*
     1310         * Search the leaf node and the righmost record of its left neighbour
     1311         * to find out whether this is a miss or va belongs to an address
     1312         * space area found there.
     1313         *
     1314         */
     1315       
     1316        /* First, search the leaf node itself. */
     1317        btree_key_t i;
     1318       
     1319        for (i = 0; i < leaf->keys; i++) {
     1320                area = (as_area_t *) leaf->value[i];
     1321               
     1322                mutex_lock(&area->lock);
     1323               
     1324                if ((area->base <= va) && (va < area->base + area->pages * PAGE_SIZE))
     1325                        return area;
     1326               
     1327                mutex_unlock(&area->lock);
     1328        }
     1329       
     1330        /*
     1331         * Second, locate the left neighbour and test its last record.
     1332         * Because of its position in the B+tree, it must have base < va.
     1333         *
     1334         */
     1335        btree_node_t *lnode = btree_leaf_node_left_neighbour(&as->as_area_btree, leaf);
     1336        if (lnode) {
     1337                area = (as_area_t *) lnode->value[lnode->keys - 1];
     1338               
     1339                mutex_lock(&area->lock);
     1340               
     1341                if (va < area->base + area->pages * PAGE_SIZE)
     1342                        return area;
     1343               
     1344                mutex_unlock(&area->lock);
     1345        }
     1346       
     1347        return NULL;
     1348}
     1349
     1350/** Check area conflicts with other areas.
     1351 *
     1352 * @param as         Address space.
     1353 * @param va         Starting virtual address of the area being tested.
     1354 * @param size       Size of the area being tested.
     1355 * @param avoid_area Do not touch this area.
     1356 *
     1357 * @return True if there is no conflict, false otherwise.
     1358 *
     1359 */
     1360bool check_area_conflicts(as_t *as, uintptr_t va, size_t size,
     1361    as_area_t *avoid_area)
     1362{
     1363        ASSERT(mutex_locked(&as->lock));
     1364
     1365        /*
     1366         * We don't want any area to have conflicts with NULL page.
     1367         *
     1368         */
     1369        if (overlaps(va, size, NULL, PAGE_SIZE))
     1370                return false;
     1371       
     1372        /*
     1373         * The leaf node is found in O(log n), where n is proportional to
     1374         * the number of address space areas belonging to as.
     1375         * The check for conflicts is then attempted on the rightmost
     1376         * record in the left neighbour, the leftmost record in the right
     1377         * neighbour and all records in the leaf node itself.
     1378         *
     1379         */
     1380        btree_node_t *leaf;
     1381        as_area_t *area =
     1382            (as_area_t *) btree_search(&as->as_area_btree, va, &leaf);
     1383        if (area) {
     1384                if (area != avoid_area)
     1385                        return false;
     1386        }
     1387       
     1388        /* First, check the two border cases. */
     1389        btree_node_t *node =
     1390            btree_leaf_node_left_neighbour(&as->as_area_btree, leaf);
     1391        if (node) {
     1392                area = (as_area_t *) node->value[node->keys - 1];
     1393               
     1394                mutex_lock(&area->lock);
     1395               
     1396                if (overlaps(va, size, area->base, area->pages * PAGE_SIZE)) {
     1397                        mutex_unlock(&area->lock);
     1398                        return false;
     1399                }
     1400               
     1401                mutex_unlock(&area->lock);
     1402        }
     1403       
     1404        node = btree_leaf_node_right_neighbour(&as->as_area_btree, leaf);
     1405        if (node) {
     1406                area = (as_area_t *) node->value[0];
     1407               
     1408                mutex_lock(&area->lock);
     1409               
     1410                if (overlaps(va, size, area->base, area->pages * PAGE_SIZE)) {
     1411                        mutex_unlock(&area->lock);
     1412                        return false;
     1413                }
     1414               
     1415                mutex_unlock(&area->lock);
     1416        }
     1417       
     1418        /* Second, check the leaf node. */
     1419        btree_key_t i;
     1420        for (i = 0; i < leaf->keys; i++) {
     1421                area = (as_area_t *) leaf->value[i];
     1422               
     1423                if (area == avoid_area)
     1424                        continue;
     1425               
     1426                mutex_lock(&area->lock);
     1427               
     1428                if (overlaps(va, size, area->base, area->pages * PAGE_SIZE)) {
     1429                        mutex_unlock(&area->lock);
     1430                        return false;
     1431                }
     1432               
     1433                mutex_unlock(&area->lock);
     1434        }
     1435       
     1436        /*
     1437         * So far, the area does not conflict with other areas.
     1438         * Check if it doesn't conflict with kernel address space.
     1439         *
     1440         */
     1441        if (!KERNEL_ADDRESS_SPACE_SHADOWED) {
     1442                return !overlaps(va, size,
     1443                    KERNEL_ADDRESS_SPACE_START,
     1444                    KERNEL_ADDRESS_SPACE_END - KERNEL_ADDRESS_SPACE_START);
     1445        }
     1446       
     1447        return true;
    14851448}
    14861449
     
    19971960}
    19981961
     1962/** Remove reference to address space area share info.
     1963 *
     1964 * If the reference count drops to 0, the sh_info is deallocated.
     1965 *
     1966 * @param sh_info Pointer to address space area share info.
     1967 *
     1968 */
     1969void sh_info_remove_reference(share_info_t *sh_info)
     1970{
     1971        bool dealloc = false;
     1972       
     1973        mutex_lock(&sh_info->lock);
     1974        ASSERT(sh_info->refcount);
     1975       
     1976        if (--sh_info->refcount == 0) {
     1977                dealloc = true;
     1978                link_t *cur;
     1979               
     1980                /*
     1981                 * Now walk carefully the pagemap B+tree and free/remove
     1982                 * reference from all frames found there.
     1983                 */
     1984                for (cur = sh_info->pagemap.leaf_head.next;
     1985                    cur != &sh_info->pagemap.leaf_head; cur = cur->next) {
     1986                        btree_node_t *node
     1987                            = list_get_instance(cur, btree_node_t, leaf_link);
     1988                        btree_key_t i;
     1989                       
     1990                        for (i = 0; i < node->keys; i++)
     1991                                frame_free((uintptr_t) node->value[i]);
     1992                }
     1993               
     1994        }
     1995        mutex_unlock(&sh_info->lock);
     1996       
     1997        if (dealloc) {
     1998                btree_destroy(&sh_info->pagemap);
     1999                free(sh_info);
     2000        }
     2001}
     2002
    19992003/*
    20002004 * Address space related syscalls.
Note: See TracChangeset for help on using the changeset viewer.