Changes in kernel/generic/src/mm/as.c [e3ee9b9:402eda5] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
kernel/generic/src/mm/as.c
re3ee9b9 r402eda5 116 116 as_t *AS_KERNEL = NULL; 117 117 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 118 123 static int as_constructor(void *obj, unsigned int flags) 119 124 { … … 291 296 if (atomic_predec(&as->refcount) == 0) 292 297 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 to319 * the number of address space areas belonging to as.320 * The check for conflicts is then attempted on the rightmost321 * record in the left neighbour, the leftmost record in the right322 * 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;393 298 } 394 299 … … 452 357 453 358 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 or462 * 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 neighbour479 * to find out whether this is a miss or va belongs to an address480 * 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;516 359 } 517 360 … … 710 553 } 711 554 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/remove732 * 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 *node737 = 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 753 555 /** Destroy address space area. 754 556 * … … 1003 805 } 1004 806 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 1031 807 /** Change adress space area flags. 1032 808 * … … 1385 1161 } 1386 1162 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 */ 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 } 1388 1188 1389 1189 /** Compute flags for virtual address translation subsytem. … … 1472 1272 /** Test whether page tables are locked. 1473 1273 * 1474 * @param as 1475 * 1476 * @return 1477 * 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. 1478 1278 */ 1479 1279 bool page_table_locked(as_t *as) … … 1483 1283 1484 1284 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; 1485 1448 } 1486 1449 … … 1997 1960 } 1998 1961 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 1999 2003 /* 2000 2004 * Address space related syscalls.
Note:
See TracChangeset
for help on using the changeset viewer.