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