1 /* 2 * Copyright 2002-2005, Axel Dörfler, axeld@pinc-software.de. 3 * Distributed under the terms of the MIT License. 4 * 5 * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. 6 * Distributed under the terms of the NewOS License. 7 */ 8 9 10 #include <OS.h> 11 #include <KernelExport.h> 12 13 #include <vm.h> 14 #include <vm_priv.h> 15 #include <vm_page.h> 16 #include <vm_cache.h> 17 #include <vm_store_anonymous_noswap.h> 18 #include <vm_store_device.h> 19 #include <vm_store_null.h> 20 #include <vm_low_memory.h> 21 #include <file_cache.h> 22 #include <memheap.h> 23 #include <debug.h> 24 #include <console.h> 25 #include <int.h> 26 #include <smp.h> 27 #include <lock.h> 28 #include <thread.h> 29 #include <team.h> 30 31 #include <boot/stage2.h> 32 #include <boot/elf.h> 33 34 #include <arch/cpu.h> 35 #include <arch/vm.h> 36 37 #include <string.h> 38 #include <ctype.h> 39 #include <stdlib.h> 40 #include <stdio.h> 41 42 //#define TRACE_VM 43 //#define TRACE_FAULTS 44 #ifdef TRACE_VM 45 # define TRACE(x) dprintf x 46 #else 47 # define TRACE(x) ; 48 #endif 49 #ifdef TRACE_FAULTS 50 # define FTRACE(x) dprintf x 51 #else 52 # define FTRACE(x) ; 53 #endif 54 55 #define ROUNDUP(a, b) (((a) + ((b)-1)) & ~((b)-1)) 56 #define ROUNDOWN(a, b) (((a) / (b)) * (b)) 57 58 59 extern vm_address_space *kernel_aspace; 60 61 #define REGION_HASH_TABLE_SIZE 1024 62 static area_id sNextAreaID; 63 static hash_table *sAreaHash; 64 static sem_id sAreaHashLock; 65 66 static off_t sAvailableMemory; 67 static benaphore sAvailableMemoryLock; 68 69 // function declarations 70 static vm_area *_vm_create_region_struct(vm_address_space *aspace, const char *name, int wiring, int lock); 71 static status_t map_backing_store(vm_address_space *aspace, vm_store *store, void **vaddr, 72 off_t offset, addr_t size, uint32 addressSpec, int wiring, int lock, int mapping, vm_area **_area, const char *area_name); 73 static status_t vm_soft_fault(addr_t address, bool is_write, bool is_user); 74 static vm_area *vm_virtual_map_lookup(vm_virtual_map *map, addr_t address); 75 static bool vm_put_area(vm_area *area); 76 77 78 static int 79 area_compare(void *_area, const void *key) 80 { 81 vm_area *area = (vm_area *)_area; 82 const area_id *id = (const area_id *)key; 83 84 if (area->id == *id) 85 return 0; 86 87 return -1; 88 } 89 90 91 static uint32 92 area_hash(void *_area, const void *key, uint32 range) 93 { 94 vm_area *area = (vm_area *)_area; 95 const area_id *id = (const area_id *)key; 96 97 if (area != NULL) 98 return area->id % range; 99 100 return *id % range; 101 } 102 103 104 static vm_area * 105 vm_get_area(area_id id) 106 { 107 vm_area *area; 108 109 acquire_sem_etc(sAreaHashLock, READ_COUNT, 0, 0); 110 111 area = (vm_area *)hash_lookup(sAreaHash, &id); 112 if (area != NULL) 113 atomic_add(&area->ref_count, 1); 114 115 release_sem_etc(sAreaHashLock, READ_COUNT, 0); 116 117 return area; 118 } 119 120 121 static vm_area * 122 _vm_create_reserved_region_struct(vm_virtual_map *map, uint32 flags) 123 { 124 vm_area *reserved = (vm_area *)malloc(sizeof(vm_area)); 125 if (reserved == NULL) 126 return NULL; 127 128 memset(reserved, 0, sizeof(vm_area)); 129 reserved->id = RESERVED_AREA_ID; 130 // this marks it as reserved space 131 reserved->protection = flags; 132 reserved->map = map; 133 134 return reserved; 135 } 136 137 138 static vm_area * 139 _vm_create_area_struct(vm_address_space *aspace, const char *name, uint32 wiring, uint32 protection) 140 { 141 vm_area *area = NULL; 142 143 // restrict the area name to B_OS_NAME_LENGTH 144 size_t length = strlen(name) + 1; 145 if (length > B_OS_NAME_LENGTH) 146 length = B_OS_NAME_LENGTH; 147 148 area = (vm_area *)malloc(sizeof(vm_area)); 149 if (area == NULL) 150 return NULL; 151 152 area->name = (char *)malloc(length); 153 if (area->name == NULL) { 154 free(area); 155 return NULL; 156 } 157 strlcpy(area->name, name, length); 158 159 area->id = atomic_add(&sNextAreaID, 1); 160 area->base = 0; 161 area->size = 0; 162 area->protection = protection; 163 area->wiring = wiring; 164 area->ref_count = 1; 165 166 area->cache_ref = NULL; 167 area->cache_offset = 0; 168 169 area->aspace = aspace; 170 area->aspace_next = NULL; 171 area->map = &aspace->virtual_map; 172 area->cache_next = area->cache_prev = NULL; 173 area->hash_next = NULL; 174 175 return area; 176 } 177 178 179 /** Finds a reserved area that covers the region spanned by \a start and 180 * \a size, inserts the \a area into that region and makes sure that 181 * there are reserved regions for the remaining parts. 182 */ 183 184 static status_t 185 find_reserved_area(vm_virtual_map *map, addr_t start, addr_t size, vm_area *area) 186 { 187 vm_area *next, *last = NULL; 188 189 next = map->areas; 190 while (next) { 191 if (next->base <= start && next->base + next->size >= start + size) { 192 // this area covers the requested range 193 if (next->id != RESERVED_AREA_ID) { 194 // but it's not reserved space, it's a real area 195 return B_BAD_VALUE; 196 } 197 198 break; 199 } 200 last = next; 201 next = next->aspace_next; 202 } 203 if (next == NULL) 204 return B_ENTRY_NOT_FOUND; 205 206 // now we have to transfer the requested part of the reserved 207 // range to the new area - and remove, resize or split the old 208 // reserved area. 209 210 if (start == next->base) { 211 // the area starts at the beginning of the reserved range 212 if (last) 213 last->aspace_next = area; 214 else 215 map->areas = area; 216 217 if (size == next->size) { 218 // the new area fully covers the reversed range 219 area->aspace_next = next->aspace_next; 220 free(next); 221 } else { 222 // resize the reserved range behind the area 223 area->aspace_next = next; 224 next->base += size; 225 next->size -= size; 226 } 227 } else if (start + size == next->base + next->size) { 228 // the area is at the end of the reserved range 229 area->aspace_next = next->aspace_next; 230 next->aspace_next = area; 231 232 // resize the reserved range before the area 233 next->size = start - next->base; 234 } else { 235 // the area splits the reserved range into two separate ones 236 // we need a new reserved area to cover this space 237 vm_area *reserved = _vm_create_reserved_region_struct(map, next->protection); 238 if (reserved == NULL) 239 return B_NO_MEMORY; 240 241 reserved->aspace_next = next->aspace_next; 242 area->aspace_next = reserved; 243 next->aspace_next = area; 244 245 // resize regions 246 reserved->size = next->base + next->size - start - size; 247 next->size = start - next->base; 248 reserved->base = start + size; 249 reserved->cache_offset = next->cache_offset; 250 } 251 252 area->base = start; 253 area->size = size; 254 map->change_count++; 255 256 return B_OK; 257 } 258 259 260 // must be called with this address space's virtual_map.sem held 261 262 static status_t 263 find_and_insert_area_slot(vm_virtual_map *map, addr_t start, addr_t size, addr_t end, 264 uint32 addressSpec, vm_area *area) 265 { 266 vm_area *last = NULL; 267 vm_area *next; 268 bool foundSpot = false; 269 270 TRACE(("find_and_insert_region_slot: map %p, start 0x%lx, size %ld, end 0x%lx, addressSpec %ld, area %p\n", 271 map, start, size, end, addressSpec, area)); 272 273 // do some sanity checking 274 if (start < map->base || size == 0 275 || (end - 1) > (map->base + (map->size - 1)) 276 || start + size > end) 277 return B_BAD_ADDRESS; 278 279 if (addressSpec == B_EXACT_ADDRESS) { 280 // search for a reserved area 281 status_t status = find_reserved_area(map, start, size, area); 282 if (status == B_OK || status == B_BAD_VALUE) 283 return status; 284 285 // there was no reserved area, and the slot doesn't seem to be used already 286 // ToDo: this could be further optimized. 287 } 288 289 // walk up to the spot where we should start searching 290 second_chance: 291 next = map->areas; 292 while (next) { 293 if (next->base >= start + size) { 294 // we have a winner 295 break; 296 } 297 last = next; 298 next = next->aspace_next; 299 } 300 301 // find the right spot depending on the address specification - the area 302 // will be inserted directly after "last" ("next" is not referenced anymore) 303 304 switch (addressSpec) { 305 case B_ANY_ADDRESS: 306 case B_ANY_KERNEL_ADDRESS: 307 case B_ANY_KERNEL_BLOCK_ADDRESS: 308 // find a hole big enough for a new area 309 if (!last) { 310 // see if we can build it at the beginning of the virtual map 311 if (!next || (next->base >= map->base + size)) { 312 foundSpot = true; 313 area->base = map->base; 314 break; 315 } 316 last = next; 317 next = next->aspace_next; 318 } 319 // keep walking 320 while (next) { 321 if (next->base >= last->base + last->size + size) { 322 // we found a spot (it'll be filled up below) 323 break; 324 } 325 last = next; 326 next = next->aspace_next; 327 } 328 329 if ((map->base + (map->size - 1)) >= (last->base + last->size + (size - 1))) { 330 // got a spot 331 foundSpot = true; 332 area->base = last->base + last->size; 333 break; 334 } else { 335 // we didn't find a free spot - if there were any reserved areas with 336 // the RESERVED_AVOID_BASE flag set, we can now test those for free 337 // space 338 // ToDo: it would make sense to start with the biggest of them 339 next = map->areas; 340 last = NULL; 341 for (last = NULL; next; next = next->aspace_next, last = next) { 342 // ToDo: take free space after the reserved area into account! 343 if (next->size == size) { 344 // the reserved area is entirely covered, and thus, removed 345 if (last) 346 last->aspace_next = next->aspace_next; 347 else 348 map->areas = next->aspace_next; 349 350 foundSpot = true; 351 area->base = next->base; 352 free(next); 353 break; 354 } 355 if (next->size >= size) { 356 // the new area will be placed at the end of the reserved 357 // area, and the reserved area will be resized to make space 358 foundSpot = true; 359 next->size -= size; 360 last = next; 361 area->base = next->base + next->size; 362 break; 363 } 364 } 365 } 366 break; 367 368 case B_BASE_ADDRESS: 369 // find a hole big enough for a new area beginning with "start" 370 if (!last) { 371 // see if we can build it at the beginning of the specified start 372 if (!next || (next->base >= start + size)) { 373 foundSpot = true; 374 area->base = start; 375 break; 376 } 377 last = next; 378 next = next->aspace_next; 379 } 380 // keep walking 381 while (next) { 382 if (next->base >= last->base + last->size + size) { 383 // we found a spot (it'll be filled up below) 384 break; 385 } 386 last = next; 387 next = next->aspace_next; 388 } 389 390 if ((map->base + (map->size - 1)) >= (last->base + last->size + (size - 1))) { 391 // got a spot 392 foundSpot = true; 393 if (last->base + last->size <= start) 394 area->base = start; 395 else 396 area->base = last->base + last->size; 397 break; 398 } 399 // we didn't find a free spot in the requested range, so we'll 400 // try again without any restrictions 401 start = map->base; 402 addressSpec = B_ANY_ADDRESS; 403 last = NULL; 404 goto second_chance; 405 406 case B_EXACT_ADDRESS: 407 // see if we can create it exactly here 408 if (!last) { 409 if (!next || (next->base >= start + size)) { 410 foundSpot = true; 411 area->base = start; 412 break; 413 } 414 } else { 415 if (next) { 416 if (last->base + last->size <= start && next->base >= start + size) { 417 foundSpot = true; 418 area->base = start; 419 break; 420 } 421 } else { 422 if ((last->base + (last->size - 1)) <= start - 1) { 423 foundSpot = true; 424 area->base = start; 425 } 426 } 427 } 428 break; 429 default: 430 return B_BAD_VALUE; 431 } 432 433 if (!foundSpot) 434 return addressSpec == B_EXACT_ADDRESS ? B_BAD_VALUE : B_NO_MEMORY; 435 436 area->size = size; 437 if (last) { 438 area->aspace_next = last->aspace_next; 439 last->aspace_next = area; 440 } else { 441 area->aspace_next = map->areas; 442 map->areas = area; 443 } 444 map->change_count++; 445 return B_OK; 446 } 447 448 449 /** This inserts the area you pass into the virtual_map of the 450 * specified address space. 451 * It will also set the "_address" argument to its base address when 452 * the call succeeds. 453 * You need to hold the virtual_map semaphore. 454 */ 455 456 static status_t 457 insert_area(vm_address_space *addressSpace, void **_address, 458 uint32 addressSpec, addr_t size, vm_area *area) 459 { 460 addr_t searchBase, searchEnd; 461 status_t status; 462 463 switch (addressSpec) { 464 case B_EXACT_ADDRESS: 465 searchBase = (addr_t)*_address; 466 searchEnd = (addr_t)*_address + size; 467 break; 468 469 case B_BASE_ADDRESS: 470 searchBase = (addr_t)*_address; 471 searchEnd = addressSpace->virtual_map.base + (addressSpace->virtual_map.size - 1); 472 break; 473 474 case B_ANY_ADDRESS: 475 case B_ANY_KERNEL_ADDRESS: 476 case B_ANY_KERNEL_BLOCK_ADDRESS: 477 searchBase = addressSpace->virtual_map.base; 478 searchEnd = addressSpace->virtual_map.base + (addressSpace->virtual_map.size - 1); 479 break; 480 481 default: 482 return B_BAD_VALUE; 483 } 484 485 status = find_and_insert_area_slot(&addressSpace->virtual_map, searchBase, size, 486 searchEnd, addressSpec, area); 487 if (status == B_OK) 488 // ToDo: do we have to do anything about B_ANY_KERNEL_ADDRESS 489 // vs. B_ANY_KERNEL_BLOCK_ADDRESS here? 490 *_address = (void *)area->base; 491 492 return status; 493 } 494 495 496 // a ref to the cache holding this store must be held before entering here 497 static status_t 498 map_backing_store(vm_address_space *aspace, vm_store *store, void **_virtualAddress, 499 off_t offset, addr_t size, uint32 addressSpec, int wiring, int protection, 500 int mapping, vm_area **_area, const char *areaName) 501 { 502 vm_cache *cache; 503 vm_cache_ref *cache_ref; 504 vm_area *area; 505 vm_cache *nu_cache; 506 vm_cache_ref *nu_cache_ref = NULL; 507 vm_store *nu_store; 508 509 int err; 510 511 TRACE(("map_backing_store: aspace %p, store %p, *vaddr %p, offset 0x%Lx, size %lu, addressSpec %ld, wiring %d, protection %d, _area %p, area_name '%s'\n", 512 aspace, store, *_virtualAddress, offset, size, addressSpec, wiring, protection, _area, areaName)); 513 514 area = _vm_create_area_struct(aspace, areaName, wiring, protection); 515 if (area == NULL) 516 return B_NO_MEMORY; 517 518 cache = store->cache; 519 cache_ref = cache->ref; 520 521 // if this is a private map, we need to create a new cache & store object 522 // pair to handle the private copies of pages as they are written to 523 if (mapping == REGION_PRIVATE_MAP) { 524 // create an anonymous store object 525 nu_store = vm_store_create_anonymous_noswap((protection & B_STACK_AREA) != 0, USER_STACK_GUARD_PAGES); 526 if (nu_store == NULL) 527 panic("map_backing_store: vm_create_store_anonymous_noswap returned NULL"); 528 nu_cache = vm_cache_create(nu_store); 529 if (nu_cache == NULL) 530 panic("map_backing_store: vm_cache_create returned NULL"); 531 nu_cache_ref = vm_cache_ref_create(nu_cache); 532 if (nu_cache_ref == NULL) 533 panic("map_backing_store: vm_cache_ref_create returned NULL"); 534 nu_cache->temporary = 1; 535 nu_cache->scan_skip = cache->scan_skip; 536 537 nu_cache->source = cache; 538 539 // grab a ref to the cache object we're now linked to as a source 540 vm_cache_acquire_ref(cache_ref, true); 541 542 cache = nu_cache; 543 cache_ref = cache->ref; 544 store = nu_store; 545 cache->virtual_size = offset + size; 546 } 547 548 err = vm_cache_set_minimal_commitment(cache_ref, offset + size); 549 if (err != B_OK) 550 goto err1a; 551 552 vm_cache_acquire_ref(cache_ref, true); 553 554 acquire_sem_etc(aspace->virtual_map.sem, WRITE_COUNT, 0, 0); 555 556 // check to see if this aspace has entered DELETE state 557 if (aspace->state == VM_ASPACE_STATE_DELETION) { 558 // okay, someone is trying to delete this aspace now, so we can't 559 // insert the area, so back out 560 err = B_BAD_TEAM_ID; 561 goto err1b; 562 } 563 564 err = insert_area(aspace, _virtualAddress, addressSpec, size, area); 565 if (err < B_OK) 566 goto err1b; 567 568 // attach the cache to the area 569 area->cache_ref = cache_ref; 570 area->cache_offset = offset; 571 // point the cache back to the area 572 vm_cache_insert_area(cache_ref, area); 573 574 // insert the area in the global area hash table 575 acquire_sem_etc(sAreaHashLock, WRITE_COUNT, 0 ,0); 576 hash_insert(sAreaHash, area); 577 release_sem_etc(sAreaHashLock, WRITE_COUNT, 0); 578 579 // grab a ref to the aspace (the area holds this) 580 atomic_add(&aspace->ref_count, 1); 581 582 release_sem_etc(aspace->virtual_map.sem, WRITE_COUNT, 0); 583 584 *_area = area; 585 return B_OK; 586 587 err1b: 588 release_sem_etc(aspace->virtual_map.sem, WRITE_COUNT, 0); 589 vm_cache_release_ref(cache_ref); 590 goto err; 591 err1a: 592 if (nu_cache_ref) { 593 // had never acquired it's initial ref, so acquire and then release it 594 // this should clean up all the objects it references 595 vm_cache_acquire_ref(cache_ref, true); 596 vm_cache_release_ref(cache_ref); 597 } 598 err: 599 free(area->name); 600 free(area); 601 return err; 602 } 603 604 605 status_t 606 vm_unreserve_address_range(aspace_id aid, void *address, addr_t size) 607 { 608 vm_address_space *addressSpace; 609 vm_area *area, *last = NULL; 610 status_t status = B_OK; 611 612 addressSpace = vm_get_aspace_by_id(aid); 613 if (addressSpace == NULL) 614 return B_BAD_TEAM_ID; 615 616 acquire_sem_etc(addressSpace->virtual_map.sem, WRITE_COUNT, 0, 0); 617 618 // check to see if this aspace has entered DELETE state 619 if (addressSpace->state == VM_ASPACE_STATE_DELETION) { 620 // okay, someone is trying to delete this aspace now, so we can't 621 // insert the area, so back out 622 status = B_BAD_TEAM_ID; 623 goto out; 624 } 625 626 // search area list and remove any matching reserved ranges 627 628 area = addressSpace->virtual_map.areas; 629 while (area) { 630 // the area must be completely part of the reserved range 631 if (area->id == RESERVED_AREA_ID && area->base >= (addr_t)address 632 && area->base + area->size <= (addr_t)address + size) { 633 // remove reserved range 634 vm_area *reserved = area; 635 if (last) 636 last->aspace_next = reserved->aspace_next; 637 else 638 addressSpace->virtual_map.areas = reserved->aspace_next; 639 640 area = reserved->aspace_next; 641 free(reserved); 642 continue; 643 } 644 645 last = area; 646 area = area->aspace_next; 647 } 648 649 out: 650 release_sem_etc(addressSpace->virtual_map.sem, WRITE_COUNT, 0); 651 vm_put_aspace(addressSpace); 652 return status; 653 } 654 655 656 status_t 657 vm_reserve_address_range(aspace_id aid, void **_address, uint32 addressSpec, 658 addr_t size, uint32 flags) 659 { 660 vm_address_space *addressSpace; 661 vm_area *area; 662 status_t status = B_OK; 663 664 if (size == 0) 665 return B_BAD_VALUE; 666 667 addressSpace = vm_get_aspace_by_id(aid); 668 if (addressSpace == NULL) 669 return B_BAD_TEAM_ID; 670 671 area = _vm_create_reserved_region_struct(&addressSpace->virtual_map, flags); 672 if (area == NULL) { 673 status = B_NO_MEMORY; 674 goto err1; 675 } 676 677 acquire_sem_etc(addressSpace->virtual_map.sem, WRITE_COUNT, 0, 0); 678 679 // check to see if this aspace has entered DELETE state 680 if (addressSpace->state == VM_ASPACE_STATE_DELETION) { 681 // okay, someone is trying to delete this aspace now, so we can't 682 // insert the area, let's back out 683 status = B_BAD_TEAM_ID; 684 goto err2; 685 } 686 687 status = insert_area(addressSpace, _address, addressSpec, size, area); 688 if (status < B_OK) 689 goto err2; 690 691 // the area is now reserved! 692 693 area->cache_offset = area->base; 694 // we cache the original base address here 695 696 release_sem_etc(addressSpace->virtual_map.sem, WRITE_COUNT, 0); 697 return B_OK; 698 699 err2: 700 release_sem_etc(addressSpace->virtual_map.sem, WRITE_COUNT, 0); 701 free(area); 702 err1: 703 vm_put_aspace(addressSpace); 704 return status; 705 } 706 707 708 area_id 709 vm_create_anonymous_area(aspace_id aid, const char *name, void **address, 710 uint32 addressSpec, addr_t size, uint32 wiring, uint32 protection) 711 { 712 vm_area *area; 713 vm_cache *cache; 714 vm_store *store; 715 vm_address_space *aspace; 716 vm_cache_ref *cache_ref; 717 vm_page *page = NULL; 718 bool isStack = (protection & B_STACK_AREA) != 0; 719 bool canOvercommit = false; 720 status_t err; 721 722 TRACE(("create_anonymous_area %s: size 0x%lx\n", name, size)); 723 724 if (!arch_vm_supports_protection(protection)) 725 return B_NOT_SUPPORTED; 726 727 if (isStack || (protection & B_OVERCOMMITTING_AREA) != 0) 728 canOvercommit = true; 729 730 #ifdef DEBUG_KERNEL_STACKS 731 if ((protection & B_KERNEL_STACK_AREA) != 0) 732 isStack = true; 733 #endif 734 735 /* check parameters */ 736 switch (addressSpec) { 737 case B_ANY_ADDRESS: 738 case B_EXACT_ADDRESS: 739 case B_BASE_ADDRESS: 740 case B_ANY_KERNEL_ADDRESS: 741 break; 742 743 default: 744 return B_BAD_VALUE; 745 } 746 747 switch (wiring) { 748 case B_NO_LOCK: 749 case B_FULL_LOCK: 750 case B_LAZY_LOCK: 751 case B_CONTIGUOUS: 752 case B_ALREADY_WIRED: 753 break; 754 case B_LOMEM: 755 //case B_SLOWMEM: 756 dprintf("B_LOMEM/SLOWMEM is not yet supported!\n"); 757 wiring = B_FULL_LOCK; 758 break; 759 default: 760 return B_BAD_VALUE; 761 } 762 763 aspace = vm_get_aspace_by_id(aid); 764 if (aspace == NULL) 765 return B_BAD_TEAM_ID; 766 767 size = PAGE_ALIGN(size); 768 769 if (wiring == B_CONTIGUOUS) { 770 // we try to allocate the page run here upfront as this may easily fail for obvious reasons 771 page = vm_page_allocate_page_run(PAGE_STATE_CLEAR, size / B_PAGE_SIZE); 772 if (page == NULL) { 773 vm_put_aspace(aspace); 774 return B_NO_MEMORY; 775 } 776 } 777 778 // create an anonymous store object 779 store = vm_store_create_anonymous_noswap(canOvercommit, isStack ? 780 ((protection & B_USER_PROTECTION) != 0 ? 781 USER_STACK_GUARD_PAGES : KERNEL_STACK_GUARD_PAGES) : 0); 782 if (store == NULL) 783 panic("vm_create_anonymous_area: vm_create_store_anonymous_noswap returned NULL"); 784 cache = vm_cache_create(store); 785 if (cache == NULL) 786 panic("vm_create_anonymous_area: vm_cache_create returned NULL"); 787 cache_ref = vm_cache_ref_create(cache); 788 if (cache_ref == NULL) 789 panic("vm_create_anonymous_area: vm_cache_ref_create returned NULL"); 790 cache->temporary = 1; 791 792 switch (wiring) { 793 case B_LAZY_LOCK: // for now 794 case B_FULL_LOCK: 795 case B_CONTIGUOUS: 796 case B_ALREADY_WIRED: 797 cache->scan_skip = 1; 798 break; 799 case B_NO_LOCK: 800 //case B_LAZY_LOCK: 801 cache->scan_skip = 0; 802 break; 803 } 804 805 vm_cache_acquire_ref(cache_ref, true); 806 err = map_backing_store(aspace, store, address, 0, size, addressSpec, wiring, protection, REGION_NO_PRIVATE_MAP, &area, name); 807 vm_cache_release_ref(cache_ref); 808 if (err < 0) { 809 vm_put_aspace(aspace); 810 811 if (wiring == B_CONTIGUOUS) { 812 // we had reserved the area space upfront... 813 addr_t pageNumber = page->ppn; 814 int32 i; 815 for (i = size / B_PAGE_SIZE; i-- > 0; pageNumber++) { 816 page = vm_lookup_page(pageNumber); 817 if (page == NULL) 818 panic("couldn't lookup physical page just allocated\n"); 819 820 vm_page_set_state(page, PAGE_STATE_FREE); 821 } 822 } 823 return err; 824 } 825 826 cache_ref = store->cache->ref; 827 switch (wiring) { 828 case B_NO_LOCK: 829 case B_LAZY_LOCK: 830 break; // do nothing 831 832 case B_FULL_LOCK: 833 { 834 // Pages aren't mapped at this point, but we just simulate a fault on 835 // every page, which should allocate them 836 // ToDo: at this point, it would probably be cheaper to allocate 837 // and map the pages directly 838 addr_t va; 839 for (va = area->base; va < area->base + area->size; va += B_PAGE_SIZE) { 840 #ifdef DEBUG_KERNEL_STACKS 841 # ifdef STACK_GROWS_DOWNWARDS 842 if (isStack && va < area->base + KERNEL_STACK_GUARD_PAGES * B_PAGE_SIZE) 843 # else 844 if (isStack && va >= area->base + area->size - KERNEL_STACK_GUARD_PAGES * B_PAGE_SIZE) 845 # endif 846 continue; 847 #endif 848 vm_soft_fault(va, false, false); 849 } 850 break; 851 } 852 853 case B_ALREADY_WIRED: 854 { 855 // the pages should already be mapped. This is only really useful during 856 // boot time. Find the appropriate vm_page objects and stick them in 857 // the cache object. 858 addr_t va; 859 addr_t pa; 860 uint32 flags; 861 int err; 862 off_t offset = 0; 863 864 if (!kernel_startup) 865 panic("ALREADY_WIRED flag used outside kernel startup\n"); 866 867 mutex_lock(&cache_ref->lock); 868 (*aspace->translation_map.ops->lock)(&aspace->translation_map); 869 for (va = area->base; va < area->base + area->size; va += B_PAGE_SIZE, offset += B_PAGE_SIZE) { 870 err = (*aspace->translation_map.ops->query)(&aspace->translation_map, va, &pa, &flags); 871 if (err < 0) { 872 // dprintf("vm_create_anonymous_area: error looking up mapping for va 0x%x\n", va); 873 continue; 874 } 875 page = vm_lookup_page(pa / B_PAGE_SIZE); 876 if (page == NULL) { 877 // dprintf("vm_create_anonymous_area: error looking up vm_page structure for pa 0x%x\n", pa); 878 continue; 879 } 880 atomic_add(&page->ref_count, 1); 881 vm_page_set_state(page, PAGE_STATE_WIRED); 882 vm_cache_insert_page(cache_ref, page, offset); 883 } 884 (*aspace->translation_map.ops->unlock)(&aspace->translation_map); 885 mutex_unlock(&cache_ref->lock); 886 break; 887 } 888 889 case B_CONTIGUOUS: 890 { 891 addr_t physicalAddress = page->ppn * B_PAGE_SIZE; 892 addr_t virtualAddress; 893 off_t offset = 0; 894 895 mutex_lock(&cache_ref->lock); 896 (*aspace->translation_map.ops->lock)(&aspace->translation_map); 897 898 for (virtualAddress = area->base; virtualAddress < area->base + area->size; 899 virtualAddress += B_PAGE_SIZE, offset += B_PAGE_SIZE, physicalAddress += B_PAGE_SIZE) { 900 page = vm_lookup_page(physicalAddress / B_PAGE_SIZE); 901 if (page == NULL) 902 panic("couldn't lookup physical page just allocated\n"); 903 904 atomic_add(&page->ref_count, 1); 905 err = (*aspace->translation_map.ops->map)(&aspace->translation_map, 906 virtualAddress, physicalAddress, protection); 907 if (err < 0) 908 panic("couldn't map physical page in page run\n"); 909 910 vm_page_set_state(page, PAGE_STATE_WIRED); 911 vm_cache_insert_page(cache_ref, page, offset); 912 } 913 914 (*aspace->translation_map.ops->unlock)(&aspace->translation_map); 915 mutex_unlock(&cache_ref->lock); 916 break; 917 } 918 919 default: 920 break; 921 } 922 vm_put_aspace(aspace); 923 924 TRACE(("vm_create_anonymous_area: done\n")); 925 926 if (area == NULL) 927 return B_NO_MEMORY; 928 929 return area->id; 930 } 931 932 933 area_id 934 vm_map_physical_memory(aspace_id aid, const char *name, void **_address, 935 uint32 addressSpec, addr_t size, uint32 protection, addr_t phys_addr) 936 { 937 vm_area *area; 938 vm_cache *cache; 939 vm_cache_ref *cache_ref; 940 vm_store *store; 941 addr_t map_offset; 942 int err; 943 vm_address_space *aspace = vm_get_aspace_by_id(aid); 944 945 TRACE(("vm_map_physical_memory(aspace = %ld, \"%s\", virtual = %p, spec = %ld," 946 " size = %lu, protection = %ld, phys = %p)\n", 947 aid, name, _address, addressSpec, size, protection, (void *)phys_addr)); 948 949 if (!arch_vm_supports_protection(protection)) 950 return B_NOT_SUPPORTED; 951 952 if (aspace == NULL) 953 return B_BAD_TEAM_ID; 954 955 // if the physical address is somewhat inside a page, 956 // move the actual area down to align on a page boundary 957 map_offset = phys_addr % B_PAGE_SIZE; 958 size += map_offset; 959 phys_addr -= map_offset; 960 961 size = PAGE_ALIGN(size); 962 963 // create an device store object 964 store = vm_store_create_device(phys_addr); 965 if (store == NULL) 966 panic("vm_map_physical_memory: vm_store_create_device returned NULL"); 967 cache = vm_cache_create(store); 968 if (cache == NULL) 969 panic("vm_map_physical_memory: vm_cache_create returned NULL"); 970 cache_ref = vm_cache_ref_create(cache); 971 if (cache_ref == NULL) 972 panic("vm_map_physical_memory: vm_cache_ref_create returned NULL"); 973 // tell the page scanner to skip over this area, it's pages are special 974 cache->scan_skip = 1; 975 976 vm_cache_acquire_ref(cache_ref, true); 977 err = map_backing_store(aspace, store, _address, 0, size, addressSpec, 0, protection, REGION_NO_PRIVATE_MAP, &area, name); 978 vm_cache_release_ref(cache_ref); 979 vm_put_aspace(aspace); 980 if (err < 0) 981 return err; 982 983 // modify the pointer returned to be offset back into the new area 984 // the same way the physical address in was offset 985 *_address = (void *)((addr_t)*_address + map_offset); 986 987 return area->id; 988 } 989 990 991 area_id 992 vm_create_null_area(aspace_id aid, const char *name, void **address, uint32 addressSpec, addr_t size) 993 { 994 vm_area *area; 995 vm_cache *cache; 996 vm_cache_ref *cache_ref; 997 vm_store *store; 998 // addr_t map_offset; 999 int err; 1000 1001 vm_address_space *aspace = vm_get_aspace_by_id(aid); 1002 if (aspace == NULL) 1003 return B_BAD_TEAM_ID; 1004 1005 size = PAGE_ALIGN(size); 1006 1007 // create an null store object 1008 store = vm_store_create_null(); 1009 if (store == NULL) 1010 panic("vm_map_physical_memory: vm_store_create_null returned NULL"); 1011 cache = vm_cache_create(store); 1012 if (cache == NULL) 1013 panic("vm_map_physical_memory: vm_cache_create returned NULL"); 1014 cache_ref = vm_cache_ref_create(cache); 1015 if (cache_ref == NULL) 1016 panic("vm_map_physical_memory: vm_cache_ref_create returned NULL"); 1017 // tell the page scanner to skip over this area, no pages will be mapped here 1018 cache->scan_skip = 1; 1019 1020 vm_cache_acquire_ref(cache_ref, true); 1021 err = map_backing_store(aspace, store, address, 0, size, addressSpec, 0, B_KERNEL_READ_AREA, REGION_NO_PRIVATE_MAP, &area, name); 1022 vm_cache_release_ref(cache_ref); 1023 vm_put_aspace(aspace); 1024 if (err < 0) 1025 return err; 1026 1027 return area->id; 1028 } 1029 1030 1031 status_t 1032 vm_create_vnode_cache(void *vnode, struct vm_cache_ref **_cacheRef) 1033 { 1034 vm_cache_ref *cacheRef; 1035 vm_cache *cache; 1036 vm_store *store; 1037 1038 // create a vnode store object 1039 store = vm_create_vnode_store(vnode); 1040 if (store == NULL) { 1041 dprintf("vm_create_vnode_cache: couldn't create vnode store\n"); 1042 return B_NO_MEMORY; 1043 } 1044 1045 cache = vm_cache_create(store); 1046 if (cache == NULL) { 1047 dprintf("vm_create_vnode_cache: vm_cache_create returned NULL\n"); 1048 return B_NO_MEMORY; 1049 } 1050 1051 cacheRef = vm_cache_ref_create(cache); 1052 if (cacheRef == NULL) { 1053 dprintf("vm_create_vnode_cache: vm_cache_ref_create returned NULL\n"); 1054 return B_NO_MEMORY; 1055 } 1056 1057 // acquire the cache ref once to represent the ref that the vnode will have 1058 // this is one of the only places where we dont want to ref to ripple down to the store 1059 vm_cache_acquire_ref(cacheRef, false); 1060 1061 *_cacheRef = cacheRef; 1062 return B_OK; 1063 } 1064 1065 1066 /** Will map the file at the path specified by \a name to an area in memory. 1067 * The file will be mirrored beginning at the specified \a offset. The \a offset 1068 * and \a size arguments have to be page aligned. 1069 */ 1070 1071 static area_id 1072 _vm_map_file(aspace_id aid, const char *name, void **_address, uint32 addressSpec, 1073 size_t size, uint32 protection, uint32 mapping, const char *path, off_t offset, bool kernel) 1074 { 1075 vm_cache_ref *cacheRef; 1076 vm_area *area; 1077 void *vnode; 1078 status_t status; 1079 1080 // ToDo: maybe attach to an FD, not a path (or both, like VFS calls) 1081 // ToDo: check file access permissions (would be already done if the above were true) 1082 // ToDo: for binary files, we want to make sure that they get the 1083 // copy of a file at a given time, ie. later changes should not 1084 // make it into the mapped copy -- this will need quite some changes 1085 // to be done in a nice way 1086 1087 vm_address_space *aspace = vm_get_aspace_by_id(aid); 1088 if (aspace == NULL) 1089 return B_BAD_TEAM_ID; 1090 1091 TRACE(("_vm_map_file(\"%s\", offset = %Ld, size = %lu, mapping %ld)\n", path, offset, size, mapping)); 1092 1093 offset = ROUNDOWN(offset, B_PAGE_SIZE); 1094 size = PAGE_ALIGN(size); 1095 1096 // get the vnode for the object, this also grabs a ref to it 1097 status = vfs_get_vnode_from_path(path, kernel, &vnode); 1098 if (status < B_OK) 1099 goto err1; 1100 1101 status = vfs_get_vnode_cache(vnode, &cacheRef); 1102 if (status < B_OK) 1103 goto err2; 1104 1105 // acquire a ref to the cache before we do work on it. Dont ripple the ref acquision to the vnode 1106 // below because we'll have to release it later anyway, since we grabbed a ref to the vnode at 1107 // vfs_get_vnode_from_path(). This puts the ref counts in sync. 1108 vm_cache_acquire_ref(cacheRef, false); 1109 status = map_backing_store(aspace, cacheRef->cache->store, _address, offset, size, 1110 addressSpec, 0, protection, mapping, &area, name); 1111 vm_cache_release_ref(cacheRef); 1112 vm_put_aspace(aspace); 1113 1114 if (status < B_OK) 1115 return status; 1116 1117 return area->id; 1118 1119 err2: 1120 vfs_vnode_release_ref(vnode); 1121 err1: 1122 vm_put_aspace(aspace); 1123 return status; 1124 } 1125 1126 1127 area_id 1128 vm_map_file(aspace_id aid, const char *name, void **address, uint32 addressSpec, 1129 addr_t size, uint32 protection, uint32 mapping, const char *path, off_t offset) 1130 { 1131 if (!arch_vm_supports_protection(protection)) 1132 return B_NOT_SUPPORTED; 1133 1134 return _vm_map_file(aid, name, address, addressSpec, size, protection, mapping, path, offset, true); 1135 } 1136 1137 1138 // ToDo: create a BeOS style call for this! 1139 1140 area_id 1141 _user_vm_map_file(const char *uname, void **uaddress, int addressSpec, 1142 addr_t size, int protection, int mapping, const char *upath, off_t offset) 1143 { 1144 char name[B_OS_NAME_LENGTH]; 1145 char path[B_PATH_NAME_LENGTH]; 1146 void *address; 1147 int rc; 1148 1149 if (!IS_USER_ADDRESS(uname) || !IS_USER_ADDRESS(uaddress) || !IS_USER_ADDRESS(upath) 1150 || user_strlcpy(name, uname, B_OS_NAME_LENGTH) < B_OK 1151 || user_strlcpy(path, upath, B_PATH_NAME_LENGTH) < B_OK 1152 || user_memcpy(&address, uaddress, sizeof(address)) < B_OK) 1153 return B_BAD_ADDRESS; 1154 1155 // userland created areas can always be accessed by the kernel 1156 protection |= B_KERNEL_READ_AREA | (protection & B_WRITE_AREA ? B_KERNEL_WRITE_AREA : 0); 1157 1158 rc = _vm_map_file(vm_get_current_user_aspace_id(), name, &address, addressSpec, size, 1159 protection, mapping, path, offset, false); 1160 if (rc < 0) 1161 return rc; 1162 1163 if (user_memcpy(uaddress, &address, sizeof(address)) < B_OK) 1164 return B_BAD_ADDRESS; 1165 1166 return rc; 1167 } 1168 1169 1170 area_id 1171 vm_clone_area(aspace_id aid, const char *name, void **address, uint32 addressSpec, 1172 uint32 protection, uint32 mapping, area_id sourceID) 1173 { 1174 vm_area *newArea = NULL; 1175 vm_area *sourceArea; 1176 status_t status; 1177 1178 vm_address_space *aspace = vm_get_aspace_by_id(aid); 1179 if (aspace == NULL) 1180 return B_BAD_TEAM_ID; 1181 1182 sourceArea = vm_get_area(sourceID); 1183 if (sourceArea == NULL) { 1184 vm_put_aspace(aspace); 1185 return B_BAD_VALUE; 1186 } 1187 1188 // ToDo: for now, B_USER_CLONEABLE is disabled, until all drivers 1189 // have been adapted. Maybe it should be part of the kernel settings, 1190 // anyway (so that old drivers can always work). 1191 #if 0 1192 if (sourceArea->aspace == kernel_aspace && aspace != kernel_aspace 1193 && !(sourceArea->protection & B_USER_CLONEABLE_AREA)) { 1194 // kernel areas must not be cloned in userland, unless explicitly 1195 // declared user-cloneable upon construction 1196 status = B_NOT_ALLOWED; 1197 } else 1198 #endif 1199 { 1200 vm_cache_acquire_ref(sourceArea->cache_ref, true); 1201 status = map_backing_store(aspace, sourceArea->cache_ref->cache->store, address, 1202 sourceArea->cache_offset, sourceArea->size, addressSpec, sourceArea->wiring, 1203 protection, mapping, &newArea, name); 1204 vm_cache_release_ref(sourceArea->cache_ref); 1205 } 1206 1207 vm_put_area(sourceArea); 1208 vm_put_aspace(aspace); 1209 1210 if (status < B_OK) 1211 return status; 1212 1213 return newArea->id; 1214 } 1215 1216 1217 static status_t 1218 _vm_delete_area(vm_address_space *aspace, area_id id) 1219 { 1220 status_t status = B_OK; 1221 vm_area *area; 1222 1223 TRACE(("vm_delete_area: aspace id 0x%lx, area id 0x%lx\n", aspace->id, id)); 1224 1225 area = vm_get_area(id); 1226 if (area == NULL) 1227 return B_BAD_VALUE; 1228 1229 if (area->aspace == aspace) { 1230 vm_put_area(area); 1231 // next put below will actually delete it 1232 } else 1233 status = B_NOT_ALLOWED; 1234 1235 vm_put_area(area); 1236 return status; 1237 } 1238 1239 1240 status_t 1241 vm_delete_area(aspace_id aid, area_id rid) 1242 { 1243 vm_address_space *aspace; 1244 status_t err; 1245 1246 aspace = vm_get_aspace_by_id(aid); 1247 if (aspace == NULL) 1248 return B_BAD_TEAM_ID; 1249 1250 err = _vm_delete_area(aspace, rid); 1251 vm_put_aspace(aspace); 1252 return err; 1253 } 1254 1255 1256 static void 1257 remove_area_from_virtual_map(vm_address_space *addressSpace, vm_area *area, bool locked) 1258 { 1259 vm_area *temp, *last = NULL; 1260 1261 if (!locked) 1262 acquire_sem_etc(addressSpace->virtual_map.sem, WRITE_COUNT, 0, 0); 1263 1264 temp = addressSpace->virtual_map.areas; 1265 while (temp != NULL) { 1266 if (area == temp) { 1267 if (last != NULL) { 1268 last->aspace_next = temp->aspace_next; 1269 } else { 1270 addressSpace->virtual_map.areas = temp->aspace_next; 1271 } 1272 addressSpace->virtual_map.change_count++; 1273 break; 1274 } 1275 last = temp; 1276 temp = temp->aspace_next; 1277 } 1278 if (area == addressSpace->virtual_map.area_hint) 1279 addressSpace->virtual_map.area_hint = NULL; 1280 1281 if (!locked) 1282 release_sem_etc(addressSpace->virtual_map.sem, WRITE_COUNT, 0); 1283 1284 if (temp == NULL) 1285 panic("vm_area_release_ref: area not found in aspace's area list\n"); 1286 } 1287 1288 1289 static bool 1290 _vm_put_area(vm_area *area, bool aspaceLocked) 1291 { 1292 vm_address_space *aspace; 1293 bool removeit = false; 1294 1295 // we should never get here, but if we do, we can handle it 1296 if (area->id == RESERVED_AREA_ID) 1297 return false; 1298 1299 acquire_sem_etc(sAreaHashLock, WRITE_COUNT, 0, 0); 1300 if (atomic_add(&area->ref_count, -1) == 1) { 1301 hash_remove(sAreaHash, area); 1302 removeit = true; 1303 } 1304 release_sem_etc(sAreaHashLock, WRITE_COUNT, 0); 1305 1306 if (!removeit) 1307 return false; 1308 1309 aspace = area->aspace; 1310 1311 remove_area_from_virtual_map(aspace, area, aspaceLocked); 1312 1313 vm_cache_remove_area(area->cache_ref, area); 1314 vm_cache_release_ref(area->cache_ref); 1315 1316 (*aspace->translation_map.ops->lock)(&aspace->translation_map); 1317 (*aspace->translation_map.ops->unmap)(&aspace->translation_map, area->base, 1318 area->base + (area->size - 1)); 1319 (*aspace->translation_map.ops->unlock)(&aspace->translation_map); 1320 1321 // now we can give up the area's reference to the address space 1322 vm_put_aspace(aspace); 1323 1324 free(area->name); 1325 free(area); 1326 return true; 1327 } 1328 1329 1330 static bool 1331 vm_put_area(vm_area *area) 1332 { 1333 return _vm_put_area(area, false); 1334 } 1335 1336 1337 static status_t 1338 vm_copy_on_write_area(vm_area *area) 1339 { 1340 vm_store *store; 1341 vm_cache *upperCache, *lowerCache; 1342 vm_cache_ref *upperCacheRef, *lowerCacheRef; 1343 vm_translation_map *map; 1344 vm_page *page; 1345 uint32 protection; 1346 status_t status; 1347 1348 TRACE(("vm_copy_on_write_area(area = %p)\n", area)); 1349 1350 // We need to separate the vm_cache from its vm_cache_ref: the area 1351 // and its cache_ref goes into a new layer on top of the old one. 1352 // So the old cache gets a new cache_ref and the area a new cache. 1353 1354 upperCacheRef = area->cache_ref; 1355 lowerCache = upperCacheRef->cache; 1356 1357 // create an anonymous store object 1358 store = vm_store_create_anonymous_noswap(false, 0); 1359 if (store == NULL) 1360 return B_NO_MEMORY; 1361 1362 upperCache = vm_cache_create(store); 1363 if (upperCache == NULL) { 1364 status = B_NO_MEMORY; 1365 goto err1; 1366 } 1367 1368 lowerCacheRef = vm_cache_ref_create(lowerCache); 1369 if (lowerCacheRef == NULL) { 1370 status = B_NO_MEMORY; 1371 goto err2; 1372 } 1373 1374 // The area must be readable in the same way it was previously writable 1375 protection = B_KERNEL_READ_AREA; 1376 if (area->protection & B_READ_AREA) 1377 protection |= B_READ_AREA; 1378 1379 // we need to hold the cache_ref lock when we want to switch its cache 1380 mutex_lock(&upperCacheRef->lock); 1381 mutex_lock(&lowerCacheRef->lock); 1382 1383 // ToDo: add a child counter to vm_cache - so that we can collapse a 1384 // cache layer when possible (ie. "the other" area was deleted) 1385 upperCache->temporary = 1; 1386 upperCache->scan_skip = lowerCache->scan_skip; 1387 upperCache->source = lowerCache; 1388 upperCache->ref = upperCacheRef; 1389 upperCacheRef->cache = upperCache; 1390 1391 // we need to manually alter the ref_count 1392 lowerCacheRef->ref_count = upperCacheRef->ref_count; 1393 upperCacheRef->ref_count = 1; 1394 1395 // grab a ref to the cache object we're now linked to as a source 1396 vm_cache_acquire_ref(lowerCacheRef, true); 1397 1398 // We now need to remap all pages from the area read-only, so that 1399 // a copy will be created on next write access 1400 1401 map = &area->aspace->translation_map; 1402 map->ops->lock(map); 1403 map->ops->unmap(map, area->base, area->base + area->size - 1); 1404 1405 for (page = lowerCache->page_list; page; page = page->cache_next) { 1406 map->ops->map(map, area->base + page->offset, page->ppn * B_PAGE_SIZE, protection); 1407 } 1408 1409 map->ops->unlock(map); 1410 1411 mutex_unlock(&lowerCacheRef->lock); 1412 mutex_unlock(&upperCacheRef->lock); 1413 1414 return B_OK; 1415 1416 err2: 1417 free(upperCache); 1418 err1: 1419 store->ops->destroy(store); 1420 return status; 1421 } 1422 1423 1424 area_id 1425 vm_copy_area(aspace_id addressSpaceID, const char *name, void **_address, uint32 addressSpec, 1426 uint32 protection, area_id sourceID) 1427 { 1428 vm_address_space *addressSpace; 1429 vm_cache_ref *cacheRef; 1430 vm_area *target, *source; 1431 status_t status; 1432 1433 if ((protection & B_KERNEL_PROTECTION) == 0) 1434 protection |= B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA; 1435 1436 if ((source = vm_get_area(sourceID)) == NULL) 1437 return B_BAD_VALUE; 1438 1439 addressSpace = vm_get_aspace_by_id(addressSpaceID); 1440 cacheRef = source->cache_ref; 1441 1442 if (addressSpec == B_CLONE_ADDRESS) { 1443 addressSpec = B_EXACT_ADDRESS; 1444 *_address = (void *)source->base; 1445 } 1446 1447 // First, create a cache on top of the source area 1448 1449 status = map_backing_store(addressSpace, cacheRef->cache->store, _address, 1450 source->cache_offset, source->size, addressSpec, source->wiring, protection, 1451 protection & (B_KERNEL_WRITE_AREA | B_WRITE_AREA) ? REGION_PRIVATE_MAP : REGION_NO_PRIVATE_MAP, 1452 &target, name); 1453 1454 if (status < B_OK) 1455 goto err; 1456 1457 // If the source area is writable, we need to move it one layer up as well 1458 1459 if ((source->protection & (B_KERNEL_WRITE_AREA | B_WRITE_AREA)) != 0) 1460 vm_copy_on_write_area(source); 1461 1462 // we want to return the ID of the newly created area 1463 status = target->id; 1464 1465 err: 1466 vm_put_aspace(addressSpace); 1467 vm_put_area(source); 1468 1469 return status; 1470 } 1471 1472 1473 static int32 1474 count_writable_areas(vm_cache_ref *ref, vm_area *ignoreArea) 1475 { 1476 struct vm_area *area = ref->areas; 1477 uint32 count = 0; 1478 1479 for (; area != NULL; area = area->cache_next) { 1480 if (area != ignoreArea 1481 && (area->protection & (B_WRITE_AREA | B_KERNEL_WRITE_AREA)) != 0) 1482 count++; 1483 } 1484 1485 return count; 1486 } 1487 1488 1489 static status_t 1490 vm_set_area_protection(aspace_id aspaceID, area_id areaID, uint32 newProtection) 1491 { 1492 vm_cache_ref *cacheRef; 1493 vm_cache *cache; 1494 vm_area *area; 1495 status_t status = B_OK; 1496 1497 TRACE(("vm_set_area_protection(aspace = %#lx, area = %#lx, protection = %#lx)\n", 1498 aspaceID, areaID, newProtection)); 1499 1500 if (!arch_vm_supports_protection(newProtection)) 1501 return B_NOT_SUPPORTED; 1502 1503 area = vm_get_area(areaID); 1504 if (area == NULL) 1505 return B_BAD_VALUE; 1506 1507 if (aspaceID != vm_get_kernel_aspace_id() && area->aspace->id != aspaceID) { 1508 // unless you're the kernel, you are only allowed to set 1509 // the protection of your own areas 1510 vm_put_area(area); 1511 return B_NOT_ALLOWED; 1512 } 1513 1514 cacheRef = area->cache_ref; 1515 cache = cacheRef->cache; 1516 1517 mutex_lock(&cacheRef->lock); 1518 1519 if ((area->protection & (B_WRITE_AREA | B_KERNEL_WRITE_AREA)) != 0 1520 && (newProtection & (B_WRITE_AREA | B_KERNEL_WRITE_AREA)) == 0) { 1521 // change from read/write to read-only 1522 1523 if (cache->source != NULL && cache->temporary) { 1524 if (count_writable_areas(cacheRef, area) == 0) { 1525 // Since this cache now lives from the pages in its source cache, 1526 // we can change the cache's commitment to take only those pages 1527 // into account that really are in this cache. 1528 1529 // count existing pages in this cache 1530 struct vm_page *page = cache->page_list; 1531 uint32 count = 0; 1532 1533 for (; page != NULL; page = page->cache_next) { 1534 count++; 1535 } 1536 1537 status = cache->store->ops->commit(cache->store, count * B_PAGE_SIZE); 1538 1539 // ToDo: we may be able to join with our source cache, if count == 0 1540 } 1541 } 1542 } else if ((area->protection & (B_WRITE_AREA | B_KERNEL_WRITE_AREA)) == 0 1543 && (newProtection & (B_WRITE_AREA | B_KERNEL_WRITE_AREA)) != 0) { 1544 // change from read-only to read/write 1545 1546 // ToDo: if this is a shared cache, insert new cache (we only know about other 1547 // areas in this cache yet, though, not about child areas) 1548 // -> use this call with care, it might currently have unwanted consequences 1549 // because of this. It should always be safe though, if there are no other 1550 // (child) areas referencing this area's cache (you just might not know). 1551 if (count_writable_areas(cacheRef, area) == 0 1552 && (cacheRef->areas != area || area->cache_next)) { 1553 // ToDo: child areas are not tested for yet 1554 dprintf("set_area_protection(): warning, would need to insert a new cache_ref (not yet implemented)!\n"); 1555 status = B_NOT_ALLOWED; 1556 } else 1557 dprintf("set_area_protection() may not work correctly yet in this direction!\n"); 1558 1559 if (status == B_OK && cache->source != NULL && cache->temporary) { 1560 // the cache's commitment must contain all possible pages 1561 status = cache->store->ops->commit(cache->store, cache->virtual_size); 1562 } 1563 } else { 1564 // we don't have anything special to do in all other cases 1565 } 1566 1567 if (status == B_OK && area->protection != newProtection) { 1568 // remap existing pages in this cache 1569 struct vm_translation_map *map = &area->aspace->translation_map; 1570 1571 map->ops->lock(map); 1572 map->ops->protect(map, area->base, area->base + area->size, newProtection); 1573 map->ops->unlock(map); 1574 1575 area->protection = newProtection; 1576 } 1577 1578 mutex_unlock(&cacheRef->lock); 1579 vm_put_area(area); 1580 1581 return status; 1582 } 1583 1584 1585 status_t 1586 vm_get_page_mapping(aspace_id aid, addr_t vaddr, addr_t *paddr) 1587 { 1588 vm_address_space *aspace; 1589 uint32 null_flags; 1590 status_t err; 1591 1592 aspace = vm_get_aspace_by_id(aid); 1593 if (aspace == NULL) 1594 return B_BAD_TEAM_ID; 1595 1596 err = aspace->translation_map.ops->query(&aspace->translation_map, 1597 vaddr, paddr, &null_flags); 1598 1599 vm_put_aspace(aspace); 1600 return err; 1601 } 1602 1603 1604 static int 1605 display_mem(int argc, char **argv) 1606 { 1607 int item_size; 1608 int display_width; 1609 int num = 1; 1610 addr_t address; 1611 int i; 1612 int j; 1613 1614 if (argc < 2) { 1615 dprintf("usage: dw/ds/db <address> [num]\n" 1616 "\tdw - 4 bytes\n" 1617 "\tds - 2 bytes\n" 1618 "\tdb - 1 byte\n"); 1619 return 0; 1620 } 1621 1622 address = strtoul(argv[1], NULL, 0); 1623 1624 if (argc >= 3) { 1625 num = -1; 1626 num = atoi(argv[2]); 1627 } 1628 1629 // build the format string 1630 if (strcmp(argv[0], "db") == 0) { 1631 item_size = 1; 1632 display_width = 16; 1633 } else if (strcmp(argv[0], "ds") == 0) { 1634 item_size = 2; 1635 display_width = 8; 1636 } else if (strcmp(argv[0], "dw") == 0) { 1637 item_size = 4; 1638 display_width = 4; 1639 } else { 1640 dprintf("display_mem called in an invalid way!\n"); 1641 return 0; 1642 } 1643 1644 dprintf("[0x%lx] '", address); 1645 for (j = 0; j < min_c(display_width, num) * item_size; j++) { 1646 char c = *((char *)address + j); 1647 if (!isalnum(c)) { 1648 c = '.'; 1649 } 1650 dprintf("%c", c); 1651 } 1652 dprintf("'"); 1653 for (i = 0; i < num; i++) { 1654 if ((i % display_width) == 0 && i != 0) { 1655 dprintf("\n[0x%lx] '", address + i * item_size); 1656 for (j = 0; j < min_c(display_width, (num-i)) * item_size; j++) { 1657 char c = *((char *)address + i * item_size + j); 1658 if (!isalnum(c)) { 1659 c = '.'; 1660 } 1661 dprintf("%c", c); 1662 } 1663 dprintf("'"); 1664 } 1665 1666 switch (item_size) { 1667 case 1: 1668 dprintf(" 0x%02x", *((uint8 *)address + i)); 1669 break; 1670 case 2: 1671 dprintf(" 0x%04x", *((uint16 *)address + i)); 1672 break; 1673 case 4: 1674 dprintf(" 0x%08lx", *((uint32 *)address + i)); 1675 break; 1676 default: 1677 dprintf("huh?\n"); 1678 } 1679 } 1680 dprintf("\n"); 1681 return 0; 1682 } 1683 1684 1685 static int 1686 dump_cache_ref(int argc, char **argv) 1687 { 1688 addr_t address; 1689 vm_area *area; 1690 vm_cache_ref *cache_ref; 1691 1692 if (argc < 2) { 1693 dprintf("cache_ref: not enough arguments\n"); 1694 return 0; 1695 } 1696 if (strlen(argv[1]) < 2 || argv[1][0] != '0' || argv[1][1] != 'x') { 1697 dprintf("cache_ref: invalid argument, pass address\n"); 1698 return 0; 1699 } 1700 1701 address = atoul(argv[1]); 1702 cache_ref = (vm_cache_ref *)address; 1703 1704 dprintf("cache_ref at %p:\n", cache_ref); 1705 dprintf("cache: %p\n", cache_ref->cache); 1706 dprintf("lock.holder: %ld\n", cache_ref->lock.holder); 1707 dprintf("lock.sem: 0x%lx\n", cache_ref->lock.sem); 1708 dprintf("areas:\n"); 1709 for (area = cache_ref->areas; area != NULL; area = area->cache_next) { 1710 dprintf(" area 0x%lx: ", area->id); 1711 dprintf("base_addr = 0x%lx ", area->base); 1712 dprintf("size = 0x%lx ", area->size); 1713 dprintf("name = '%s' ", area->name); 1714 dprintf("protection = 0x%lx\n", area->protection); 1715 } 1716 dprintf("ref_count: %ld\n", cache_ref->ref_count); 1717 return 0; 1718 } 1719 1720 1721 static const char * 1722 page_state_to_text(int state) 1723 { 1724 switch(state) { 1725 case PAGE_STATE_ACTIVE: 1726 return "active"; 1727 case PAGE_STATE_INACTIVE: 1728 return "inactive"; 1729 case PAGE_STATE_BUSY: 1730 return "busy"; 1731 case PAGE_STATE_MODIFIED: 1732 return "modified"; 1733 case PAGE_STATE_FREE: 1734 return "free"; 1735 case PAGE_STATE_CLEAR: 1736 return "clear"; 1737 case PAGE_STATE_WIRED: 1738 return "wired"; 1739 case PAGE_STATE_UNUSED: 1740 return "unused"; 1741 default: 1742 return "unknown"; 1743 } 1744 } 1745 1746 1747 static int 1748 dump_cache(int argc, char **argv) 1749 { 1750 addr_t address; 1751 vm_cache *cache; 1752 vm_page *page; 1753 1754 if (argc < 2) { 1755 dprintf("cache: not enough arguments\n"); 1756 return 0; 1757 } 1758 if (strlen(argv[1]) < 2 || argv[1][0] != '0' || argv[1][1] != 'x') { 1759 dprintf("cache: invalid argument, pass address\n"); 1760 return 0; 1761 } 1762 1763 address = atoul(argv[1]); 1764 cache = (vm_cache *)address; 1765 1766 dprintf("cache at %p:\n", cache); 1767 dprintf("cache_ref: %p\n", cache->ref); 1768 dprintf("source: %p\n", cache->source); 1769 dprintf("store: %p\n", cache->store); 1770 // XXX 64-bit 1771 dprintf("virtual_size: 0x%Lx\n", cache->virtual_size); 1772 dprintf("temporary: %ld\n", cache->temporary); 1773 dprintf("scan_skip: %ld\n", cache->scan_skip); 1774 dprintf("page_list:\n"); 1775 for (page = cache->page_list; page != NULL; page = page->cache_next) { 1776 // XXX offset is 64-bit 1777 if (page->type == PAGE_TYPE_PHYSICAL) { 1778 dprintf(" %p ppn 0x%lx offset 0x%Lx type %ld state %ld (%s) ref_count %ld\n", 1779 page, page->ppn, page->offset, page->type, page->state, 1780 page_state_to_text(page->state), page->ref_count); 1781 } else if(page->type == PAGE_TYPE_DUMMY) { 1782 dprintf(" %p DUMMY PAGE state %ld (%s)\n", 1783 page, page->state, page_state_to_text(page->state)); 1784 } else 1785 dprintf(" %p UNKNOWN PAGE type %ld\n", page, page->type); 1786 } 1787 return 0; 1788 } 1789 1790 1791 static void 1792 _dump_area(vm_area *area) 1793 { 1794 dprintf("dump of area at %p:\n", area); 1795 dprintf("name: '%s'\n", area->name); 1796 dprintf("id: 0x%lx\n", area->id); 1797 dprintf("base: 0x%lx\n", area->base); 1798 dprintf("size: 0x%lx\n", area->size); 1799 dprintf("protection: 0x%lx\n", area->protection); 1800 dprintf("wiring: 0x%lx\n", area->wiring); 1801 dprintf("ref_count: %ld\n", area->ref_count); 1802 dprintf("cache_ref: %p\n", area->cache_ref); 1803 // XXX 64-bit 1804 dprintf("cache_offset: 0x%Lx\n", area->cache_offset); 1805 dprintf("cache_next: %p\n", area->cache_next); 1806 dprintf("cache_prev: %p\n", area->cache_prev); 1807 } 1808 1809 1810 static int 1811 dump_area(int argc, char **argv) 1812 { 1813 // int i; 1814 vm_area *area; 1815 1816 if (argc < 2) { 1817 dprintf("area: not enough arguments\n"); 1818 return 0; 1819 } 1820 1821 // if the argument looks like a hex number, treat it as such 1822 if (strlen(argv[1]) > 2 && argv[1][0] == '0' && argv[1][1] == 'x') { 1823 uint32 num = strtoul(argv[1], NULL, 16); 1824 area_id id = num; 1825 1826 area = (vm_area *)hash_lookup(sAreaHash, &id); 1827 if (area == NULL) { 1828 dprintf("invalid area id\n"); 1829 } else { 1830 _dump_area(area); 1831 } 1832 return 0; 1833 } else { 1834 // walk through the area list, looking for the arguments as a name 1835 struct hash_iterator iter; 1836 1837 hash_open(sAreaHash, &iter); 1838 while ((area = (vm_area *)hash_next(sAreaHash, &iter)) != NULL) { 1839 if (area->name != NULL && strcmp(argv[1], area->name) == 0) { 1840 _dump_area(area); 1841 } 1842 } 1843 } 1844 return 0; 1845 } 1846 1847 1848 static int 1849 dump_area_list(int argc, char **argv) 1850 { 1851 vm_area *area; 1852 struct hash_iterator iter; 1853 1854 dprintf("addr\t id base\t\tsize\t\tprotect\tlock\tname\n"); 1855 1856 hash_open(sAreaHash, &iter); 1857 while ((area = (vm_area *)hash_next(sAreaHash, &iter)) != NULL) { 1858 dprintf("%p %5lx %p\t%p\t%ld\t%ld\t%s\n", area, area->id, (void *)area->base, 1859 (void *)area->size, area->protection, area->wiring, area->name); 1860 } 1861 hash_close(sAreaHash, &iter, false); 1862 return 0; 1863 } 1864 1865 1866 status_t 1867 vm_delete_areas(struct vm_address_space *aspace) 1868 { 1869 vm_area *area; 1870 vm_area *next, *last = NULL; 1871 1872 TRACE(("vm_delete_areas: called on aspace 0x%lx\n", aspace->id)); 1873 1874 acquire_sem_etc(aspace->virtual_map.sem, WRITE_COUNT, 0, 0); 1875 1876 // remove all reserved areas in this address space 1877 1878 for (area = aspace->virtual_map.areas; area; area = next) { 1879 next = area->aspace_next; 1880 1881 if (area->id == RESERVED_AREA_ID) { 1882 // just remove it 1883 if (last) 1884 last->aspace_next = area->aspace_next; 1885 else 1886 aspace->virtual_map.areas = area->aspace_next; 1887 1888 free(area); 1889 continue; 1890 } 1891 1892 last = area; 1893 } 1894 1895 // delete all the areas in this aspace 1896 1897 for (area = aspace->virtual_map.areas; area; area = next) { 1898 next = area->aspace_next; 1899 1900 // decrement the ref on this area, may actually push the ref < 0, if there 1901 // is a concurrent delete_area() on that specific area, but that's ok here 1902 if (!_vm_put_area(area, true)) 1903 dprintf("vm_delete_areas() did not delete area %p\n", area); 1904 } 1905 1906 release_sem_etc(aspace->virtual_map.sem, WRITE_COUNT, 0); 1907 1908 return B_OK; 1909 } 1910 1911 1912 static area_id 1913 vm_area_for(aspace_id aid, addr_t address) 1914 { 1915 vm_address_space *addressSpace; 1916 area_id id = B_ERROR; 1917 vm_area *area; 1918 1919 addressSpace = vm_get_aspace_by_id(aid); 1920 if (addressSpace == NULL) 1921 return B_BAD_TEAM_ID; 1922 1923 acquire_sem_etc(addressSpace->virtual_map.sem, READ_COUNT, 0, 0); 1924 1925 area = addressSpace->virtual_map.areas; 1926 for (; area != NULL; area = area->aspace_next) { 1927 // ignore reserved space regions 1928 if (area->id == RESERVED_AREA_ID) 1929 continue; 1930 1931 if (address >= area->base && address < area->base + area->size) { 1932 id = area->id; 1933 break; 1934 } 1935 } 1936 1937 release_sem_etc(addressSpace->virtual_map.sem, READ_COUNT, 0); 1938 vm_put_aspace(addressSpace); 1939 1940 return id; 1941 } 1942 1943 1944 static void 1945 unmap_and_free_physical_pages(vm_translation_map *map, addr_t start, addr_t end) 1946 { 1947 // free all physical pages in the specified range 1948 1949 for (addr_t current = start; current < end; current += B_PAGE_SIZE) { 1950 addr_t physicalAddress; 1951 uint32 flags; 1952 1953 if (map->ops->query(map, current, &physicalAddress, &flags) == B_OK) { 1954 vm_page *page = vm_lookup_page(current / B_PAGE_SIZE); 1955 if (page != NULL) 1956 vm_page_set_state(page, PAGE_STATE_FREE); 1957 } 1958 } 1959 1960 // unmap the memory 1961 map->ops->unmap(map, start, end - 1); 1962 } 1963 1964 1965 void 1966 vm_free_unused_boot_loader_range(addr_t start, addr_t size) 1967 { 1968 vm_translation_map *map = &kernel_aspace->translation_map; 1969 addr_t end = start + size; 1970 addr_t lastEnd = start; 1971 vm_area *area; 1972 1973 TRACE(("vm_free_unused_boot_loader_range(): asked to free %p - %p\n", (void *)start, (void *)end)); 1974 1975 // The areas are sorted in virtual address space order, so 1976 // we just have to find the holes between them that fall 1977 // into the area we should dispose 1978 1979 map->ops->lock(map); 1980 1981 for (area = kernel_aspace->virtual_map.areas; area; area = area->aspace_next) { 1982 addr_t areaStart = area->base; 1983 addr_t areaEnd = areaStart + area->size; 1984 1985 if (area->id == RESERVED_AREA_ID) 1986 continue; 1987 1988 if (areaEnd >= end) { 1989 // we are done, the areas are already beyond of what we have to free 1990 lastEnd = end; 1991 break; 1992 } 1993 1994 if (areaStart > lastEnd) { 1995 // this is something we can free 1996 TRACE(("free boot range: get rid of %p - %p\n", (void *)lastEnd, (void *)areaStart)); 1997 unmap_and_free_physical_pages(map, lastEnd, areaStart); 1998 } 1999 2000 lastEnd = areaEnd; 2001 } 2002 2003 if (lastEnd < end) { 2004 // we can also get rid of some space at the end of the area 2005 TRACE(("free boot range: also remove %p - %p\n", (void *)lastEnd, (void *)end)); 2006 unmap_and_free_physical_pages(map, lastEnd, end); 2007 } 2008 2009 map->ops->unlock(map); 2010 } 2011 2012 2013 static void 2014 create_preloaded_image_areas(struct preloaded_image *image) 2015 { 2016 char name[B_OS_NAME_LENGTH]; 2017 void *address; 2018 int32 length; 2019 2020 // use file name to create a good area name 2021 char *fileName = strrchr(image->name, '/'); 2022 if (fileName == NULL) 2023 fileName = image->name; 2024 else 2025 fileName++; 2026 2027 length = strlen(fileName); 2028 // make sure there is enough space for the suffix 2029 if (length > 25) 2030 length = 25; 2031 2032 memcpy(name, fileName, length); 2033 strcpy(name + length, "_text"); 2034 address = (void *)ROUNDOWN(image->text_region.start, B_PAGE_SIZE); 2035 image->text_region.id = create_area(name, &address, B_EXACT_ADDRESS, 2036 PAGE_ALIGN(image->text_region.size), B_ALREADY_WIRED, 2037 B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA); 2038 2039 strcpy(name + length, "_data"); 2040 address = (void *)ROUNDOWN(image->data_region.start, B_PAGE_SIZE); 2041 image->data_region.id = create_area(name, &address, B_EXACT_ADDRESS, 2042 PAGE_ALIGN(image->data_region.size), B_ALREADY_WIRED, 2043 B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA); 2044 } 2045 2046 2047 /** Frees all previously kernel arguments areas from the kernel_args structure. 2048 * Any boot loader resources contained in that arguments must not be accessed 2049 * anymore past this point. 2050 */ 2051 2052 void 2053 vm_free_kernel_args(kernel_args *args) 2054 { 2055 uint32 i; 2056 2057 TRACE(("vm_free_kernel_args()\n")); 2058 2059 for (i = 0; i < args->num_kernel_args_ranges; i++) { 2060 area_id area = area_for((void *)args->kernel_args_range[i].start); 2061 if (area >= B_OK) 2062 delete_area(area); 2063 } 2064 } 2065 2066 2067 static void 2068 allocate_kernel_args(kernel_args *args) 2069 { 2070 uint32 i; 2071 2072 TRACE(("allocate_kernel_args()\n")); 2073 2074 for (i = 0; i < args->num_kernel_args_ranges; i++) { 2075 void *address = (void *)args->kernel_args_range[i].start; 2076 2077 create_area("_kernel args_", &address, B_EXACT_ADDRESS, args->kernel_args_range[i].size, 2078 B_ALREADY_WIRED, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA); 2079 } 2080 } 2081 2082 2083 static void 2084 unreserve_boot_loader_ranges(kernel_args *args) 2085 { 2086 uint32 i; 2087 2088 TRACE(("unreserve_boot_loader_ranges()\n")); 2089 2090 for (i = 0; i < args->num_virtual_allocated_ranges; i++) { 2091 vm_unreserve_address_range(vm_get_kernel_aspace_id(), 2092 (void *)args->virtual_allocated_range[i].start, 2093 args->virtual_allocated_range[i].size); 2094 } 2095 } 2096 2097 2098 static void 2099 reserve_boot_loader_ranges(kernel_args *args) 2100 { 2101 uint32 i; 2102 2103 TRACE(("reserve_boot_loader_ranges()\n")); 2104 2105 for (i = 0; i < args->num_virtual_allocated_ranges; i++) { 2106 void *address = (void *)args->virtual_allocated_range[i].start; 2107 status_t status = vm_reserve_address_range(vm_get_kernel_aspace_id(), &address, 2108 B_EXACT_ADDRESS, args->virtual_allocated_range[i].size, 0); 2109 if (status < B_OK) 2110 panic("could not reserve boot loader ranges\n"); 2111 } 2112 } 2113 2114 2115 status_t 2116 vm_init(kernel_args *args) 2117 { 2118 struct preloaded_image *image; 2119 addr_t heap_base; 2120 void *address; 2121 status_t err = 0; 2122 uint32 i; 2123 2124 TRACE(("vm_init: entry\n")); 2125 err = arch_vm_translation_map_init(args); 2126 err = arch_vm_init(args); 2127 2128 // initialize some globals 2129 sNextAreaID = 1; 2130 sAreaHashLock = -1; 2131 2132 // map in the new heap and initialize it 2133 heap_base = vm_alloc_from_kernel_args(args, HEAP_SIZE, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA); 2134 TRACE(("heap at 0x%lx\n", heap_base)); 2135 heap_init(heap_base); 2136 2137 // initialize the free page list and physical page mapper 2138 vm_page_init(args); 2139 sAvailableMemory = vm_page_num_pages() * B_PAGE_SIZE; 2140 2141 // initialize the hash table that stores the pages mapped to caches 2142 vm_cache_init(args); 2143 2144 { 2145 vm_area *area; 2146 sAreaHash = hash_init(REGION_HASH_TABLE_SIZE, (addr_t)&area->hash_next - (addr_t)area, 2147 &area_compare, &area_hash); 2148 if (sAreaHash == NULL) 2149 panic("vm_init: error creating aspace hash table\n"); 2150 } 2151 2152 vm_aspace_init(); 2153 reserve_boot_loader_ranges(args); 2154 2155 // do any further initialization that the architecture dependant layers may need now 2156 arch_vm_translation_map_init_post_area(args); 2157 arch_vm_init_post_area(args); 2158 vm_page_init_post_area(args); 2159 2160 // allocate areas to represent stuff that already exists 2161 2162 address = (void *)ROUNDOWN(heap_base, B_PAGE_SIZE); 2163 create_area("kernel heap", &address, B_EXACT_ADDRESS, HEAP_SIZE, 2164 B_ALREADY_WIRED, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA); 2165 2166 allocate_kernel_args(args); 2167 2168 args->kernel_image.name = "kernel"; 2169 // the lazy boot loader currently doesn't set the kernel's name... 2170 create_preloaded_image_areas(&args->kernel_image); 2171 2172 // allocate areas for preloaded images 2173 for (image = args->preloaded_images; image != NULL; image = image->next) { 2174 create_preloaded_image_areas(image); 2175 } 2176 2177 // allocate kernel stacks 2178 for (i = 0; i < args->num_cpus; i++) { 2179 char name[64]; 2180 2181 sprintf(name, "idle thread %lu kstack", i + 1); 2182 address = (void *)args->cpu_kstack[i].start; 2183 create_area(name, &address, B_EXACT_ADDRESS, args->cpu_kstack[i].size, 2184 B_ALREADY_WIRED, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA); 2185 } 2186 { 2187 void *null; 2188 vm_map_physical_memory(vm_get_kernel_aspace_id(), "bootdir", &null, B_ANY_KERNEL_ADDRESS, 2189 args->bootdir_addr.size, B_KERNEL_READ_AREA, args->bootdir_addr.start); 2190 } 2191 2192 // add some debugger commands 2193 add_debugger_command("areas", &dump_area_list, "Dump a list of all areas"); 2194 add_debugger_command("area", &dump_area, "Dump info about a particular area"); 2195 add_debugger_command("cache_ref", &dump_cache_ref, "Dump cache_ref data structure"); 2196 add_debugger_command("cache", &dump_cache, "Dump cache_ref data structure"); 2197 // add_debugger_command("dl", &display_mem, "dump memory long words (64-bit)"); 2198 add_debugger_command("dw", &display_mem, "dump memory words (32-bit)"); 2199 add_debugger_command("ds", &display_mem, "dump memory shorts (16-bit)"); 2200 add_debugger_command("db", &display_mem, "dump memory bytes (8-bit)"); 2201 2202 TRACE(("vm_init: exit\n")); 2203 2204 return err; 2205 } 2206 2207 2208 status_t 2209 vm_init_post_sem(kernel_args *args) 2210 { 2211 vm_area *area; 2212 2213 // This frees all unused boot loader resources and makes its space available again 2214 arch_vm_init_end(args); 2215 unreserve_boot_loader_ranges(args); 2216 2217 // fill in all of the semaphores that were not allocated before 2218 // since we're still single threaded and only the kernel address space exists, 2219 // it isn't that hard to find all of the ones we need to create 2220 2221 benaphore_init(&sAvailableMemoryLock, "available memory lock"); 2222 arch_vm_translation_map_init_post_sem(args); 2223 vm_aspace_init_post_sem(); 2224 2225 for (area = kernel_aspace->virtual_map.areas; area; area = area->aspace_next) { 2226 if (area->id == RESERVED_AREA_ID) 2227 continue; 2228 2229 if (area->cache_ref->lock.sem < 0) 2230 mutex_init(&area->cache_ref->lock, "cache_ref_mutex"); 2231 } 2232 2233 sAreaHashLock = create_sem(WRITE_COUNT, "area hash"); 2234 2235 return heap_init_post_sem(args); 2236 } 2237 2238 2239 status_t 2240 vm_init_post_thread(kernel_args *args) 2241 { 2242 vm_page_init_post_thread(args); 2243 vm_daemon_init(); 2244 vm_low_memory_init(); 2245 2246 return heap_init_post_thread(args); 2247 } 2248 2249 2250 void 2251 permit_page_faults(void) 2252 { 2253 struct thread *thread = thread_get_current_thread(); 2254 if (thread != NULL) 2255 atomic_add(&thread->page_faults_allowed, 1); 2256 } 2257 2258 2259 void 2260 forbid_page_faults(void) 2261 { 2262 struct thread *thread = thread_get_current_thread(); 2263 if (thread != NULL) 2264 atomic_add(&thread->page_faults_allowed, -1); 2265 } 2266 2267 2268 status_t 2269 vm_page_fault(addr_t address, addr_t fault_address, bool is_write, bool is_user, addr_t *newip) 2270 { 2271 int err; 2272 2273 FTRACE(("vm_page_fault: page fault at 0x%lx, ip 0x%lx\n", address, fault_address)); 2274 2275 *newip = 0; 2276 2277 err = vm_soft_fault(address, is_write, is_user); 2278 if (err < 0) { 2279 dprintf("vm_page_fault: vm_soft_fault returned error %d on fault at 0x%lx, ip 0x%lx, write %d, user %d, thread 0x%lx\n", 2280 err, address, fault_address, is_write, is_user, thread_get_current_thread_id()); 2281 if (!is_user) { 2282 struct thread *t = thread_get_current_thread(); 2283 if (t && t->fault_handler != 0) { 2284 // this will cause the arch dependant page fault handler to 2285 // modify the IP on the interrupt frame or whatever to return 2286 // to this address 2287 *newip = t->fault_handler; 2288 } else { 2289 // unhandled page fault in the kernel 2290 panic("vm_page_fault: unhandled page fault in kernel space at 0x%lx, ip 0x%lx\n", 2291 address, fault_address); 2292 } 2293 } else { 2294 #if 1 2295 // ToDo: remove me once we have proper userland debugging support (and tools) 2296 vm_address_space *aspace = vm_get_current_user_aspace(); 2297 vm_virtual_map *map = &aspace->virtual_map; 2298 vm_area *area; 2299 2300 acquire_sem_etc(map->sem, READ_COUNT, 0, 0); 2301 area = vm_virtual_map_lookup(map, fault_address); 2302 2303 dprintf("vm_page_fault: killing team 0x%lx, ip %#lx (\"%s\" +%#lx)\n", 2304 thread_get_current_thread()->team->id, fault_address, 2305 area ? area->name : "???", fault_address - (area ? area->base : 0x0)); 2306 2307 // We can print a stack trace of the userland thread here. Since we're accessing 2308 // user memory freely and unchecked, this is not enabled by default. 2309 #if 0 2310 if (area) { 2311 struct stack_frame { 2312 #ifdef __INTEL__ 2313 struct stack_frame* previous; 2314 void* return_address; 2315 #else 2316 // ... 2317 #endif 2318 }; 2319 struct iframe *iframe = i386_get_user_iframe(); 2320 struct stack_frame *frame = (struct stack_frame *)iframe->ebp; 2321 2322 dprintf("stack trace:\n"); 2323 for (; frame; frame = frame->previous) { 2324 dprintf(" 0x%p", frame->return_address); 2325 area = vm_virtual_map_lookup(map, 2326 (addr_t)frame->return_address); 2327 if (area) { 2328 dprintf(" (%s + %#lx)", area->name, 2329 (addr_t)frame->return_address - area->base); 2330 } 2331 dprintf("\n"); 2332 } 2333 } 2334 #endif // 0 (stack trace) 2335 2336 release_sem_etc(map->sem, READ_COUNT, 0); 2337 vm_put_aspace(aspace); 2338 #endif 2339 if (user_debug_exception_occurred(B_SEGMENT_VIOLATION, SIGSEGV)) 2340 send_signal(team_get_current_team_id(), SIGSEGV); 2341 } 2342 } 2343 2344 return B_HANDLED_INTERRUPT; 2345 } 2346 2347 2348 static status_t 2349 vm_soft_fault(addr_t originalAddress, bool isWrite, bool isUser) 2350 { 2351 vm_address_space *aspace; 2352 vm_virtual_map *map; 2353 vm_area *area; 2354 vm_cache_ref *cache_ref; 2355 vm_cache_ref *last_cache_ref; 2356 vm_cache_ref *top_cache_ref; 2357 off_t cache_offset; 2358 vm_page dummy_page; 2359 vm_page *page = NULL; 2360 addr_t address; 2361 int change_count; 2362 int err; 2363 2364 FTRACE(("vm_soft_fault: thid 0x%lx address 0x%lx, isWrite %d, isUser %d\n", 2365 thread_get_current_thread_id(), originalAddress, isWrite, isUser)); 2366 2367 address = ROUNDOWN(originalAddress, B_PAGE_SIZE); 2368 2369 if (IS_KERNEL_ADDRESS(address)) { 2370 aspace = vm_get_kernel_aspace(); 2371 } else if (IS_USER_ADDRESS(address)) { 2372 aspace = vm_get_current_user_aspace(); 2373 if (aspace == NULL) { 2374 if (isUser == false) { 2375 dprintf("vm_soft_fault: kernel thread accessing invalid user memory!\n"); 2376 return B_BAD_ADDRESS; 2377 } else { 2378 // XXX weird state. 2379 panic("vm_soft_fault: non kernel thread accessing user memory that doesn't exist!\n"); 2380 } 2381 } 2382 } else { 2383 // the hit was probably in the 64k DMZ between kernel and user space 2384 // this keeps a user space thread from passing a buffer that crosses into kernel space 2385 return B_BAD_ADDRESS; 2386 } 2387 map = &aspace->virtual_map; 2388 atomic_add(&aspace->fault_count, 1); 2389 2390 // Get the area the fault was in 2391 2392 acquire_sem_etc(map->sem, READ_COUNT, 0, 0); 2393 area = vm_virtual_map_lookup(map, address); 2394 if (area == NULL) { 2395 release_sem_etc(map->sem, READ_COUNT, 0); 2396 vm_put_aspace(aspace); 2397 dprintf("vm_soft_fault: va 0x%lx not covered by area in address space\n", originalAddress); 2398 return B_BAD_ADDRESS; 2399 } 2400 2401 // check permissions 2402 if (isUser && (area->protection & B_USER_PROTECTION) == 0) { 2403 release_sem_etc(map->sem, READ_COUNT, 0); 2404 vm_put_aspace(aspace); 2405 dprintf("user access on kernel area 0x%lx at %p\n", area->id, (void *)originalAddress); 2406 return B_PERMISSION_DENIED; 2407 } 2408 if (isWrite && (area->protection & (B_WRITE_AREA | (isUser ? 0 : B_KERNEL_WRITE_AREA))) == 0) { 2409 release_sem_etc(map->sem, READ_COUNT, 0); 2410 vm_put_aspace(aspace); 2411 dprintf("write access attempted on read-only area 0x%lx at %p\n", area->id, (void *)originalAddress); 2412 return B_PERMISSION_DENIED; 2413 } 2414 2415 // We have the area, it was a valid access, so let's try to resolve the page fault now. 2416 // At first, the top most cache from the area is investigated 2417 2418 top_cache_ref = area->cache_ref; 2419 cache_offset = address - area->base + area->cache_offset; 2420 vm_cache_acquire_ref(top_cache_ref, true); 2421 change_count = map->change_count; 2422 release_sem_etc(map->sem, READ_COUNT, 0); 2423 2424 // See if this cache has a fault handler - this will do all the work for us 2425 if (top_cache_ref->cache->store->ops->fault != NULL) { 2426 // Note, since the page fault is resolved with interrupts enabled, the 2427 // fault handler could be called more than once for the same reason - 2428 // the store must take this into account 2429 status_t status = (*top_cache_ref->cache->store->ops->fault)(top_cache_ref->cache->store, aspace, cache_offset); 2430 if (status != B_BAD_HANDLER) { 2431 vm_cache_release_ref(top_cache_ref); 2432 vm_put_aspace(aspace); 2433 return status; 2434 } 2435 } 2436 2437 // The top most cache has no fault handler, so let's see if the cache or its sources 2438 // already have the page we're searching for (we're going from top to bottom) 2439 2440 dummy_page.state = PAGE_STATE_INACTIVE; 2441 dummy_page.type = PAGE_TYPE_DUMMY; 2442 2443 last_cache_ref = top_cache_ref; 2444 for (cache_ref = top_cache_ref; cache_ref; cache_ref = (cache_ref->cache->source) ? cache_ref->cache->source->ref : NULL) { 2445 mutex_lock(&cache_ref->lock); 2446 2447 for (;;) { 2448 page = vm_cache_lookup_page(cache_ref, cache_offset); 2449 if (page != NULL && page->state != PAGE_STATE_BUSY) { 2450 vm_page_set_state(page, PAGE_STATE_BUSY); 2451 mutex_unlock(&cache_ref->lock); 2452 break; 2453 } 2454 2455 if (page == NULL) 2456 break; 2457 2458 // page must be busy 2459 // ToDo: don't wait forever! 2460 mutex_unlock(&cache_ref->lock); 2461 snooze(20000); 2462 mutex_lock(&cache_ref->lock); 2463 } 2464 2465 if (page != NULL) 2466 break; 2467 2468 // The current cache does not contain the page we're looking for 2469 2470 // If we're at the top most cache, insert the dummy page here to keep other threads 2471 // from faulting on the same address and chasing us up the cache chain 2472 if (cache_ref == top_cache_ref) { 2473 dummy_page.state = PAGE_STATE_BUSY; 2474 vm_cache_insert_page(cache_ref, &dummy_page, cache_offset); 2475 } 2476 2477 // see if the vm_store has it 2478 if (cache_ref->cache->store->ops->has_page != NULL 2479 && cache_ref->cache->store->ops->has_page(cache_ref->cache->store, cache_offset)) { 2480 size_t bytesRead; 2481 iovec vec; 2482 2483 vec.iov_len = bytesRead = B_PAGE_SIZE; 2484 2485 mutex_unlock(&cache_ref->lock); 2486 2487 page = vm_page_allocate_page(PAGE_STATE_FREE); 2488 aspace->translation_map.ops->get_physical_page(page->ppn * B_PAGE_SIZE, (addr_t *)&vec.iov_base, PHYSICAL_PAGE_CAN_WAIT); 2489 // ToDo: handle errors here 2490 err = cache_ref->cache->store->ops->read(cache_ref->cache->store, cache_offset, &vec, 1, &bytesRead); 2491 aspace->translation_map.ops->put_physical_page((addr_t)vec.iov_base); 2492 2493 mutex_lock(&cache_ref->lock); 2494 2495 if (cache_ref == top_cache_ref) { 2496 vm_cache_remove_page(cache_ref, &dummy_page); 2497 dummy_page.state = PAGE_STATE_INACTIVE; 2498 } 2499 vm_cache_insert_page(cache_ref, page, cache_offset); 2500 mutex_unlock(&cache_ref->lock); 2501 break; 2502 } 2503 mutex_unlock(&cache_ref->lock); 2504 last_cache_ref = cache_ref; 2505 } 2506 2507 if (!cache_ref) { 2508 // We rolled off the end of the cache chain, so we need to decide which 2509 // cache will get the new page we're about to create. 2510 2511 cache_ref = isWrite ? top_cache_ref : last_cache_ref; 2512 // Read-only pages come in the deepest cache - only the 2513 // top most cache may have direct write access. 2514 } 2515 2516 if (page == NULL) { 2517 // we still haven't found a page, so we allocate a clean one 2518 page = vm_page_allocate_page(PAGE_STATE_CLEAR); 2519 FTRACE(("vm_soft_fault: just allocated page 0x%lx\n", page->ppn)); 2520 2521 // Insert the new page into our cache, and replace it with the dummy page if necessary 2522 2523 mutex_lock(&cache_ref->lock); 2524 2525 // if we inserted a dummy page into this cache, we have to remove it now 2526 if (dummy_page.state == PAGE_STATE_BUSY && dummy_page.cache == cache_ref->cache) { 2527 vm_cache_remove_page(cache_ref, &dummy_page); 2528 dummy_page.state = PAGE_STATE_INACTIVE; 2529 } 2530 2531 vm_cache_insert_page(cache_ref, page, cache_offset); 2532 mutex_unlock(&cache_ref->lock); 2533 2534 if (dummy_page.state == PAGE_STATE_BUSY) { 2535 // we had inserted the dummy cache in another cache, so let's remove it from there 2536 vm_cache_ref *temp_cache = dummy_page.cache->ref; 2537 mutex_lock(&temp_cache->lock); 2538 vm_cache_remove_page(temp_cache, &dummy_page); 2539 mutex_unlock(&temp_cache->lock); 2540 dummy_page.state = PAGE_STATE_INACTIVE; 2541 } 2542 } 2543 2544 // We now have the page and a cache it belongs to - we now need to make 2545 // sure that the area's cache can access it, too, and sees the correct data 2546 2547 if (page->cache != top_cache_ref->cache && isWrite) { 2548 // now we have a page that has the data we want, but in the wrong cache object 2549 // so we need to copy it and stick it into the top cache 2550 vm_page *src_page = page; 2551 void *src, *dest; 2552 2553 FTRACE(("get new page, copy it, and put it into the topmost cache\n")); 2554 page = vm_page_allocate_page(PAGE_STATE_FREE); 2555 2556 // try to get a mapping for the src and dest page so we can copy it 2557 for (;;) { 2558 (*aspace->translation_map.ops->get_physical_page)(src_page->ppn * B_PAGE_SIZE, (addr_t *)&src, PHYSICAL_PAGE_CAN_WAIT); 2559 err = (*aspace->translation_map.ops->get_physical_page)(page->ppn * B_PAGE_SIZE, (addr_t *)&dest, PHYSICAL_PAGE_NO_WAIT); 2560 if (err == B_NO_ERROR) 2561 break; 2562 2563 // it couldn't map the second one, so sleep and retry 2564 // keeps an extremely rare deadlock from occuring 2565 (*aspace->translation_map.ops->put_physical_page)((addr_t)src); 2566 snooze(5000); 2567 } 2568 2569 memcpy(dest, src, B_PAGE_SIZE); 2570 (*aspace->translation_map.ops->put_physical_page)((addr_t)src); 2571 (*aspace->translation_map.ops->put_physical_page)((addr_t)dest); 2572 2573 vm_page_set_state(src_page, PAGE_STATE_ACTIVE); 2574 2575 mutex_lock(&top_cache_ref->lock); 2576 2577 // Insert the new page into our cache, and replace it with the dummy page if necessary 2578 2579 // if we inserted a dummy page into this cache, we have to remove it now 2580 if (dummy_page.state == PAGE_STATE_BUSY && dummy_page.cache == top_cache_ref->cache) { 2581 vm_cache_remove_page(top_cache_ref, &dummy_page); 2582 dummy_page.state = PAGE_STATE_INACTIVE; 2583 } 2584 2585 vm_cache_insert_page(top_cache_ref, page, cache_offset); 2586 mutex_unlock(&top_cache_ref->lock); 2587 2588 if (dummy_page.state == PAGE_STATE_BUSY) { 2589 // we had inserted the dummy cache in another cache, so let's remove it from there 2590 vm_cache_ref *temp_cache = dummy_page.cache->ref; 2591 mutex_lock(&temp_cache->lock); 2592 vm_cache_remove_page(temp_cache, &dummy_page); 2593 mutex_unlock(&temp_cache->lock); 2594 dummy_page.state = PAGE_STATE_INACTIVE; 2595 } 2596 } 2597 2598 err = B_OK; 2599 acquire_sem_etc(map->sem, READ_COUNT, 0, 0); 2600 if (change_count != map->change_count) { 2601 // something may have changed, see if the address is still valid 2602 area = vm_virtual_map_lookup(map, address); 2603 if (area == NULL 2604 || area->cache_ref != top_cache_ref 2605 || (address - area->base + area->cache_offset) != cache_offset) { 2606 dprintf("vm_soft_fault: address space layout changed effecting ongoing soft fault\n"); 2607 err = B_BAD_ADDRESS; 2608 } 2609 } 2610 2611 if (err == B_OK) { 2612 // All went fine, all there is left to do is to map the page into the address space 2613 2614 // If the page doesn't reside in the area's cache, we need to make sure it's 2615 // mapped in read-only, so that we cannot overwrite someone else's data (copy-on-write) 2616 uint32 newProtection = area->protection; 2617 if (page->cache != top_cache_ref->cache && !isWrite) 2618 newProtection &= ~(isUser ? B_WRITE_AREA : B_KERNEL_WRITE_AREA); 2619 2620 atomic_add(&page->ref_count, 1); 2621 (*aspace->translation_map.ops->lock)(&aspace->translation_map); 2622 (*aspace->translation_map.ops->map)(&aspace->translation_map, address, 2623 page->ppn * B_PAGE_SIZE, newProtection); 2624 (*aspace->translation_map.ops->unlock)(&aspace->translation_map); 2625 } 2626 2627 release_sem_etc(map->sem, READ_COUNT, 0); 2628 2629 if (dummy_page.state == PAGE_STATE_BUSY) { 2630 // We still have the dummy page in the cache - that happens if we didn't need 2631 // to allocate a new page before, but could use one in another cache 2632 vm_cache_ref *temp_cache = dummy_page.cache->ref; 2633 mutex_lock(&temp_cache->lock); 2634 vm_cache_remove_page(temp_cache, &dummy_page); 2635 mutex_unlock(&temp_cache->lock); 2636 dummy_page.state = PAGE_STATE_INACTIVE; 2637 } 2638 2639 vm_page_set_state(page, PAGE_STATE_ACTIVE); 2640 2641 vm_cache_release_ref(top_cache_ref); 2642 vm_put_aspace(aspace); 2643 2644 return err; 2645 } 2646 2647 2648 static vm_area * 2649 vm_virtual_map_lookup(vm_virtual_map *map, addr_t address) 2650 { 2651 vm_area *area; 2652 2653 // check the areas list first 2654 area = map->area_hint; 2655 if (area && area->base <= address && (area->base + area->size) > address) 2656 return area; 2657 2658 for (area = map->areas; area != NULL; area = area->aspace_next) { 2659 if (area->id == RESERVED_AREA_ID) 2660 continue; 2661 2662 if (area->base <= address && (area->base + area->size) > address) 2663 break; 2664 } 2665 2666 if (area) 2667 map->area_hint = area; 2668 return area; 2669 } 2670 2671 2672 status_t 2673 vm_get_physical_page(addr_t paddr, addr_t *_vaddr, int flags) 2674 { 2675 return (*kernel_aspace->translation_map.ops->get_physical_page)(paddr, _vaddr, flags); 2676 } 2677 2678 2679 status_t 2680 vm_put_physical_page(addr_t vaddr) 2681 { 2682 return (*kernel_aspace->translation_map.ops->put_physical_page)(vaddr); 2683 } 2684 2685 2686 void 2687 vm_unreserve_memory(size_t amount) 2688 { 2689 benaphore_lock(&sAvailableMemoryLock); 2690 2691 sAvailableMemory += amount; 2692 2693 benaphore_unlock(&sAvailableMemoryLock); 2694 } 2695 2696 2697 status_t 2698 vm_try_reserve_memory(size_t amount) 2699 { 2700 status_t status; 2701 benaphore_lock(&sAvailableMemoryLock); 2702 2703 if (sAvailableMemory > amount) { 2704 sAvailableMemory -= amount; 2705 status = B_OK; 2706 } else 2707 status = B_NO_MEMORY; 2708 2709 benaphore_unlock(&sAvailableMemoryLock); 2710 return status; 2711 } 2712 2713 2714 /** This function enforces some protection properties: 2715 * - if B_WRITE_AREA is set, B_WRITE_KERNEL_AREA is set as well 2716 * - if only B_READ_AREA has been set, B_KERNEL_READ_AREA is also set 2717 * - if no protection is specified, it defaults to B_KERNEL_READ_AREA 2718 * and B_KERNEL_WRITE_AREA. 2719 */ 2720 2721 static void 2722 fix_protection(uint32 *protection) 2723 { 2724 if ((*protection & B_KERNEL_PROTECTION) == 0) { 2725 if ((*protection & B_USER_PROTECTION) == 0 2726 || (*protection & B_WRITE_AREA) != 0) 2727 *protection |= B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA; 2728 else 2729 *protection |= B_KERNEL_READ_AREA; 2730 } 2731 } 2732 2733 2734 // #pragma mark - 2735 2736 2737 status_t 2738 user_memcpy(void *to, const void *from, size_t size) 2739 { 2740 return arch_cpu_user_memcpy(to, from, size, &thread_get_current_thread()->fault_handler); 2741 } 2742 2743 2744 /** \brief Copies at most (\a size - 1) characters from the string in \a from to 2745 * the string in \a to, NULL-terminating the result. 2746 * 2747 * \param to Pointer to the destination C-string. 2748 * \param from Pointer to the source C-string. 2749 * \param size Size in bytes of the string buffer pointed to by \a to. 2750 * 2751 * \return strlen(\a from). 2752 */ 2753 2754 ssize_t 2755 user_strlcpy(char *to, const char *from, size_t size) 2756 { 2757 return arch_cpu_user_strlcpy(to, from, size, &thread_get_current_thread()->fault_handler); 2758 } 2759 2760 2761 status_t 2762 user_memset(void *s, char c, size_t count) 2763 { 2764 return arch_cpu_user_memset(s, c, count, &thread_get_current_thread()->fault_handler); 2765 } 2766 2767 2768 // #pragma mark - 2769 2770 2771 long 2772 lock_memory(void *address, ulong numBytes, ulong flags) 2773 { 2774 vm_address_space *aspace = NULL; 2775 struct vm_translation_map *map; 2776 addr_t base = (addr_t)address; 2777 addr_t end = base + numBytes; 2778 bool isUser = IS_USER_ADDRESS(address); 2779 2780 // ToDo: Our VM currently doesn't support locking, this function 2781 // will now at least make sure that the memory is paged in, but 2782 // that's about it. 2783 // Nevertheless, it must be implemented as soon as we're able to 2784 // swap pages out of memory. 2785 2786 // ToDo: this is a hack, too; the iospace area is a null region and 2787 // officially cannot be written to or read; ie. vm_soft_fault() will 2788 // fail there. Furthermore, this is x86 specific as well. 2789 #define IOSPACE_SIZE (256 * 1024 * 1024) 2790 if (base >= KERNEL_BASE + IOSPACE_SIZE && base + numBytes < KERNEL_BASE + 2 * IOSPACE_SIZE) 2791 return B_OK; 2792 2793 if (isUser) 2794 aspace = vm_get_current_user_aspace(); 2795 else 2796 aspace = vm_get_kernel_aspace(); 2797 if (aspace == NULL) 2798 return B_ERROR; 2799 2800 map = &aspace->translation_map; 2801 2802 for (; base < end; base += B_PAGE_SIZE) { 2803 addr_t physicalAddress; 2804 uint32 protection; 2805 status_t status; 2806 2807 map->ops->lock(map); 2808 map->ops->query(map, base, &physicalAddress, &protection); 2809 map->ops->unlock(map); 2810 2811 if ((protection & PAGE_PRESENT) != 0) { 2812 // if B_READ_DEVICE is set, the caller intents to write to the locked 2813 // memory, so if it hasn't been mapped writable, we'll try the soft 2814 // fault anyway 2815 if ((flags & B_READ_DEVICE) == 0 2816 || (protection & (B_WRITE_AREA | B_KERNEL_WRITE_AREA)) != 0) 2817 continue; 2818 } 2819 2820 status = vm_soft_fault(base, (flags & B_READ_DEVICE) != 0, isUser); 2821 if (status != B_OK) { 2822 dprintf("lock_memory(address = %p, numBytes = %lu, flags = %lu) failed: %s\n", 2823 address, numBytes, flags, strerror(status)); 2824 vm_put_aspace(aspace); 2825 return status; 2826 } 2827 } 2828 2829 vm_put_aspace(aspace); 2830 return B_OK; 2831 } 2832 2833 2834 long 2835 unlock_memory(void *buffer, ulong numBytes, ulong flags) 2836 { 2837 return B_OK; 2838 } 2839 2840 2841 /** According to the BeBook, this function should always succeed. 2842 * This is no longer the case. 2843 */ 2844 2845 long 2846 get_memory_map(const void *address, ulong numBytes, physical_entry *table, long numEntries) 2847 { 2848 vm_address_space *addressSpace; 2849 addr_t virtualAddress = (addr_t)address; 2850 addr_t pageOffset = virtualAddress & (B_PAGE_SIZE - 1); 2851 addr_t physicalAddress; 2852 status_t status = B_OK; 2853 int32 index = -1; 2854 addr_t offset = 0; 2855 uint32 flags; 2856 2857 TRACE(("get_memory_map(%p, %lu bytes, %ld entries)\n", address, numBytes, numEntries)); 2858 2859 if (numEntries == 0 || numBytes == 0) 2860 return B_BAD_VALUE; 2861 2862 // in which address space is the address to be found? 2863 if (IS_USER_ADDRESS(virtualAddress)) 2864 addressSpace = vm_get_current_user_aspace(); 2865 else 2866 addressSpace = vm_get_kernel_aspace(); 2867 2868 if (addressSpace == NULL) 2869 return B_ERROR; 2870 2871 (*addressSpace->translation_map.ops->lock)(&addressSpace->translation_map); 2872 2873 while (offset < numBytes) { 2874 addr_t bytes = min_c(numBytes - offset, B_PAGE_SIZE); 2875 2876 status = (*addressSpace->translation_map.ops->query)(&addressSpace->translation_map, 2877 (addr_t)address + offset, &physicalAddress, &flags); 2878 if (status < 0) 2879 break; 2880 2881 if (index < 0 && pageOffset > 0) { 2882 physicalAddress += pageOffset; 2883 if (bytes > B_PAGE_SIZE - pageOffset) 2884 bytes = B_PAGE_SIZE - pageOffset; 2885 } 2886 2887 // need to switch to the next physical_entry? 2888 if (index < 0 || (addr_t)table[index].address != physicalAddress - table[index].size) { 2889 if (++index + 1 > numEntries) { 2890 // table to small 2891 status = B_BUFFER_OVERFLOW; 2892 break; 2893 } 2894 table[index].address = (void *)physicalAddress; 2895 table[index].size = bytes; 2896 } else { 2897 // page does fit in current entry 2898 table[index].size += bytes; 2899 } 2900 2901 offset += bytes; 2902 } 2903 (*addressSpace->translation_map.ops->unlock)(&addressSpace->translation_map); 2904 2905 // close the entry list 2906 2907 if (status == B_OK) { 2908 // if it's only one entry, we will silently accept the missing ending 2909 if (numEntries == 1) 2910 return B_OK; 2911 2912 if (++index + 1 > numEntries) 2913 return B_BUFFER_OVERFLOW; 2914 2915 table[index].address = NULL; 2916 table[index].size = 0; 2917 } 2918 2919 return status; 2920 } 2921 2922 2923 area_id 2924 area_for(void *address) 2925 { 2926 return vm_area_for(vm_get_kernel_aspace_id(), (addr_t)address); 2927 } 2928 2929 2930 area_id 2931 find_area(const char *name) 2932 { 2933 struct hash_iterator iterator; 2934 vm_area *area; 2935 area_id id = B_NAME_NOT_FOUND; 2936 2937 acquire_sem_etc(sAreaHashLock, READ_COUNT, 0, 0); 2938 hash_open(sAreaHash, &iterator); 2939 2940 while ((area = (vm_area *)hash_next(sAreaHash, &iterator)) != NULL) { 2941 if (area->id == RESERVED_AREA_ID) 2942 continue; 2943 2944 if (!strcmp(area->name, name)) { 2945 id = area->id; 2946 break; 2947 } 2948 } 2949 2950 hash_close(sAreaHash, &iterator, false); 2951 release_sem_etc(sAreaHashLock, READ_COUNT, 0); 2952 2953 return id; 2954 } 2955 2956 2957 static void 2958 fill_area_info(struct vm_area *area, area_info *info, size_t size) 2959 { 2960 strlcpy(info->name, area->name, B_OS_NAME_LENGTH); 2961 info->area = area->id; 2962 info->address = (void *)area->base; 2963 info->size = area->size; 2964 info->protection = area->protection & B_USER_PROTECTION; 2965 info->lock = B_FULL_LOCK; 2966 info->team = area->aspace->id; 2967 info->ram_size = area->size; 2968 info->copy_count = 0; 2969 info->in_count = 0; 2970 info->out_count = 0; 2971 // ToDo: retrieve real values here! 2972 } 2973 2974 2975 status_t 2976 _get_area_info(area_id id, area_info *info, size_t size) 2977 { 2978 vm_area *area; 2979 2980 if (size != sizeof(area_info) || info == NULL) 2981 return B_BAD_VALUE; 2982 2983 area = vm_get_area(id); 2984 if (area == NULL) 2985 return B_BAD_VALUE; 2986 2987 fill_area_info(area, info, size); 2988 vm_put_area(area); 2989 2990 return B_OK; 2991 } 2992 2993 2994 status_t 2995 _get_next_area_info(team_id team, int32 *cookie, area_info *info, size_t size) 2996 { 2997 addr_t nextBase = *(addr_t *)cookie; 2998 vm_address_space *addressSpace; 2999 vm_area *area; 3000 3001 // we're already through the list 3002 if (nextBase == (addr_t)-1) 3003 return B_ENTRY_NOT_FOUND; 3004 3005 if (team == B_CURRENT_TEAM) 3006 team = team_get_current_team_id(); 3007 3008 if (!team_is_valid(team) 3009 || team_get_address_space(team, &addressSpace) != B_OK) 3010 return B_BAD_VALUE; 3011 3012 acquire_sem_etc(addressSpace->virtual_map.sem, READ_COUNT, 0, 0); 3013 3014 for (area = addressSpace->virtual_map.areas; area; area = area->aspace_next) { 3015 if (area->id == RESERVED_AREA_ID) 3016 continue; 3017 3018 if (area->base > nextBase) 3019 break; 3020 } 3021 3022 // make sure this area won't go away 3023 if (area != NULL) 3024 area = vm_get_area(area->id); 3025 3026 release_sem_etc(addressSpace->virtual_map.sem, READ_COUNT, 0); 3027 vm_put_aspace(addressSpace); 3028 3029 if (area == NULL) { 3030 nextBase = (addr_t)-1; 3031 return B_ENTRY_NOT_FOUND; 3032 } 3033 3034 fill_area_info(area, info, size); 3035 *cookie = (int32)(area->base); 3036 3037 vm_put_area(area); 3038 3039 return B_OK; 3040 } 3041 3042 3043 status_t 3044 set_area_protection(area_id area, uint32 newProtection) 3045 { 3046 fix_protection(&newProtection); 3047 3048 return vm_set_area_protection(vm_get_kernel_aspace_id(), area, newProtection); 3049 } 3050 3051 3052 status_t 3053 resize_area(area_id areaID, size_t newSize) 3054 { 3055 vm_cache_ref *cache; 3056 vm_area *area, *current; 3057 status_t status = B_OK; 3058 size_t oldSize; 3059 3060 // is newSize a multiple of B_PAGE_SIZE? 3061 if (newSize & (B_PAGE_SIZE - 1)) 3062 return B_BAD_VALUE; 3063 3064 area = vm_get_area(areaID); 3065 if (area == NULL) 3066 return B_BAD_VALUE; 3067 3068 // Resize all areas of this area's cache 3069 3070 cache = area->cache_ref; 3071 oldSize = area->size; 3072 3073 // ToDo: we should only allow to resize anonymous memory areas! 3074 if (!cache->cache->temporary) { 3075 status = B_NOT_ALLOWED; 3076 goto err1; 3077 } 3078 3079 // ToDo: we must lock all address spaces here! 3080 3081 mutex_lock(&cache->lock); 3082 3083 if (oldSize < newSize) { 3084 // We need to check if all areas of this cache can be resized 3085 3086 for (current = cache->areas; current; current = current->cache_next) { 3087 if (current->aspace_next && current->aspace_next->base <= (current->base + newSize)) { 3088 // if the area was created inside a reserved area, it can also be 3089 // resized in that area 3090 // ToDo: if there is free space after the reserved area, it could be used as well... 3091 vm_area *next = current->aspace_next; 3092 if (next->id == RESERVED_AREA_ID && next->cache_offset <= current->base 3093 && next->base - 1 + next->size >= current->base - 1 + newSize) 3094 continue; 3095 3096 status = B_ERROR; 3097 goto err2; 3098 } 3099 } 3100 } 3101 3102 // Okay, looks good so far, so let's do it 3103 3104 for (current = cache->areas; current; current = current->cache_next) { 3105 if (current->aspace_next && current->aspace_next->base <= (current->base + newSize)) { 3106 vm_area *next = current->aspace_next; 3107 if (next->id == RESERVED_AREA_ID && next->cache_offset <= current->base 3108 && next->base - 1 + next->size >= current->base - 1 + newSize) { 3109 // resize reserved area 3110 addr_t offset = current->base + newSize - next->base; 3111 if (next->size <= offset) { 3112 current->aspace_next = next->aspace_next; 3113 free(next); 3114 } else { 3115 next->size -= offset; 3116 next->base += offset; 3117 } 3118 } else { 3119 status = B_ERROR; 3120 break; 3121 } 3122 } 3123 3124 current->size = newSize; 3125 3126 // we also need to unmap all pages beyond the new size, if the area has shrinked 3127 if (newSize < oldSize) { 3128 vm_translation_map *map = ¤t->aspace->translation_map; 3129 3130 map->ops->lock(map); 3131 map->ops->unmap(map, current->base + newSize, current->base + oldSize - 1); 3132 map->ops->unlock(map); 3133 } 3134 } 3135 3136 if (status == B_OK) 3137 status = vm_cache_resize(cache, newSize); 3138 3139 if (status < B_OK) { 3140 // This shouldn't really be possible, but hey, who knows 3141 for (current = cache->areas; current; current = current->cache_next) 3142 current->size = oldSize; 3143 } 3144 3145 err2: 3146 mutex_unlock(&cache->lock); 3147 err1: 3148 vm_put_area(area); 3149 3150 // ToDo: we must honour the lock restrictions of this area 3151 return status; 3152 } 3153 3154 3155 /** Transfers the specified area to a new team. The caller must be the owner 3156 * of the area (not yet enforced but probably should be). 3157 * This function is currently not exported to the kernel namespace, but is 3158 * only accessible using the _kern_transfer_area() syscall. 3159 */ 3160 3161 static status_t 3162 transfer_area(area_id id, void **_address, uint32 addressSpec, team_id target) 3163 { 3164 vm_address_space *sourceAddressSpace, *targetAddressSpace; 3165 vm_translation_map *map; 3166 vm_area *area, *reserved; 3167 void *reservedAddress; 3168 status_t status; 3169 3170 area = vm_get_area(id); 3171 if (area == NULL) 3172 return B_BAD_VALUE; 3173 3174 // ToDo: check if the current team owns the area 3175 3176 status = team_get_address_space(target, &targetAddressSpace); 3177 if (status != B_OK) 3178 goto err1; 3179 3180 // We will first remove the area, and then reserve its former 3181 // address range so that we can later reclaim it if the 3182 // transfer failed. 3183 3184 sourceAddressSpace = area->aspace; 3185 3186 reserved = _vm_create_reserved_region_struct(&sourceAddressSpace->virtual_map, 0); 3187 if (reserved == NULL) { 3188 status = B_NO_MEMORY; 3189 goto err2; 3190 } 3191 3192 acquire_sem_etc(sourceAddressSpace->virtual_map.sem, WRITE_COUNT, 0, 0); 3193 3194 reservedAddress = (void *)area->base; 3195 remove_area_from_virtual_map(sourceAddressSpace, area, true); 3196 status = insert_area(sourceAddressSpace, &reservedAddress, B_EXACT_ADDRESS, 3197 area->size, reserved); 3198 // famous last words: this cannot fail :) 3199 3200 release_sem_etc(sourceAddressSpace->virtual_map.sem, WRITE_COUNT, 0); 3201 3202 if (status != B_OK) 3203 goto err3; 3204 3205 // unmap the area in the source address space 3206 map = &sourceAddressSpace->translation_map; 3207 map->ops->lock(map); 3208 map->ops->unmap(map, area->base, area->base + (area->size - 1)); 3209 map->ops->unlock(map); 3210 3211 // insert the area into the target address space 3212 3213 acquire_sem_etc(targetAddressSpace->virtual_map.sem, WRITE_COUNT, 0, 0); 3214 // check to see if this aspace has entered DELETE state 3215 if (targetAddressSpace->state == VM_ASPACE_STATE_DELETION) { 3216 // okay, someone is trying to delete this aspace now, so we can't 3217 // insert the area, so back out 3218 status = B_BAD_TEAM_ID; 3219 goto err4; 3220 } 3221 3222 status = insert_area(targetAddressSpace, _address, addressSpec, area->size, area); 3223 if (status < B_OK) 3224 goto err4; 3225 3226 // The area was successfully transferred to the new team when we got here 3227 area->aspace = targetAddressSpace; 3228 3229 release_sem_etc(targetAddressSpace->virtual_map.sem, WRITE_COUNT, 0); 3230 3231 vm_unreserve_address_range(sourceAddressSpace->id, reservedAddress, area->size); 3232 vm_put_aspace(sourceAddressSpace); 3233 // we keep the reference of the target address space for the 3234 // area, so we only have to put the one from the source 3235 vm_put_area(area); 3236 3237 return B_OK; 3238 3239 err4: 3240 release_sem_etc(targetAddressSpace->virtual_map.sem, WRITE_COUNT, 0); 3241 err3: 3242 // insert the area again into the source address space 3243 acquire_sem_etc(sourceAddressSpace->virtual_map.sem, WRITE_COUNT, 0, 0); 3244 // check to see if this aspace has entered DELETE state 3245 if (sourceAddressSpace->state == VM_ASPACE_STATE_DELETION 3246 || insert_area(sourceAddressSpace, &reservedAddress, B_EXACT_ADDRESS, area->size, area) != B_OK) { 3247 // We can't insert the area anymore - we have to delete it manually 3248 vm_cache_remove_area(area->cache_ref, area); 3249 vm_cache_release_ref(area->cache_ref); 3250 free(area->name); 3251 free(area); 3252 area = NULL; 3253 } 3254 release_sem_etc(sourceAddressSpace->virtual_map.sem, WRITE_COUNT, 0); 3255 err2: 3256 vm_put_aspace(targetAddressSpace); 3257 err1: 3258 if (area != NULL) 3259 vm_put_area(area); 3260 return status; 3261 } 3262 3263 3264 area_id 3265 map_physical_memory(const char *name, void *physicalAddress, size_t numBytes, 3266 uint32 addressSpec, uint32 protection, void **_virtualAddress) 3267 { 3268 if (!arch_vm_supports_protection(protection)) 3269 return B_NOT_SUPPORTED; 3270 3271 fix_protection(&protection); 3272 3273 return vm_map_physical_memory(vm_get_kernel_aspace_id(), name, _virtualAddress, 3274 addressSpec, numBytes, protection, (addr_t)physicalAddress); 3275 } 3276 3277 3278 area_id 3279 clone_area(const char *name, void **_address, uint32 addressSpec, uint32 protection, 3280 area_id source) 3281 { 3282 if ((protection & B_KERNEL_PROTECTION) == 0) 3283 protection |= B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA; 3284 3285 return vm_clone_area(vm_get_kernel_aspace_id(), name, _address, addressSpec, 3286 protection, REGION_NO_PRIVATE_MAP, source); 3287 } 3288 3289 3290 area_id 3291 create_area_etc(struct team *team, const char *name, void **address, uint32 addressSpec, 3292 uint32 size, uint32 lock, uint32 protection) 3293 { 3294 fix_protection(&protection); 3295 3296 return vm_create_anonymous_area(team->aspace->id, (char *)name, address, 3297 addressSpec, size, lock, protection); 3298 } 3299 3300 3301 area_id 3302 create_area(const char *name, void **_address, uint32 addressSpec, size_t size, uint32 lock, 3303 uint32 protection) 3304 { 3305 fix_protection(&protection); 3306 3307 return vm_create_anonymous_area(vm_get_kernel_aspace_id(), (char *)name, _address, 3308 addressSpec, size, lock, protection); 3309 } 3310 3311 3312 status_t 3313 delete_area_etc(struct team *team, area_id area) 3314 { 3315 return vm_delete_area(team->aspace->id, area); 3316 } 3317 3318 3319 status_t 3320 delete_area(area_id area) 3321 { 3322 return vm_delete_area(vm_get_kernel_aspace_id(), area); 3323 } 3324 3325 3326 // #pragma mark - 3327 3328 3329 status_t 3330 _user_init_heap_address_range(addr_t base, addr_t size) 3331 { 3332 return vm_reserve_address_range(vm_get_current_user_aspace_id(), (void **)&base, 3333 B_EXACT_ADDRESS, size, RESERVED_AVOID_BASE); 3334 } 3335 3336 3337 area_id 3338 _user_area_for(void *address) 3339 { 3340 return vm_area_for(vm_get_current_user_aspace_id(), (addr_t)address); 3341 } 3342 3343 3344 area_id 3345 _user_find_area(const char *userName) 3346 { 3347 char name[B_OS_NAME_LENGTH]; 3348 3349 if (!IS_USER_ADDRESS(userName) 3350 || user_strlcpy(name, userName, B_OS_NAME_LENGTH) < B_OK) 3351 return B_BAD_ADDRESS; 3352 3353 return find_area(name); 3354 } 3355 3356 3357 status_t 3358 _user_get_area_info(area_id area, area_info *userInfo) 3359 { 3360 area_info info; 3361 status_t status; 3362 3363 if (!IS_USER_ADDRESS(userInfo)) 3364 return B_BAD_ADDRESS; 3365 3366 status = get_area_info(area, &info); 3367 if (status < B_OK) 3368 return status; 3369 3370 if (user_memcpy(userInfo, &info, sizeof(area_info)) < B_OK) 3371 return B_BAD_ADDRESS; 3372 3373 return status; 3374 } 3375 3376 3377 status_t 3378 _user_get_next_area_info(team_id team, int32 *userCookie, area_info *userInfo) 3379 { 3380 status_t status; 3381 area_info info; 3382 int32 cookie; 3383 3384 if (!IS_USER_ADDRESS(userCookie) 3385 || !IS_USER_ADDRESS(userInfo) 3386 || user_memcpy(&cookie, userCookie, sizeof(int32)) < B_OK) 3387 return B_BAD_ADDRESS; 3388 3389 status = _get_next_area_info(team, &cookie, &info, sizeof(area_info)); 3390 if (status != B_OK) 3391 return status; 3392 3393 if (user_memcpy(userCookie, &cookie, sizeof(int32)) < B_OK 3394 || user_memcpy(userInfo, &info, sizeof(area_info)) < B_OK) 3395 return B_BAD_ADDRESS; 3396 3397 return status; 3398 } 3399 3400 3401 status_t 3402 _user_set_area_protection(area_id area, uint32 newProtection) 3403 { 3404 if ((newProtection & ~B_USER_PROTECTION) != 0) 3405 return B_BAD_VALUE; 3406 3407 fix_protection(&newProtection); 3408 3409 return vm_set_area_protection(vm_get_current_user_aspace_id(), area, 3410 newProtection); 3411 } 3412 3413 3414 status_t 3415 _user_resize_area(area_id area, size_t newSize) 3416 { 3417 // ToDo: Since we restrict deleting of areas to those owned by the team, 3418 // we should also do that for resizing (check other functions, too). 3419 return resize_area(area, newSize); 3420 } 3421 3422 3423 status_t 3424 _user_transfer_area(area_id area, void **userAddress, uint32 addressSpec, team_id target) 3425 { 3426 status_t status; 3427 void *address; 3428 3429 // filter out some unavailable values (for userland) 3430 switch (addressSpec) { 3431 case B_ANY_KERNEL_ADDRESS: 3432 case B_ANY_KERNEL_BLOCK_ADDRESS: 3433 return B_BAD_VALUE; 3434 } 3435 3436 if (!IS_USER_ADDRESS(userAddress) 3437 || user_memcpy(&address, userAddress, sizeof(address)) < B_OK) 3438 return B_BAD_ADDRESS; 3439 3440 status = transfer_area(area, &address, addressSpec, target); 3441 if (status < B_OK) 3442 return status; 3443 3444 if (user_memcpy(userAddress, &address, sizeof(address)) < B_OK) 3445 return B_BAD_ADDRESS; 3446 3447 return status; 3448 } 3449 3450 3451 area_id 3452 _user_clone_area(const char *userName, void **userAddress, uint32 addressSpec, 3453 uint32 protection, area_id sourceArea) 3454 { 3455 char name[B_OS_NAME_LENGTH]; 3456 void *address; 3457 area_id clonedArea; 3458 3459 // filter out some unavailable values (for userland) 3460 switch (addressSpec) { 3461 case B_ANY_KERNEL_ADDRESS: 3462 case B_ANY_KERNEL_BLOCK_ADDRESS: 3463 return B_BAD_VALUE; 3464 } 3465 if ((protection & ~B_USER_PROTECTION) != 0) 3466 return B_BAD_VALUE; 3467 3468 if (!IS_USER_ADDRESS(userName) 3469 || !IS_USER_ADDRESS(userAddress) 3470 || user_strlcpy(name, userName, sizeof(name)) < B_OK 3471 || user_memcpy(&address, userAddress, sizeof(address)) < B_OK) 3472 return B_BAD_ADDRESS; 3473 3474 fix_protection(&protection); 3475 3476 clonedArea = vm_clone_area(vm_get_current_user_aspace_id(), name, &address, 3477 addressSpec, protection, REGION_NO_PRIVATE_MAP, sourceArea); 3478 if (clonedArea < B_OK) 3479 return clonedArea; 3480 3481 if (user_memcpy(userAddress, &address, sizeof(address)) < B_OK) { 3482 delete_area(clonedArea); 3483 return B_BAD_ADDRESS; 3484 } 3485 3486 return clonedArea; 3487 } 3488 3489 3490 area_id 3491 _user_create_area(const char *userName, void **userAddress, uint32 addressSpec, 3492 size_t size, uint32 lock, uint32 protection) 3493 { 3494 char name[B_OS_NAME_LENGTH]; 3495 area_id area; 3496 void *address; 3497 3498 // filter out some unavailable values (for userland) 3499 switch (addressSpec) { 3500 case B_ANY_KERNEL_ADDRESS: 3501 case B_ANY_KERNEL_BLOCK_ADDRESS: 3502 return B_BAD_VALUE; 3503 } 3504 if ((protection & ~B_USER_PROTECTION) != 0) 3505 return B_BAD_VALUE; 3506 3507 if (!IS_USER_ADDRESS(userName) 3508 || !IS_USER_ADDRESS(userAddress) 3509 || user_strlcpy(name, userName, sizeof(name)) < B_OK 3510 || user_memcpy(&address, userAddress, sizeof(address)) < B_OK) 3511 return B_BAD_ADDRESS; 3512 3513 if (addressSpec == B_EXACT_ADDRESS 3514 && IS_KERNEL_ADDRESS(address)) 3515 return B_BAD_VALUE; 3516 3517 fix_protection(&protection); 3518 3519 area = vm_create_anonymous_area(vm_get_current_user_aspace_id(), (char *)name, &address, 3520 addressSpec, size, lock, protection); 3521 3522 if (area >= B_OK && user_memcpy(userAddress, &address, sizeof(address)) < B_OK) { 3523 delete_area(area); 3524 return B_BAD_ADDRESS; 3525 } 3526 3527 return area; 3528 } 3529 3530 3531 status_t 3532 _user_delete_area(area_id area) 3533 { 3534 // Unlike the BeOS implementation, you can now only delete areas 3535 // that you have created yourself from userland. 3536 // The documentation to delete_area() explicetly states that this 3537 // will be restricted in the future, and so it will. 3538 return vm_delete_area(vm_get_current_user_aspace_id(), area); 3539 } 3540 3541