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


Ignore:
Timestamp:
2010-07-02T14:22:35Z (14 years ago)
Author:
Jakub Jermar <jakub@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
09b859c
Parents:
4d1be48 (diff), e3ee9b9 (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.

File:
1 edited

Legend:

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

    r4d1be48 re2ea4ab1  
    116116as_t *AS_KERNEL = NULL;
    117117
    118 static unsigned int area_flags_to_page_flags(unsigned int);
    119 static as_area_t *find_area_and_lock(as_t *, uintptr_t);
    120 static bool check_area_conflicts(as_t *, uintptr_t, size_t, as_area_t *);
    121 static void sh_info_remove_reference(share_info_t *);
    122 
    123118static int as_constructor(void *obj, unsigned int flags)
    124119{
     
    296291        if (atomic_predec(&as->refcount) == 0)
    297292                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 */
     305static 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;
    298393}
    299394
     
    357452       
    358453        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 */
     465static 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;
    359516}
    360517
     
    553710}
    554711
     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 */
     719static 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
    555753/** Destroy address space area.
    556754 *
     
    8051003}
    8061004
     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 */
     1012static 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
    8071031/** Change adress space area flags.
    8081032 *
     
    11611385}
    11621386
    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  */
    1170 unsigned 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 }
     1387
    11881388
    11891389/** Compute flags for virtual address translation subsytem.
     
    12721472/** Test whether page tables are locked.
    12731473 *
    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.
     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.
    12781478 */
    12791479bool page_table_locked(as_t *as)
     
    12831483
    12841484        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  */
    1297 as_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  */
    1360 bool 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;
    14481485}
    14491486
     
    19601997}
    19611998
    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  */
    1969 void 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 
    20031999/*
    20042000 * Address space related syscalls.
Note: See TracChangeset for help on using the changeset viewer.