1 /* 2 * Copyright 2009-2011, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Copyright 2002-2010, Axel Dörfler, axeld@pinc-software.de. 4 * Distributed under the terms of the MIT License. 5 * 6 * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. 7 * Distributed under the terms of the NewOS License. 8 */ 9 10 11 #include <vm/vm.h> 12 13 #include <ctype.h> 14 #include <stdlib.h> 15 #include <stdio.h> 16 #include <string.h> 17 #include <sys/mman.h> 18 19 #include <algorithm> 20 21 #include <OS.h> 22 #include <KernelExport.h> 23 24 #include <AutoDeleter.h> 25 26 #include <symbol_versioning.h> 27 28 #include <arch/cpu.h> 29 #include <arch/vm.h> 30 #include <boot/elf.h> 31 #include <boot/stage2.h> 32 #include <condition_variable.h> 33 #include <console.h> 34 #include <debug.h> 35 #include <file_cache.h> 36 #include <fs/fd.h> 37 #include <heap.h> 38 #include <kernel.h> 39 #include <int.h> 40 #include <lock.h> 41 #include <low_resource_manager.h> 42 #include <slab/Slab.h> 43 #include <smp.h> 44 #include <system_info.h> 45 #include <thread.h> 46 #include <team.h> 47 #include <tracing.h> 48 #include <util/AutoLock.h> 49 #include <util/khash.h> 50 #include <vm/vm_page.h> 51 #include <vm/vm_priv.h> 52 #include <vm/VMAddressSpace.h> 53 #include <vm/VMArea.h> 54 #include <vm/VMCache.h> 55 56 #include "VMAddressSpaceLocking.h" 57 #include "VMAnonymousCache.h" 58 #include "IORequest.h" 59 60 61 //#define TRACE_VM 62 //#define TRACE_FAULTS 63 #ifdef TRACE_VM 64 # define TRACE(x) dprintf x 65 #else 66 # define TRACE(x) ; 67 #endif 68 #ifdef TRACE_FAULTS 69 # define FTRACE(x) dprintf x 70 #else 71 # define FTRACE(x) ; 72 #endif 73 74 75 class AreaCacheLocking { 76 public: 77 inline bool Lock(VMCache* lockable) 78 { 79 return false; 80 } 81 82 inline void Unlock(VMCache* lockable) 83 { 84 vm_area_put_locked_cache(lockable); 85 } 86 }; 87 88 class AreaCacheLocker : public AutoLocker<VMCache, AreaCacheLocking> { 89 public: 90 inline AreaCacheLocker(VMCache* cache = NULL) 91 : AutoLocker<VMCache, AreaCacheLocking>(cache, true) 92 { 93 } 94 95 inline AreaCacheLocker(VMArea* area) 96 : AutoLocker<VMCache, AreaCacheLocking>() 97 { 98 SetTo(area); 99 } 100 101 inline void SetTo(VMCache* cache, bool alreadyLocked) 102 { 103 AutoLocker<VMCache, AreaCacheLocking>::SetTo(cache, alreadyLocked); 104 } 105 106 inline void SetTo(VMArea* area) 107 { 108 return AutoLocker<VMCache, AreaCacheLocking>::SetTo( 109 area != NULL ? vm_area_get_locked_cache(area) : NULL, true, true); 110 } 111 }; 112 113 114 class VMCacheChainLocker { 115 public: 116 VMCacheChainLocker() 117 : 118 fTopCache(NULL), 119 fBottomCache(NULL) 120 { 121 } 122 123 VMCacheChainLocker(VMCache* topCache) 124 : 125 fTopCache(topCache), 126 fBottomCache(topCache) 127 { 128 } 129 130 ~VMCacheChainLocker() 131 { 132 Unlock(); 133 } 134 135 void SetTo(VMCache* topCache) 136 { 137 fTopCache = topCache; 138 fBottomCache = topCache; 139 140 if (topCache != NULL) 141 topCache->SetUserData(NULL); 142 } 143 144 VMCache* LockSourceCache() 145 { 146 if (fBottomCache == NULL || fBottomCache->source == NULL) 147 return NULL; 148 149 VMCache* previousCache = fBottomCache; 150 151 fBottomCache = fBottomCache->source; 152 fBottomCache->Lock(); 153 fBottomCache->AcquireRefLocked(); 154 fBottomCache->SetUserData(previousCache); 155 156 return fBottomCache; 157 } 158 159 void LockAllSourceCaches() 160 { 161 while (LockSourceCache() != NULL) { 162 } 163 } 164 165 void Unlock(VMCache* exceptCache = NULL) 166 { 167 if (fTopCache == NULL) 168 return; 169 170 // Unlock caches in source -> consumer direction. This is important to 171 // avoid double-locking and a reversal of locking order in case a cache 172 // is eligable for merging. 173 VMCache* cache = fBottomCache; 174 while (cache != NULL) { 175 VMCache* nextCache = (VMCache*)cache->UserData(); 176 if (cache != exceptCache) 177 cache->ReleaseRefAndUnlock(cache != fTopCache); 178 179 if (cache == fTopCache) 180 break; 181 182 cache = nextCache; 183 } 184 185 fTopCache = NULL; 186 fBottomCache = NULL; 187 } 188 189 void UnlockKeepRefs(bool keepTopCacheLocked) 190 { 191 if (fTopCache == NULL) 192 return; 193 194 VMCache* nextCache = fBottomCache; 195 VMCache* cache = NULL; 196 197 while (keepTopCacheLocked 198 ? nextCache != fTopCache : cache != fTopCache) { 199 cache = nextCache; 200 nextCache = (VMCache*)cache->UserData(); 201 cache->Unlock(cache != fTopCache); 202 } 203 } 204 205 void RelockCaches(bool topCacheLocked) 206 { 207 if (fTopCache == NULL) 208 return; 209 210 VMCache* nextCache = fTopCache; 211 VMCache* cache = NULL; 212 if (topCacheLocked) { 213 cache = nextCache; 214 nextCache = cache->source; 215 } 216 217 while (cache != fBottomCache && nextCache != NULL) { 218 VMCache* consumer = cache; 219 cache = nextCache; 220 nextCache = cache->source; 221 cache->Lock(); 222 cache->SetUserData(consumer); 223 } 224 } 225 226 private: 227 VMCache* fTopCache; 228 VMCache* fBottomCache; 229 }; 230 231 232 // The memory reserve an allocation of the certain priority must not touch. 233 static const size_t kMemoryReserveForPriority[] = { 234 VM_MEMORY_RESERVE_USER, // user 235 VM_MEMORY_RESERVE_SYSTEM, // system 236 0 // VIP 237 }; 238 239 240 ObjectCache* gPageMappingsObjectCache; 241 242 static rw_lock sAreaCacheLock = RW_LOCK_INITIALIZER("area->cache"); 243 244 static off_t sAvailableMemory; 245 static off_t sNeededMemory; 246 static mutex sAvailableMemoryLock = MUTEX_INITIALIZER("available memory lock"); 247 static uint32 sPageFaults; 248 249 static VMPhysicalPageMapper* sPhysicalPageMapper; 250 251 #if DEBUG_CACHE_LIST 252 253 struct cache_info { 254 VMCache* cache; 255 addr_t page_count; 256 addr_t committed; 257 }; 258 259 static const int kCacheInfoTableCount = 100 * 1024; 260 static cache_info* sCacheInfoTable; 261 262 #endif // DEBUG_CACHE_LIST 263 264 265 // function declarations 266 static void delete_area(VMAddressSpace* addressSpace, VMArea* area, 267 bool addressSpaceCleanup); 268 static status_t vm_soft_fault(VMAddressSpace* addressSpace, addr_t address, 269 bool isWrite, bool isUser, vm_page** wirePage, 270 VMAreaWiredRange* wiredRange = NULL); 271 static status_t map_backing_store(VMAddressSpace* addressSpace, 272 VMCache* cache, off_t offset, const char* areaName, addr_t size, int wiring, 273 int protection, int mapping, uint32 flags, 274 const virtual_address_restrictions* addressRestrictions, bool kernel, 275 VMArea** _area, void** _virtualAddress); 276 277 278 // #pragma mark - 279 280 281 #if VM_PAGE_FAULT_TRACING 282 283 namespace VMPageFaultTracing { 284 285 class PageFaultStart : public AbstractTraceEntry { 286 public: 287 PageFaultStart(addr_t address, bool write, bool user, addr_t pc) 288 : 289 fAddress(address), 290 fPC(pc), 291 fWrite(write), 292 fUser(user) 293 { 294 Initialized(); 295 } 296 297 virtual void AddDump(TraceOutput& out) 298 { 299 out.Print("page fault %#lx %s %s, pc: %#lx", fAddress, 300 fWrite ? "write" : "read", fUser ? "user" : "kernel", fPC); 301 } 302 303 private: 304 addr_t fAddress; 305 addr_t fPC; 306 bool fWrite; 307 bool fUser; 308 }; 309 310 311 // page fault errors 312 enum { 313 PAGE_FAULT_ERROR_NO_AREA = 0, 314 PAGE_FAULT_ERROR_KERNEL_ONLY, 315 PAGE_FAULT_ERROR_WRITE_PROTECTED, 316 PAGE_FAULT_ERROR_READ_PROTECTED, 317 PAGE_FAULT_ERROR_KERNEL_BAD_USER_MEMORY, 318 PAGE_FAULT_ERROR_NO_ADDRESS_SPACE 319 }; 320 321 322 class PageFaultError : public AbstractTraceEntry { 323 public: 324 PageFaultError(area_id area, status_t error) 325 : 326 fArea(area), 327 fError(error) 328 { 329 Initialized(); 330 } 331 332 virtual void AddDump(TraceOutput& out) 333 { 334 switch (fError) { 335 case PAGE_FAULT_ERROR_NO_AREA: 336 out.Print("page fault error: no area"); 337 break; 338 case PAGE_FAULT_ERROR_KERNEL_ONLY: 339 out.Print("page fault error: area: %ld, kernel only", fArea); 340 break; 341 case PAGE_FAULT_ERROR_WRITE_PROTECTED: 342 out.Print("page fault error: area: %ld, write protected", 343 fArea); 344 break; 345 case PAGE_FAULT_ERROR_READ_PROTECTED: 346 out.Print("page fault error: area: %ld, read protected", fArea); 347 break; 348 case PAGE_FAULT_ERROR_KERNEL_BAD_USER_MEMORY: 349 out.Print("page fault error: kernel touching bad user memory"); 350 break; 351 case PAGE_FAULT_ERROR_NO_ADDRESS_SPACE: 352 out.Print("page fault error: no address space"); 353 break; 354 default: 355 out.Print("page fault error: area: %ld, error: %s", fArea, 356 strerror(fError)); 357 break; 358 } 359 } 360 361 private: 362 area_id fArea; 363 status_t fError; 364 }; 365 366 367 class PageFaultDone : public AbstractTraceEntry { 368 public: 369 PageFaultDone(area_id area, VMCache* topCache, VMCache* cache, 370 vm_page* page) 371 : 372 fArea(area), 373 fTopCache(topCache), 374 fCache(cache), 375 fPage(page) 376 { 377 Initialized(); 378 } 379 380 virtual void AddDump(TraceOutput& out) 381 { 382 out.Print("page fault done: area: %ld, top cache: %p, cache: %p, " 383 "page: %p", fArea, fTopCache, fCache, fPage); 384 } 385 386 private: 387 area_id fArea; 388 VMCache* fTopCache; 389 VMCache* fCache; 390 vm_page* fPage; 391 }; 392 393 } // namespace VMPageFaultTracing 394 395 # define TPF(x) new(std::nothrow) VMPageFaultTracing::x; 396 #else 397 # define TPF(x) ; 398 #endif // VM_PAGE_FAULT_TRACING 399 400 401 // #pragma mark - 402 403 404 /*! The page's cache must be locked. 405 */ 406 static inline void 407 increment_page_wired_count(vm_page* page) 408 { 409 if (!page->IsMapped()) 410 atomic_add(&gMappedPagesCount, 1); 411 page->IncrementWiredCount(); 412 } 413 414 415 /*! The page's cache must be locked. 416 */ 417 static inline void 418 decrement_page_wired_count(vm_page* page) 419 { 420 page->DecrementWiredCount(); 421 if (!page->IsMapped()) 422 atomic_add(&gMappedPagesCount, -1); 423 } 424 425 426 static inline addr_t 427 virtual_page_address(VMArea* area, vm_page* page) 428 { 429 return area->Base() 430 + ((page->cache_offset << PAGE_SHIFT) - area->cache_offset); 431 } 432 433 434 //! You need to have the address space locked when calling this function 435 static VMArea* 436 lookup_area(VMAddressSpace* addressSpace, area_id id) 437 { 438 VMAreaHash::ReadLock(); 439 440 VMArea* area = VMAreaHash::LookupLocked(id); 441 if (area != NULL && area->address_space != addressSpace) 442 area = NULL; 443 444 VMAreaHash::ReadUnlock(); 445 446 return area; 447 } 448 449 450 static inline void 451 set_area_page_protection(VMArea* area, addr_t pageAddress, uint32 protection) 452 { 453 protection &= B_READ_AREA | B_WRITE_AREA | B_EXECUTE_AREA; 454 uint32 pageIndex = (pageAddress - area->Base()) / B_PAGE_SIZE; 455 uint8& entry = area->page_protections[pageIndex / 2]; 456 if (pageIndex % 2 == 0) 457 entry = (entry & 0xf0) | protection; 458 else 459 entry = (entry & 0x0f) | (protection << 4); 460 } 461 462 463 static inline uint32 464 get_area_page_protection(VMArea* area, addr_t pageAddress) 465 { 466 if (area->page_protections == NULL) 467 return area->protection; 468 469 uint32 pageIndex = (pageAddress - area->Base()) / B_PAGE_SIZE; 470 uint32 protection = area->page_protections[pageIndex / 2]; 471 if (pageIndex % 2 == 0) 472 protection &= 0x0f; 473 else 474 protection >>= 4; 475 476 return protection | B_KERNEL_READ_AREA 477 | (protection & B_WRITE_AREA ? B_KERNEL_WRITE_AREA : 0); 478 } 479 480 481 /*! The caller must have reserved enough pages the translation map 482 implementation might need to map this page. 483 The page's cache must be locked. 484 */ 485 static status_t 486 map_page(VMArea* area, vm_page* page, addr_t address, uint32 protection, 487 vm_page_reservation* reservation) 488 { 489 VMTranslationMap* map = area->address_space->TranslationMap(); 490 491 bool wasMapped = page->IsMapped(); 492 493 if (area->wiring == B_NO_LOCK) { 494 DEBUG_PAGE_ACCESS_CHECK(page); 495 496 bool isKernelSpace = area->address_space == VMAddressSpace::Kernel(); 497 vm_page_mapping* mapping = (vm_page_mapping*)object_cache_alloc( 498 gPageMappingsObjectCache, 499 CACHE_DONT_WAIT_FOR_MEMORY 500 | (isKernelSpace ? CACHE_DONT_LOCK_KERNEL_SPACE : 0)); 501 if (mapping == NULL) 502 return B_NO_MEMORY; 503 504 mapping->page = page; 505 mapping->area = area; 506 507 map->Lock(); 508 509 map->Map(address, page->physical_page_number * B_PAGE_SIZE, protection, 510 area->MemoryType(), reservation); 511 512 // insert mapping into lists 513 if (!page->IsMapped()) 514 atomic_add(&gMappedPagesCount, 1); 515 516 page->mappings.Add(mapping); 517 area->mappings.Add(mapping); 518 519 map->Unlock(); 520 } else { 521 DEBUG_PAGE_ACCESS_CHECK(page); 522 523 map->Lock(); 524 map->Map(address, page->physical_page_number * B_PAGE_SIZE, protection, 525 area->MemoryType(), reservation); 526 map->Unlock(); 527 528 increment_page_wired_count(page); 529 } 530 531 if (!wasMapped) { 532 // The page is mapped now, so we must not remain in the cached queue. 533 // It also makes sense to move it from the inactive to the active, since 534 // otherwise the page daemon wouldn't come to keep track of it (in idle 535 // mode) -- if the page isn't touched, it will be deactivated after a 536 // full iteration through the queue at the latest. 537 if (page->State() == PAGE_STATE_CACHED 538 || page->State() == PAGE_STATE_INACTIVE) { 539 vm_page_set_state(page, PAGE_STATE_ACTIVE); 540 } 541 } 542 543 return B_OK; 544 } 545 546 547 /*! If \a preserveModified is \c true, the caller must hold the lock of the 548 page's cache. 549 */ 550 static inline bool 551 unmap_page(VMArea* area, addr_t virtualAddress) 552 { 553 return area->address_space->TranslationMap()->UnmapPage(area, 554 virtualAddress, true); 555 } 556 557 558 /*! If \a preserveModified is \c true, the caller must hold the lock of all 559 mapped pages' caches. 560 */ 561 static inline void 562 unmap_pages(VMArea* area, addr_t base, size_t size) 563 { 564 area->address_space->TranslationMap()->UnmapPages(area, base, size, true); 565 } 566 567 568 /*! Cuts a piece out of an area. If the given cut range covers the complete 569 area, it is deleted. If it covers the beginning or the end, the area is 570 resized accordingly. If the range covers some part in the middle of the 571 area, it is split in two; in this case the second area is returned via 572 \a _secondArea (the variable is left untouched in the other cases). 573 The address space must be write locked. 574 The caller must ensure that no part of the given range is wired. 575 */ 576 static status_t 577 cut_area(VMAddressSpace* addressSpace, VMArea* area, addr_t address, 578 addr_t lastAddress, VMArea** _secondArea, bool kernel) 579 { 580 // Does the cut range intersect with the area at all? 581 addr_t areaLast = area->Base() + (area->Size() - 1); 582 if (area->Base() > lastAddress || areaLast < address) 583 return B_OK; 584 585 // Is the area fully covered? 586 if (area->Base() >= address && areaLast <= lastAddress) { 587 delete_area(addressSpace, area, false); 588 return B_OK; 589 } 590 591 int priority; 592 uint32 allocationFlags; 593 if (addressSpace == VMAddressSpace::Kernel()) { 594 priority = VM_PRIORITY_SYSTEM; 595 allocationFlags = HEAP_DONT_WAIT_FOR_MEMORY 596 | HEAP_DONT_LOCK_KERNEL_SPACE; 597 } else { 598 priority = VM_PRIORITY_USER; 599 allocationFlags = 0; 600 } 601 602 VMCache* cache = vm_area_get_locked_cache(area); 603 VMCacheChainLocker cacheChainLocker(cache); 604 cacheChainLocker.LockAllSourceCaches(); 605 606 // Cut the end only? 607 if (areaLast <= lastAddress) { 608 size_t oldSize = area->Size(); 609 size_t newSize = address - area->Base(); 610 611 status_t error = addressSpace->ShrinkAreaTail(area, newSize, 612 allocationFlags); 613 if (error != B_OK) 614 return error; 615 616 // unmap pages 617 unmap_pages(area, address, oldSize - newSize); 618 619 // If no one else uses the area's cache, we can resize it, too. 620 if (cache->areas == area && area->cache_next == NULL 621 && list_is_empty(&cache->consumers) 622 && cache->type == CACHE_TYPE_RAM) { 623 // Since VMCache::Resize() can temporarily drop the lock, we must 624 // unlock all lower caches to prevent locking order inversion. 625 cacheChainLocker.Unlock(cache); 626 cache->Resize(cache->virtual_base + newSize, priority); 627 cache->ReleaseRefAndUnlock(); 628 } 629 630 return B_OK; 631 } 632 633 // Cut the beginning only? 634 if (area->Base() >= address) { 635 addr_t oldBase = area->Base(); 636 addr_t newBase = lastAddress + 1; 637 size_t newSize = areaLast - lastAddress; 638 639 // unmap pages 640 unmap_pages(area, oldBase, newBase - oldBase); 641 642 // resize the area 643 status_t error = addressSpace->ShrinkAreaHead(area, newSize, 644 allocationFlags); 645 if (error != B_OK) 646 return error; 647 648 // TODO: If no one else uses the area's cache, we should resize it, too! 649 650 area->cache_offset += newBase - oldBase; 651 652 return B_OK; 653 } 654 655 // The tough part -- cut a piece out of the middle of the area. 656 // We do that by shrinking the area to the begin section and creating a 657 // new area for the end section. 658 659 addr_t firstNewSize = address - area->Base(); 660 addr_t secondBase = lastAddress + 1; 661 addr_t secondSize = areaLast - lastAddress; 662 663 // unmap pages 664 unmap_pages(area, address, area->Size() - firstNewSize); 665 666 // resize the area 667 addr_t oldSize = area->Size(); 668 status_t error = addressSpace->ShrinkAreaTail(area, firstNewSize, 669 allocationFlags); 670 if (error != B_OK) 671 return error; 672 673 // TODO: If no one else uses the area's cache, we might want to create a 674 // new cache for the second area, transfer the concerned pages from the 675 // first cache to it and resize the first cache. 676 677 // map the second area 678 virtual_address_restrictions addressRestrictions = {}; 679 addressRestrictions.address = (void*)secondBase; 680 addressRestrictions.address_specification = B_EXACT_ADDRESS; 681 VMArea* secondArea; 682 error = map_backing_store(addressSpace, cache, 683 area->cache_offset + (secondBase - area->Base()), area->name, 684 secondSize, area->wiring, area->protection, REGION_NO_PRIVATE_MAP, 0, 685 &addressRestrictions, kernel, &secondArea, NULL); 686 if (error != B_OK) { 687 addressSpace->ShrinkAreaTail(area, oldSize, allocationFlags); 688 return error; 689 } 690 691 // We need a cache reference for the new area. 692 cache->AcquireRefLocked(); 693 694 if (_secondArea != NULL) 695 *_secondArea = secondArea; 696 697 return B_OK; 698 } 699 700 701 /*! Deletes all areas in the given address range. 702 The address space must be write-locked. 703 The caller must ensure that no part of the given range is wired. 704 */ 705 static status_t 706 unmap_address_range(VMAddressSpace* addressSpace, addr_t address, addr_t size, 707 bool kernel) 708 { 709 size = PAGE_ALIGN(size); 710 addr_t lastAddress = address + (size - 1); 711 712 // Check, whether the caller is allowed to modify the concerned areas. 713 if (!kernel) { 714 for (VMAddressSpace::AreaIterator it = addressSpace->GetAreaIterator(); 715 VMArea* area = it.Next();) { 716 addr_t areaLast = area->Base() + (area->Size() - 1); 717 if (area->Base() < lastAddress && address < areaLast) { 718 if ((area->protection & B_KERNEL_AREA) != 0) 719 return B_NOT_ALLOWED; 720 } 721 } 722 } 723 724 for (VMAddressSpace::AreaIterator it = addressSpace->GetAreaIterator(); 725 VMArea* area = it.Next();) { 726 addr_t areaLast = area->Base() + (area->Size() - 1); 727 if (area->Base() < lastAddress && address < areaLast) { 728 status_t error = cut_area(addressSpace, area, address, 729 lastAddress, NULL, kernel); 730 if (error != B_OK) 731 return error; 732 // Failing after already messing with areas is ugly, but we 733 // can't do anything about it. 734 } 735 } 736 737 return B_OK; 738 } 739 740 741 /*! You need to hold the lock of the cache and the write lock of the address 742 space when calling this function. 743 Note, that in case of error your cache will be temporarily unlocked. 744 If \a addressSpec is \c B_EXACT_ADDRESS and the 745 \c CREATE_AREA_UNMAP_ADDRESS_RANGE flag is specified, the caller must ensure 746 that no part of the specified address range (base \c *_virtualAddress, size 747 \a size) is wired. 748 */ 749 static status_t 750 map_backing_store(VMAddressSpace* addressSpace, VMCache* cache, off_t offset, 751 const char* areaName, addr_t size, int wiring, int protection, int mapping, 752 uint32 flags, const virtual_address_restrictions* addressRestrictions, 753 bool kernel, VMArea** _area, void** _virtualAddress) 754 { 755 TRACE(("map_backing_store: aspace %p, cache %p, virtual %p, offset 0x%Lx, " 756 "size %lu, addressSpec %ld, wiring %d, protection %d, area %p, areaName " 757 "'%s'\n", addressSpace, cache, addressRestrictions->address, offset, 758 size, addressRestrictions->address_specification, wiring, protection, 759 _area, areaName)); 760 cache->AssertLocked(); 761 762 uint32 allocationFlags = HEAP_DONT_WAIT_FOR_MEMORY 763 | HEAP_DONT_LOCK_KERNEL_SPACE; 764 int priority; 765 if (addressSpace != VMAddressSpace::Kernel()) { 766 priority = VM_PRIORITY_USER; 767 } else if ((flags & CREATE_AREA_PRIORITY_VIP) != 0) { 768 priority = VM_PRIORITY_VIP; 769 allocationFlags |= HEAP_PRIORITY_VIP; 770 } else 771 priority = VM_PRIORITY_SYSTEM; 772 773 VMArea* area = addressSpace->CreateArea(areaName, wiring, protection, 774 allocationFlags); 775 if (area == NULL) 776 return B_NO_MEMORY; 777 778 status_t status; 779 780 // if this is a private map, we need to create a new cache 781 // to handle the private copies of pages as they are written to 782 VMCache* sourceCache = cache; 783 if (mapping == REGION_PRIVATE_MAP) { 784 VMCache* newCache; 785 786 // create an anonymous cache 787 bool isStack = (protection & B_STACK_AREA) != 0; 788 status = VMCacheFactory::CreateAnonymousCache(newCache, 789 isStack || (protection & B_OVERCOMMITTING_AREA) != 0, 0, 790 isStack ? USER_STACK_GUARD_PAGES : 0, true, VM_PRIORITY_USER); 791 if (status != B_OK) 792 goto err1; 793 794 newCache->Lock(); 795 newCache->temporary = 1; 796 newCache->virtual_base = offset; 797 newCache->virtual_end = offset + size; 798 799 cache->AddConsumer(newCache); 800 801 cache = newCache; 802 } 803 804 if ((flags & CREATE_AREA_DONT_COMMIT_MEMORY) == 0) { 805 status = cache->SetMinimalCommitment(size, priority); 806 if (status != B_OK) 807 goto err2; 808 } 809 810 // check to see if this address space has entered DELETE state 811 if (addressSpace->IsBeingDeleted()) { 812 // okay, someone is trying to delete this address space now, so we can't 813 // insert the area, so back out 814 status = B_BAD_TEAM_ID; 815 goto err2; 816 } 817 818 if (addressRestrictions->address_specification == B_EXACT_ADDRESS 819 && (flags & CREATE_AREA_UNMAP_ADDRESS_RANGE) != 0) { 820 status = unmap_address_range(addressSpace, 821 (addr_t)addressRestrictions->address, size, kernel); 822 if (status != B_OK) 823 goto err2; 824 } 825 826 status = addressSpace->InsertArea(area, size, addressRestrictions, 827 allocationFlags, _virtualAddress); 828 if (status != B_OK) { 829 // TODO: wait and try again once this is working in the backend 830 #if 0 831 if (status == B_NO_MEMORY && addressSpec == B_ANY_KERNEL_ADDRESS) { 832 low_resource(B_KERNEL_RESOURCE_ADDRESS_SPACE, size, 833 0, 0); 834 } 835 #endif 836 goto err2; 837 } 838 839 // attach the cache to the area 840 area->cache = cache; 841 area->cache_offset = offset; 842 843 // point the cache back to the area 844 cache->InsertAreaLocked(area); 845 if (mapping == REGION_PRIVATE_MAP) 846 cache->Unlock(); 847 848 // insert the area in the global area hash table 849 VMAreaHash::Insert(area); 850 851 // grab a ref to the address space (the area holds this) 852 addressSpace->Get(); 853 854 // ktrace_printf("map_backing_store: cache: %p (source: %p), \"%s\" -> %p", 855 // cache, sourceCache, areaName, area); 856 857 *_area = area; 858 return B_OK; 859 860 err2: 861 if (mapping == REGION_PRIVATE_MAP) { 862 // We created this cache, so we must delete it again. Note, that we 863 // need to temporarily unlock the source cache or we'll otherwise 864 // deadlock, since VMCache::_RemoveConsumer() will try to lock it, too. 865 sourceCache->Unlock(); 866 cache->ReleaseRefAndUnlock(); 867 sourceCache->Lock(); 868 } 869 err1: 870 addressSpace->DeleteArea(area, allocationFlags); 871 return status; 872 } 873 874 875 /*! Equivalent to wait_if_area_range_is_wired(area, area->Base(), area->Size(), 876 locker1, locker2). 877 */ 878 template<typename LockerType1, typename LockerType2> 879 static inline bool 880 wait_if_area_is_wired(VMArea* area, LockerType1* locker1, LockerType2* locker2) 881 { 882 area->cache->AssertLocked(); 883 884 VMAreaUnwiredWaiter waiter; 885 if (!area->AddWaiterIfWired(&waiter)) 886 return false; 887 888 // unlock everything and wait 889 if (locker1 != NULL) 890 locker1->Unlock(); 891 if (locker2 != NULL) 892 locker2->Unlock(); 893 894 waiter.waitEntry.Wait(); 895 896 return true; 897 } 898 899 900 /*! Checks whether the given area has any wired ranges intersecting with the 901 specified range and waits, if so. 902 903 When it has to wait, the function calls \c Unlock() on both \a locker1 904 and \a locker2, if given. 905 The area's top cache must be locked and must be unlocked as a side effect 906 of calling \c Unlock() on either \a locker1 or \a locker2. 907 908 If the function does not have to wait it does not modify or unlock any 909 object. 910 911 \param area The area to be checked. 912 \param base The base address of the range to check. 913 \param size The size of the address range to check. 914 \param locker1 An object to be unlocked when before starting to wait (may 915 be \c NULL). 916 \param locker2 An object to be unlocked when before starting to wait (may 917 be \c NULL). 918 \return \c true, if the function had to wait, \c false otherwise. 919 */ 920 template<typename LockerType1, typename LockerType2> 921 static inline bool 922 wait_if_area_range_is_wired(VMArea* area, addr_t base, size_t size, 923 LockerType1* locker1, LockerType2* locker2) 924 { 925 area->cache->AssertLocked(); 926 927 VMAreaUnwiredWaiter waiter; 928 if (!area->AddWaiterIfWired(&waiter, base, size)) 929 return false; 930 931 // unlock everything and wait 932 if (locker1 != NULL) 933 locker1->Unlock(); 934 if (locker2 != NULL) 935 locker2->Unlock(); 936 937 waiter.waitEntry.Wait(); 938 939 return true; 940 } 941 942 943 /*! Checks whether the given address space has any wired ranges intersecting 944 with the specified range and waits, if so. 945 946 Similar to wait_if_area_range_is_wired(), with the following differences: 947 - All areas intersecting with the range are checked (respectively all until 948 one is found that contains a wired range intersecting with the given 949 range). 950 - The given address space must at least be read-locked and must be unlocked 951 when \c Unlock() is called on \a locker. 952 - None of the areas' caches are allowed to be locked. 953 */ 954 template<typename LockerType> 955 static inline bool 956 wait_if_address_range_is_wired(VMAddressSpace* addressSpace, addr_t base, 957 size_t size, LockerType* locker) 958 { 959 addr_t end = base + size - 1; 960 for (VMAddressSpace::AreaIterator it = addressSpace->GetAreaIterator(); 961 VMArea* area = it.Next();) { 962 // TODO: Introduce a VMAddressSpace method to get a close iterator! 963 if (area->Base() > end) 964 return false; 965 966 if (base >= area->Base() + area->Size() - 1) 967 continue; 968 969 AreaCacheLocker cacheLocker(vm_area_get_locked_cache(area)); 970 971 if (wait_if_area_range_is_wired(area, base, size, locker, &cacheLocker)) 972 return true; 973 } 974 975 return false; 976 } 977 978 979 status_t 980 vm_block_address_range(const char* name, void* address, addr_t size) 981 { 982 if (!arch_vm_supports_protection(0)) 983 return B_NOT_SUPPORTED; 984 985 AddressSpaceWriteLocker locker; 986 status_t status = locker.SetTo(VMAddressSpace::KernelID()); 987 if (status != B_OK) 988 return status; 989 990 VMAddressSpace* addressSpace = locker.AddressSpace(); 991 992 // create an anonymous cache 993 VMCache* cache; 994 status = VMCacheFactory::CreateAnonymousCache(cache, false, 0, 0, false, 995 VM_PRIORITY_SYSTEM); 996 if (status != B_OK) 997 return status; 998 999 cache->temporary = 1; 1000 cache->virtual_end = size; 1001 cache->Lock(); 1002 1003 VMArea* area; 1004 virtual_address_restrictions addressRestrictions = {}; 1005 addressRestrictions.address = address; 1006 addressRestrictions.address_specification = B_EXACT_ADDRESS; 1007 status = map_backing_store(addressSpace, cache, 0, name, size, 1008 B_ALREADY_WIRED, B_ALREADY_WIRED, REGION_NO_PRIVATE_MAP, 0, 1009 &addressRestrictions, true, &area, NULL); 1010 if (status != B_OK) { 1011 cache->ReleaseRefAndUnlock(); 1012 return status; 1013 } 1014 1015 cache->Unlock(); 1016 area->cache_type = CACHE_TYPE_RAM; 1017 return area->id; 1018 } 1019 1020 1021 status_t 1022 vm_unreserve_address_range(team_id team, void* address, addr_t size) 1023 { 1024 AddressSpaceWriteLocker locker(team); 1025 if (!locker.IsLocked()) 1026 return B_BAD_TEAM_ID; 1027 1028 VMAddressSpace* addressSpace = locker.AddressSpace(); 1029 return addressSpace->UnreserveAddressRange((addr_t)address, size, 1030 addressSpace == VMAddressSpace::Kernel() 1031 ? HEAP_DONT_WAIT_FOR_MEMORY | HEAP_DONT_LOCK_KERNEL_SPACE : 0); 1032 } 1033 1034 1035 status_t 1036 vm_reserve_address_range(team_id team, void** _address, uint32 addressSpec, 1037 addr_t size, uint32 flags) 1038 { 1039 if (size == 0) 1040 return B_BAD_VALUE; 1041 1042 AddressSpaceWriteLocker locker(team); 1043 if (!locker.IsLocked()) 1044 return B_BAD_TEAM_ID; 1045 1046 virtual_address_restrictions addressRestrictions = {}; 1047 addressRestrictions.address = *_address; 1048 addressRestrictions.address_specification = addressSpec; 1049 VMAddressSpace* addressSpace = locker.AddressSpace(); 1050 return addressSpace->ReserveAddressRange(size, &addressRestrictions, flags, 1051 addressSpace == VMAddressSpace::Kernel() 1052 ? HEAP_DONT_WAIT_FOR_MEMORY | HEAP_DONT_LOCK_KERNEL_SPACE : 0, 1053 _address); 1054 } 1055 1056 1057 area_id 1058 vm_create_anonymous_area(team_id team, const char *name, addr_t size, 1059 uint32 wiring, uint32 protection, uint32 flags, 1060 const virtual_address_restrictions* virtualAddressRestrictions, 1061 const physical_address_restrictions* physicalAddressRestrictions, 1062 bool kernel, void** _address) 1063 { 1064 VMArea* area; 1065 VMCache* cache; 1066 vm_page* page = NULL; 1067 bool isStack = (protection & B_STACK_AREA) != 0; 1068 page_num_t guardPages; 1069 bool canOvercommit = false; 1070 uint32 pageAllocFlags = (flags & CREATE_AREA_DONT_CLEAR) == 0 1071 ? VM_PAGE_ALLOC_CLEAR : 0; 1072 1073 TRACE(("create_anonymous_area [%ld] %s: size 0x%lx\n", team, name, size)); 1074 1075 size = PAGE_ALIGN(size); 1076 1077 if (size == 0) 1078 return B_BAD_VALUE; 1079 if (!arch_vm_supports_protection(protection)) 1080 return B_NOT_SUPPORTED; 1081 1082 if (isStack || (protection & B_OVERCOMMITTING_AREA) != 0) 1083 canOvercommit = true; 1084 1085 #ifdef DEBUG_KERNEL_STACKS 1086 if ((protection & B_KERNEL_STACK_AREA) != 0) 1087 isStack = true; 1088 #endif 1089 1090 // check parameters 1091 switch (virtualAddressRestrictions->address_specification) { 1092 case B_ANY_ADDRESS: 1093 case B_EXACT_ADDRESS: 1094 case B_BASE_ADDRESS: 1095 case B_ANY_KERNEL_ADDRESS: 1096 case B_ANY_KERNEL_BLOCK_ADDRESS: 1097 break; 1098 1099 default: 1100 return B_BAD_VALUE; 1101 } 1102 1103 // If low or high physical address restrictions are given, we force 1104 // B_CONTIGUOUS wiring, since only then we'll use 1105 // vm_page_allocate_page_run() which deals with those restrictions. 1106 if (physicalAddressRestrictions->low_address != 0 1107 || physicalAddressRestrictions->high_address != 0) { 1108 wiring = B_CONTIGUOUS; 1109 } 1110 1111 physical_address_restrictions stackPhysicalRestrictions; 1112 bool doReserveMemory = false; 1113 switch (wiring) { 1114 case B_NO_LOCK: 1115 break; 1116 case B_FULL_LOCK: 1117 case B_LAZY_LOCK: 1118 case B_CONTIGUOUS: 1119 doReserveMemory = true; 1120 break; 1121 case B_ALREADY_WIRED: 1122 break; 1123 case B_LOMEM: 1124 stackPhysicalRestrictions = *physicalAddressRestrictions; 1125 stackPhysicalRestrictions.high_address = 16 * 1024 * 1024; 1126 physicalAddressRestrictions = &stackPhysicalRestrictions; 1127 wiring = B_CONTIGUOUS; 1128 doReserveMemory = true; 1129 break; 1130 case B_32_BIT_FULL_LOCK: 1131 if (B_HAIKU_PHYSICAL_BITS <= 32 1132 || (uint64)vm_page_max_address() < (uint64)1 << 32) { 1133 wiring = B_FULL_LOCK; 1134 doReserveMemory = true; 1135 break; 1136 } 1137 // TODO: We don't really support this mode efficiently. Just fall 1138 // through for now ... 1139 case B_32_BIT_CONTIGUOUS: 1140 #if B_HAIKU_PHYSICAL_BITS > 32 1141 if (vm_page_max_address() >= (phys_addr_t)1 << 32) { 1142 stackPhysicalRestrictions = *physicalAddressRestrictions; 1143 stackPhysicalRestrictions.high_address 1144 = (phys_addr_t)1 << 32; 1145 physicalAddressRestrictions = &stackPhysicalRestrictions; 1146 } 1147 #endif 1148 wiring = B_CONTIGUOUS; 1149 doReserveMemory = true; 1150 break; 1151 default: 1152 return B_BAD_VALUE; 1153 } 1154 1155 // Optimization: For a single-page contiguous allocation without low/high 1156 // memory restriction B_FULL_LOCK wiring suffices. 1157 if (wiring == B_CONTIGUOUS && size == B_PAGE_SIZE 1158 && physicalAddressRestrictions->low_address == 0 1159 && physicalAddressRestrictions->high_address == 0) { 1160 wiring = B_FULL_LOCK; 1161 } 1162 1163 // For full lock or contiguous areas we're also going to map the pages and 1164 // thus need to reserve pages for the mapping backend upfront. 1165 addr_t reservedMapPages = 0; 1166 if (wiring == B_FULL_LOCK || wiring == B_CONTIGUOUS) { 1167 AddressSpaceWriteLocker locker; 1168 status_t status = locker.SetTo(team); 1169 if (status != B_OK) 1170 return status; 1171 1172 VMTranslationMap* map = locker.AddressSpace()->TranslationMap(); 1173 reservedMapPages = map->MaxPagesNeededToMap(0, size - 1); 1174 } 1175 1176 int priority; 1177 if (team != VMAddressSpace::KernelID()) 1178 priority = VM_PRIORITY_USER; 1179 else if ((flags & CREATE_AREA_PRIORITY_VIP) != 0) 1180 priority = VM_PRIORITY_VIP; 1181 else 1182 priority = VM_PRIORITY_SYSTEM; 1183 1184 // Reserve memory before acquiring the address space lock. This reduces the 1185 // chances of failure, since while holding the write lock to the address 1186 // space (if it is the kernel address space that is), the low memory handler 1187 // won't be able to free anything for us. 1188 addr_t reservedMemory = 0; 1189 if (doReserveMemory) { 1190 bigtime_t timeout = (flags & CREATE_AREA_DONT_WAIT) != 0 ? 0 : 1000000; 1191 if (vm_try_reserve_memory(size, priority, timeout) != B_OK) 1192 return B_NO_MEMORY; 1193 reservedMemory = size; 1194 // TODO: We don't reserve the memory for the pages for the page 1195 // directories/tables. We actually need to do since we currently don't 1196 // reclaim them (and probably can't reclaim all of them anyway). Thus 1197 // there are actually less physical pages than there should be, which 1198 // can get the VM into trouble in low memory situations. 1199 } 1200 1201 AddressSpaceWriteLocker locker; 1202 VMAddressSpace* addressSpace; 1203 status_t status; 1204 1205 // For full lock areas reserve the pages before locking the address 1206 // space. E.g. block caches can't release their memory while we hold the 1207 // address space lock. 1208 page_num_t reservedPages = reservedMapPages; 1209 if (wiring == B_FULL_LOCK) 1210 reservedPages += size / B_PAGE_SIZE; 1211 1212 vm_page_reservation reservation; 1213 if (reservedPages > 0) { 1214 if ((flags & CREATE_AREA_DONT_WAIT) != 0) { 1215 if (!vm_page_try_reserve_pages(&reservation, reservedPages, 1216 priority)) { 1217 reservedPages = 0; 1218 status = B_WOULD_BLOCK; 1219 goto err0; 1220 } 1221 } else 1222 vm_page_reserve_pages(&reservation, reservedPages, priority); 1223 } 1224 1225 if (wiring == B_CONTIGUOUS) { 1226 // we try to allocate the page run here upfront as this may easily 1227 // fail for obvious reasons 1228 page = vm_page_allocate_page_run(PAGE_STATE_WIRED | pageAllocFlags, 1229 size / B_PAGE_SIZE, physicalAddressRestrictions, priority); 1230 if (page == NULL) { 1231 status = B_NO_MEMORY; 1232 goto err0; 1233 } 1234 } 1235 1236 // Lock the address space and, if B_EXACT_ADDRESS and 1237 // CREATE_AREA_UNMAP_ADDRESS_RANGE were specified, ensure the address range 1238 // is not wired. 1239 do { 1240 status = locker.SetTo(team); 1241 if (status != B_OK) 1242 goto err1; 1243 1244 addressSpace = locker.AddressSpace(); 1245 } while (virtualAddressRestrictions->address_specification 1246 == B_EXACT_ADDRESS 1247 && (flags & CREATE_AREA_UNMAP_ADDRESS_RANGE) != 0 1248 && wait_if_address_range_is_wired(addressSpace, 1249 (addr_t)virtualAddressRestrictions->address, size, &locker)); 1250 1251 // create an anonymous cache 1252 // if it's a stack, make sure that two pages are available at least 1253 guardPages = isStack ? ((protection & B_USER_PROTECTION) != 0 1254 ? USER_STACK_GUARD_PAGES : KERNEL_STACK_GUARD_PAGES) : 0; 1255 status = VMCacheFactory::CreateAnonymousCache(cache, canOvercommit, 1256 isStack ? (min_c(2, size / B_PAGE_SIZE - guardPages)) : 0, guardPages, 1257 wiring == B_NO_LOCK, priority); 1258 if (status != B_OK) 1259 goto err1; 1260 1261 cache->temporary = 1; 1262 cache->virtual_end = size; 1263 cache->committed_size = reservedMemory; 1264 // TODO: This should be done via a method. 1265 reservedMemory = 0; 1266 1267 cache->Lock(); 1268 1269 status = map_backing_store(addressSpace, cache, 0, name, size, wiring, 1270 protection, REGION_NO_PRIVATE_MAP, flags, virtualAddressRestrictions, 1271 kernel, &area, _address); 1272 1273 if (status != B_OK) { 1274 cache->ReleaseRefAndUnlock(); 1275 goto err1; 1276 } 1277 1278 locker.DegradeToReadLock(); 1279 1280 switch (wiring) { 1281 case B_NO_LOCK: 1282 case B_LAZY_LOCK: 1283 // do nothing - the pages are mapped in as needed 1284 break; 1285 1286 case B_FULL_LOCK: 1287 { 1288 // Allocate and map all pages for this area 1289 1290 off_t offset = 0; 1291 for (addr_t address = area->Base(); 1292 address < area->Base() + (area->Size() - 1); 1293 address += B_PAGE_SIZE, offset += B_PAGE_SIZE) { 1294 #ifdef DEBUG_KERNEL_STACKS 1295 # ifdef STACK_GROWS_DOWNWARDS 1296 if (isStack && address < area->Base() 1297 + KERNEL_STACK_GUARD_PAGES * B_PAGE_SIZE) 1298 # else 1299 if (isStack && address >= area->Base() + area->Size() 1300 - KERNEL_STACK_GUARD_PAGES * B_PAGE_SIZE) 1301 # endif 1302 continue; 1303 #endif 1304 vm_page* page = vm_page_allocate_page(&reservation, 1305 PAGE_STATE_WIRED | pageAllocFlags); 1306 cache->InsertPage(page, offset); 1307 map_page(area, page, address, protection, &reservation); 1308 1309 DEBUG_PAGE_ACCESS_END(page); 1310 } 1311 1312 break; 1313 } 1314 1315 case B_ALREADY_WIRED: 1316 { 1317 // The pages should already be mapped. This is only really useful 1318 // during boot time. Find the appropriate vm_page objects and stick 1319 // them in the cache object. 1320 VMTranslationMap* map = addressSpace->TranslationMap(); 1321 off_t offset = 0; 1322 1323 if (!gKernelStartup) 1324 panic("ALREADY_WIRED flag used outside kernel startup\n"); 1325 1326 map->Lock(); 1327 1328 for (addr_t virtualAddress = area->Base(); 1329 virtualAddress < area->Base() + (area->Size() - 1); 1330 virtualAddress += B_PAGE_SIZE, offset += B_PAGE_SIZE) { 1331 phys_addr_t physicalAddress; 1332 uint32 flags; 1333 status = map->Query(virtualAddress, &physicalAddress, &flags); 1334 if (status < B_OK) { 1335 panic("looking up mapping failed for va 0x%lx\n", 1336 virtualAddress); 1337 } 1338 page = vm_lookup_page(physicalAddress / B_PAGE_SIZE); 1339 if (page == NULL) { 1340 panic("looking up page failed for pa %#" B_PRIxPHYSADDR 1341 "\n", physicalAddress); 1342 } 1343 1344 DEBUG_PAGE_ACCESS_START(page); 1345 1346 cache->InsertPage(page, offset); 1347 increment_page_wired_count(page); 1348 vm_page_set_state(page, PAGE_STATE_WIRED); 1349 page->busy = false; 1350 1351 DEBUG_PAGE_ACCESS_END(page); 1352 } 1353 1354 map->Unlock(); 1355 break; 1356 } 1357 1358 case B_CONTIGUOUS: 1359 { 1360 // We have already allocated our continuous pages run, so we can now 1361 // just map them in the address space 1362 VMTranslationMap* map = addressSpace->TranslationMap(); 1363 phys_addr_t physicalAddress 1364 = (phys_addr_t)page->physical_page_number * B_PAGE_SIZE; 1365 addr_t virtualAddress = area->Base(); 1366 off_t offset = 0; 1367 1368 map->Lock(); 1369 1370 for (virtualAddress = area->Base(); virtualAddress < area->Base() 1371 + (area->Size() - 1); virtualAddress += B_PAGE_SIZE, 1372 offset += B_PAGE_SIZE, physicalAddress += B_PAGE_SIZE) { 1373 page = vm_lookup_page(physicalAddress / B_PAGE_SIZE); 1374 if (page == NULL) 1375 panic("couldn't lookup physical page just allocated\n"); 1376 1377 status = map->Map(virtualAddress, physicalAddress, protection, 1378 area->MemoryType(), &reservation); 1379 if (status < B_OK) 1380 panic("couldn't map physical page in page run\n"); 1381 1382 cache->InsertPage(page, offset); 1383 increment_page_wired_count(page); 1384 1385 DEBUG_PAGE_ACCESS_END(page); 1386 } 1387 1388 map->Unlock(); 1389 break; 1390 } 1391 1392 default: 1393 break; 1394 } 1395 1396 cache->Unlock(); 1397 1398 if (reservedPages > 0) 1399 vm_page_unreserve_pages(&reservation); 1400 1401 TRACE(("vm_create_anonymous_area: done\n")); 1402 1403 area->cache_type = CACHE_TYPE_RAM; 1404 return area->id; 1405 1406 err1: 1407 if (wiring == B_CONTIGUOUS) { 1408 // we had reserved the area space upfront... 1409 phys_addr_t pageNumber = page->physical_page_number; 1410 int32 i; 1411 for (i = size / B_PAGE_SIZE; i-- > 0; pageNumber++) { 1412 page = vm_lookup_page(pageNumber); 1413 if (page == NULL) 1414 panic("couldn't lookup physical page just allocated\n"); 1415 1416 vm_page_set_state(page, PAGE_STATE_FREE); 1417 } 1418 } 1419 1420 err0: 1421 if (reservedPages > 0) 1422 vm_page_unreserve_pages(&reservation); 1423 if (reservedMemory > 0) 1424 vm_unreserve_memory(reservedMemory); 1425 1426 return status; 1427 } 1428 1429 1430 area_id 1431 vm_map_physical_memory(team_id team, const char* name, void** _address, 1432 uint32 addressSpec, addr_t size, uint32 protection, 1433 phys_addr_t physicalAddress, bool alreadyWired) 1434 { 1435 VMArea* area; 1436 VMCache* cache; 1437 addr_t mapOffset; 1438 1439 TRACE(("vm_map_physical_memory(aspace = %ld, \"%s\", virtual = %p, " 1440 "spec = %ld, size = %lu, protection = %ld, phys = %#lx)\n", team, 1441 name, *_address, addressSpec, size, protection, physicalAddress)); 1442 1443 if (!arch_vm_supports_protection(protection)) 1444 return B_NOT_SUPPORTED; 1445 1446 AddressSpaceWriteLocker locker(team); 1447 if (!locker.IsLocked()) 1448 return B_BAD_TEAM_ID; 1449 1450 // if the physical address is somewhat inside a page, 1451 // move the actual area down to align on a page boundary 1452 mapOffset = physicalAddress % B_PAGE_SIZE; 1453 size += mapOffset; 1454 physicalAddress -= mapOffset; 1455 1456 size = PAGE_ALIGN(size); 1457 1458 // create a device cache 1459 status_t status = VMCacheFactory::CreateDeviceCache(cache, physicalAddress); 1460 if (status != B_OK) 1461 return status; 1462 1463 cache->virtual_end = size; 1464 1465 cache->Lock(); 1466 1467 virtual_address_restrictions addressRestrictions = {}; 1468 addressRestrictions.address = *_address; 1469 addressRestrictions.address_specification = addressSpec & ~B_MTR_MASK; 1470 status = map_backing_store(locker.AddressSpace(), cache, 0, name, size, 1471 B_FULL_LOCK, protection, REGION_NO_PRIVATE_MAP, 0, &addressRestrictions, 1472 true, &area, _address); 1473 1474 if (status < B_OK) 1475 cache->ReleaseRefLocked(); 1476 1477 cache->Unlock(); 1478 1479 if (status == B_OK) { 1480 // set requested memory type -- use uncached, if not given 1481 uint32 memoryType = addressSpec & B_MTR_MASK; 1482 if (memoryType == 0) 1483 memoryType = B_MTR_UC; 1484 1485 area->SetMemoryType(memoryType); 1486 1487 status = arch_vm_set_memory_type(area, physicalAddress, memoryType); 1488 if (status != B_OK) 1489 delete_area(locker.AddressSpace(), area, false); 1490 } 1491 1492 if (status != B_OK) 1493 return status; 1494 1495 VMTranslationMap* map = locker.AddressSpace()->TranslationMap(); 1496 1497 if (alreadyWired) { 1498 // The area is already mapped, but possibly not with the right 1499 // memory type. 1500 map->Lock(); 1501 map->ProtectArea(area, area->protection); 1502 map->Unlock(); 1503 } else { 1504 // Map the area completely. 1505 1506 // reserve pages needed for the mapping 1507 size_t reservePages = map->MaxPagesNeededToMap(area->Base(), 1508 area->Base() + (size - 1)); 1509 vm_page_reservation reservation; 1510 vm_page_reserve_pages(&reservation, reservePages, 1511 team == VMAddressSpace::KernelID() 1512 ? VM_PRIORITY_SYSTEM : VM_PRIORITY_USER); 1513 1514 map->Lock(); 1515 1516 for (addr_t offset = 0; offset < size; offset += B_PAGE_SIZE) { 1517 map->Map(area->Base() + offset, physicalAddress + offset, 1518 protection, area->MemoryType(), &reservation); 1519 } 1520 1521 map->Unlock(); 1522 1523 vm_page_unreserve_pages(&reservation); 1524 } 1525 1526 // modify the pointer returned to be offset back into the new area 1527 // the same way the physical address in was offset 1528 *_address = (void*)((addr_t)*_address + mapOffset); 1529 1530 area->cache_type = CACHE_TYPE_DEVICE; 1531 return area->id; 1532 } 1533 1534 1535 /*! Don't use! 1536 TODO: This function was introduced to map physical page vecs to 1537 contiguous virtual memory in IOBuffer::GetNextVirtualVec(). It does 1538 use a device cache and does not track vm_page::wired_count! 1539 */ 1540 area_id 1541 vm_map_physical_memory_vecs(team_id team, const char* name, void** _address, 1542 uint32 addressSpec, addr_t* _size, uint32 protection, 1543 struct generic_io_vec* vecs, uint32 vecCount) 1544 { 1545 TRACE(("vm_map_physical_memory_vecs(team = %ld, \"%s\", virtual = %p, " 1546 "spec = %ld, _size = %p, protection = %ld, vecs = %p, " 1547 "vecCount = %ld)\n", team, name, *_address, addressSpec, _size, 1548 protection, vecs, vecCount)); 1549 1550 if (!arch_vm_supports_protection(protection) 1551 || (addressSpec & B_MTR_MASK) != 0) { 1552 return B_NOT_SUPPORTED; 1553 } 1554 1555 AddressSpaceWriteLocker locker(team); 1556 if (!locker.IsLocked()) 1557 return B_BAD_TEAM_ID; 1558 1559 if (vecCount == 0) 1560 return B_BAD_VALUE; 1561 1562 addr_t size = 0; 1563 for (uint32 i = 0; i < vecCount; i++) { 1564 if (vecs[i].base % B_PAGE_SIZE != 0 1565 || vecs[i].length % B_PAGE_SIZE != 0) { 1566 return B_BAD_VALUE; 1567 } 1568 1569 size += vecs[i].length; 1570 } 1571 1572 // create a device cache 1573 VMCache* cache; 1574 status_t result = VMCacheFactory::CreateDeviceCache(cache, vecs[0].base); 1575 if (result != B_OK) 1576 return result; 1577 1578 cache->virtual_end = size; 1579 1580 cache->Lock(); 1581 1582 VMArea* area; 1583 virtual_address_restrictions addressRestrictions = {}; 1584 addressRestrictions.address = *_address; 1585 addressRestrictions.address_specification = addressSpec & ~B_MTR_MASK; 1586 result = map_backing_store(locker.AddressSpace(), cache, 0, name, 1587 size, B_FULL_LOCK, protection, REGION_NO_PRIVATE_MAP, 0, 1588 &addressRestrictions, true, &area, _address); 1589 1590 if (result != B_OK) 1591 cache->ReleaseRefLocked(); 1592 1593 cache->Unlock(); 1594 1595 if (result != B_OK) 1596 return result; 1597 1598 VMTranslationMap* map = locker.AddressSpace()->TranslationMap(); 1599 size_t reservePages = map->MaxPagesNeededToMap(area->Base(), 1600 area->Base() + (size - 1)); 1601 1602 vm_page_reservation reservation; 1603 vm_page_reserve_pages(&reservation, reservePages, 1604 team == VMAddressSpace::KernelID() 1605 ? VM_PRIORITY_SYSTEM : VM_PRIORITY_USER); 1606 map->Lock(); 1607 1608 uint32 vecIndex = 0; 1609 size_t vecOffset = 0; 1610 for (addr_t offset = 0; offset < size; offset += B_PAGE_SIZE) { 1611 while (vecOffset >= vecs[vecIndex].length && vecIndex < vecCount) { 1612 vecOffset = 0; 1613 vecIndex++; 1614 } 1615 1616 if (vecIndex >= vecCount) 1617 break; 1618 1619 map->Map(area->Base() + offset, vecs[vecIndex].base + vecOffset, 1620 protection, area->MemoryType(), &reservation); 1621 1622 vecOffset += B_PAGE_SIZE; 1623 } 1624 1625 map->Unlock(); 1626 vm_page_unreserve_pages(&reservation); 1627 1628 if (_size != NULL) 1629 *_size = size; 1630 1631 area->cache_type = CACHE_TYPE_DEVICE; 1632 return area->id; 1633 } 1634 1635 1636 area_id 1637 vm_create_null_area(team_id team, const char* name, void** address, 1638 uint32 addressSpec, addr_t size, uint32 flags) 1639 { 1640 size = PAGE_ALIGN(size); 1641 1642 // Lock the address space and, if B_EXACT_ADDRESS and 1643 // CREATE_AREA_UNMAP_ADDRESS_RANGE were specified, ensure the address range 1644 // is not wired. 1645 AddressSpaceWriteLocker locker; 1646 do { 1647 if (locker.SetTo(team) != B_OK) 1648 return B_BAD_TEAM_ID; 1649 } while (addressSpec == B_EXACT_ADDRESS 1650 && (flags & CREATE_AREA_UNMAP_ADDRESS_RANGE) != 0 1651 && wait_if_address_range_is_wired(locker.AddressSpace(), 1652 (addr_t)*address, size, &locker)); 1653 1654 // create a null cache 1655 int priority = (flags & CREATE_AREA_PRIORITY_VIP) != 0 1656 ? VM_PRIORITY_VIP : VM_PRIORITY_SYSTEM; 1657 VMCache* cache; 1658 status_t status = VMCacheFactory::CreateNullCache(priority, cache); 1659 if (status != B_OK) 1660 return status; 1661 1662 cache->temporary = 1; 1663 cache->virtual_end = size; 1664 1665 cache->Lock(); 1666 1667 VMArea* area; 1668 virtual_address_restrictions addressRestrictions = {}; 1669 addressRestrictions.address = *address; 1670 addressRestrictions.address_specification = addressSpec; 1671 status = map_backing_store(locker.AddressSpace(), cache, 0, name, size, 1672 B_LAZY_LOCK, B_KERNEL_READ_AREA, REGION_NO_PRIVATE_MAP, flags, 1673 &addressRestrictions, true, &area, address); 1674 1675 if (status < B_OK) { 1676 cache->ReleaseRefAndUnlock(); 1677 return status; 1678 } 1679 1680 cache->Unlock(); 1681 1682 area->cache_type = CACHE_TYPE_NULL; 1683 return area->id; 1684 } 1685 1686 1687 /*! Creates the vnode cache for the specified \a vnode. 1688 The vnode has to be marked busy when calling this function. 1689 */ 1690 status_t 1691 vm_create_vnode_cache(struct vnode* vnode, struct VMCache** cache) 1692 { 1693 return VMCacheFactory::CreateVnodeCache(*cache, vnode); 1694 } 1695 1696 1697 /*! \a cache must be locked. The area's address space must be read-locked. 1698 */ 1699 static void 1700 pre_map_area_pages(VMArea* area, VMCache* cache, 1701 vm_page_reservation* reservation) 1702 { 1703 addr_t baseAddress = area->Base(); 1704 addr_t cacheOffset = area->cache_offset; 1705 page_num_t firstPage = cacheOffset / B_PAGE_SIZE; 1706 page_num_t endPage = firstPage + area->Size() / B_PAGE_SIZE; 1707 1708 for (VMCachePagesTree::Iterator it 1709 = cache->pages.GetIterator(firstPage, true, true); 1710 vm_page* page = it.Next();) { 1711 if (page->cache_offset >= endPage) 1712 break; 1713 1714 // skip busy and inactive pages 1715 if (page->busy || page->usage_count == 0) 1716 continue; 1717 1718 DEBUG_PAGE_ACCESS_START(page); 1719 map_page(area, page, 1720 baseAddress + (page->cache_offset * B_PAGE_SIZE - cacheOffset), 1721 B_READ_AREA | B_KERNEL_READ_AREA, reservation); 1722 DEBUG_PAGE_ACCESS_END(page); 1723 } 1724 } 1725 1726 1727 /*! Will map the file specified by \a fd to an area in memory. 1728 The file will be mirrored beginning at the specified \a offset. The 1729 \a offset and \a size arguments have to be page aligned. 1730 */ 1731 static area_id 1732 _vm_map_file(team_id team, const char* name, void** _address, 1733 uint32 addressSpec, size_t size, uint32 protection, uint32 mapping, 1734 bool unmapAddressRange, int fd, off_t offset, bool kernel) 1735 { 1736 // TODO: for binary files, we want to make sure that they get the 1737 // copy of a file at a given time, ie. later changes should not 1738 // make it into the mapped copy -- this will need quite some changes 1739 // to be done in a nice way 1740 TRACE(("_vm_map_file(fd = %d, offset = %Ld, size = %lu, mapping %ld)\n", 1741 fd, offset, size, mapping)); 1742 1743 offset = ROUNDDOWN(offset, B_PAGE_SIZE); 1744 size = PAGE_ALIGN(size); 1745 1746 if (mapping == REGION_NO_PRIVATE_MAP) 1747 protection |= B_SHARED_AREA; 1748 if (addressSpec != B_EXACT_ADDRESS) 1749 unmapAddressRange = false; 1750 1751 if (fd < 0) { 1752 uint32 flags = unmapAddressRange ? CREATE_AREA_UNMAP_ADDRESS_RANGE : 0; 1753 virtual_address_restrictions virtualRestrictions = {}; 1754 virtualRestrictions.address = *_address; 1755 virtualRestrictions.address_specification = addressSpec; 1756 physical_address_restrictions physicalRestrictions = {}; 1757 return vm_create_anonymous_area(team, name, size, B_NO_LOCK, protection, 1758 flags, &virtualRestrictions, &physicalRestrictions, kernel, 1759 _address); 1760 } 1761 1762 // get the open flags of the FD 1763 file_descriptor* descriptor = get_fd(get_current_io_context(kernel), fd); 1764 if (descriptor == NULL) 1765 return EBADF; 1766 int32 openMode = descriptor->open_mode; 1767 put_fd(descriptor); 1768 1769 // The FD must open for reading at any rate. For shared mapping with write 1770 // access, additionally the FD must be open for writing. 1771 if ((openMode & O_ACCMODE) == O_WRONLY 1772 || (mapping == REGION_NO_PRIVATE_MAP 1773 && (protection & (B_WRITE_AREA | B_KERNEL_WRITE_AREA)) != 0 1774 && (openMode & O_ACCMODE) == O_RDONLY)) { 1775 return EACCES; 1776 } 1777 1778 // get the vnode for the object, this also grabs a ref to it 1779 struct vnode* vnode = NULL; 1780 status_t status = vfs_get_vnode_from_fd(fd, kernel, &vnode); 1781 if (status < B_OK) 1782 return status; 1783 CObjectDeleter<struct vnode> vnodePutter(vnode, vfs_put_vnode); 1784 1785 // If we're going to pre-map pages, we need to reserve the pages needed by 1786 // the mapping backend upfront. 1787 page_num_t reservedPreMapPages = 0; 1788 vm_page_reservation reservation; 1789 if ((protection & B_READ_AREA) != 0) { 1790 AddressSpaceWriteLocker locker; 1791 status = locker.SetTo(team); 1792 if (status != B_OK) 1793 return status; 1794 1795 VMTranslationMap* map = locker.AddressSpace()->TranslationMap(); 1796 reservedPreMapPages = map->MaxPagesNeededToMap(0, size - 1); 1797 1798 locker.Unlock(); 1799 1800 vm_page_reserve_pages(&reservation, reservedPreMapPages, 1801 team == VMAddressSpace::KernelID() 1802 ? VM_PRIORITY_SYSTEM : VM_PRIORITY_USER); 1803 } 1804 1805 struct PageUnreserver { 1806 PageUnreserver(vm_page_reservation* reservation) 1807 : 1808 fReservation(reservation) 1809 { 1810 } 1811 1812 ~PageUnreserver() 1813 { 1814 if (fReservation != NULL) 1815 vm_page_unreserve_pages(fReservation); 1816 } 1817 1818 vm_page_reservation* fReservation; 1819 } pageUnreserver(reservedPreMapPages > 0 ? &reservation : NULL); 1820 1821 // Lock the address space and, if the specified address range shall be 1822 // unmapped, ensure it is not wired. 1823 AddressSpaceWriteLocker locker; 1824 do { 1825 if (locker.SetTo(team) != B_OK) 1826 return B_BAD_TEAM_ID; 1827 } while (unmapAddressRange 1828 && wait_if_address_range_is_wired(locker.AddressSpace(), 1829 (addr_t)*_address, size, &locker)); 1830 1831 // TODO: this only works for file systems that use the file cache 1832 VMCache* cache; 1833 status = vfs_get_vnode_cache(vnode, &cache, false); 1834 if (status < B_OK) 1835 return status; 1836 1837 cache->Lock(); 1838 1839 VMArea* area; 1840 virtual_address_restrictions addressRestrictions = {}; 1841 addressRestrictions.address = *_address; 1842 addressRestrictions.address_specification = addressSpec; 1843 status = map_backing_store(locker.AddressSpace(), cache, offset, name, size, 1844 0, protection, mapping, 1845 unmapAddressRange ? CREATE_AREA_UNMAP_ADDRESS_RANGE : 0, 1846 &addressRestrictions, kernel, &area, _address); 1847 1848 if (status != B_OK || mapping == REGION_PRIVATE_MAP) { 1849 // map_backing_store() cannot know we no longer need the ref 1850 cache->ReleaseRefLocked(); 1851 } 1852 1853 if (status == B_OK && (protection & B_READ_AREA) != 0) 1854 pre_map_area_pages(area, cache, &reservation); 1855 1856 cache->Unlock(); 1857 1858 if (status == B_OK) { 1859 // TODO: this probably deserves a smarter solution, ie. don't always 1860 // prefetch stuff, and also, probably don't trigger it at this place. 1861 cache_prefetch_vnode(vnode, offset, min_c(size, 10LL * 1024 * 1024)); 1862 // prefetches at max 10 MB starting from "offset" 1863 } 1864 1865 if (status != B_OK) 1866 return status; 1867 1868 area->cache_type = CACHE_TYPE_VNODE; 1869 return area->id; 1870 } 1871 1872 1873 area_id 1874 vm_map_file(team_id aid, const char* name, void** address, uint32 addressSpec, 1875 addr_t size, uint32 protection, uint32 mapping, bool unmapAddressRange, 1876 int fd, off_t offset) 1877 { 1878 if (!arch_vm_supports_protection(protection)) 1879 return B_NOT_SUPPORTED; 1880 1881 return _vm_map_file(aid, name, address, addressSpec, size, protection, 1882 mapping, unmapAddressRange, fd, offset, true); 1883 } 1884 1885 1886 VMCache* 1887 vm_area_get_locked_cache(VMArea* area) 1888 { 1889 rw_lock_read_lock(&sAreaCacheLock); 1890 1891 while (true) { 1892 VMCache* cache = area->cache; 1893 1894 if (!cache->SwitchFromReadLock(&sAreaCacheLock)) { 1895 // cache has been deleted 1896 rw_lock_read_lock(&sAreaCacheLock); 1897 continue; 1898 } 1899 1900 rw_lock_read_lock(&sAreaCacheLock); 1901 1902 if (cache == area->cache) { 1903 cache->AcquireRefLocked(); 1904 rw_lock_read_unlock(&sAreaCacheLock); 1905 return cache; 1906 } 1907 1908 // the cache changed in the meantime 1909 cache->Unlock(); 1910 } 1911 } 1912 1913 1914 void 1915 vm_area_put_locked_cache(VMCache* cache) 1916 { 1917 cache->ReleaseRefAndUnlock(); 1918 } 1919 1920 1921 area_id 1922 vm_clone_area(team_id team, const char* name, void** address, 1923 uint32 addressSpec, uint32 protection, uint32 mapping, area_id sourceID, 1924 bool kernel) 1925 { 1926 VMArea* newArea = NULL; 1927 VMArea* sourceArea; 1928 1929 // Check whether the source area exists and is cloneable. If so, mark it 1930 // B_SHARED_AREA, so that we don't get problems with copy-on-write. 1931 { 1932 AddressSpaceWriteLocker locker; 1933 status_t status = locker.SetFromArea(sourceID, sourceArea); 1934 if (status != B_OK) 1935 return status; 1936 1937 if (!kernel && (sourceArea->protection & B_KERNEL_AREA) != 0) 1938 return B_NOT_ALLOWED; 1939 1940 sourceArea->protection |= B_SHARED_AREA; 1941 protection |= B_SHARED_AREA; 1942 } 1943 1944 // Now lock both address spaces and actually do the cloning. 1945 1946 MultiAddressSpaceLocker locker; 1947 VMAddressSpace* sourceAddressSpace; 1948 status_t status = locker.AddArea(sourceID, false, &sourceAddressSpace); 1949 if (status != B_OK) 1950 return status; 1951 1952 VMAddressSpace* targetAddressSpace; 1953 status = locker.AddTeam(team, true, &targetAddressSpace); 1954 if (status != B_OK) 1955 return status; 1956 1957 status = locker.Lock(); 1958 if (status != B_OK) 1959 return status; 1960 1961 sourceArea = lookup_area(sourceAddressSpace, sourceID); 1962 if (sourceArea == NULL) 1963 return B_BAD_VALUE; 1964 1965 if (!kernel && (sourceArea->protection & B_KERNEL_AREA) != 0) 1966 return B_NOT_ALLOWED; 1967 1968 VMCache* cache = vm_area_get_locked_cache(sourceArea); 1969 1970 // TODO: for now, B_USER_CLONEABLE is disabled, until all drivers 1971 // have been adapted. Maybe it should be part of the kernel settings, 1972 // anyway (so that old drivers can always work). 1973 #if 0 1974 if (sourceArea->aspace == VMAddressSpace::Kernel() 1975 && addressSpace != VMAddressSpace::Kernel() 1976 && !(sourceArea->protection & B_USER_CLONEABLE_AREA)) { 1977 // kernel areas must not be cloned in userland, unless explicitly 1978 // declared user-cloneable upon construction 1979 status = B_NOT_ALLOWED; 1980 } else 1981 #endif 1982 if (sourceArea->cache_type == CACHE_TYPE_NULL) 1983 status = B_NOT_ALLOWED; 1984 else { 1985 virtual_address_restrictions addressRestrictions = {}; 1986 addressRestrictions.address = *address; 1987 addressRestrictions.address_specification = addressSpec; 1988 status = map_backing_store(targetAddressSpace, cache, 1989 sourceArea->cache_offset, name, sourceArea->Size(), 1990 sourceArea->wiring, protection, mapping, 0, &addressRestrictions, 1991 kernel, &newArea, address); 1992 } 1993 if (status == B_OK && mapping != REGION_PRIVATE_MAP) { 1994 // If the mapping is REGION_PRIVATE_MAP, map_backing_store() needed 1995 // to create a new cache, and has therefore already acquired a reference 1996 // to the source cache - but otherwise it has no idea that we need 1997 // one. 1998 cache->AcquireRefLocked(); 1999 } 2000 if (status == B_OK && newArea->wiring == B_FULL_LOCK) { 2001 // we need to map in everything at this point 2002 if (sourceArea->cache_type == CACHE_TYPE_DEVICE) { 2003 // we don't have actual pages to map but a physical area 2004 VMTranslationMap* map 2005 = sourceArea->address_space->TranslationMap(); 2006 map->Lock(); 2007 2008 phys_addr_t physicalAddress; 2009 uint32 oldProtection; 2010 map->Query(sourceArea->Base(), &physicalAddress, &oldProtection); 2011 2012 map->Unlock(); 2013 2014 map = targetAddressSpace->TranslationMap(); 2015 size_t reservePages = map->MaxPagesNeededToMap(newArea->Base(), 2016 newArea->Base() + (newArea->Size() - 1)); 2017 2018 vm_page_reservation reservation; 2019 vm_page_reserve_pages(&reservation, reservePages, 2020 targetAddressSpace == VMAddressSpace::Kernel() 2021 ? VM_PRIORITY_SYSTEM : VM_PRIORITY_USER); 2022 map->Lock(); 2023 2024 for (addr_t offset = 0; offset < newArea->Size(); 2025 offset += B_PAGE_SIZE) { 2026 map->Map(newArea->Base() + offset, physicalAddress + offset, 2027 protection, newArea->MemoryType(), &reservation); 2028 } 2029 2030 map->Unlock(); 2031 vm_page_unreserve_pages(&reservation); 2032 } else { 2033 VMTranslationMap* map = targetAddressSpace->TranslationMap(); 2034 size_t reservePages = map->MaxPagesNeededToMap( 2035 newArea->Base(), newArea->Base() + (newArea->Size() - 1)); 2036 vm_page_reservation reservation; 2037 vm_page_reserve_pages(&reservation, reservePages, 2038 targetAddressSpace == VMAddressSpace::Kernel() 2039 ? VM_PRIORITY_SYSTEM : VM_PRIORITY_USER); 2040 2041 // map in all pages from source 2042 for (VMCachePagesTree::Iterator it = cache->pages.GetIterator(); 2043 vm_page* page = it.Next();) { 2044 if (!page->busy) { 2045 DEBUG_PAGE_ACCESS_START(page); 2046 map_page(newArea, page, 2047 newArea->Base() + ((page->cache_offset << PAGE_SHIFT) 2048 - newArea->cache_offset), 2049 protection, &reservation); 2050 DEBUG_PAGE_ACCESS_END(page); 2051 } 2052 } 2053 // TODO: B_FULL_LOCK means that all pages are locked. We are not 2054 // ensuring that! 2055 2056 vm_page_unreserve_pages(&reservation); 2057 } 2058 } 2059 if (status == B_OK) 2060 newArea->cache_type = sourceArea->cache_type; 2061 2062 vm_area_put_locked_cache(cache); 2063 2064 if (status < B_OK) 2065 return status; 2066 2067 return newArea->id; 2068 } 2069 2070 2071 /*! Deletes the specified area of the given address space. 2072 2073 The address space must be write-locked. 2074 The caller must ensure that the area does not have any wired ranges. 2075 2076 \param addressSpace The address space containing the area. 2077 \param area The area to be deleted. 2078 \param deletingAddressSpace \c true, if the address space is in the process 2079 of being deleted. 2080 */ 2081 static void 2082 delete_area(VMAddressSpace* addressSpace, VMArea* area, 2083 bool deletingAddressSpace) 2084 { 2085 ASSERT(!area->IsWired()); 2086 2087 VMAreaHash::Remove(area); 2088 2089 // At this point the area is removed from the global hash table, but 2090 // still exists in the area list. 2091 2092 // Unmap the virtual address space the area occupied. 2093 { 2094 // We need to lock the complete cache chain. 2095 VMCache* topCache = vm_area_get_locked_cache(area); 2096 VMCacheChainLocker cacheChainLocker(topCache); 2097 cacheChainLocker.LockAllSourceCaches(); 2098 2099 // If the area's top cache is a temporary cache and the area is the only 2100 // one referencing it (besides us currently holding a second reference), 2101 // the unmapping code doesn't need to care about preserving the accessed 2102 // and dirty flags of the top cache page mappings. 2103 bool ignoreTopCachePageFlags 2104 = topCache->temporary && topCache->RefCount() == 2; 2105 2106 area->address_space->TranslationMap()->UnmapArea(area, 2107 deletingAddressSpace, ignoreTopCachePageFlags); 2108 } 2109 2110 if (!area->cache->temporary) 2111 area->cache->WriteModified(); 2112 2113 uint32 allocationFlags = addressSpace == VMAddressSpace::Kernel() 2114 ? HEAP_DONT_WAIT_FOR_MEMORY | HEAP_DONT_LOCK_KERNEL_SPACE : 0; 2115 2116 arch_vm_unset_memory_type(area); 2117 addressSpace->RemoveArea(area, allocationFlags); 2118 addressSpace->Put(); 2119 2120 area->cache->RemoveArea(area); 2121 area->cache->ReleaseRef(); 2122 2123 addressSpace->DeleteArea(area, allocationFlags); 2124 } 2125 2126 2127 status_t 2128 vm_delete_area(team_id team, area_id id, bool kernel) 2129 { 2130 TRACE(("vm_delete_area(team = 0x%lx, area = 0x%lx)\n", team, id)); 2131 2132 // lock the address space and make sure the area isn't wired 2133 AddressSpaceWriteLocker locker; 2134 VMArea* area; 2135 AreaCacheLocker cacheLocker; 2136 2137 do { 2138 status_t status = locker.SetFromArea(team, id, area); 2139 if (status != B_OK) 2140 return status; 2141 2142 cacheLocker.SetTo(area); 2143 } while (wait_if_area_is_wired(area, &locker, &cacheLocker)); 2144 2145 cacheLocker.Unlock(); 2146 2147 if (!kernel && (area->protection & B_KERNEL_AREA) != 0) 2148 return B_NOT_ALLOWED; 2149 2150 delete_area(locker.AddressSpace(), area, false); 2151 return B_OK; 2152 } 2153 2154 2155 /*! Creates a new cache on top of given cache, moves all areas from 2156 the old cache to the new one, and changes the protection of all affected 2157 areas' pages to read-only. If requested, wired pages are moved up to the 2158 new cache and copies are added to the old cache in their place. 2159 Preconditions: 2160 - The given cache must be locked. 2161 - All of the cache's areas' address spaces must be read locked. 2162 - Either the cache must not have any wired ranges or a page reservation for 2163 all wired pages must be provided, so they can be copied. 2164 2165 \param lowerCache The cache on top of which a new cache shall be created. 2166 \param wiredPagesReservation If \c NULL there must not be any wired pages 2167 in \a lowerCache. Otherwise as many pages must be reserved as the cache 2168 has wired page. The wired pages are copied in this case. 2169 */ 2170 static status_t 2171 vm_copy_on_write_area(VMCache* lowerCache, 2172 vm_page_reservation* wiredPagesReservation) 2173 { 2174 VMCache* upperCache; 2175 2176 TRACE(("vm_copy_on_write_area(cache = %p)\n", lowerCache)); 2177 2178 // We need to separate the cache from its areas. The cache goes one level 2179 // deeper and we create a new cache inbetween. 2180 2181 // create an anonymous cache 2182 status_t status = VMCacheFactory::CreateAnonymousCache(upperCache, false, 0, 2183 0, true, VM_PRIORITY_USER); 2184 if (status != B_OK) 2185 return status; 2186 2187 upperCache->Lock(); 2188 2189 upperCache->temporary = 1; 2190 upperCache->virtual_base = lowerCache->virtual_base; 2191 upperCache->virtual_end = lowerCache->virtual_end; 2192 2193 // transfer the lower cache areas to the upper cache 2194 rw_lock_write_lock(&sAreaCacheLock); 2195 upperCache->TransferAreas(lowerCache); 2196 rw_lock_write_unlock(&sAreaCacheLock); 2197 2198 lowerCache->AddConsumer(upperCache); 2199 2200 // We now need to remap all pages from all of the cache's areas read-only, 2201 // so that a copy will be created on next write access. If there are wired 2202 // pages, we keep their protection, move them to the upper cache and create 2203 // copies for the lower cache. 2204 if (wiredPagesReservation != NULL) { 2205 // We need to handle wired pages -- iterate through the cache's pages. 2206 for (VMCachePagesTree::Iterator it = lowerCache->pages.GetIterator(); 2207 vm_page* page = it.Next();) { 2208 if (page->WiredCount() > 0) { 2209 // allocate a new page and copy the wired one 2210 vm_page* copiedPage = vm_page_allocate_page( 2211 wiredPagesReservation, PAGE_STATE_ACTIVE); 2212 2213 vm_memcpy_physical_page( 2214 copiedPage->physical_page_number * B_PAGE_SIZE, 2215 page->physical_page_number * B_PAGE_SIZE); 2216 2217 // move the wired page to the upper cache (note: removing is OK 2218 // with the SplayTree iterator) and insert the copy 2219 upperCache->MovePage(page); 2220 lowerCache->InsertPage(copiedPage, 2221 page->cache_offset * B_PAGE_SIZE); 2222 2223 DEBUG_PAGE_ACCESS_END(copiedPage); 2224 } else { 2225 // Change the protection of this page in all areas. 2226 for (VMArea* tempArea = upperCache->areas; tempArea != NULL; 2227 tempArea = tempArea->cache_next) { 2228 // The area must be readable in the same way it was 2229 // previously writable. 2230 uint32 protection = B_KERNEL_READ_AREA; 2231 if ((tempArea->protection & B_READ_AREA) != 0) 2232 protection |= B_READ_AREA; 2233 2234 VMTranslationMap* map 2235 = tempArea->address_space->TranslationMap(); 2236 map->Lock(); 2237 map->ProtectPage(tempArea, 2238 virtual_page_address(tempArea, page), protection); 2239 map->Unlock(); 2240 } 2241 } 2242 } 2243 } else { 2244 // just change the protection of all areas 2245 for (VMArea* tempArea = upperCache->areas; tempArea != NULL; 2246 tempArea = tempArea->cache_next) { 2247 // The area must be readable in the same way it was previously 2248 // writable. 2249 uint32 protection = B_KERNEL_READ_AREA; 2250 if ((tempArea->protection & B_READ_AREA) != 0) 2251 protection |= B_READ_AREA; 2252 2253 VMTranslationMap* map = tempArea->address_space->TranslationMap(); 2254 map->Lock(); 2255 map->ProtectArea(tempArea, protection); 2256 map->Unlock(); 2257 } 2258 } 2259 2260 vm_area_put_locked_cache(upperCache); 2261 2262 return B_OK; 2263 } 2264 2265 2266 area_id 2267 vm_copy_area(team_id team, const char* name, void** _address, 2268 uint32 addressSpec, uint32 protection, area_id sourceID) 2269 { 2270 bool writableCopy = (protection & (B_KERNEL_WRITE_AREA | B_WRITE_AREA)) != 0; 2271 2272 if ((protection & B_KERNEL_PROTECTION) == 0) { 2273 // set the same protection for the kernel as for userland 2274 protection |= B_KERNEL_READ_AREA; 2275 if (writableCopy) 2276 protection |= B_KERNEL_WRITE_AREA; 2277 } 2278 2279 // Do the locking: target address space, all address spaces associated with 2280 // the source cache, and the cache itself. 2281 MultiAddressSpaceLocker locker; 2282 VMAddressSpace* targetAddressSpace; 2283 VMCache* cache; 2284 VMArea* source; 2285 AreaCacheLocker cacheLocker; 2286 status_t status; 2287 bool sharedArea; 2288 2289 page_num_t wiredPages = 0; 2290 vm_page_reservation wiredPagesReservation; 2291 2292 bool restart; 2293 do { 2294 restart = false; 2295 2296 locker.Unset(); 2297 status = locker.AddTeam(team, true, &targetAddressSpace); 2298 if (status == B_OK) { 2299 status = locker.AddAreaCacheAndLock(sourceID, false, false, source, 2300 &cache); 2301 } 2302 if (status != B_OK) 2303 return status; 2304 2305 cacheLocker.SetTo(cache, true); // already locked 2306 2307 sharedArea = (source->protection & B_SHARED_AREA) != 0; 2308 2309 page_num_t oldWiredPages = wiredPages; 2310 wiredPages = 0; 2311 2312 // If the source area isn't shared, count the number of wired pages in 2313 // the cache and reserve as many pages. 2314 if (!sharedArea) { 2315 wiredPages = cache->WiredPagesCount(); 2316 2317 if (wiredPages > oldWiredPages) { 2318 cacheLocker.Unlock(); 2319 locker.Unlock(); 2320 2321 if (oldWiredPages > 0) 2322 vm_page_unreserve_pages(&wiredPagesReservation); 2323 2324 vm_page_reserve_pages(&wiredPagesReservation, wiredPages, 2325 VM_PRIORITY_USER); 2326 2327 restart = true; 2328 } 2329 } else if (oldWiredPages > 0) 2330 vm_page_unreserve_pages(&wiredPagesReservation); 2331 } while (restart); 2332 2333 // unreserve pages later 2334 struct PagesUnreserver { 2335 PagesUnreserver(vm_page_reservation* reservation) 2336 : 2337 fReservation(reservation) 2338 { 2339 } 2340 2341 ~PagesUnreserver() 2342 { 2343 if (fReservation != NULL) 2344 vm_page_unreserve_pages(fReservation); 2345 } 2346 2347 private: 2348 vm_page_reservation* fReservation; 2349 } pagesUnreserver(wiredPages > 0 ? &wiredPagesReservation : NULL); 2350 2351 if (addressSpec == B_CLONE_ADDRESS) { 2352 addressSpec = B_EXACT_ADDRESS; 2353 *_address = (void*)source->Base(); 2354 } 2355 2356 // First, create a cache on top of the source area, respectively use the 2357 // existing one, if this is a shared area. 2358 2359 VMArea* target; 2360 virtual_address_restrictions addressRestrictions = {}; 2361 addressRestrictions.address = *_address; 2362 addressRestrictions.address_specification = addressSpec; 2363 status = map_backing_store(targetAddressSpace, cache, source->cache_offset, 2364 name, source->Size(), source->wiring, protection, 2365 sharedArea ? REGION_NO_PRIVATE_MAP : REGION_PRIVATE_MAP, 2366 writableCopy ? 0 : CREATE_AREA_DONT_COMMIT_MEMORY, 2367 &addressRestrictions, true, &target, _address); 2368 if (status < B_OK) 2369 return status; 2370 2371 if (sharedArea) { 2372 // The new area uses the old area's cache, but map_backing_store() 2373 // hasn't acquired a ref. So we have to do that now. 2374 cache->AcquireRefLocked(); 2375 } 2376 2377 // If the source area is writable, we need to move it one layer up as well 2378 2379 if (!sharedArea) { 2380 if ((source->protection & (B_KERNEL_WRITE_AREA | B_WRITE_AREA)) != 0) { 2381 // TODO: do something more useful if this fails! 2382 if (vm_copy_on_write_area(cache, 2383 wiredPages > 0 ? &wiredPagesReservation : NULL) < B_OK) { 2384 panic("vm_copy_on_write_area() failed!\n"); 2385 } 2386 } 2387 } 2388 2389 // we return the ID of the newly created area 2390 return target->id; 2391 } 2392 2393 2394 static status_t 2395 vm_set_area_protection(team_id team, area_id areaID, uint32 newProtection, 2396 bool kernel) 2397 { 2398 TRACE(("vm_set_area_protection(team = %#lx, area = %#lx, protection = " 2399 "%#lx)\n", team, areaID, newProtection)); 2400 2401 if (!arch_vm_supports_protection(newProtection)) 2402 return B_NOT_SUPPORTED; 2403 2404 bool becomesWritable 2405 = (newProtection & (B_WRITE_AREA | B_KERNEL_WRITE_AREA)) != 0; 2406 2407 // lock address spaces and cache 2408 MultiAddressSpaceLocker locker; 2409 VMCache* cache; 2410 VMArea* area; 2411 status_t status; 2412 AreaCacheLocker cacheLocker; 2413 bool isWritable; 2414 2415 bool restart; 2416 do { 2417 restart = false; 2418 2419 locker.Unset(); 2420 status = locker.AddAreaCacheAndLock(areaID, true, false, area, &cache); 2421 if (status != B_OK) 2422 return status; 2423 2424 cacheLocker.SetTo(cache, true); // already locked 2425 2426 if (!kernel && (area->protection & B_KERNEL_AREA) != 0) 2427 return B_NOT_ALLOWED; 2428 2429 if (area->protection == newProtection) 2430 return B_OK; 2431 2432 if (team != VMAddressSpace::KernelID() 2433 && area->address_space->ID() != team) { 2434 // unless you're the kernel, you are only allowed to set 2435 // the protection of your own areas 2436 return B_NOT_ALLOWED; 2437 } 2438 2439 isWritable 2440 = (area->protection & (B_WRITE_AREA | B_KERNEL_WRITE_AREA)) != 0; 2441 2442 // Make sure the area (respectively, if we're going to call 2443 // vm_copy_on_write_area(), all areas of the cache) doesn't have any 2444 // wired ranges. 2445 if (!isWritable && becomesWritable && !list_is_empty(&cache->consumers)) { 2446 for (VMArea* otherArea = cache->areas; otherArea != NULL; 2447 otherArea = otherArea->cache_next) { 2448 if (wait_if_area_is_wired(otherArea, &locker, &cacheLocker)) { 2449 restart = true; 2450 break; 2451 } 2452 } 2453 } else { 2454 if (wait_if_area_is_wired(area, &locker, &cacheLocker)) 2455 restart = true; 2456 } 2457 } while (restart); 2458 2459 bool changePageProtection = true; 2460 bool changeTopCachePagesOnly = false; 2461 2462 if (isWritable && !becomesWritable) { 2463 // writable -> !writable 2464 2465 if (cache->source != NULL && cache->temporary) { 2466 if (cache->CountWritableAreas(area) == 0) { 2467 // Since this cache now lives from the pages in its source cache, 2468 // we can change the cache's commitment to take only those pages 2469 // into account that really are in this cache. 2470 2471 status = cache->Commit(cache->page_count * B_PAGE_SIZE, 2472 team == VMAddressSpace::KernelID() 2473 ? VM_PRIORITY_SYSTEM : VM_PRIORITY_USER); 2474 2475 // TODO: we may be able to join with our source cache, if 2476 // count == 0 2477 } 2478 } 2479 2480 // If only the writability changes, we can just remap the pages of the 2481 // top cache, since the pages of lower caches are mapped read-only 2482 // anyway. That's advantageous only, if the number of pages in the cache 2483 // is significantly smaller than the number of pages in the area, 2484 // though. 2485 if (newProtection 2486 == (area->protection & ~(B_WRITE_AREA | B_KERNEL_WRITE_AREA)) 2487 && cache->page_count * 2 < area->Size() / B_PAGE_SIZE) { 2488 changeTopCachePagesOnly = true; 2489 } 2490 } else if (!isWritable && becomesWritable) { 2491 // !writable -> writable 2492 2493 if (!list_is_empty(&cache->consumers)) { 2494 // There are consumers -- we have to insert a new cache. Fortunately 2495 // vm_copy_on_write_area() does everything that's needed. 2496 changePageProtection = false; 2497 status = vm_copy_on_write_area(cache, NULL); 2498 } else { 2499 // No consumers, so we don't need to insert a new one. 2500 if (cache->source != NULL && cache->temporary) { 2501 // the cache's commitment must contain all possible pages 2502 status = cache->Commit(cache->virtual_end - cache->virtual_base, 2503 team == VMAddressSpace::KernelID() 2504 ? VM_PRIORITY_SYSTEM : VM_PRIORITY_USER); 2505 } 2506 2507 if (status == B_OK && cache->source != NULL) { 2508 // There's a source cache, hence we can't just change all pages' 2509 // protection or we might allow writing into pages belonging to 2510 // a lower cache. 2511 changeTopCachePagesOnly = true; 2512 } 2513 } 2514 } else { 2515 // we don't have anything special to do in all other cases 2516 } 2517 2518 if (status == B_OK) { 2519 // remap existing pages in this cache 2520 if (changePageProtection) { 2521 VMTranslationMap* map = area->address_space->TranslationMap(); 2522 map->Lock(); 2523 2524 if (changeTopCachePagesOnly) { 2525 page_num_t firstPageOffset = area->cache_offset / B_PAGE_SIZE; 2526 page_num_t lastPageOffset 2527 = firstPageOffset + area->Size() / B_PAGE_SIZE; 2528 for (VMCachePagesTree::Iterator it = cache->pages.GetIterator(); 2529 vm_page* page = it.Next();) { 2530 if (page->cache_offset >= firstPageOffset 2531 && page->cache_offset <= lastPageOffset) { 2532 addr_t address = virtual_page_address(area, page); 2533 map->ProtectPage(area, address, newProtection); 2534 } 2535 } 2536 } else 2537 map->ProtectArea(area, newProtection); 2538 2539 map->Unlock(); 2540 } 2541 2542 area->protection = newProtection; 2543 } 2544 2545 return status; 2546 } 2547 2548 2549 status_t 2550 vm_get_page_mapping(team_id team, addr_t vaddr, phys_addr_t* paddr) 2551 { 2552 VMAddressSpace* addressSpace = VMAddressSpace::Get(team); 2553 if (addressSpace == NULL) 2554 return B_BAD_TEAM_ID; 2555 2556 VMTranslationMap* map = addressSpace->TranslationMap(); 2557 2558 map->Lock(); 2559 uint32 dummyFlags; 2560 status_t status = map->Query(vaddr, paddr, &dummyFlags); 2561 map->Unlock(); 2562 2563 addressSpace->Put(); 2564 return status; 2565 } 2566 2567 2568 /*! The page's cache must be locked. 2569 */ 2570 bool 2571 vm_test_map_modification(vm_page* page) 2572 { 2573 if (page->modified) 2574 return true; 2575 2576 vm_page_mappings::Iterator iterator = page->mappings.GetIterator(); 2577 vm_page_mapping* mapping; 2578 while ((mapping = iterator.Next()) != NULL) { 2579 VMArea* area = mapping->area; 2580 VMTranslationMap* map = area->address_space->TranslationMap(); 2581 2582 phys_addr_t physicalAddress; 2583 uint32 flags; 2584 map->Lock(); 2585 map->Query(virtual_page_address(area, page), &physicalAddress, &flags); 2586 map->Unlock(); 2587 2588 if ((flags & PAGE_MODIFIED) != 0) 2589 return true; 2590 } 2591 2592 return false; 2593 } 2594 2595 2596 /*! The page's cache must be locked. 2597 */ 2598 void 2599 vm_clear_map_flags(vm_page* page, uint32 flags) 2600 { 2601 if ((flags & PAGE_ACCESSED) != 0) 2602 page->accessed = false; 2603 if ((flags & PAGE_MODIFIED) != 0) 2604 page->modified = false; 2605 2606 vm_page_mappings::Iterator iterator = page->mappings.GetIterator(); 2607 vm_page_mapping* mapping; 2608 while ((mapping = iterator.Next()) != NULL) { 2609 VMArea* area = mapping->area; 2610 VMTranslationMap* map = area->address_space->TranslationMap(); 2611 2612 map->Lock(); 2613 map->ClearFlags(virtual_page_address(area, page), flags); 2614 map->Unlock(); 2615 } 2616 } 2617 2618 2619 /*! Removes all mappings from a page. 2620 After you've called this function, the page is unmapped from memory and 2621 the page's \c accessed and \c modified flags have been updated according 2622 to the state of the mappings. 2623 The page's cache must be locked. 2624 */ 2625 void 2626 vm_remove_all_page_mappings(vm_page* page) 2627 { 2628 while (vm_page_mapping* mapping = page->mappings.Head()) { 2629 VMArea* area = mapping->area; 2630 VMTranslationMap* map = area->address_space->TranslationMap(); 2631 addr_t address = virtual_page_address(area, page); 2632 map->UnmapPage(area, address, false); 2633 } 2634 } 2635 2636 2637 int32 2638 vm_clear_page_mapping_accessed_flags(struct vm_page *page) 2639 { 2640 int32 count = 0; 2641 2642 vm_page_mappings::Iterator iterator = page->mappings.GetIterator(); 2643 vm_page_mapping* mapping; 2644 while ((mapping = iterator.Next()) != NULL) { 2645 VMArea* area = mapping->area; 2646 VMTranslationMap* map = area->address_space->TranslationMap(); 2647 2648 bool modified; 2649 if (map->ClearAccessedAndModified(area, 2650 virtual_page_address(area, page), false, modified)) { 2651 count++; 2652 } 2653 2654 page->modified |= modified; 2655 } 2656 2657 2658 if (page->accessed) { 2659 count++; 2660 page->accessed = false; 2661 } 2662 2663 return count; 2664 } 2665 2666 2667 /*! Removes all mappings of a page and/or clears the accessed bits of the 2668 mappings. 2669 The function iterates through the page mappings and removes them until 2670 encountering one that has been accessed. From then on it will continue to 2671 iterate, but only clear the accessed flag of the mapping. The page's 2672 \c modified bit will be updated accordingly, the \c accessed bit will be 2673 cleared. 2674 \return The number of mapping accessed bits encountered, including the 2675 \c accessed bit of the page itself. If \c 0 is returned, all mappings 2676 of the page have been removed. 2677 */ 2678 int32 2679 vm_remove_all_page_mappings_if_unaccessed(struct vm_page *page) 2680 { 2681 ASSERT(page->WiredCount() == 0); 2682 2683 if (page->accessed) 2684 return vm_clear_page_mapping_accessed_flags(page); 2685 2686 while (vm_page_mapping* mapping = page->mappings.Head()) { 2687 VMArea* area = mapping->area; 2688 VMTranslationMap* map = area->address_space->TranslationMap(); 2689 addr_t address = virtual_page_address(area, page); 2690 bool modified = false; 2691 if (map->ClearAccessedAndModified(area, address, true, modified)) { 2692 page->accessed = true; 2693 page->modified |= modified; 2694 return vm_clear_page_mapping_accessed_flags(page); 2695 } 2696 page->modified |= modified; 2697 } 2698 2699 return 0; 2700 } 2701 2702 2703 static int 2704 display_mem(int argc, char** argv) 2705 { 2706 bool physical = false; 2707 addr_t copyAddress; 2708 int32 displayWidth; 2709 int32 itemSize; 2710 int32 num = -1; 2711 addr_t address; 2712 int i = 1, j; 2713 2714 if (argc > 1 && argv[1][0] == '-') { 2715 if (!strcmp(argv[1], "-p") || !strcmp(argv[1], "--physical")) { 2716 physical = true; 2717 i++; 2718 } else 2719 i = 99; 2720 } 2721 2722 if (argc < i + 1 || argc > i + 2) { 2723 kprintf("usage: dl/dw/ds/db/string [-p|--physical] <address> [num]\n" 2724 "\tdl - 8 bytes\n" 2725 "\tdw - 4 bytes\n" 2726 "\tds - 2 bytes\n" 2727 "\tdb - 1 byte\n" 2728 "\tstring - a whole string\n" 2729 " -p or --physical only allows memory from a single page to be " 2730 "displayed.\n"); 2731 return 0; 2732 } 2733 2734 address = parse_expression(argv[i]); 2735 2736 if (argc > i + 1) 2737 num = parse_expression(argv[i + 1]); 2738 2739 // build the format string 2740 if (strcmp(argv[0], "db") == 0) { 2741 itemSize = 1; 2742 displayWidth = 16; 2743 } else if (strcmp(argv[0], "ds") == 0) { 2744 itemSize = 2; 2745 displayWidth = 8; 2746 } else if (strcmp(argv[0], "dw") == 0) { 2747 itemSize = 4; 2748 displayWidth = 4; 2749 } else if (strcmp(argv[0], "dl") == 0) { 2750 itemSize = 8; 2751 displayWidth = 2; 2752 } else if (strcmp(argv[0], "string") == 0) { 2753 itemSize = 1; 2754 displayWidth = -1; 2755 } else { 2756 kprintf("display_mem called in an invalid way!\n"); 2757 return 0; 2758 } 2759 2760 if (num <= 0) 2761 num = displayWidth; 2762 2763 void* physicalPageHandle = NULL; 2764 2765 if (physical) { 2766 int32 offset = address & (B_PAGE_SIZE - 1); 2767 if (num * itemSize + offset > B_PAGE_SIZE) { 2768 num = (B_PAGE_SIZE - offset) / itemSize; 2769 kprintf("NOTE: number of bytes has been cut to page size\n"); 2770 } 2771 2772 address = ROUNDDOWN(address, B_PAGE_SIZE); 2773 2774 if (vm_get_physical_page_debug(address, ©Address, 2775 &physicalPageHandle) != B_OK) { 2776 kprintf("getting the hardware page failed."); 2777 return 0; 2778 } 2779 2780 address += offset; 2781 copyAddress += offset; 2782 } else 2783 copyAddress = address; 2784 2785 if (!strcmp(argv[0], "string")) { 2786 kprintf("%p \"", (char*)copyAddress); 2787 2788 // string mode 2789 for (i = 0; true; i++) { 2790 char c; 2791 if (debug_memcpy(B_CURRENT_TEAM, &c, (char*)copyAddress + i, 1) 2792 != B_OK 2793 || c == '\0') { 2794 break; 2795 } 2796 2797 if (c == '\n') 2798 kprintf("\\n"); 2799 else if (c == '\t') 2800 kprintf("\\t"); 2801 else { 2802 if (!isprint(c)) 2803 c = '.'; 2804 2805 kprintf("%c", c); 2806 } 2807 } 2808 2809 kprintf("\"\n"); 2810 } else { 2811 // number mode 2812 for (i = 0; i < num; i++) { 2813 uint32 value; 2814 2815 if ((i % displayWidth) == 0) { 2816 int32 displayed = min_c(displayWidth, (num-i)) * itemSize; 2817 if (i != 0) 2818 kprintf("\n"); 2819 2820 kprintf("[0x%lx] ", address + i * itemSize); 2821 2822 for (j = 0; j < displayed; j++) { 2823 char c; 2824 if (debug_memcpy(B_CURRENT_TEAM, &c, 2825 (char*)copyAddress + i * itemSize + j, 1) != B_OK) { 2826 displayed = j; 2827 break; 2828 } 2829 if (!isprint(c)) 2830 c = '.'; 2831 2832 kprintf("%c", c); 2833 } 2834 if (num > displayWidth) { 2835 // make sure the spacing in the last line is correct 2836 for (j = displayed; j < displayWidth * itemSize; j++) 2837 kprintf(" "); 2838 } 2839 kprintf(" "); 2840 } 2841 2842 if (debug_memcpy(B_CURRENT_TEAM, &value, 2843 (uint8*)copyAddress + i * itemSize, itemSize) != B_OK) { 2844 kprintf("read fault"); 2845 break; 2846 } 2847 2848 switch (itemSize) { 2849 case 1: 2850 kprintf(" %02x", *(uint8*)&value); 2851 break; 2852 case 2: 2853 kprintf(" %04x", *(uint16*)&value); 2854 break; 2855 case 4: 2856 kprintf(" %08lx", *(uint32*)&value); 2857 break; 2858 case 8: 2859 kprintf(" %016Lx", *(uint64*)&value); 2860 break; 2861 } 2862 } 2863 2864 kprintf("\n"); 2865 } 2866 2867 if (physical) { 2868 copyAddress = ROUNDDOWN(copyAddress, B_PAGE_SIZE); 2869 vm_put_physical_page_debug(copyAddress, physicalPageHandle); 2870 } 2871 return 0; 2872 } 2873 2874 2875 static void 2876 dump_cache_tree_recursively(VMCache* cache, int level, 2877 VMCache* highlightCache) 2878 { 2879 // print this cache 2880 for (int i = 0; i < level; i++) 2881 kprintf(" "); 2882 if (cache == highlightCache) 2883 kprintf("%p <--\n", cache); 2884 else 2885 kprintf("%p\n", cache); 2886 2887 // recursively print its consumers 2888 VMCache* consumer = NULL; 2889 while ((consumer = (VMCache*)list_get_next_item(&cache->consumers, 2890 consumer)) != NULL) { 2891 dump_cache_tree_recursively(consumer, level + 1, highlightCache); 2892 } 2893 } 2894 2895 2896 static int 2897 dump_cache_tree(int argc, char** argv) 2898 { 2899 if (argc != 2 || !strcmp(argv[1], "--help")) { 2900 kprintf("usage: %s <address>\n", argv[0]); 2901 return 0; 2902 } 2903 2904 addr_t address = parse_expression(argv[1]); 2905 if (address == 0) 2906 return 0; 2907 2908 VMCache* cache = (VMCache*)address; 2909 VMCache* root = cache; 2910 2911 // find the root cache (the transitive source) 2912 while (root->source != NULL) 2913 root = root->source; 2914 2915 dump_cache_tree_recursively(root, 0, cache); 2916 2917 return 0; 2918 } 2919 2920 2921 const char* 2922 vm_cache_type_to_string(int32 type) 2923 { 2924 switch (type) { 2925 case CACHE_TYPE_RAM: 2926 return "RAM"; 2927 case CACHE_TYPE_DEVICE: 2928 return "device"; 2929 case CACHE_TYPE_VNODE: 2930 return "vnode"; 2931 case CACHE_TYPE_NULL: 2932 return "null"; 2933 2934 default: 2935 return "unknown"; 2936 } 2937 } 2938 2939 2940 #if DEBUG_CACHE_LIST 2941 2942 static void 2943 update_cache_info_recursively(VMCache* cache, cache_info& info) 2944 { 2945 info.page_count += cache->page_count; 2946 if (cache->type == CACHE_TYPE_RAM) 2947 info.committed += cache->committed_size; 2948 2949 // recurse 2950 VMCache* consumer = NULL; 2951 while ((consumer = (VMCache*)list_get_next_item(&cache->consumers, 2952 consumer)) != NULL) { 2953 update_cache_info_recursively(consumer, info); 2954 } 2955 } 2956 2957 2958 static int 2959 cache_info_compare_page_count(const void* _a, const void* _b) 2960 { 2961 const cache_info* a = (const cache_info*)_a; 2962 const cache_info* b = (const cache_info*)_b; 2963 if (a->page_count == b->page_count) 2964 return 0; 2965 return a->page_count < b->page_count ? 1 : -1; 2966 } 2967 2968 2969 static int 2970 cache_info_compare_committed(const void* _a, const void* _b) 2971 { 2972 const cache_info* a = (const cache_info*)_a; 2973 const cache_info* b = (const cache_info*)_b; 2974 if (a->committed == b->committed) 2975 return 0; 2976 return a->committed < b->committed ? 1 : -1; 2977 } 2978 2979 2980 static void 2981 dump_caches_recursively(VMCache* cache, cache_info& info, int level) 2982 { 2983 for (int i = 0; i < level; i++) 2984 kprintf(" "); 2985 2986 kprintf("%p: type: %s, base: %lld, size: %lld, pages: %lu", cache, 2987 vm_cache_type_to_string(cache->type), cache->virtual_base, 2988 cache->virtual_end, cache->page_count); 2989 2990 if (level == 0) 2991 kprintf("/%lu", info.page_count); 2992 2993 if (cache->type == CACHE_TYPE_RAM || (level == 0 && info.committed > 0)) { 2994 kprintf(", committed: %lld", cache->committed_size); 2995 2996 if (level == 0) 2997 kprintf("/%lu", info.committed); 2998 } 2999 3000 // areas 3001 if (cache->areas != NULL) { 3002 VMArea* area = cache->areas; 3003 kprintf(", areas: %ld (%s, team: %ld)", area->id, area->name, 3004 area->address_space->ID()); 3005 3006 while (area->cache_next != NULL) { 3007 area = area->cache_next; 3008 kprintf(", %ld", area->id); 3009 } 3010 } 3011 3012 kputs("\n"); 3013 3014 // recurse 3015 VMCache* consumer = NULL; 3016 while ((consumer = (VMCache*)list_get_next_item(&cache->consumers, 3017 consumer)) != NULL) { 3018 dump_caches_recursively(consumer, info, level + 1); 3019 } 3020 } 3021 3022 3023 static int 3024 dump_caches(int argc, char** argv) 3025 { 3026 if (sCacheInfoTable == NULL) { 3027 kprintf("No cache info table!\n"); 3028 return 0; 3029 } 3030 3031 bool sortByPageCount = true; 3032 3033 for (int32 i = 1; i < argc; i++) { 3034 if (strcmp(argv[i], "-c") == 0) { 3035 sortByPageCount = false; 3036 } else { 3037 print_debugger_command_usage(argv[0]); 3038 return 0; 3039 } 3040 } 3041 3042 uint32 totalCount = 0; 3043 uint32 rootCount = 0; 3044 off_t totalCommitted = 0; 3045 page_num_t totalPages = 0; 3046 3047 VMCache* cache = gDebugCacheList; 3048 while (cache) { 3049 totalCount++; 3050 if (cache->source == NULL) { 3051 cache_info stackInfo; 3052 cache_info& info = rootCount < (uint32)kCacheInfoTableCount 3053 ? sCacheInfoTable[rootCount] : stackInfo; 3054 rootCount++; 3055 info.cache = cache; 3056 info.page_count = 0; 3057 info.committed = 0; 3058 update_cache_info_recursively(cache, info); 3059 totalCommitted += info.committed; 3060 totalPages += info.page_count; 3061 } 3062 3063 cache = cache->debug_next; 3064 } 3065 3066 if (rootCount <= (uint32)kCacheInfoTableCount) { 3067 qsort(sCacheInfoTable, rootCount, sizeof(cache_info), 3068 sortByPageCount 3069 ? &cache_info_compare_page_count 3070 : &cache_info_compare_committed); 3071 } 3072 3073 kprintf("total committed memory: %" B_PRIdOFF ", total used pages: %" 3074 B_PRIuPHYSADDR "\n", totalCommitted, totalPages); 3075 kprintf("%lu caches (%lu root caches), sorted by %s per cache " 3076 "tree...\n\n", totalCount, rootCount, 3077 sortByPageCount ? "page count" : "committed size"); 3078 3079 if (rootCount <= (uint32)kCacheInfoTableCount) { 3080 for (uint32 i = 0; i < rootCount; i++) { 3081 cache_info& info = sCacheInfoTable[i]; 3082 dump_caches_recursively(info.cache, info, 0); 3083 } 3084 } else 3085 kprintf("Cache info table too small! Can't sort and print caches!\n"); 3086 3087 return 0; 3088 } 3089 3090 #endif // DEBUG_CACHE_LIST 3091 3092 3093 static int 3094 dump_cache(int argc, char** argv) 3095 { 3096 VMCache* cache; 3097 bool showPages = false; 3098 int i = 1; 3099 3100 if (argc < 2 || !strcmp(argv[1], "--help")) { 3101 kprintf("usage: %s [-ps] <address>\n" 3102 " if -p is specified, all pages are shown, if -s is used\n" 3103 " only the cache info is shown respectively.\n", argv[0]); 3104 return 0; 3105 } 3106 while (argv[i][0] == '-') { 3107 char* arg = argv[i] + 1; 3108 while (arg[0]) { 3109 if (arg[0] == 'p') 3110 showPages = true; 3111 arg++; 3112 } 3113 i++; 3114 } 3115 if (argv[i] == NULL) { 3116 kprintf("%s: invalid argument, pass address\n", argv[0]); 3117 return 0; 3118 } 3119 3120 addr_t address = parse_expression(argv[i]); 3121 if (address == 0) 3122 return 0; 3123 3124 cache = (VMCache*)address; 3125 3126 cache->Dump(showPages); 3127 3128 set_debug_variable("_sourceCache", (addr_t)cache->source); 3129 3130 return 0; 3131 } 3132 3133 3134 static void 3135 dump_area_struct(VMArea* area, bool mappings) 3136 { 3137 kprintf("AREA: %p\n", area); 3138 kprintf("name:\t\t'%s'\n", area->name); 3139 kprintf("owner:\t\t0x%lx\n", area->address_space->ID()); 3140 kprintf("id:\t\t0x%lx\n", area->id); 3141 kprintf("base:\t\t0x%lx\n", area->Base()); 3142 kprintf("size:\t\t0x%lx\n", area->Size()); 3143 kprintf("protection:\t0x%lx\n", area->protection); 3144 kprintf("wiring:\t\t0x%x\n", area->wiring); 3145 kprintf("memory_type:\t%#" B_PRIx32 "\n", area->MemoryType()); 3146 kprintf("cache:\t\t%p\n", area->cache); 3147 kprintf("cache_type:\t%s\n", vm_cache_type_to_string(area->cache_type)); 3148 kprintf("cache_offset:\t0x%Lx\n", area->cache_offset); 3149 kprintf("cache_next:\t%p\n", area->cache_next); 3150 kprintf("cache_prev:\t%p\n", area->cache_prev); 3151 3152 VMAreaMappings::Iterator iterator = area->mappings.GetIterator(); 3153 if (mappings) { 3154 kprintf("page mappings:\n"); 3155 while (iterator.HasNext()) { 3156 vm_page_mapping* mapping = iterator.Next(); 3157 kprintf(" %p", mapping->page); 3158 } 3159 kprintf("\n"); 3160 } else { 3161 uint32 count = 0; 3162 while (iterator.Next() != NULL) { 3163 count++; 3164 } 3165 kprintf("page mappings:\t%lu\n", count); 3166 } 3167 } 3168 3169 3170 static int 3171 dump_area(int argc, char** argv) 3172 { 3173 bool mappings = false; 3174 bool found = false; 3175 int32 index = 1; 3176 VMArea* area; 3177 addr_t num; 3178 3179 if (argc < 2 || !strcmp(argv[1], "--help")) { 3180 kprintf("usage: area [-m] [id|contains|address|name] <id|address|name>\n" 3181 "All areas matching either id/address/name are listed. You can\n" 3182 "force to check only a specific item by prefixing the specifier\n" 3183 "with the id/contains/address/name keywords.\n" 3184 "-m shows the area's mappings as well.\n"); 3185 return 0; 3186 } 3187 3188 if (!strcmp(argv[1], "-m")) { 3189 mappings = true; 3190 index++; 3191 } 3192 3193 int32 mode = 0xf; 3194 if (!strcmp(argv[index], "id")) 3195 mode = 1; 3196 else if (!strcmp(argv[index], "contains")) 3197 mode = 2; 3198 else if (!strcmp(argv[index], "name")) 3199 mode = 4; 3200 else if (!strcmp(argv[index], "address")) 3201 mode = 0; 3202 if (mode != 0xf) 3203 index++; 3204 3205 if (index >= argc) { 3206 kprintf("No area specifier given.\n"); 3207 return 0; 3208 } 3209 3210 num = parse_expression(argv[index]); 3211 3212 if (mode == 0) { 3213 dump_area_struct((struct VMArea*)num, mappings); 3214 } else { 3215 // walk through the area list, looking for the arguments as a name 3216 3217 VMAreaHashTable::Iterator it = VMAreaHash::GetIterator(); 3218 while ((area = it.Next()) != NULL) { 3219 if (((mode & 4) != 0 && area->name != NULL 3220 && !strcmp(argv[index], area->name)) 3221 || (num != 0 && (((mode & 1) != 0 && (addr_t)area->id == num) 3222 || (((mode & 2) != 0 && area->Base() <= num 3223 && area->Base() + area->Size() > num))))) { 3224 dump_area_struct(area, mappings); 3225 found = true; 3226 } 3227 } 3228 3229 if (!found) 3230 kprintf("could not find area %s (%ld)\n", argv[index], num); 3231 } 3232 3233 return 0; 3234 } 3235 3236 3237 static int 3238 dump_area_list(int argc, char** argv) 3239 { 3240 VMArea* area; 3241 const char* name = NULL; 3242 int32 id = 0; 3243 3244 if (argc > 1) { 3245 id = parse_expression(argv[1]); 3246 if (id == 0) 3247 name = argv[1]; 3248 } 3249 3250 kprintf("addr id base\t\tsize protect lock name\n"); 3251 3252 VMAreaHashTable::Iterator it = VMAreaHash::GetIterator(); 3253 while ((area = it.Next()) != NULL) { 3254 if ((id != 0 && area->address_space->ID() != id) 3255 || (name != NULL && strstr(area->name, name) == NULL)) 3256 continue; 3257 3258 kprintf("%p %5lx %p\t%p %4lx\t%4d %s\n", area, area->id, 3259 (void*)area->Base(), (void*)area->Size(), area->protection, 3260 area->wiring, area->name); 3261 } 3262 return 0; 3263 } 3264 3265 3266 static int 3267 dump_available_memory(int argc, char** argv) 3268 { 3269 kprintf("Available memory: %" B_PRIdOFF "/%" B_PRIuPHYSADDR " bytes\n", 3270 sAvailableMemory, (phys_addr_t)vm_page_num_pages() * B_PAGE_SIZE); 3271 return 0; 3272 } 3273 3274 3275 /*! Deletes all areas and reserved regions in the given address space. 3276 3277 The caller must ensure that none of the areas has any wired ranges. 3278 3279 \param addressSpace The address space. 3280 \param deletingAddressSpace \c true, if the address space is in the process 3281 of being deleted. 3282 */ 3283 void 3284 vm_delete_areas(struct VMAddressSpace* addressSpace, bool deletingAddressSpace) 3285 { 3286 TRACE(("vm_delete_areas: called on address space 0x%lx\n", 3287 addressSpace->ID())); 3288 3289 addressSpace->WriteLock(); 3290 3291 // remove all reserved areas in this address space 3292 addressSpace->UnreserveAllAddressRanges(0); 3293 3294 // delete all the areas in this address space 3295 while (VMArea* area = addressSpace->FirstArea()) { 3296 ASSERT(!area->IsWired()); 3297 delete_area(addressSpace, area, deletingAddressSpace); 3298 } 3299 3300 addressSpace->WriteUnlock(); 3301 } 3302 3303 3304 static area_id 3305 vm_area_for(addr_t address, bool kernel) 3306 { 3307 team_id team; 3308 if (IS_USER_ADDRESS(address)) { 3309 // we try the user team address space, if any 3310 team = VMAddressSpace::CurrentID(); 3311 if (team < 0) 3312 return team; 3313 } else 3314 team = VMAddressSpace::KernelID(); 3315 3316 AddressSpaceReadLocker locker(team); 3317 if (!locker.IsLocked()) 3318 return B_BAD_TEAM_ID; 3319 3320 VMArea* area = locker.AddressSpace()->LookupArea(address); 3321 if (area != NULL) { 3322 if (!kernel && (area->protection & (B_READ_AREA | B_WRITE_AREA)) == 0) 3323 return B_ERROR; 3324 3325 return area->id; 3326 } 3327 3328 return B_ERROR; 3329 } 3330 3331 3332 /*! Frees physical pages that were used during the boot process. 3333 \a end is inclusive. 3334 */ 3335 static void 3336 unmap_and_free_physical_pages(VMTranslationMap* map, addr_t start, addr_t end) 3337 { 3338 // free all physical pages in the specified range 3339 3340 for (addr_t current = start; current < end; current += B_PAGE_SIZE) { 3341 phys_addr_t physicalAddress; 3342 uint32 flags; 3343 3344 if (map->Query(current, &physicalAddress, &flags) == B_OK 3345 && (flags & PAGE_PRESENT) != 0) { 3346 vm_page* page = vm_lookup_page(physicalAddress / B_PAGE_SIZE); 3347 if (page != NULL && page->State() != PAGE_STATE_FREE 3348 && page->State() != PAGE_STATE_CLEAR 3349 && page->State() != PAGE_STATE_UNUSED) { 3350 DEBUG_PAGE_ACCESS_START(page); 3351 vm_page_set_state(page, PAGE_STATE_FREE); 3352 } 3353 } 3354 } 3355 3356 // unmap the memory 3357 map->Unmap(start, end); 3358 } 3359 3360 3361 void 3362 vm_free_unused_boot_loader_range(addr_t start, addr_t size) 3363 { 3364 VMTranslationMap* map = VMAddressSpace::Kernel()->TranslationMap(); 3365 addr_t end = start + (size - 1); 3366 addr_t lastEnd = start; 3367 3368 TRACE(("vm_free_unused_boot_loader_range(): asked to free %p - %p\n", 3369 (void*)start, (void*)end)); 3370 3371 // The areas are sorted in virtual address space order, so 3372 // we just have to find the holes between them that fall 3373 // into the area we should dispose 3374 3375 map->Lock(); 3376 3377 for (VMAddressSpace::AreaIterator it 3378 = VMAddressSpace::Kernel()->GetAreaIterator(); 3379 VMArea* area = it.Next();) { 3380 addr_t areaStart = area->Base(); 3381 addr_t areaEnd = areaStart + (area->Size() - 1); 3382 3383 if (areaEnd < start) 3384 continue; 3385 3386 if (areaStart > end) { 3387 // we are done, the area is already beyond of what we have to free 3388 break; 3389 } 3390 3391 if (areaStart > lastEnd) { 3392 // this is something we can free 3393 TRACE(("free boot range: get rid of %p - %p\n", (void*)lastEnd, 3394 (void*)areaStart)); 3395 unmap_and_free_physical_pages(map, lastEnd, areaStart - 1); 3396 } 3397 3398 if (areaEnd >= end) { 3399 lastEnd = areaEnd; 3400 // no +1 to prevent potential overflow 3401 break; 3402 } 3403 3404 lastEnd = areaEnd + 1; 3405 } 3406 3407 if (lastEnd < end) { 3408 // we can also get rid of some space at the end of the area 3409 TRACE(("free boot range: also remove %p - %p\n", (void*)lastEnd, 3410 (void*)end)); 3411 unmap_and_free_physical_pages(map, lastEnd, end); 3412 } 3413 3414 map->Unlock(); 3415 } 3416 3417 3418 static void 3419 create_preloaded_image_areas(struct preloaded_image* image) 3420 { 3421 char name[B_OS_NAME_LENGTH]; 3422 void* address; 3423 int32 length; 3424 3425 // use file name to create a good area name 3426 char* fileName = strrchr(image->name, '/'); 3427 if (fileName == NULL) 3428 fileName = image->name; 3429 else 3430 fileName++; 3431 3432 length = strlen(fileName); 3433 // make sure there is enough space for the suffix 3434 if (length > 25) 3435 length = 25; 3436 3437 memcpy(name, fileName, length); 3438 strcpy(name + length, "_text"); 3439 address = (void*)ROUNDDOWN(image->text_region.start, B_PAGE_SIZE); 3440 image->text_region.id = create_area(name, &address, B_EXACT_ADDRESS, 3441 PAGE_ALIGN(image->text_region.size), B_ALREADY_WIRED, 3442 B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA); 3443 // this will later be remapped read-only/executable by the 3444 // ELF initialization code 3445 3446 strcpy(name + length, "_data"); 3447 address = (void*)ROUNDDOWN(image->data_region.start, B_PAGE_SIZE); 3448 image->data_region.id = create_area(name, &address, B_EXACT_ADDRESS, 3449 PAGE_ALIGN(image->data_region.size), B_ALREADY_WIRED, 3450 B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA); 3451 } 3452 3453 3454 /*! Frees all previously kernel arguments areas from the kernel_args structure. 3455 Any boot loader resources contained in that arguments must not be accessed 3456 anymore past this point. 3457 */ 3458 void 3459 vm_free_kernel_args(kernel_args* args) 3460 { 3461 uint32 i; 3462 3463 TRACE(("vm_free_kernel_args()\n")); 3464 3465 for (i = 0; i < args->num_kernel_args_ranges; i++) { 3466 area_id area = area_for((void*)args->kernel_args_range[i].start); 3467 if (area >= B_OK) 3468 delete_area(area); 3469 } 3470 } 3471 3472 3473 static void 3474 allocate_kernel_args(kernel_args* args) 3475 { 3476 TRACE(("allocate_kernel_args()\n")); 3477 3478 for (uint32 i = 0; i < args->num_kernel_args_ranges; i++) { 3479 void* address = (void*)args->kernel_args_range[i].start; 3480 3481 create_area("_kernel args_", &address, B_EXACT_ADDRESS, 3482 args->kernel_args_range[i].size, B_ALREADY_WIRED, 3483 B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA); 3484 } 3485 } 3486 3487 3488 static void 3489 unreserve_boot_loader_ranges(kernel_args* args) 3490 { 3491 TRACE(("unreserve_boot_loader_ranges()\n")); 3492 3493 for (uint32 i = 0; i < args->num_virtual_allocated_ranges; i++) { 3494 vm_unreserve_address_range(VMAddressSpace::KernelID(), 3495 (void*)args->virtual_allocated_range[i].start, 3496 args->virtual_allocated_range[i].size); 3497 } 3498 } 3499 3500 3501 static void 3502 reserve_boot_loader_ranges(kernel_args* args) 3503 { 3504 TRACE(("reserve_boot_loader_ranges()\n")); 3505 3506 for (uint32 i = 0; i < args->num_virtual_allocated_ranges; i++) { 3507 void* address = (void*)args->virtual_allocated_range[i].start; 3508 3509 // If the address is no kernel address, we just skip it. The 3510 // architecture specific code has to deal with it. 3511 if (!IS_KERNEL_ADDRESS(address)) { 3512 dprintf("reserve_boot_loader_ranges(): Skipping range: %p, %lu\n", 3513 address, args->virtual_allocated_range[i].size); 3514 continue; 3515 } 3516 3517 status_t status = vm_reserve_address_range(VMAddressSpace::KernelID(), 3518 &address, B_EXACT_ADDRESS, args->virtual_allocated_range[i].size, 0); 3519 if (status < B_OK) 3520 panic("could not reserve boot loader ranges\n"); 3521 } 3522 } 3523 3524 3525 static addr_t 3526 allocate_early_virtual(kernel_args* args, size_t size, addr_t alignment) 3527 { 3528 size = PAGE_ALIGN(size); 3529 3530 // find a slot in the virtual allocation addr range 3531 for (uint32 i = 1; i < args->num_virtual_allocated_ranges; i++) { 3532 // check to see if the space between this one and the last is big enough 3533 addr_t rangeStart = args->virtual_allocated_range[i].start; 3534 addr_t previousRangeEnd = args->virtual_allocated_range[i - 1].start 3535 + args->virtual_allocated_range[i - 1].size; 3536 3537 addr_t base = alignment > 0 3538 ? ROUNDUP(previousRangeEnd, alignment) : previousRangeEnd; 3539 3540 if (base >= KERNEL_BASE && base < rangeStart 3541 && rangeStart - base >= size) { 3542 args->virtual_allocated_range[i - 1].size 3543 += base + size - previousRangeEnd; 3544 return base; 3545 } 3546 } 3547 3548 // we hadn't found one between allocation ranges. this is ok. 3549 // see if there's a gap after the last one 3550 int lastEntryIndex = args->num_virtual_allocated_ranges - 1; 3551 addr_t lastRangeEnd = args->virtual_allocated_range[lastEntryIndex].start 3552 + args->virtual_allocated_range[lastEntryIndex].size; 3553 addr_t base = alignment > 0 3554 ? ROUNDUP(lastRangeEnd, alignment) : lastRangeEnd; 3555 if (KERNEL_BASE + (KERNEL_SIZE - 1) - base >= size) { 3556 args->virtual_allocated_range[lastEntryIndex].size 3557 += base + size - lastRangeEnd; 3558 return base; 3559 } 3560 3561 // see if there's a gap before the first one 3562 addr_t rangeStart = args->virtual_allocated_range[0].start; 3563 if (rangeStart > KERNEL_BASE && rangeStart - KERNEL_BASE >= size) { 3564 base = rangeStart - size; 3565 if (alignment > 0) 3566 base = ROUNDDOWN(base, alignment); 3567 3568 if (base >= KERNEL_BASE) { 3569 args->virtual_allocated_range[0].start = base; 3570 args->virtual_allocated_range[0].size += rangeStart - base; 3571 return base; 3572 } 3573 } 3574 3575 return 0; 3576 } 3577 3578 3579 static bool 3580 is_page_in_physical_memory_range(kernel_args* args, phys_addr_t address) 3581 { 3582 // TODO: horrible brute-force method of determining if the page can be 3583 // allocated 3584 for (uint32 i = 0; i < args->num_physical_memory_ranges; i++) { 3585 if (address >= args->physical_memory_range[i].start 3586 && address < args->physical_memory_range[i].start 3587 + args->physical_memory_range[i].size) 3588 return true; 3589 } 3590 return false; 3591 } 3592 3593 3594 page_num_t 3595 vm_allocate_early_physical_page(kernel_args* args) 3596 { 3597 for (uint32 i = 0; i < args->num_physical_allocated_ranges; i++) { 3598 phys_addr_t nextPage; 3599 3600 nextPage = args->physical_allocated_range[i].start 3601 + args->physical_allocated_range[i].size; 3602 // see if the page after the next allocated paddr run can be allocated 3603 if (i + 1 < args->num_physical_allocated_ranges 3604 && args->physical_allocated_range[i + 1].size != 0) { 3605 // see if the next page will collide with the next allocated range 3606 if (nextPage >= args->physical_allocated_range[i+1].start) 3607 continue; 3608 } 3609 // see if the next physical page fits in the memory block 3610 if (is_page_in_physical_memory_range(args, nextPage)) { 3611 // we got one! 3612 args->physical_allocated_range[i].size += B_PAGE_SIZE; 3613 return nextPage / B_PAGE_SIZE; 3614 } 3615 } 3616 3617 return 0; 3618 // could not allocate a block 3619 } 3620 3621 3622 /*! This one uses the kernel_args' physical and virtual memory ranges to 3623 allocate some pages before the VM is completely up. 3624 */ 3625 addr_t 3626 vm_allocate_early(kernel_args* args, size_t virtualSize, size_t physicalSize, 3627 uint32 attributes, addr_t alignment) 3628 { 3629 if (physicalSize > virtualSize) 3630 physicalSize = virtualSize; 3631 3632 // find the vaddr to allocate at 3633 addr_t virtualBase = allocate_early_virtual(args, virtualSize, alignment); 3634 //dprintf("vm_allocate_early: vaddr 0x%lx\n", virtualBase); 3635 3636 // map the pages 3637 for (uint32 i = 0; i < PAGE_ALIGN(physicalSize) / B_PAGE_SIZE; i++) { 3638 page_num_t physicalAddress = vm_allocate_early_physical_page(args); 3639 if (physicalAddress == 0) 3640 panic("error allocating early page!\n"); 3641 3642 //dprintf("vm_allocate_early: paddr 0x%lx\n", physicalAddress); 3643 3644 arch_vm_translation_map_early_map(args, virtualBase + i * B_PAGE_SIZE, 3645 physicalAddress * B_PAGE_SIZE, attributes, 3646 &vm_allocate_early_physical_page); 3647 } 3648 3649 return virtualBase; 3650 } 3651 3652 3653 /*! The main entrance point to initialize the VM. */ 3654 status_t 3655 vm_init(kernel_args* args) 3656 { 3657 struct preloaded_image* image; 3658 void* address; 3659 status_t err = 0; 3660 uint32 i; 3661 3662 TRACE(("vm_init: entry\n")); 3663 err = arch_vm_translation_map_init(args, &sPhysicalPageMapper); 3664 err = arch_vm_init(args); 3665 3666 // initialize some globals 3667 vm_page_init_num_pages(args); 3668 sAvailableMemory = vm_page_num_pages() * B_PAGE_SIZE; 3669 3670 size_t heapSize = INITIAL_HEAP_SIZE; 3671 // try to accomodate low memory systems 3672 while (heapSize > sAvailableMemory / 8) 3673 heapSize /= 2; 3674 if (heapSize < 1024 * 1024) 3675 panic("vm_init: go buy some RAM please."); 3676 3677 slab_init(args); 3678 3679 #if !USE_SLAB_ALLOCATOR_FOR_MALLOC 3680 // map in the new heap and initialize it 3681 addr_t heapBase = vm_allocate_early(args, heapSize, heapSize, 3682 B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, 0); 3683 TRACE(("heap at 0x%lx\n", heapBase)); 3684 heap_init(heapBase, heapSize); 3685 #endif 3686 3687 // initialize the free page list and physical page mapper 3688 vm_page_init(args); 3689 3690 // initialize the hash table that stores the pages mapped to caches 3691 vm_cache_init(args); 3692 3693 { 3694 status_t error = VMAreaHash::Init(); 3695 if (error != B_OK) 3696 panic("vm_init: error initializing area hash table\n"); 3697 } 3698 3699 VMAddressSpace::Init(); 3700 reserve_boot_loader_ranges(args); 3701 3702 #if !USE_SLAB_ALLOCATOR_FOR_MALLOC 3703 heap_init_post_area(); 3704 #endif 3705 3706 // Do any further initialization that the architecture dependant layers may 3707 // need now 3708 arch_vm_translation_map_init_post_area(args); 3709 arch_vm_init_post_area(args); 3710 vm_page_init_post_area(args); 3711 slab_init_post_area(); 3712 3713 // allocate areas to represent stuff that already exists 3714 3715 #if !USE_SLAB_ALLOCATOR_FOR_MALLOC 3716 address = (void*)ROUNDDOWN(heapBase, B_PAGE_SIZE); 3717 create_area("kernel heap", &address, B_EXACT_ADDRESS, heapSize, 3718 B_ALREADY_WIRED, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA); 3719 #endif 3720 3721 allocate_kernel_args(args); 3722 3723 create_preloaded_image_areas(&args->kernel_image); 3724 3725 // allocate areas for preloaded images 3726 for (image = args->preloaded_images; image != NULL; image = image->next) 3727 create_preloaded_image_areas(image); 3728 3729 // allocate kernel stacks 3730 for (i = 0; i < args->num_cpus; i++) { 3731 char name[64]; 3732 3733 sprintf(name, "idle thread %lu kstack", i + 1); 3734 address = (void*)args->cpu_kstack[i].start; 3735 create_area(name, &address, B_EXACT_ADDRESS, args->cpu_kstack[i].size, 3736 B_ALREADY_WIRED, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA); 3737 } 3738 3739 void* lastPage = (void*)ROUNDDOWN(~(addr_t)0, B_PAGE_SIZE); 3740 vm_block_address_range("overflow protection", lastPage, B_PAGE_SIZE); 3741 3742 // create the object cache for the page mappings 3743 gPageMappingsObjectCache = create_object_cache_etc("page mappings", 3744 sizeof(vm_page_mapping), 0, 0, 64, 128, CACHE_LARGE_SLAB, NULL, NULL, 3745 NULL, NULL); 3746 if (gPageMappingsObjectCache == NULL) 3747 panic("failed to create page mappings object cache"); 3748 3749 object_cache_set_minimum_reserve(gPageMappingsObjectCache, 1024); 3750 3751 #if DEBUG_CACHE_LIST 3752 if (vm_page_num_free_pages() >= 200 * 1024 * 1024 / B_PAGE_SIZE) { 3753 virtual_address_restrictions virtualRestrictions = {}; 3754 virtualRestrictions.address_specification = B_ANY_KERNEL_ADDRESS; 3755 physical_address_restrictions physicalRestrictions = {}; 3756 create_area_etc(VMAddressSpace::KernelID(), "cache info table", 3757 ROUNDUP(kCacheInfoTableCount * sizeof(cache_info), B_PAGE_SIZE), 3758 B_FULL_LOCK, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, 3759 CREATE_AREA_DONT_WAIT, &virtualRestrictions, &physicalRestrictions, 3760 (void**)&sCacheInfoTable); 3761 } 3762 #endif // DEBUG_CACHE_LIST 3763 3764 // add some debugger commands 3765 add_debugger_command("areas", &dump_area_list, "Dump a list of all areas"); 3766 add_debugger_command("area", &dump_area, 3767 "Dump info about a particular area"); 3768 add_debugger_command("cache", &dump_cache, "Dump VMCache"); 3769 add_debugger_command("cache_tree", &dump_cache_tree, "Dump VMCache tree"); 3770 #if DEBUG_CACHE_LIST 3771 if (sCacheInfoTable != NULL) { 3772 add_debugger_command_etc("caches", &dump_caches, 3773 "List all VMCache trees", 3774 "[ \"-c\" ]\n" 3775 "All cache trees are listed sorted in decreasing order by number " 3776 "of\n" 3777 "used pages or, if \"-c\" is specified, by size of committed " 3778 "memory.\n", 3779 0); 3780 } 3781 #endif 3782 add_debugger_command("avail", &dump_available_memory, 3783 "Dump available memory"); 3784 add_debugger_command("dl", &display_mem, "dump memory long words (64-bit)"); 3785 add_debugger_command("dw", &display_mem, "dump memory words (32-bit)"); 3786 add_debugger_command("ds", &display_mem, "dump memory shorts (16-bit)"); 3787 add_debugger_command("db", &display_mem, "dump memory bytes (8-bit)"); 3788 add_debugger_command("string", &display_mem, "dump strings"); 3789 3790 TRACE(("vm_init: exit\n")); 3791 3792 vm_cache_init_post_heap(); 3793 3794 return err; 3795 } 3796 3797 3798 status_t 3799 vm_init_post_sem(kernel_args* args) 3800 { 3801 // This frees all unused boot loader resources and makes its space available 3802 // again 3803 arch_vm_init_end(args); 3804 unreserve_boot_loader_ranges(args); 3805 3806 // fill in all of the semaphores that were not allocated before 3807 // since we're still single threaded and only the kernel address space 3808 // exists, it isn't that hard to find all of the ones we need to create 3809 3810 arch_vm_translation_map_init_post_sem(args); 3811 3812 slab_init_post_sem(); 3813 3814 #if !USE_SLAB_ALLOCATOR_FOR_MALLOC 3815 heap_init_post_sem(); 3816 #endif 3817 3818 return B_OK; 3819 } 3820 3821 3822 status_t 3823 vm_init_post_thread(kernel_args* args) 3824 { 3825 vm_page_init_post_thread(args); 3826 slab_init_post_thread(); 3827 return heap_init_post_thread(); 3828 } 3829 3830 3831 status_t 3832 vm_init_post_modules(kernel_args* args) 3833 { 3834 return arch_vm_init_post_modules(args); 3835 } 3836 3837 3838 void 3839 permit_page_faults(void) 3840 { 3841 Thread* thread = thread_get_current_thread(); 3842 if (thread != NULL) 3843 atomic_add(&thread->page_faults_allowed, 1); 3844 } 3845 3846 3847 void 3848 forbid_page_faults(void) 3849 { 3850 Thread* thread = thread_get_current_thread(); 3851 if (thread != NULL) 3852 atomic_add(&thread->page_faults_allowed, -1); 3853 } 3854 3855 3856 status_t 3857 vm_page_fault(addr_t address, addr_t faultAddress, bool isWrite, bool isUser, 3858 addr_t* newIP) 3859 { 3860 FTRACE(("vm_page_fault: page fault at 0x%lx, ip 0x%lx\n", address, 3861 faultAddress)); 3862 3863 TPF(PageFaultStart(address, isWrite, isUser, faultAddress)); 3864 3865 addr_t pageAddress = ROUNDDOWN(address, B_PAGE_SIZE); 3866 VMAddressSpace* addressSpace = NULL; 3867 3868 status_t status = B_OK; 3869 *newIP = 0; 3870 atomic_add((int32*)&sPageFaults, 1); 3871 3872 if (IS_KERNEL_ADDRESS(pageAddress)) { 3873 addressSpace = VMAddressSpace::GetKernel(); 3874 } else if (IS_USER_ADDRESS(pageAddress)) { 3875 addressSpace = VMAddressSpace::GetCurrent(); 3876 if (addressSpace == NULL) { 3877 if (!isUser) { 3878 dprintf("vm_page_fault: kernel thread accessing invalid user " 3879 "memory!\n"); 3880 status = B_BAD_ADDRESS; 3881 TPF(PageFaultError(-1, 3882 VMPageFaultTracing 3883 ::PAGE_FAULT_ERROR_KERNEL_BAD_USER_MEMORY)); 3884 } else { 3885 // XXX weird state. 3886 panic("vm_page_fault: non kernel thread accessing user memory " 3887 "that doesn't exist!\n"); 3888 status = B_BAD_ADDRESS; 3889 } 3890 } 3891 } else { 3892 // the hit was probably in the 64k DMZ between kernel and user space 3893 // this keeps a user space thread from passing a buffer that crosses 3894 // into kernel space 3895 status = B_BAD_ADDRESS; 3896 TPF(PageFaultError(-1, 3897 VMPageFaultTracing::PAGE_FAULT_ERROR_NO_ADDRESS_SPACE)); 3898 } 3899 3900 if (status == B_OK) { 3901 status = vm_soft_fault(addressSpace, pageAddress, isWrite, isUser, 3902 NULL); 3903 } 3904 3905 if (status < B_OK) { 3906 dprintf("vm_page_fault: vm_soft_fault returned error '%s' on fault at " 3907 "0x%lx, ip 0x%lx, write %d, user %d, thread 0x%lx\n", 3908 strerror(status), address, faultAddress, isWrite, isUser, 3909 thread_get_current_thread_id()); 3910 if (!isUser) { 3911 Thread* thread = thread_get_current_thread(); 3912 if (thread != NULL && thread->fault_handler != 0) { 3913 // this will cause the arch dependant page fault handler to 3914 // modify the IP on the interrupt frame or whatever to return 3915 // to this address 3916 *newIP = thread->fault_handler; 3917 } else { 3918 // unhandled page fault in the kernel 3919 panic("vm_page_fault: unhandled page fault in kernel space at " 3920 "0x%lx, ip 0x%lx\n", address, faultAddress); 3921 } 3922 } else { 3923 #if 1 3924 addressSpace->ReadLock(); 3925 3926 // TODO: remove me once we have proper userland debugging support 3927 // (and tools) 3928 VMArea* area = addressSpace->LookupArea(faultAddress); 3929 3930 Thread* thread = thread_get_current_thread(); 3931 dprintf("vm_page_fault: thread \"%s\" (%ld) in team \"%s\" (%ld) " 3932 "tried to %s address %#lx, ip %#lx (\"%s\" +%#lx)\n", 3933 thread->name, thread->id, thread->team->Name(), 3934 thread->team->id, isWrite ? "write" : "read", address, 3935 faultAddress, area ? area->name : "???", 3936 faultAddress - (area ? area->Base() : 0x0)); 3937 3938 // We can print a stack trace of the userland thread here. 3939 // TODO: The user_memcpy() below can cause a deadlock, if it causes a page 3940 // fault and someone is already waiting for a write lock on the same address 3941 // space. This thread will then try to acquire the lock again and will 3942 // be queued after the writer. 3943 # if 0 3944 if (area) { 3945 struct stack_frame { 3946 #if defined(__INTEL__) || defined(__POWERPC__) || defined(__M68K__) 3947 struct stack_frame* previous; 3948 void* return_address; 3949 #else 3950 // ... 3951 #warning writeme 3952 #endif 3953 } frame; 3954 # ifdef __INTEL__ 3955 struct iframe* iframe = i386_get_user_iframe(); 3956 if (iframe == NULL) 3957 panic("iframe is NULL!"); 3958 3959 status_t status = user_memcpy(&frame, (void*)iframe->ebp, 3960 sizeof(struct stack_frame)); 3961 # elif defined(__POWERPC__) 3962 struct iframe* iframe = ppc_get_user_iframe(); 3963 if (iframe == NULL) 3964 panic("iframe is NULL!"); 3965 3966 status_t status = user_memcpy(&frame, (void*)iframe->r1, 3967 sizeof(struct stack_frame)); 3968 # else 3969 # warning "vm_page_fault() stack trace won't work" 3970 status = B_ERROR; 3971 # endif 3972 3973 dprintf("stack trace:\n"); 3974 int32 maxFrames = 50; 3975 while (status == B_OK && --maxFrames >= 0 3976 && frame.return_address != NULL) { 3977 dprintf(" %p", frame.return_address); 3978 area = addressSpace->LookupArea( 3979 (addr_t)frame.return_address); 3980 if (area) { 3981 dprintf(" (%s + %#lx)", area->name, 3982 (addr_t)frame.return_address - area->Base()); 3983 } 3984 dprintf("\n"); 3985 3986 status = user_memcpy(&frame, frame.previous, 3987 sizeof(struct stack_frame)); 3988 } 3989 } 3990 # endif // 0 (stack trace) 3991 3992 addressSpace->ReadUnlock(); 3993 #endif 3994 3995 // TODO: the fault_callback is a temporary solution for vm86 3996 if (thread->fault_callback == NULL 3997 || thread->fault_callback(address, faultAddress, isWrite)) { 3998 // If the thread has a signal handler for SIGSEGV, we simply 3999 // send it the signal. Otherwise we notify the user debugger 4000 // first. 4001 struct sigaction action; 4002 if ((sigaction(SIGSEGV, NULL, &action) == 0 4003 && action.sa_handler != SIG_DFL 4004 && action.sa_handler != SIG_IGN) 4005 || user_debug_exception_occurred(B_SEGMENT_VIOLATION, 4006 SIGSEGV)) { 4007 Signal signal(SIGSEGV, 4008 status == B_PERMISSION_DENIED 4009 ? SEGV_ACCERR : SEGV_MAPERR, 4010 EFAULT, thread->team->id); 4011 signal.SetAddress((void*)address); 4012 send_signal_to_thread(thread, signal, 0); 4013 } 4014 } 4015 } 4016 } 4017 4018 if (addressSpace != NULL) 4019 addressSpace->Put(); 4020 4021 return B_HANDLED_INTERRUPT; 4022 } 4023 4024 4025 struct PageFaultContext { 4026 AddressSpaceReadLocker addressSpaceLocker; 4027 VMCacheChainLocker cacheChainLocker; 4028 4029 VMTranslationMap* map; 4030 VMCache* topCache; 4031 off_t cacheOffset; 4032 vm_page_reservation reservation; 4033 bool isWrite; 4034 4035 // return values 4036 vm_page* page; 4037 bool restart; 4038 4039 4040 PageFaultContext(VMAddressSpace* addressSpace, bool isWrite) 4041 : 4042 addressSpaceLocker(addressSpace, true), 4043 map(addressSpace->TranslationMap()), 4044 isWrite(isWrite) 4045 { 4046 } 4047 4048 ~PageFaultContext() 4049 { 4050 UnlockAll(); 4051 vm_page_unreserve_pages(&reservation); 4052 } 4053 4054 void Prepare(VMCache* topCache, off_t cacheOffset) 4055 { 4056 this->topCache = topCache; 4057 this->cacheOffset = cacheOffset; 4058 page = NULL; 4059 restart = false; 4060 4061 cacheChainLocker.SetTo(topCache); 4062 } 4063 4064 void UnlockAll(VMCache* exceptCache = NULL) 4065 { 4066 topCache = NULL; 4067 addressSpaceLocker.Unlock(); 4068 cacheChainLocker.Unlock(exceptCache); 4069 } 4070 }; 4071 4072 4073 /*! Gets the page that should be mapped into the area. 4074 Returns an error code other than \c B_OK, if the page couldn't be found or 4075 paged in. The locking state of the address space and the caches is undefined 4076 in that case. 4077 Returns \c B_OK with \c context.restart set to \c true, if the functions 4078 had to unlock the address space and all caches and is supposed to be called 4079 again. 4080 Returns \c B_OK with \c context.restart set to \c false, if the page was 4081 found. It is returned in \c context.page. The address space will still be 4082 locked as well as all caches starting from the top cache to at least the 4083 cache the page lives in. 4084 */ 4085 static status_t 4086 fault_get_page(PageFaultContext& context) 4087 { 4088 VMCache* cache = context.topCache; 4089 VMCache* lastCache = NULL; 4090 vm_page* page = NULL; 4091 4092 while (cache != NULL) { 4093 // We already hold the lock of the cache at this point. 4094 4095 lastCache = cache; 4096 4097 page = cache->LookupPage(context.cacheOffset); 4098 if (page != NULL && page->busy) { 4099 // page must be busy -- wait for it to become unbusy 4100 context.UnlockAll(cache); 4101 cache->ReleaseRefLocked(); 4102 cache->WaitForPageEvents(page, PAGE_EVENT_NOT_BUSY, false); 4103 4104 // restart the whole process 4105 context.restart = true; 4106 return B_OK; 4107 } 4108 4109 if (page != NULL) 4110 break; 4111 4112 // The current cache does not contain the page we're looking for. 4113 4114 // see if the backing store has it 4115 if (cache->HasPage(context.cacheOffset)) { 4116 // insert a fresh page and mark it busy -- we're going to read it in 4117 page = vm_page_allocate_page(&context.reservation, 4118 PAGE_STATE_ACTIVE | VM_PAGE_ALLOC_BUSY); 4119 cache->InsertPage(page, context.cacheOffset); 4120 4121 // We need to unlock all caches and the address space while reading 4122 // the page in. Keep a reference to the cache around. 4123 cache->AcquireRefLocked(); 4124 context.UnlockAll(); 4125 4126 // read the page in 4127 generic_io_vec vec; 4128 vec.base = (phys_addr_t)page->physical_page_number * B_PAGE_SIZE; 4129 generic_size_t bytesRead = vec.length = B_PAGE_SIZE; 4130 4131 status_t status = cache->Read(context.cacheOffset, &vec, 1, 4132 B_PHYSICAL_IO_REQUEST, &bytesRead); 4133 4134 cache->Lock(); 4135 4136 if (status < B_OK) { 4137 // on error remove and free the page 4138 dprintf("reading page from cache %p returned: %s!\n", 4139 cache, strerror(status)); 4140 4141 cache->NotifyPageEvents(page, PAGE_EVENT_NOT_BUSY); 4142 cache->RemovePage(page); 4143 vm_page_set_state(page, PAGE_STATE_FREE); 4144 4145 cache->ReleaseRefAndUnlock(); 4146 return status; 4147 } 4148 4149 // mark the page unbusy again 4150 cache->MarkPageUnbusy(page); 4151 4152 DEBUG_PAGE_ACCESS_END(page); 4153 4154 // Since we needed to unlock everything temporarily, the area 4155 // situation might have changed. So we need to restart the whole 4156 // process. 4157 cache->ReleaseRefAndUnlock(); 4158 context.restart = true; 4159 return B_OK; 4160 } 4161 4162 cache = context.cacheChainLocker.LockSourceCache(); 4163 } 4164 4165 if (page == NULL) { 4166 // There was no adequate page, determine the cache for a clean one. 4167 // Read-only pages come in the deepest cache, only the top most cache 4168 // may have direct write access. 4169 cache = context.isWrite ? context.topCache : lastCache; 4170 4171 // allocate a clean page 4172 page = vm_page_allocate_page(&context.reservation, 4173 PAGE_STATE_ACTIVE | VM_PAGE_ALLOC_CLEAR); 4174 FTRACE(("vm_soft_fault: just allocated page 0x%lx\n", 4175 page->physical_page_number)); 4176 4177 // insert the new page into our cache 4178 cache->InsertPage(page, context.cacheOffset); 4179 } else if (page->Cache() != context.topCache && context.isWrite) { 4180 // We have a page that has the data we want, but in the wrong cache 4181 // object so we need to copy it and stick it into the top cache. 4182 vm_page* sourcePage = page; 4183 4184 // TODO: If memory is low, it might be a good idea to steal the page 4185 // from our source cache -- if possible, that is. 4186 FTRACE(("get new page, copy it, and put it into the topmost cache\n")); 4187 page = vm_page_allocate_page(&context.reservation, PAGE_STATE_ACTIVE); 4188 4189 // To not needlessly kill concurrency we unlock all caches but the top 4190 // one while copying the page. Lacking another mechanism to ensure that 4191 // the source page doesn't disappear, we mark it busy. 4192 sourcePage->busy = true; 4193 context.cacheChainLocker.UnlockKeepRefs(true); 4194 4195 // copy the page 4196 vm_memcpy_physical_page(page->physical_page_number * B_PAGE_SIZE, 4197 sourcePage->physical_page_number * B_PAGE_SIZE); 4198 4199 context.cacheChainLocker.RelockCaches(true); 4200 sourcePage->Cache()->MarkPageUnbusy(sourcePage); 4201 4202 // insert the new page into our cache 4203 context.topCache->InsertPage(page, context.cacheOffset); 4204 } else 4205 DEBUG_PAGE_ACCESS_START(page); 4206 4207 context.page = page; 4208 return B_OK; 4209 } 4210 4211 4212 /*! Makes sure the address in the given address space is mapped. 4213 4214 \param addressSpace The address space. 4215 \param originalAddress The address. Doesn't need to be page aligned. 4216 \param isWrite If \c true the address shall be write-accessible. 4217 \param isUser If \c true the access is requested by a userland team. 4218 \param wirePage On success, if non \c NULL, the wired count of the page 4219 mapped at the given address is incremented and the page is returned 4220 via this parameter. 4221 \param wiredRange If given, this wiredRange is ignored when checking whether 4222 an already mapped page at the virtual address can be unmapped. 4223 \return \c B_OK on success, another error code otherwise. 4224 */ 4225 static status_t 4226 vm_soft_fault(VMAddressSpace* addressSpace, addr_t originalAddress, 4227 bool isWrite, bool isUser, vm_page** wirePage, VMAreaWiredRange* wiredRange) 4228 { 4229 FTRACE(("vm_soft_fault: thid 0x%lx address 0x%lx, isWrite %d, isUser %d\n", 4230 thread_get_current_thread_id(), originalAddress, isWrite, isUser)); 4231 4232 PageFaultContext context(addressSpace, isWrite); 4233 4234 addr_t address = ROUNDDOWN(originalAddress, B_PAGE_SIZE); 4235 status_t status = B_OK; 4236 4237 addressSpace->IncrementFaultCount(); 4238 4239 // We may need up to 2 pages plus pages needed for mapping them -- reserving 4240 // the pages upfront makes sure we don't have any cache locked, so that the 4241 // page daemon/thief can do their job without problems. 4242 size_t reservePages = 2 + context.map->MaxPagesNeededToMap(originalAddress, 4243 originalAddress); 4244 context.addressSpaceLocker.Unlock(); 4245 vm_page_reserve_pages(&context.reservation, reservePages, 4246 addressSpace == VMAddressSpace::Kernel() 4247 ? VM_PRIORITY_SYSTEM : VM_PRIORITY_USER); 4248 4249 while (true) { 4250 context.addressSpaceLocker.Lock(); 4251 4252 // get the area the fault was in 4253 VMArea* area = addressSpace->LookupArea(address); 4254 if (area == NULL) { 4255 dprintf("vm_soft_fault: va 0x%lx not covered by area in address " 4256 "space\n", originalAddress); 4257 TPF(PageFaultError(-1, 4258 VMPageFaultTracing::PAGE_FAULT_ERROR_NO_AREA)); 4259 status = B_BAD_ADDRESS; 4260 break; 4261 } 4262 4263 // check permissions 4264 uint32 protection = get_area_page_protection(area, address); 4265 if (isUser && (protection & B_USER_PROTECTION) == 0) { 4266 dprintf("user access on kernel area 0x%lx at %p\n", area->id, 4267 (void*)originalAddress); 4268 TPF(PageFaultError(area->id, 4269 VMPageFaultTracing::PAGE_FAULT_ERROR_KERNEL_ONLY)); 4270 status = B_PERMISSION_DENIED; 4271 break; 4272 } 4273 if (isWrite && (protection 4274 & (B_WRITE_AREA | (isUser ? 0 : B_KERNEL_WRITE_AREA))) == 0) { 4275 dprintf("write access attempted on write-protected area 0x%lx at" 4276 " %p\n", area->id, (void*)originalAddress); 4277 TPF(PageFaultError(area->id, 4278 VMPageFaultTracing::PAGE_FAULT_ERROR_WRITE_PROTECTED)); 4279 status = B_PERMISSION_DENIED; 4280 break; 4281 } else if (!isWrite && (protection 4282 & (B_READ_AREA | (isUser ? 0 : B_KERNEL_READ_AREA))) == 0) { 4283 dprintf("read access attempted on read-protected area 0x%lx at" 4284 " %p\n", area->id, (void*)originalAddress); 4285 TPF(PageFaultError(area->id, 4286 VMPageFaultTracing::PAGE_FAULT_ERROR_READ_PROTECTED)); 4287 status = B_PERMISSION_DENIED; 4288 break; 4289 } 4290 4291 // We have the area, it was a valid access, so let's try to resolve the 4292 // page fault now. 4293 // At first, the top most cache from the area is investigated. 4294 4295 context.Prepare(vm_area_get_locked_cache(area), 4296 address - area->Base() + area->cache_offset); 4297 4298 // See if this cache has a fault handler -- this will do all the work 4299 // for us. 4300 { 4301 // Note, since the page fault is resolved with interrupts enabled, 4302 // the fault handler could be called more than once for the same 4303 // reason -- the store must take this into account. 4304 status = context.topCache->Fault(addressSpace, context.cacheOffset); 4305 if (status != B_BAD_HANDLER) 4306 break; 4307 } 4308 4309 // The top most cache has no fault handler, so let's see if the cache or 4310 // its sources already have the page we're searching for (we're going 4311 // from top to bottom). 4312 status = fault_get_page(context); 4313 if (status != B_OK) { 4314 TPF(PageFaultError(area->id, status)); 4315 break; 4316 } 4317 4318 if (context.restart) 4319 continue; 4320 4321 // All went fine, all there is left to do is to map the page into the 4322 // address space. 4323 TPF(PageFaultDone(area->id, context.topCache, context.page->Cache(), 4324 context.page)); 4325 4326 // If the page doesn't reside in the area's cache, we need to make sure 4327 // it's mapped in read-only, so that we cannot overwrite someone else's 4328 // data (copy-on-write) 4329 uint32 newProtection = protection; 4330 if (context.page->Cache() != context.topCache && !isWrite) 4331 newProtection &= ~(B_WRITE_AREA | B_KERNEL_WRITE_AREA); 4332 4333 bool unmapPage = false; 4334 bool mapPage = true; 4335 4336 // check whether there's already a page mapped at the address 4337 context.map->Lock(); 4338 4339 phys_addr_t physicalAddress; 4340 uint32 flags; 4341 vm_page* mappedPage = NULL; 4342 if (context.map->Query(address, &physicalAddress, &flags) == B_OK 4343 && (flags & PAGE_PRESENT) != 0 4344 && (mappedPage = vm_lookup_page(physicalAddress / B_PAGE_SIZE)) 4345 != NULL) { 4346 // Yep there's already a page. If it's ours, we can simply adjust 4347 // its protection. Otherwise we have to unmap it. 4348 if (mappedPage == context.page) { 4349 context.map->ProtectPage(area, address, newProtection); 4350 // Note: We assume that ProtectPage() is atomic (i.e. 4351 // the page isn't temporarily unmapped), otherwise we'd have 4352 // to make sure it isn't wired. 4353 mapPage = false; 4354 } else 4355 unmapPage = true; 4356 } 4357 4358 context.map->Unlock(); 4359 4360 if (unmapPage) { 4361 // If the page is wired, we can't unmap it. Wait until it is unwired 4362 // again and restart. 4363 VMAreaUnwiredWaiter waiter; 4364 if (area->AddWaiterIfWired(&waiter, address, B_PAGE_SIZE, 4365 wiredRange)) { 4366 // unlock everything and wait 4367 context.UnlockAll(); 4368 waiter.waitEntry.Wait(); 4369 continue; 4370 } 4371 4372 // Note: The mapped page is a page of a lower cache. We are 4373 // guaranteed to have that cached locked, our new page is a copy of 4374 // that page, and the page is not busy. The logic for that guarantee 4375 // is as follows: Since the page is mapped, it must live in the top 4376 // cache (ruled out above) or any of its lower caches, and there is 4377 // (was before the new page was inserted) no other page in any 4378 // cache between the top cache and the page's cache (otherwise that 4379 // would be mapped instead). That in turn means that our algorithm 4380 // must have found it and therefore it cannot be busy either. 4381 DEBUG_PAGE_ACCESS_START(mappedPage); 4382 unmap_page(area, address); 4383 DEBUG_PAGE_ACCESS_END(mappedPage); 4384 } 4385 4386 if (mapPage) { 4387 if (map_page(area, context.page, address, newProtection, 4388 &context.reservation) != B_OK) { 4389 // Mapping can only fail, when the page mapping object couldn't 4390 // be allocated. Save for the missing mapping everything is 4391 // fine, though. If this was a regular page fault, we'll simply 4392 // leave and probably fault again. To make sure we'll have more 4393 // luck then, we ensure that the minimum object reserve is 4394 // available. 4395 DEBUG_PAGE_ACCESS_END(context.page); 4396 4397 context.UnlockAll(); 4398 4399 if (object_cache_reserve(gPageMappingsObjectCache, 1, 0) 4400 != B_OK) { 4401 // Apparently the situation is serious. Let's get ourselves 4402 // killed. 4403 status = B_NO_MEMORY; 4404 } else if (wirePage != NULL) { 4405 // The caller expects us to wire the page. Since 4406 // object_cache_reserve() succeeded, we should now be able 4407 // to allocate a mapping structure. Restart. 4408 continue; 4409 } 4410 4411 break; 4412 } 4413 } else if (context.page->State() == PAGE_STATE_INACTIVE) 4414 vm_page_set_state(context.page, PAGE_STATE_ACTIVE); 4415 4416 // also wire the page, if requested 4417 if (wirePage != NULL && status == B_OK) { 4418 increment_page_wired_count(context.page); 4419 *wirePage = context.page; 4420 } 4421 4422 DEBUG_PAGE_ACCESS_END(context.page); 4423 4424 break; 4425 } 4426 4427 return status; 4428 } 4429 4430 4431 status_t 4432 vm_get_physical_page(phys_addr_t paddr, addr_t* _vaddr, void** _handle) 4433 { 4434 return sPhysicalPageMapper->GetPage(paddr, _vaddr, _handle); 4435 } 4436 4437 status_t 4438 vm_put_physical_page(addr_t vaddr, void* handle) 4439 { 4440 return sPhysicalPageMapper->PutPage(vaddr, handle); 4441 } 4442 4443 4444 status_t 4445 vm_get_physical_page_current_cpu(phys_addr_t paddr, addr_t* _vaddr, 4446 void** _handle) 4447 { 4448 return sPhysicalPageMapper->GetPageCurrentCPU(paddr, _vaddr, _handle); 4449 } 4450 4451 status_t 4452 vm_put_physical_page_current_cpu(addr_t vaddr, void* handle) 4453 { 4454 return sPhysicalPageMapper->PutPageCurrentCPU(vaddr, handle); 4455 } 4456 4457 4458 status_t 4459 vm_get_physical_page_debug(phys_addr_t paddr, addr_t* _vaddr, void** _handle) 4460 { 4461 return sPhysicalPageMapper->GetPageDebug(paddr, _vaddr, _handle); 4462 } 4463 4464 status_t 4465 vm_put_physical_page_debug(addr_t vaddr, void* handle) 4466 { 4467 return sPhysicalPageMapper->PutPageDebug(vaddr, handle); 4468 } 4469 4470 4471 void 4472 vm_get_info(system_memory_info* info) 4473 { 4474 swap_get_info(info); 4475 4476 info->max_memory = vm_page_num_pages() * B_PAGE_SIZE; 4477 info->page_faults = sPageFaults; 4478 4479 MutexLocker locker(sAvailableMemoryLock); 4480 info->free_memory = sAvailableMemory; 4481 info->needed_memory = sNeededMemory; 4482 } 4483 4484 4485 uint32 4486 vm_num_page_faults(void) 4487 { 4488 return sPageFaults; 4489 } 4490 4491 4492 off_t 4493 vm_available_memory(void) 4494 { 4495 MutexLocker locker(sAvailableMemoryLock); 4496 return sAvailableMemory; 4497 } 4498 4499 4500 off_t 4501 vm_available_not_needed_memory(void) 4502 { 4503 MutexLocker locker(sAvailableMemoryLock); 4504 return sAvailableMemory - sNeededMemory; 4505 } 4506 4507 4508 /*! Like vm_available_not_needed_memory(), but only for use in the kernel 4509 debugger. 4510 */ 4511 off_t 4512 vm_available_not_needed_memory_debug(void) 4513 { 4514 return sAvailableMemory - sNeededMemory; 4515 } 4516 4517 4518 size_t 4519 vm_kernel_address_space_left(void) 4520 { 4521 return VMAddressSpace::Kernel()->FreeSpace(); 4522 } 4523 4524 4525 void 4526 vm_unreserve_memory(size_t amount) 4527 { 4528 mutex_lock(&sAvailableMemoryLock); 4529 4530 sAvailableMemory += amount; 4531 4532 mutex_unlock(&sAvailableMemoryLock); 4533 } 4534 4535 4536 status_t 4537 vm_try_reserve_memory(size_t amount, int priority, bigtime_t timeout) 4538 { 4539 size_t reserve = kMemoryReserveForPriority[priority]; 4540 4541 MutexLocker locker(sAvailableMemoryLock); 4542 4543 //dprintf("try to reserve %lu bytes, %Lu left\n", amount, sAvailableMemory); 4544 4545 if (sAvailableMemory >= amount + reserve) { 4546 sAvailableMemory -= amount; 4547 return B_OK; 4548 } 4549 4550 if (timeout <= 0) 4551 return B_NO_MEMORY; 4552 4553 // turn timeout into an absolute timeout 4554 timeout += system_time(); 4555 4556 // loop until we've got the memory or the timeout occurs 4557 do { 4558 sNeededMemory += amount; 4559 4560 // call the low resource manager 4561 locker.Unlock(); 4562 low_resource(B_KERNEL_RESOURCE_MEMORY, sNeededMemory - sAvailableMemory, 4563 B_ABSOLUTE_TIMEOUT, timeout); 4564 locker.Lock(); 4565 4566 sNeededMemory -= amount; 4567 4568 if (sAvailableMemory >= amount + reserve) { 4569 sAvailableMemory -= amount; 4570 return B_OK; 4571 } 4572 } while (timeout > system_time()); 4573 4574 return B_NO_MEMORY; 4575 } 4576 4577 4578 status_t 4579 vm_set_area_memory_type(area_id id, phys_addr_t physicalBase, uint32 type) 4580 { 4581 // NOTE: The caller is responsible for synchronizing calls to this function! 4582 4583 AddressSpaceReadLocker locker; 4584 VMArea* area; 4585 status_t status = locker.SetFromArea(id, area); 4586 if (status != B_OK) 4587 return status; 4588 4589 // nothing to do, if the type doesn't change 4590 uint32 oldType = area->MemoryType(); 4591 if (type == oldType) 4592 return B_OK; 4593 4594 // set the memory type of the area and the mapped pages 4595 VMTranslationMap* map = area->address_space->TranslationMap(); 4596 map->Lock(); 4597 area->SetMemoryType(type); 4598 map->ProtectArea(area, area->protection); 4599 map->Unlock(); 4600 4601 // set the physical memory type 4602 status_t error = arch_vm_set_memory_type(area, physicalBase, type); 4603 if (error != B_OK) { 4604 // reset the memory type of the area and the mapped pages 4605 map->Lock(); 4606 area->SetMemoryType(oldType); 4607 map->ProtectArea(area, area->protection); 4608 map->Unlock(); 4609 return error; 4610 } 4611 4612 return B_OK; 4613 4614 } 4615 4616 4617 /*! This function enforces some protection properties: 4618 - if B_WRITE_AREA is set, B_WRITE_KERNEL_AREA is set as well 4619 - if only B_READ_AREA has been set, B_KERNEL_READ_AREA is also set 4620 - if no protection is specified, it defaults to B_KERNEL_READ_AREA 4621 and B_KERNEL_WRITE_AREA. 4622 */ 4623 static void 4624 fix_protection(uint32* protection) 4625 { 4626 if ((*protection & B_KERNEL_PROTECTION) == 0) { 4627 if ((*protection & B_USER_PROTECTION) == 0 4628 || (*protection & B_WRITE_AREA) != 0) 4629 *protection |= B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA; 4630 else 4631 *protection |= B_KERNEL_READ_AREA; 4632 } 4633 } 4634 4635 4636 static void 4637 fill_area_info(struct VMArea* area, area_info* info, size_t size) 4638 { 4639 strlcpy(info->name, area->name, B_OS_NAME_LENGTH); 4640 info->area = area->id; 4641 info->address = (void*)area->Base(); 4642 info->size = area->Size(); 4643 info->protection = area->protection; 4644 info->lock = B_FULL_LOCK; 4645 info->team = area->address_space->ID(); 4646 info->copy_count = 0; 4647 info->in_count = 0; 4648 info->out_count = 0; 4649 // TODO: retrieve real values here! 4650 4651 VMCache* cache = vm_area_get_locked_cache(area); 4652 4653 // Note, this is a simplification; the cache could be larger than this area 4654 info->ram_size = cache->page_count * B_PAGE_SIZE; 4655 4656 vm_area_put_locked_cache(cache); 4657 } 4658 4659 4660 static status_t 4661 vm_resize_area(area_id areaID, size_t newSize, bool kernel) 4662 { 4663 // is newSize a multiple of B_PAGE_SIZE? 4664 if (newSize & (B_PAGE_SIZE - 1)) 4665 return B_BAD_VALUE; 4666 4667 // lock all affected address spaces and the cache 4668 VMArea* area; 4669 VMCache* cache; 4670 4671 MultiAddressSpaceLocker locker; 4672 AreaCacheLocker cacheLocker; 4673 4674 status_t status; 4675 size_t oldSize; 4676 bool anyKernelArea; 4677 bool restart; 4678 4679 do { 4680 anyKernelArea = false; 4681 restart = false; 4682 4683 locker.Unset(); 4684 status = locker.AddAreaCacheAndLock(areaID, true, true, area, &cache); 4685 if (status != B_OK) 4686 return status; 4687 cacheLocker.SetTo(cache, true); // already locked 4688 4689 // enforce restrictions 4690 if (!kernel) { 4691 if ((area->protection & B_KERNEL_AREA) != 0) 4692 return B_NOT_ALLOWED; 4693 // TODO: Enforce all restrictions (team, etc.)! 4694 } 4695 4696 oldSize = area->Size(); 4697 if (newSize == oldSize) 4698 return B_OK; 4699 4700 if (cache->type != CACHE_TYPE_RAM) 4701 return B_NOT_ALLOWED; 4702 4703 if (oldSize < newSize) { 4704 // We need to check if all areas of this cache can be resized. 4705 for (VMArea* current = cache->areas; current != NULL; 4706 current = current->cache_next) { 4707 if (!current->address_space->CanResizeArea(current, newSize)) 4708 return B_ERROR; 4709 anyKernelArea 4710 |= current->address_space == VMAddressSpace::Kernel(); 4711 } 4712 } else { 4713 // We're shrinking the areas, so we must make sure the affected 4714 // ranges are not wired. 4715 for (VMArea* current = cache->areas; current != NULL; 4716 current = current->cache_next) { 4717 anyKernelArea 4718 |= current->address_space == VMAddressSpace::Kernel(); 4719 4720 if (wait_if_area_range_is_wired(current, 4721 current->Base() + newSize, oldSize - newSize, &locker, 4722 &cacheLocker)) { 4723 restart = true; 4724 break; 4725 } 4726 } 4727 } 4728 } while (restart); 4729 4730 // Okay, looks good so far, so let's do it 4731 4732 int priority = kernel && anyKernelArea 4733 ? VM_PRIORITY_SYSTEM : VM_PRIORITY_USER; 4734 uint32 allocationFlags = kernel && anyKernelArea 4735 ? HEAP_DONT_WAIT_FOR_MEMORY | HEAP_DONT_LOCK_KERNEL_SPACE : 0; 4736 4737 if (oldSize < newSize) { 4738 // Growing the cache can fail, so we do it first. 4739 status = cache->Resize(cache->virtual_base + newSize, priority); 4740 if (status != B_OK) 4741 return status; 4742 } 4743 4744 for (VMArea* current = cache->areas; current != NULL; 4745 current = current->cache_next) { 4746 status = current->address_space->ResizeArea(current, newSize, 4747 allocationFlags); 4748 if (status != B_OK) 4749 break; 4750 4751 // We also need to unmap all pages beyond the new size, if the area has 4752 // shrunk 4753 if (newSize < oldSize) { 4754 VMCacheChainLocker cacheChainLocker(cache); 4755 cacheChainLocker.LockAllSourceCaches(); 4756 4757 unmap_pages(current, current->Base() + newSize, 4758 oldSize - newSize); 4759 4760 cacheChainLocker.Unlock(cache); 4761 } 4762 } 4763 4764 if (status == B_OK) { 4765 // Shrink or grow individual page protections if in use. 4766 if (area->page_protections != NULL) { 4767 uint32 bytes = (newSize / B_PAGE_SIZE + 1) / 2; 4768 uint8* newProtections 4769 = (uint8*)realloc(area->page_protections, bytes); 4770 if (newProtections == NULL) 4771 status = B_NO_MEMORY; 4772 else { 4773 area->page_protections = newProtections; 4774 4775 if (oldSize < newSize) { 4776 // init the additional page protections to that of the area 4777 uint32 offset = (oldSize / B_PAGE_SIZE + 1) / 2; 4778 uint32 areaProtection = area->protection 4779 & (B_READ_AREA | B_WRITE_AREA | B_EXECUTE_AREA); 4780 memset(area->page_protections + offset, 4781 areaProtection | (areaProtection << 4), bytes - offset); 4782 if ((oldSize / B_PAGE_SIZE) % 2 != 0) { 4783 uint8& entry = area->page_protections[offset - 1]; 4784 entry = (entry & 0x0f) | (areaProtection << 4); 4785 } 4786 } 4787 } 4788 } 4789 } 4790 4791 // shrinking the cache can't fail, so we do it now 4792 if (status == B_OK && newSize < oldSize) 4793 status = cache->Resize(cache->virtual_base + newSize, priority); 4794 4795 if (status != B_OK) { 4796 // Something failed -- resize the areas back to their original size. 4797 // This can fail, too, in which case we're seriously screwed. 4798 for (VMArea* current = cache->areas; current != NULL; 4799 current = current->cache_next) { 4800 if (current->address_space->ResizeArea(current, oldSize, 4801 allocationFlags) != B_OK) { 4802 panic("vm_resize_area(): Failed and not being able to restore " 4803 "original state."); 4804 } 4805 } 4806 4807 cache->Resize(cache->virtual_base + oldSize, priority); 4808 } 4809 4810 // TODO: we must honour the lock restrictions of this area 4811 return status; 4812 } 4813 4814 4815 status_t 4816 vm_memset_physical(phys_addr_t address, int value, size_t length) 4817 { 4818 return sPhysicalPageMapper->MemsetPhysical(address, value, length); 4819 } 4820 4821 4822 status_t 4823 vm_memcpy_from_physical(void* to, phys_addr_t from, size_t length, bool user) 4824 { 4825 return sPhysicalPageMapper->MemcpyFromPhysical(to, from, length, user); 4826 } 4827 4828 4829 status_t 4830 vm_memcpy_to_physical(phys_addr_t to, const void* _from, size_t length, 4831 bool user) 4832 { 4833 return sPhysicalPageMapper->MemcpyToPhysical(to, _from, length, user); 4834 } 4835 4836 4837 void 4838 vm_memcpy_physical_page(phys_addr_t to, phys_addr_t from) 4839 { 4840 return sPhysicalPageMapper->MemcpyPhysicalPage(to, from); 4841 } 4842 4843 4844 /*! Copies a range of memory directly from/to a page that might not be mapped 4845 at the moment. 4846 4847 For \a unsafeMemory the current mapping (if any is ignored). The function 4848 walks through the respective area's cache chain to find the physical page 4849 and copies from/to it directly. 4850 The memory range starting at \a unsafeMemory with a length of \a size bytes 4851 must not cross a page boundary. 4852 4853 \param teamID The team ID identifying the address space \a unsafeMemory is 4854 to be interpreted in. Ignored, if \a unsafeMemory is a kernel address 4855 (the kernel address space is assumed in this case). If \c B_CURRENT_TEAM 4856 is passed, the address space of the thread returned by 4857 debug_get_debugged_thread() is used. 4858 \param unsafeMemory The start of the unsafe memory range to be copied 4859 from/to. 4860 \param buffer A safely accessible kernel buffer to be copied from/to. 4861 \param size The number of bytes to be copied. 4862 \param copyToUnsafe If \c true, memory is copied from \a buffer to 4863 \a unsafeMemory, the other way around otherwise. 4864 */ 4865 status_t 4866 vm_debug_copy_page_memory(team_id teamID, void* unsafeMemory, void* buffer, 4867 size_t size, bool copyToUnsafe) 4868 { 4869 if (size > B_PAGE_SIZE || ROUNDDOWN((addr_t)unsafeMemory, B_PAGE_SIZE) 4870 != ROUNDDOWN((addr_t)unsafeMemory + size - 1, B_PAGE_SIZE)) { 4871 return B_BAD_VALUE; 4872 } 4873 4874 // get the address space for the debugged thread 4875 VMAddressSpace* addressSpace; 4876 if (IS_KERNEL_ADDRESS(unsafeMemory)) { 4877 addressSpace = VMAddressSpace::Kernel(); 4878 } else if (teamID == B_CURRENT_TEAM) { 4879 Thread* thread = debug_get_debugged_thread(); 4880 if (thread == NULL || thread->team == NULL) 4881 return B_BAD_ADDRESS; 4882 4883 addressSpace = thread->team->address_space; 4884 } else 4885 addressSpace = VMAddressSpace::DebugGet(teamID); 4886 4887 if (addressSpace == NULL) 4888 return B_BAD_ADDRESS; 4889 4890 // get the area 4891 VMArea* area = addressSpace->LookupArea((addr_t)unsafeMemory); 4892 if (area == NULL) 4893 return B_BAD_ADDRESS; 4894 4895 // search the page 4896 off_t cacheOffset = (addr_t)unsafeMemory - area->Base() 4897 + area->cache_offset; 4898 VMCache* cache = area->cache; 4899 vm_page* page = NULL; 4900 while (cache != NULL) { 4901 page = cache->DebugLookupPage(cacheOffset); 4902 if (page != NULL) 4903 break; 4904 4905 // Page not found in this cache -- if it is paged out, we must not try 4906 // to get it from lower caches. 4907 if (cache->DebugHasPage(cacheOffset)) 4908 break; 4909 4910 cache = cache->source; 4911 } 4912 4913 if (page == NULL) 4914 return B_UNSUPPORTED; 4915 4916 // copy from/to physical memory 4917 phys_addr_t physicalAddress = page->physical_page_number * B_PAGE_SIZE 4918 + (addr_t)unsafeMemory % B_PAGE_SIZE; 4919 4920 if (copyToUnsafe) { 4921 if (page->Cache() != area->cache) 4922 return B_UNSUPPORTED; 4923 4924 return vm_memcpy_to_physical(physicalAddress, buffer, size, false); 4925 } 4926 4927 return vm_memcpy_from_physical(buffer, physicalAddress, size, false); 4928 } 4929 4930 4931 // #pragma mark - kernel public API 4932 4933 4934 status_t 4935 user_memcpy(void* to, const void* from, size_t size) 4936 { 4937 // don't allow address overflows 4938 if ((addr_t)from + size < (addr_t)from || (addr_t)to + size < (addr_t)to) 4939 return B_BAD_ADDRESS; 4940 4941 if (arch_cpu_user_memcpy(to, from, size, 4942 &thread_get_current_thread()->fault_handler) < B_OK) 4943 return B_BAD_ADDRESS; 4944 4945 return B_OK; 4946 } 4947 4948 4949 /*! \brief Copies at most (\a size - 1) characters from the string in \a from to 4950 the string in \a to, NULL-terminating the result. 4951 4952 \param to Pointer to the destination C-string. 4953 \param from Pointer to the source C-string. 4954 \param size Size in bytes of the string buffer pointed to by \a to. 4955 4956 \return strlen(\a from). 4957 */ 4958 ssize_t 4959 user_strlcpy(char* to, const char* from, size_t size) 4960 { 4961 if (to == NULL && size != 0) 4962 return B_BAD_VALUE; 4963 if (from == NULL) 4964 return B_BAD_ADDRESS; 4965 4966 // limit size to avoid address overflows 4967 size_t maxSize = std::min(size, 4968 ~(addr_t)0 - std::max((addr_t)from, (addr_t)to) + 1); 4969 // NOTE: Since arch_cpu_user_strlcpy() determines the length of \a from, 4970 // the source address might still overflow. 4971 4972 ssize_t result = arch_cpu_user_strlcpy(to, from, maxSize, 4973 &thread_get_current_thread()->fault_handler); 4974 4975 // If we hit the address overflow boundary, fail. 4976 if (result >= 0 && (size_t)result >= maxSize && maxSize < size) 4977 return B_BAD_ADDRESS; 4978 4979 return result; 4980 } 4981 4982 4983 status_t 4984 user_memset(void* s, char c, size_t count) 4985 { 4986 // don't allow address overflows 4987 if ((addr_t)s + count < (addr_t)s) 4988 return B_BAD_ADDRESS; 4989 4990 if (arch_cpu_user_memset(s, c, count, 4991 &thread_get_current_thread()->fault_handler) < B_OK) 4992 return B_BAD_ADDRESS; 4993 4994 return B_OK; 4995 } 4996 4997 4998 /*! Wires a single page at the given address. 4999 5000 \param team The team whose address space the address belongs to. Supports 5001 also \c B_CURRENT_TEAM. If the given address is a kernel address, the 5002 parameter is ignored. 5003 \param address address The virtual address to wire down. Does not need to 5004 be page aligned. 5005 \param writable If \c true the page shall be writable. 5006 \param info On success the info is filled in, among other things 5007 containing the physical address the given virtual one translates to. 5008 \return \c B_OK, when the page could be wired, another error code otherwise. 5009 */ 5010 status_t 5011 vm_wire_page(team_id team, addr_t address, bool writable, 5012 VMPageWiringInfo* info) 5013 { 5014 addr_t pageAddress = ROUNDDOWN((addr_t)address, B_PAGE_SIZE); 5015 info->range.SetTo(pageAddress, B_PAGE_SIZE, writable, false); 5016 5017 // compute the page protection that is required 5018 bool isUser = IS_USER_ADDRESS(address); 5019 uint32 requiredProtection = PAGE_PRESENT 5020 | B_KERNEL_READ_AREA | (isUser ? B_READ_AREA : 0); 5021 if (writable) 5022 requiredProtection |= B_KERNEL_WRITE_AREA | (isUser ? B_WRITE_AREA : 0); 5023 5024 // get and read lock the address space 5025 VMAddressSpace* addressSpace = NULL; 5026 if (isUser) { 5027 if (team == B_CURRENT_TEAM) 5028 addressSpace = VMAddressSpace::GetCurrent(); 5029 else 5030 addressSpace = VMAddressSpace::Get(team); 5031 } else 5032 addressSpace = VMAddressSpace::GetKernel(); 5033 if (addressSpace == NULL) 5034 return B_ERROR; 5035 5036 AddressSpaceReadLocker addressSpaceLocker(addressSpace, true); 5037 5038 VMTranslationMap* map = addressSpace->TranslationMap(); 5039 status_t error = B_OK; 5040 5041 // get the area 5042 VMArea* area = addressSpace->LookupArea(pageAddress); 5043 if (area == NULL) { 5044 addressSpace->Put(); 5045 return B_BAD_ADDRESS; 5046 } 5047 5048 // Lock the area's top cache. This is a requirement for VMArea::Wire(). 5049 VMCacheChainLocker cacheChainLocker(vm_area_get_locked_cache(area)); 5050 5051 // mark the area range wired 5052 area->Wire(&info->range); 5053 5054 // Lock the area's cache chain and the translation map. Needed to look 5055 // up the page and play with its wired count. 5056 cacheChainLocker.LockAllSourceCaches(); 5057 map->Lock(); 5058 5059 phys_addr_t physicalAddress; 5060 uint32 flags; 5061 vm_page* page; 5062 if (map->Query(pageAddress, &physicalAddress, &flags) == B_OK 5063 && (flags & requiredProtection) == requiredProtection 5064 && (page = vm_lookup_page(physicalAddress / B_PAGE_SIZE)) 5065 != NULL) { 5066 // Already mapped with the correct permissions -- just increment 5067 // the page's wired count. 5068 increment_page_wired_count(page); 5069 5070 map->Unlock(); 5071 cacheChainLocker.Unlock(); 5072 addressSpaceLocker.Unlock(); 5073 } else { 5074 // Let vm_soft_fault() map the page for us, if possible. We need 5075 // to fully unlock to avoid deadlocks. Since we have already 5076 // wired the area itself, nothing disturbing will happen with it 5077 // in the meantime. 5078 map->Unlock(); 5079 cacheChainLocker.Unlock(); 5080 addressSpaceLocker.Unlock(); 5081 5082 error = vm_soft_fault(addressSpace, pageAddress, writable, isUser, 5083 &page, &info->range); 5084 5085 if (error != B_OK) { 5086 // The page could not be mapped -- clean up. 5087 VMCache* cache = vm_area_get_locked_cache(area); 5088 area->Unwire(&info->range); 5089 cache->ReleaseRefAndUnlock(); 5090 addressSpace->Put(); 5091 return error; 5092 } 5093 } 5094 5095 info->physicalAddress 5096 = (phys_addr_t)page->physical_page_number * B_PAGE_SIZE 5097 + address % B_PAGE_SIZE; 5098 info->page = page; 5099 5100 return B_OK; 5101 } 5102 5103 5104 /*! Unwires a single page previously wired via vm_wire_page(). 5105 5106 \param info The same object passed to vm_wire_page() before. 5107 */ 5108 void 5109 vm_unwire_page(VMPageWiringInfo* info) 5110 { 5111 // lock the address space 5112 VMArea* area = info->range.area; 5113 AddressSpaceReadLocker addressSpaceLocker(area->address_space, false); 5114 // takes over our reference 5115 5116 // lock the top cache 5117 VMCache* cache = vm_area_get_locked_cache(area); 5118 VMCacheChainLocker cacheChainLocker(cache); 5119 5120 if (info->page->Cache() != cache) { 5121 // The page is not in the top cache, so we lock the whole cache chain 5122 // before touching the page's wired count. 5123 cacheChainLocker.LockAllSourceCaches(); 5124 } 5125 5126 decrement_page_wired_count(info->page); 5127 5128 // remove the wired range from the range 5129 area->Unwire(&info->range); 5130 5131 cacheChainLocker.Unlock(); 5132 } 5133 5134 5135 /*! Wires down the given address range in the specified team's address space. 5136 5137 If successful the function 5138 - acquires a reference to the specified team's address space, 5139 - adds respective wired ranges to all areas that intersect with the given 5140 address range, 5141 - makes sure all pages in the given address range are mapped with the 5142 requested access permissions and increments their wired count. 5143 5144 It fails, when \a team doesn't specify a valid address space, when any part 5145 of the specified address range is not covered by areas, when the concerned 5146 areas don't allow mapping with the requested permissions, or when mapping 5147 failed for another reason. 5148 5149 When successful the call must be balanced by a unlock_memory_etc() call with 5150 the exact same parameters. 5151 5152 \param team Identifies the address (via team ID). \c B_CURRENT_TEAM is 5153 supported. 5154 \param address The start of the address range to be wired. 5155 \param numBytes The size of the address range to be wired. 5156 \param flags Flags. Currently only \c B_READ_DEVICE is defined, which 5157 requests that the range must be wired writable ("read from device 5158 into memory"). 5159 \return \c B_OK on success, another error code otherwise. 5160 */ 5161 status_t 5162 lock_memory_etc(team_id team, void* address, size_t numBytes, uint32 flags) 5163 { 5164 addr_t lockBaseAddress = ROUNDDOWN((addr_t)address, B_PAGE_SIZE); 5165 addr_t lockEndAddress = ROUNDUP((addr_t)address + numBytes, B_PAGE_SIZE); 5166 5167 // compute the page protection that is required 5168 bool isUser = IS_USER_ADDRESS(address); 5169 bool writable = (flags & B_READ_DEVICE) == 0; 5170 uint32 requiredProtection = PAGE_PRESENT 5171 | B_KERNEL_READ_AREA | (isUser ? B_READ_AREA : 0); 5172 if (writable) 5173 requiredProtection |= B_KERNEL_WRITE_AREA | (isUser ? B_WRITE_AREA : 0); 5174 5175 uint32 mallocFlags = isUser 5176 ? 0 : HEAP_DONT_WAIT_FOR_MEMORY | HEAP_DONT_LOCK_KERNEL_SPACE; 5177 5178 // get and read lock the address space 5179 VMAddressSpace* addressSpace = NULL; 5180 if (isUser) { 5181 if (team == B_CURRENT_TEAM) 5182 addressSpace = VMAddressSpace::GetCurrent(); 5183 else 5184 addressSpace = VMAddressSpace::Get(team); 5185 } else 5186 addressSpace = VMAddressSpace::GetKernel(); 5187 if (addressSpace == NULL) 5188 return B_ERROR; 5189 5190 AddressSpaceReadLocker addressSpaceLocker(addressSpace, true); 5191 5192 VMTranslationMap* map = addressSpace->TranslationMap(); 5193 status_t error = B_OK; 5194 5195 // iterate through all concerned areas 5196 addr_t nextAddress = lockBaseAddress; 5197 while (nextAddress != lockEndAddress) { 5198 // get the next area 5199 VMArea* area = addressSpace->LookupArea(nextAddress); 5200 if (area == NULL) { 5201 error = B_BAD_ADDRESS; 5202 break; 5203 } 5204 5205 addr_t areaStart = nextAddress; 5206 addr_t areaEnd = std::min(lockEndAddress, area->Base() + area->Size()); 5207 5208 // allocate the wired range (do that before locking the cache to avoid 5209 // deadlocks) 5210 VMAreaWiredRange* range = new(malloc_flags(mallocFlags)) 5211 VMAreaWiredRange(areaStart, areaEnd - areaStart, writable, true); 5212 if (range == NULL) { 5213 error = B_NO_MEMORY; 5214 break; 5215 } 5216 5217 // Lock the area's top cache. This is a requirement for VMArea::Wire(). 5218 VMCacheChainLocker cacheChainLocker(vm_area_get_locked_cache(area)); 5219 5220 // mark the area range wired 5221 area->Wire(range); 5222 5223 // Depending on the area cache type and the wiring, we may not need to 5224 // look at the individual pages. 5225 if (area->cache_type == CACHE_TYPE_NULL 5226 || area->cache_type == CACHE_TYPE_DEVICE 5227 || area->wiring == B_FULL_LOCK 5228 || area->wiring == B_CONTIGUOUS) { 5229 nextAddress = areaEnd; 5230 continue; 5231 } 5232 5233 // Lock the area's cache chain and the translation map. Needed to look 5234 // up pages and play with their wired count. 5235 cacheChainLocker.LockAllSourceCaches(); 5236 map->Lock(); 5237 5238 // iterate through the pages and wire them 5239 for (; nextAddress != areaEnd; nextAddress += B_PAGE_SIZE) { 5240 phys_addr_t physicalAddress; 5241 uint32 flags; 5242 5243 vm_page* page; 5244 if (map->Query(nextAddress, &physicalAddress, &flags) == B_OK 5245 && (flags & requiredProtection) == requiredProtection 5246 && (page = vm_lookup_page(physicalAddress / B_PAGE_SIZE)) 5247 != NULL) { 5248 // Already mapped with the correct permissions -- just increment 5249 // the page's wired count. 5250 increment_page_wired_count(page); 5251 } else { 5252 // Let vm_soft_fault() map the page for us, if possible. We need 5253 // to fully unlock to avoid deadlocks. Since we have already 5254 // wired the area itself, nothing disturbing will happen with it 5255 // in the meantime. 5256 map->Unlock(); 5257 cacheChainLocker.Unlock(); 5258 addressSpaceLocker.Unlock(); 5259 5260 error = vm_soft_fault(addressSpace, nextAddress, writable, 5261 isUser, &page, range); 5262 5263 addressSpaceLocker.Lock(); 5264 cacheChainLocker.SetTo(vm_area_get_locked_cache(area)); 5265 cacheChainLocker.LockAllSourceCaches(); 5266 map->Lock(); 5267 } 5268 5269 if (error != B_OK) 5270 break; 5271 } 5272 5273 map->Unlock(); 5274 5275 if (error == B_OK) { 5276 cacheChainLocker.Unlock(); 5277 } else { 5278 // An error occurred, so abort right here. If the current address 5279 // is the first in this area, unwire the area, since we won't get 5280 // to it when reverting what we've done so far. 5281 if (nextAddress == areaStart) { 5282 area->Unwire(range); 5283 cacheChainLocker.Unlock(); 5284 range->~VMAreaWiredRange(); 5285 free_etc(range, mallocFlags); 5286 } else 5287 cacheChainLocker.Unlock(); 5288 5289 break; 5290 } 5291 } 5292 5293 if (error != B_OK) { 5294 // An error occurred, so unwire all that we've already wired. Note that 5295 // even if not a single page was wired, unlock_memory_etc() is called 5296 // to put the address space reference. 5297 addressSpaceLocker.Unlock(); 5298 unlock_memory_etc(team, (void*)address, nextAddress - lockBaseAddress, 5299 flags); 5300 } 5301 5302 return error; 5303 } 5304 5305 5306 status_t 5307 lock_memory(void* address, size_t numBytes, uint32 flags) 5308 { 5309 return lock_memory_etc(B_CURRENT_TEAM, address, numBytes, flags); 5310 } 5311 5312 5313 /*! Unwires an address range previously wired with lock_memory_etc(). 5314 5315 Note that a call to this function must balance a previous lock_memory_etc() 5316 call with exactly the same parameters. 5317 */ 5318 status_t 5319 unlock_memory_etc(team_id team, void* address, size_t numBytes, uint32 flags) 5320 { 5321 addr_t lockBaseAddress = ROUNDDOWN((addr_t)address, B_PAGE_SIZE); 5322 addr_t lockEndAddress = ROUNDUP((addr_t)address + numBytes, B_PAGE_SIZE); 5323 5324 // compute the page protection that is required 5325 bool isUser = IS_USER_ADDRESS(address); 5326 bool writable = (flags & B_READ_DEVICE) == 0; 5327 uint32 requiredProtection = PAGE_PRESENT 5328 | B_KERNEL_READ_AREA | (isUser ? B_READ_AREA : 0); 5329 if (writable) 5330 requiredProtection |= B_KERNEL_WRITE_AREA | (isUser ? B_WRITE_AREA : 0); 5331 5332 uint32 mallocFlags = isUser 5333 ? 0 : HEAP_DONT_WAIT_FOR_MEMORY | HEAP_DONT_LOCK_KERNEL_SPACE; 5334 5335 // get and read lock the address space 5336 VMAddressSpace* addressSpace = NULL; 5337 if (isUser) { 5338 if (team == B_CURRENT_TEAM) 5339 addressSpace = VMAddressSpace::GetCurrent(); 5340 else 5341 addressSpace = VMAddressSpace::Get(team); 5342 } else 5343 addressSpace = VMAddressSpace::GetKernel(); 5344 if (addressSpace == NULL) 5345 return B_ERROR; 5346 5347 AddressSpaceReadLocker addressSpaceLocker(addressSpace, true); 5348 5349 VMTranslationMap* map = addressSpace->TranslationMap(); 5350 status_t error = B_OK; 5351 5352 // iterate through all concerned areas 5353 addr_t nextAddress = lockBaseAddress; 5354 while (nextAddress != lockEndAddress) { 5355 // get the next area 5356 VMArea* area = addressSpace->LookupArea(nextAddress); 5357 if (area == NULL) { 5358 error = B_BAD_ADDRESS; 5359 break; 5360 } 5361 5362 addr_t areaStart = nextAddress; 5363 addr_t areaEnd = std::min(lockEndAddress, area->Base() + area->Size()); 5364 5365 // Lock the area's top cache. This is a requirement for 5366 // VMArea::Unwire(). 5367 VMCacheChainLocker cacheChainLocker(vm_area_get_locked_cache(area)); 5368 5369 // Depending on the area cache type and the wiring, we may not need to 5370 // look at the individual pages. 5371 if (area->cache_type == CACHE_TYPE_NULL 5372 || area->cache_type == CACHE_TYPE_DEVICE 5373 || area->wiring == B_FULL_LOCK 5374 || area->wiring == B_CONTIGUOUS) { 5375 // unwire the range (to avoid deadlocks we delete the range after 5376 // unlocking the cache) 5377 nextAddress = areaEnd; 5378 VMAreaWiredRange* range = area->Unwire(areaStart, 5379 areaEnd - areaStart, writable); 5380 cacheChainLocker.Unlock(); 5381 if (range != NULL) { 5382 range->~VMAreaWiredRange(); 5383 free_etc(range, mallocFlags); 5384 } 5385 continue; 5386 } 5387 5388 // Lock the area's cache chain and the translation map. Needed to look 5389 // up pages and play with their wired count. 5390 cacheChainLocker.LockAllSourceCaches(); 5391 map->Lock(); 5392 5393 // iterate through the pages and unwire them 5394 for (; nextAddress != areaEnd; nextAddress += B_PAGE_SIZE) { 5395 phys_addr_t physicalAddress; 5396 uint32 flags; 5397 5398 vm_page* page; 5399 if (map->Query(nextAddress, &physicalAddress, &flags) == B_OK 5400 && (flags & PAGE_PRESENT) != 0 5401 && (page = vm_lookup_page(physicalAddress / B_PAGE_SIZE)) 5402 != NULL) { 5403 // Already mapped with the correct permissions -- just increment 5404 // the page's wired count. 5405 decrement_page_wired_count(page); 5406 } else { 5407 panic("unlock_memory_etc(): Failed to unwire page: address " 5408 "space %p, address: %#" B_PRIxADDR, addressSpace, 5409 nextAddress); 5410 error = B_BAD_VALUE; 5411 break; 5412 } 5413 } 5414 5415 map->Unlock(); 5416 5417 // All pages are unwired. Remove the area's wired range as well (to 5418 // avoid deadlocks we delete the range after unlocking the cache). 5419 VMAreaWiredRange* range = area->Unwire(areaStart, 5420 areaEnd - areaStart, writable); 5421 5422 cacheChainLocker.Unlock(); 5423 5424 if (range != NULL) { 5425 range->~VMAreaWiredRange(); 5426 free_etc(range, mallocFlags); 5427 } 5428 5429 if (error != B_OK) 5430 break; 5431 } 5432 5433 // get rid of the address space reference 5434 addressSpace->Put(); 5435 5436 return error; 5437 } 5438 5439 5440 status_t 5441 unlock_memory(void* address, size_t numBytes, uint32 flags) 5442 { 5443 return unlock_memory_etc(B_CURRENT_TEAM, address, numBytes, flags); 5444 } 5445 5446 5447 /*! Similar to get_memory_map(), but also allows to specify the address space 5448 for the memory in question and has a saner semantics. 5449 Returns \c B_OK when the complete range could be translated or 5450 \c B_BUFFER_OVERFLOW, if the provided array wasn't big enough. In either 5451 case the actual number of entries is written to \c *_numEntries. Any other 5452 error case indicates complete failure; \c *_numEntries will be set to \c 0 5453 in this case. 5454 */ 5455 status_t 5456 get_memory_map_etc(team_id team, const void* address, size_t numBytes, 5457 physical_entry* table, uint32* _numEntries) 5458 { 5459 uint32 numEntries = *_numEntries; 5460 *_numEntries = 0; 5461 5462 VMAddressSpace* addressSpace; 5463 addr_t virtualAddress = (addr_t)address; 5464 addr_t pageOffset = virtualAddress & (B_PAGE_SIZE - 1); 5465 phys_addr_t physicalAddress; 5466 status_t status = B_OK; 5467 int32 index = -1; 5468 addr_t offset = 0; 5469 bool interrupts = are_interrupts_enabled(); 5470 5471 TRACE(("get_memory_map_etc(%ld, %p, %lu bytes, %ld entries)\n", team, 5472 address, numBytes, numEntries)); 5473 5474 if (numEntries == 0 || numBytes == 0) 5475 return B_BAD_VALUE; 5476 5477 // in which address space is the address to be found? 5478 if (IS_USER_ADDRESS(virtualAddress)) { 5479 if (team == B_CURRENT_TEAM) 5480 addressSpace = VMAddressSpace::GetCurrent(); 5481 else 5482 addressSpace = VMAddressSpace::Get(team); 5483 } else 5484 addressSpace = VMAddressSpace::GetKernel(); 5485 5486 if (addressSpace == NULL) 5487 return B_ERROR; 5488 5489 VMTranslationMap* map = addressSpace->TranslationMap(); 5490 5491 if (interrupts) 5492 map->Lock(); 5493 5494 while (offset < numBytes) { 5495 addr_t bytes = min_c(numBytes - offset, B_PAGE_SIZE); 5496 uint32 flags; 5497 5498 if (interrupts) { 5499 status = map->Query((addr_t)address + offset, &physicalAddress, 5500 &flags); 5501 } else { 5502 status = map->QueryInterrupt((addr_t)address + offset, 5503 &physicalAddress, &flags); 5504 } 5505 if (status < B_OK) 5506 break; 5507 if ((flags & PAGE_PRESENT) == 0) { 5508 panic("get_memory_map() called on unmapped memory!"); 5509 return B_BAD_ADDRESS; 5510 } 5511 5512 if (index < 0 && pageOffset > 0) { 5513 physicalAddress += pageOffset; 5514 if (bytes > B_PAGE_SIZE - pageOffset) 5515 bytes = B_PAGE_SIZE - pageOffset; 5516 } 5517 5518 // need to switch to the next physical_entry? 5519 if (index < 0 || table[index].address 5520 != physicalAddress - table[index].size) { 5521 if ((uint32)++index + 1 > numEntries) { 5522 // table to small 5523 break; 5524 } 5525 table[index].address = physicalAddress; 5526 table[index].size = bytes; 5527 } else { 5528 // page does fit in current entry 5529 table[index].size += bytes; 5530 } 5531 5532 offset += bytes; 5533 } 5534 5535 if (interrupts) 5536 map->Unlock(); 5537 5538 if (status != B_OK) 5539 return status; 5540 5541 if ((uint32)index + 1 > numEntries) { 5542 *_numEntries = index; 5543 return B_BUFFER_OVERFLOW; 5544 } 5545 5546 *_numEntries = index + 1; 5547 return B_OK; 5548 } 5549 5550 5551 /*! According to the BeBook, this function should always succeed. 5552 This is no longer the case. 5553 */ 5554 extern "C" int32 5555 __get_memory_map_haiku(const void* address, size_t numBytes, 5556 physical_entry* table, int32 numEntries) 5557 { 5558 uint32 entriesRead = numEntries; 5559 status_t error = get_memory_map_etc(B_CURRENT_TEAM, address, numBytes, 5560 table, &entriesRead); 5561 if (error != B_OK) 5562 return error; 5563 5564 // close the entry list 5565 5566 // if it's only one entry, we will silently accept the missing ending 5567 if (numEntries == 1) 5568 return B_OK; 5569 5570 if (entriesRead + 1 > (uint32)numEntries) 5571 return B_BUFFER_OVERFLOW; 5572 5573 table[entriesRead].address = 0; 5574 table[entriesRead].size = 0; 5575 5576 return B_OK; 5577 } 5578 5579 5580 area_id 5581 area_for(void* address) 5582 { 5583 return vm_area_for((addr_t)address, true); 5584 } 5585 5586 5587 area_id 5588 find_area(const char* name) 5589 { 5590 return VMAreaHash::Find(name); 5591 } 5592 5593 5594 status_t 5595 _get_area_info(area_id id, area_info* info, size_t size) 5596 { 5597 if (size != sizeof(area_info) || info == NULL) 5598 return B_BAD_VALUE; 5599 5600 AddressSpaceReadLocker locker; 5601 VMArea* area; 5602 status_t status = locker.SetFromArea(id, area); 5603 if (status != B_OK) 5604 return status; 5605 5606 fill_area_info(area, info, size); 5607 return B_OK; 5608 } 5609 5610 5611 status_t 5612 _get_next_area_info(team_id team, int32* cookie, area_info* info, size_t size) 5613 { 5614 addr_t nextBase = *(addr_t*)cookie; 5615 5616 // we're already through the list 5617 if (nextBase == (addr_t)-1) 5618 return B_ENTRY_NOT_FOUND; 5619 5620 if (team == B_CURRENT_TEAM) 5621 team = team_get_current_team_id(); 5622 5623 AddressSpaceReadLocker locker(team); 5624 if (!locker.IsLocked()) 5625 return B_BAD_TEAM_ID; 5626 5627 VMArea* area; 5628 for (VMAddressSpace::AreaIterator it 5629 = locker.AddressSpace()->GetAreaIterator(); 5630 (area = it.Next()) != NULL;) { 5631 if (area->Base() > nextBase) 5632 break; 5633 } 5634 5635 if (area == NULL) { 5636 nextBase = (addr_t)-1; 5637 return B_ENTRY_NOT_FOUND; 5638 } 5639 5640 fill_area_info(area, info, size); 5641 *cookie = (int32)(area->Base()); 5642 // TODO: Not 64 bit safe! 5643 5644 return B_OK; 5645 } 5646 5647 5648 status_t 5649 set_area_protection(area_id area, uint32 newProtection) 5650 { 5651 fix_protection(&newProtection); 5652 5653 return vm_set_area_protection(VMAddressSpace::KernelID(), area, 5654 newProtection, true); 5655 } 5656 5657 5658 status_t 5659 resize_area(area_id areaID, size_t newSize) 5660 { 5661 return vm_resize_area(areaID, newSize, true); 5662 } 5663 5664 5665 /*! Transfers the specified area to a new team. The caller must be the owner 5666 of the area. 5667 */ 5668 area_id 5669 transfer_area(area_id id, void** _address, uint32 addressSpec, team_id target, 5670 bool kernel) 5671 { 5672 area_info info; 5673 status_t status = get_area_info(id, &info); 5674 if (status != B_OK) 5675 return status; 5676 5677 if (info.team != thread_get_current_thread()->team->id) 5678 return B_PERMISSION_DENIED; 5679 5680 area_id clonedArea = vm_clone_area(target, info.name, _address, 5681 addressSpec, info.protection, REGION_NO_PRIVATE_MAP, id, kernel); 5682 if (clonedArea < 0) 5683 return clonedArea; 5684 5685 status = vm_delete_area(info.team, id, kernel); 5686 if (status != B_OK) { 5687 vm_delete_area(target, clonedArea, kernel); 5688 return status; 5689 } 5690 5691 // TODO: The clonedArea is B_SHARED_AREA, which is not really desired. 5692 5693 return clonedArea; 5694 } 5695 5696 5697 extern "C" area_id 5698 __map_physical_memory_haiku(const char* name, phys_addr_t physicalAddress, 5699 size_t numBytes, uint32 addressSpec, uint32 protection, 5700 void** _virtualAddress) 5701 { 5702 if (!arch_vm_supports_protection(protection)) 5703 return B_NOT_SUPPORTED; 5704 5705 fix_protection(&protection); 5706 5707 return vm_map_physical_memory(VMAddressSpace::KernelID(), name, 5708 _virtualAddress, addressSpec, numBytes, protection, physicalAddress, 5709 false); 5710 } 5711 5712 5713 area_id 5714 clone_area(const char* name, void** _address, uint32 addressSpec, 5715 uint32 protection, area_id source) 5716 { 5717 if ((protection & B_KERNEL_PROTECTION) == 0) 5718 protection |= B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA; 5719 5720 return vm_clone_area(VMAddressSpace::KernelID(), name, _address, 5721 addressSpec, protection, REGION_NO_PRIVATE_MAP, source, true); 5722 } 5723 5724 5725 area_id 5726 create_area_etc(team_id team, const char* name, uint32 size, uint32 lock, 5727 uint32 protection, uint32 flags, 5728 const virtual_address_restrictions* virtualAddressRestrictions, 5729 const physical_address_restrictions* physicalAddressRestrictions, 5730 void** _address) 5731 { 5732 fix_protection(&protection); 5733 5734 return vm_create_anonymous_area(team, name, size, lock, protection, flags, 5735 virtualAddressRestrictions, physicalAddressRestrictions, true, 5736 _address); 5737 } 5738 5739 5740 extern "C" area_id 5741 __create_area_haiku(const char* name, void** _address, uint32 addressSpec, 5742 size_t size, uint32 lock, uint32 protection) 5743 { 5744 fix_protection(&protection); 5745 5746 virtual_address_restrictions virtualRestrictions = {}; 5747 virtualRestrictions.address = *_address; 5748 virtualRestrictions.address_specification = addressSpec; 5749 physical_address_restrictions physicalRestrictions = {}; 5750 return vm_create_anonymous_area(VMAddressSpace::KernelID(), name, size, 5751 lock, protection, 0, &virtualRestrictions, &physicalRestrictions, true, 5752 _address); 5753 } 5754 5755 5756 status_t 5757 delete_area(area_id area) 5758 { 5759 return vm_delete_area(VMAddressSpace::KernelID(), area, true); 5760 } 5761 5762 5763 // #pragma mark - Userland syscalls 5764 5765 5766 status_t 5767 _user_reserve_address_range(addr_t* userAddress, uint32 addressSpec, 5768 addr_t size) 5769 { 5770 // filter out some unavailable values (for userland) 5771 switch (addressSpec) { 5772 case B_ANY_KERNEL_ADDRESS: 5773 case B_ANY_KERNEL_BLOCK_ADDRESS: 5774 return B_BAD_VALUE; 5775 } 5776 5777 addr_t address; 5778 5779 if (!IS_USER_ADDRESS(userAddress) 5780 || user_memcpy(&address, userAddress, sizeof(address)) != B_OK) 5781 return B_BAD_ADDRESS; 5782 5783 status_t status = vm_reserve_address_range( 5784 VMAddressSpace::CurrentID(), (void**)&address, addressSpec, size, 5785 RESERVED_AVOID_BASE); 5786 if (status != B_OK) 5787 return status; 5788 5789 if (user_memcpy(userAddress, &address, sizeof(address)) != B_OK) { 5790 vm_unreserve_address_range(VMAddressSpace::CurrentID(), 5791 (void*)address, size); 5792 return B_BAD_ADDRESS; 5793 } 5794 5795 return B_OK; 5796 } 5797 5798 5799 status_t 5800 _user_unreserve_address_range(addr_t address, addr_t size) 5801 { 5802 return vm_unreserve_address_range(VMAddressSpace::CurrentID(), 5803 (void*)address, size); 5804 } 5805 5806 5807 area_id 5808 _user_area_for(void* address) 5809 { 5810 return vm_area_for((addr_t)address, false); 5811 } 5812 5813 5814 area_id 5815 _user_find_area(const char* userName) 5816 { 5817 char name[B_OS_NAME_LENGTH]; 5818 5819 if (!IS_USER_ADDRESS(userName) 5820 || user_strlcpy(name, userName, B_OS_NAME_LENGTH) < B_OK) 5821 return B_BAD_ADDRESS; 5822 5823 return find_area(name); 5824 } 5825 5826 5827 status_t 5828 _user_get_area_info(area_id area, area_info* userInfo) 5829 { 5830 if (!IS_USER_ADDRESS(userInfo)) 5831 return B_BAD_ADDRESS; 5832 5833 area_info info; 5834 status_t status = get_area_info(area, &info); 5835 if (status < B_OK) 5836 return status; 5837 5838 // TODO: do we want to prevent userland from seeing kernel protections? 5839 //info.protection &= B_USER_PROTECTION; 5840 5841 if (user_memcpy(userInfo, &info, sizeof(area_info)) < B_OK) 5842 return B_BAD_ADDRESS; 5843 5844 return status; 5845 } 5846 5847 5848 status_t 5849 _user_get_next_area_info(team_id team, int32* userCookie, area_info* userInfo) 5850 { 5851 int32 cookie; 5852 5853 if (!IS_USER_ADDRESS(userCookie) 5854 || !IS_USER_ADDRESS(userInfo) 5855 || user_memcpy(&cookie, userCookie, sizeof(int32)) < B_OK) 5856 return B_BAD_ADDRESS; 5857 5858 area_info info; 5859 status_t status = _get_next_area_info(team, &cookie, &info, 5860 sizeof(area_info)); 5861 if (status != B_OK) 5862 return status; 5863 5864 //info.protection &= B_USER_PROTECTION; 5865 5866 if (user_memcpy(userCookie, &cookie, sizeof(int32)) < B_OK 5867 || user_memcpy(userInfo, &info, sizeof(area_info)) < B_OK) 5868 return B_BAD_ADDRESS; 5869 5870 return status; 5871 } 5872 5873 5874 status_t 5875 _user_set_area_protection(area_id area, uint32 newProtection) 5876 { 5877 if ((newProtection & ~B_USER_PROTECTION) != 0) 5878 return B_BAD_VALUE; 5879 5880 fix_protection(&newProtection); 5881 5882 return vm_set_area_protection(VMAddressSpace::CurrentID(), area, 5883 newProtection, false); 5884 } 5885 5886 5887 status_t 5888 _user_resize_area(area_id area, size_t newSize) 5889 { 5890 // TODO: Since we restrict deleting of areas to those owned by the team, 5891 // we should also do that for resizing (check other functions, too). 5892 return vm_resize_area(area, newSize, false); 5893 } 5894 5895 5896 area_id 5897 _user_transfer_area(area_id area, void** userAddress, uint32 addressSpec, 5898 team_id target) 5899 { 5900 // filter out some unavailable values (for userland) 5901 switch (addressSpec) { 5902 case B_ANY_KERNEL_ADDRESS: 5903 case B_ANY_KERNEL_BLOCK_ADDRESS: 5904 return B_BAD_VALUE; 5905 } 5906 5907 void* address; 5908 if (!IS_USER_ADDRESS(userAddress) 5909 || user_memcpy(&address, userAddress, sizeof(address)) < B_OK) 5910 return B_BAD_ADDRESS; 5911 5912 area_id newArea = transfer_area(area, &address, addressSpec, target, false); 5913 if (newArea < B_OK) 5914 return newArea; 5915 5916 if (user_memcpy(userAddress, &address, sizeof(address)) < B_OK) 5917 return B_BAD_ADDRESS; 5918 5919 return newArea; 5920 } 5921 5922 5923 area_id 5924 _user_clone_area(const char* userName, void** userAddress, uint32 addressSpec, 5925 uint32 protection, area_id sourceArea) 5926 { 5927 char name[B_OS_NAME_LENGTH]; 5928 void* address; 5929 5930 // filter out some unavailable values (for userland) 5931 switch (addressSpec) { 5932 case B_ANY_KERNEL_ADDRESS: 5933 case B_ANY_KERNEL_BLOCK_ADDRESS: 5934 return B_BAD_VALUE; 5935 } 5936 if ((protection & ~B_USER_AREA_FLAGS) != 0) 5937 return B_BAD_VALUE; 5938 5939 if (!IS_USER_ADDRESS(userName) 5940 || !IS_USER_ADDRESS(userAddress) 5941 || user_strlcpy(name, userName, sizeof(name)) < B_OK 5942 || user_memcpy(&address, userAddress, sizeof(address)) < B_OK) 5943 return B_BAD_ADDRESS; 5944 5945 fix_protection(&protection); 5946 5947 area_id clonedArea = vm_clone_area(VMAddressSpace::CurrentID(), name, 5948 &address, addressSpec, protection, REGION_NO_PRIVATE_MAP, sourceArea, 5949 false); 5950 if (clonedArea < B_OK) 5951 return clonedArea; 5952 5953 if (user_memcpy(userAddress, &address, sizeof(address)) < B_OK) { 5954 delete_area(clonedArea); 5955 return B_BAD_ADDRESS; 5956 } 5957 5958 return clonedArea; 5959 } 5960 5961 5962 area_id 5963 _user_create_area(const char* userName, void** userAddress, uint32 addressSpec, 5964 size_t size, uint32 lock, uint32 protection) 5965 { 5966 char name[B_OS_NAME_LENGTH]; 5967 void* address; 5968 5969 // filter out some unavailable values (for userland) 5970 switch (addressSpec) { 5971 case B_ANY_KERNEL_ADDRESS: 5972 case B_ANY_KERNEL_BLOCK_ADDRESS: 5973 return B_BAD_VALUE; 5974 } 5975 if ((protection & ~B_USER_AREA_FLAGS) != 0) 5976 return B_BAD_VALUE; 5977 5978 if (!IS_USER_ADDRESS(userName) 5979 || !IS_USER_ADDRESS(userAddress) 5980 || user_strlcpy(name, userName, sizeof(name)) < B_OK 5981 || user_memcpy(&address, userAddress, sizeof(address)) < B_OK) 5982 return B_BAD_ADDRESS; 5983 5984 if (addressSpec == B_EXACT_ADDRESS 5985 && IS_KERNEL_ADDRESS(address)) 5986 return B_BAD_VALUE; 5987 5988 fix_protection(&protection); 5989 5990 virtual_address_restrictions virtualRestrictions = {}; 5991 virtualRestrictions.address = address; 5992 virtualRestrictions.address_specification = addressSpec; 5993 physical_address_restrictions physicalRestrictions = {}; 5994 area_id area = vm_create_anonymous_area(VMAddressSpace::CurrentID(), name, 5995 size, lock, protection, 0, &virtualRestrictions, &physicalRestrictions, 5996 false, &address); 5997 5998 if (area >= B_OK 5999 && user_memcpy(userAddress, &address, sizeof(address)) < B_OK) { 6000 delete_area(area); 6001 return B_BAD_ADDRESS; 6002 } 6003 6004 return area; 6005 } 6006 6007 6008 status_t 6009 _user_delete_area(area_id area) 6010 { 6011 // Unlike the BeOS implementation, you can now only delete areas 6012 // that you have created yourself from userland. 6013 // The documentation to delete_area() explicitly states that this 6014 // will be restricted in the future, and so it will. 6015 return vm_delete_area(VMAddressSpace::CurrentID(), area, false); 6016 } 6017 6018 6019 // TODO: create a BeOS style call for this! 6020 6021 area_id 6022 _user_map_file(const char* userName, void** userAddress, uint32 addressSpec, 6023 size_t size, uint32 protection, uint32 mapping, bool unmapAddressRange, 6024 int fd, off_t offset) 6025 { 6026 char name[B_OS_NAME_LENGTH]; 6027 void* address; 6028 area_id area; 6029 6030 if ((protection & ~B_USER_AREA_FLAGS) != 0) 6031 return B_BAD_VALUE; 6032 6033 fix_protection(&protection); 6034 6035 if (!IS_USER_ADDRESS(userName) || !IS_USER_ADDRESS(userAddress) 6036 || user_strlcpy(name, userName, B_OS_NAME_LENGTH) < B_OK 6037 || user_memcpy(&address, userAddress, sizeof(address)) < B_OK) 6038 return B_BAD_ADDRESS; 6039 6040 if (addressSpec == B_EXACT_ADDRESS) { 6041 if ((addr_t)address + size < (addr_t)address 6042 || (addr_t)address % B_PAGE_SIZE != 0) { 6043 return B_BAD_VALUE; 6044 } 6045 if (!IS_USER_ADDRESS(address) 6046 || !IS_USER_ADDRESS((addr_t)address + size)) { 6047 return B_BAD_ADDRESS; 6048 } 6049 } 6050 6051 area = _vm_map_file(VMAddressSpace::CurrentID(), name, &address, 6052 addressSpec, size, protection, mapping, unmapAddressRange, fd, offset, 6053 false); 6054 if (area < B_OK) 6055 return area; 6056 6057 if (user_memcpy(userAddress, &address, sizeof(address)) < B_OK) 6058 return B_BAD_ADDRESS; 6059 6060 return area; 6061 } 6062 6063 6064 status_t 6065 _user_unmap_memory(void* _address, size_t size) 6066 { 6067 addr_t address = (addr_t)_address; 6068 6069 // check params 6070 if (size == 0 || (addr_t)address + size < (addr_t)address 6071 || (addr_t)address % B_PAGE_SIZE != 0) { 6072 return B_BAD_VALUE; 6073 } 6074 6075 if (!IS_USER_ADDRESS(address) || !IS_USER_ADDRESS((addr_t)address + size)) 6076 return B_BAD_ADDRESS; 6077 6078 // Write lock the address space and ensure the address range is not wired. 6079 AddressSpaceWriteLocker locker; 6080 do { 6081 status_t status = locker.SetTo(team_get_current_team_id()); 6082 if (status != B_OK) 6083 return status; 6084 } while (wait_if_address_range_is_wired(locker.AddressSpace(), address, 6085 size, &locker)); 6086 6087 // unmap 6088 return unmap_address_range(locker.AddressSpace(), address, size, false); 6089 } 6090 6091 6092 status_t 6093 _user_set_memory_protection(void* _address, size_t size, uint32 protection) 6094 { 6095 // check address range 6096 addr_t address = (addr_t)_address; 6097 size = PAGE_ALIGN(size); 6098 6099 if ((address % B_PAGE_SIZE) != 0) 6100 return B_BAD_VALUE; 6101 if ((addr_t)address + size < (addr_t)address || !IS_USER_ADDRESS(address) 6102 || !IS_USER_ADDRESS((addr_t)address + size)) { 6103 // weird error code required by POSIX 6104 return ENOMEM; 6105 } 6106 6107 // extend and check protection 6108 if ((protection & ~B_USER_PROTECTION) != 0) 6109 return B_BAD_VALUE; 6110 6111 fix_protection(&protection); 6112 6113 // We need to write lock the address space, since we're going to play with 6114 // the areas. Also make sure that none of the areas is wired and that we're 6115 // actually allowed to change the protection. 6116 AddressSpaceWriteLocker locker; 6117 6118 bool restart; 6119 do { 6120 restart = false; 6121 6122 status_t status = locker.SetTo(team_get_current_team_id()); 6123 if (status != B_OK) 6124 return status; 6125 6126 // First round: Check whether the whole range is covered by areas and we 6127 // are allowed to modify them. 6128 addr_t currentAddress = address; 6129 size_t sizeLeft = size; 6130 while (sizeLeft > 0) { 6131 VMArea* area = locker.AddressSpace()->LookupArea(currentAddress); 6132 if (area == NULL) 6133 return B_NO_MEMORY; 6134 6135 if ((area->protection & B_KERNEL_AREA) != 0) 6136 return B_NOT_ALLOWED; 6137 6138 AreaCacheLocker cacheLocker(area); 6139 6140 if (wait_if_area_is_wired(area, &locker, &cacheLocker)) { 6141 restart = true; 6142 break; 6143 } 6144 6145 cacheLocker.Unlock(); 6146 6147 // TODO: For (shared) mapped files we should check whether the new 6148 // protections are compatible with the file permissions. We don't 6149 // have a way to do that yet, though. 6150 6151 addr_t offset = currentAddress - area->Base(); 6152 size_t rangeSize = min_c(area->Size() - offset, sizeLeft); 6153 6154 currentAddress += rangeSize; 6155 sizeLeft -= rangeSize; 6156 } 6157 } while (restart); 6158 6159 // Second round: If the protections differ from that of the area, create a 6160 // page protection array and re-map mapped pages. 6161 VMTranslationMap* map = locker.AddressSpace()->TranslationMap(); 6162 addr_t currentAddress = address; 6163 size_t sizeLeft = size; 6164 while (sizeLeft > 0) { 6165 VMArea* area = locker.AddressSpace()->LookupArea(currentAddress); 6166 if (area == NULL) 6167 return B_NO_MEMORY; 6168 6169 addr_t offset = currentAddress - area->Base(); 6170 size_t rangeSize = min_c(area->Size() - offset, sizeLeft); 6171 6172 currentAddress += rangeSize; 6173 sizeLeft -= rangeSize; 6174 6175 if (area->page_protections == NULL) { 6176 if (area->protection == protection) 6177 continue; 6178 6179 // In the page protections we store only the three user protections, 6180 // so we use 4 bits per page. 6181 uint32 bytes = (area->Size() / B_PAGE_SIZE + 1) / 2; 6182 area->page_protections = (uint8*)malloc(bytes); 6183 if (area->page_protections == NULL) 6184 return B_NO_MEMORY; 6185 6186 // init the page protections for all pages to that of the area 6187 uint32 areaProtection = area->protection 6188 & (B_READ_AREA | B_WRITE_AREA | B_EXECUTE_AREA); 6189 memset(area->page_protections, 6190 areaProtection | (areaProtection << 4), bytes); 6191 } 6192 6193 // We need to lock the complete cache chain, since we potentially unmap 6194 // pages of lower caches. 6195 VMCache* topCache = vm_area_get_locked_cache(area); 6196 VMCacheChainLocker cacheChainLocker(topCache); 6197 cacheChainLocker.LockAllSourceCaches(); 6198 6199 for (addr_t pageAddress = area->Base() + offset; 6200 pageAddress < currentAddress; pageAddress += B_PAGE_SIZE) { 6201 map->Lock(); 6202 6203 set_area_page_protection(area, pageAddress, protection); 6204 6205 phys_addr_t physicalAddress; 6206 uint32 flags; 6207 6208 status_t error = map->Query(pageAddress, &physicalAddress, &flags); 6209 if (error != B_OK || (flags & PAGE_PRESENT) == 0) { 6210 map->Unlock(); 6211 continue; 6212 } 6213 6214 vm_page* page = vm_lookup_page(physicalAddress / B_PAGE_SIZE); 6215 if (page == NULL) { 6216 panic("area %p looking up page failed for pa %#" B_PRIxPHYSADDR 6217 "\n", area, physicalAddress); 6218 map->Unlock(); 6219 return B_ERROR; 6220 } 6221 6222 // If the page is not in the topmost cache and write access is 6223 // requested, we have to unmap it. Otherwise we can re-map it with 6224 // the new protection. 6225 bool unmapPage = page->Cache() != topCache 6226 && (protection & B_WRITE_AREA) != 0; 6227 6228 if (!unmapPage) 6229 map->ProtectPage(area, pageAddress, protection); 6230 6231 map->Unlock(); 6232 6233 if (unmapPage) { 6234 DEBUG_PAGE_ACCESS_START(page); 6235 unmap_page(area, pageAddress); 6236 DEBUG_PAGE_ACCESS_END(page); 6237 } 6238 } 6239 } 6240 6241 return B_OK; 6242 } 6243 6244 6245 status_t 6246 _user_sync_memory(void* _address, size_t size, uint32 flags) 6247 { 6248 addr_t address = (addr_t)_address; 6249 size = PAGE_ALIGN(size); 6250 6251 // check params 6252 if ((address % B_PAGE_SIZE) != 0) 6253 return B_BAD_VALUE; 6254 if ((addr_t)address + size < (addr_t)address || !IS_USER_ADDRESS(address) 6255 || !IS_USER_ADDRESS((addr_t)address + size)) { 6256 // weird error code required by POSIX 6257 return ENOMEM; 6258 } 6259 6260 bool writeSync = (flags & MS_SYNC) != 0; 6261 bool writeAsync = (flags & MS_ASYNC) != 0; 6262 if (writeSync && writeAsync) 6263 return B_BAD_VALUE; 6264 6265 if (size == 0 || (!writeSync && !writeAsync)) 6266 return B_OK; 6267 6268 // iterate through the range and sync all concerned areas 6269 while (size > 0) { 6270 // read lock the address space 6271 AddressSpaceReadLocker locker; 6272 status_t error = locker.SetTo(team_get_current_team_id()); 6273 if (error != B_OK) 6274 return error; 6275 6276 // get the first area 6277 VMArea* area = locker.AddressSpace()->LookupArea(address); 6278 if (area == NULL) 6279 return B_NO_MEMORY; 6280 6281 uint32 offset = address - area->Base(); 6282 size_t rangeSize = min_c(area->Size() - offset, size); 6283 offset += area->cache_offset; 6284 6285 // lock the cache 6286 AreaCacheLocker cacheLocker(area); 6287 if (!cacheLocker) 6288 return B_BAD_VALUE; 6289 VMCache* cache = area->cache; 6290 6291 locker.Unlock(); 6292 6293 uint32 firstPage = offset >> PAGE_SHIFT; 6294 uint32 endPage = firstPage + (rangeSize >> PAGE_SHIFT); 6295 6296 // write the pages 6297 if (cache->type == CACHE_TYPE_VNODE) { 6298 if (writeSync) { 6299 // synchronous 6300 error = vm_page_write_modified_page_range(cache, firstPage, 6301 endPage); 6302 if (error != B_OK) 6303 return error; 6304 } else { 6305 // asynchronous 6306 vm_page_schedule_write_page_range(cache, firstPage, endPage); 6307 // TODO: This is probably not quite what is supposed to happen. 6308 // Especially when a lot has to be written, it might take ages 6309 // until it really hits the disk. 6310 } 6311 } 6312 6313 address += rangeSize; 6314 size -= rangeSize; 6315 } 6316 6317 // NOTE: If I understand it correctly the purpose of MS_INVALIDATE is to 6318 // synchronize multiple mappings of the same file. In our VM they never get 6319 // out of sync, though, so we don't have to do anything. 6320 6321 return B_OK; 6322 } 6323 6324 6325 status_t 6326 _user_memory_advice(void* address, size_t size, uint32 advice) 6327 { 6328 // TODO: Implement! 6329 return B_OK; 6330 } 6331 6332 6333 status_t 6334 _user_get_memory_properties(team_id teamID, const void* address, 6335 uint32* _protected, uint32* _lock) 6336 { 6337 if (!IS_USER_ADDRESS(_protected) || !IS_USER_ADDRESS(_lock)) 6338 return B_BAD_ADDRESS; 6339 6340 AddressSpaceReadLocker locker; 6341 status_t error = locker.SetTo(teamID); 6342 if (error != B_OK) 6343 return error; 6344 6345 VMArea* area = locker.AddressSpace()->LookupArea((addr_t)address); 6346 if (area == NULL) 6347 return B_NO_MEMORY; 6348 6349 6350 uint32 protection = area->protection; 6351 if (area->page_protections != NULL) 6352 protection = get_area_page_protection(area, (addr_t)address); 6353 6354 uint32 wiring = area->wiring; 6355 6356 locker.Unlock(); 6357 6358 error = user_memcpy(_protected, &protection, sizeof(protection)); 6359 if (error != B_OK) 6360 return error; 6361 6362 error = user_memcpy(_lock, &wiring, sizeof(wiring)); 6363 6364 return error; 6365 } 6366 6367 6368 // #pragma mark -- compatibility 6369 6370 6371 #if defined(__INTEL__) && B_HAIKU_PHYSICAL_BITS > 32 6372 6373 6374 struct physical_entry_beos { 6375 uint32 address; 6376 uint32 size; 6377 }; 6378 6379 6380 /*! The physical_entry structure has changed. We need to translate it to the 6381 old one. 6382 */ 6383 extern "C" int32 6384 __get_memory_map_beos(const void* _address, size_t numBytes, 6385 physical_entry_beos* table, int32 numEntries) 6386 { 6387 if (numEntries <= 0) 6388 return B_BAD_VALUE; 6389 6390 const uint8* address = (const uint8*)_address; 6391 6392 int32 count = 0; 6393 while (numBytes > 0 && count < numEntries) { 6394 physical_entry entry; 6395 status_t result = __get_memory_map_haiku(address, numBytes, &entry, 1); 6396 if (result < 0) { 6397 if (result != B_BUFFER_OVERFLOW) 6398 return result; 6399 } 6400 6401 if (entry.address >= (phys_addr_t)1 << 32) { 6402 panic("get_memory_map(): Address is greater 4 GB!"); 6403 return B_ERROR; 6404 } 6405 6406 table[count].address = entry.address; 6407 table[count++].size = entry.size; 6408 6409 address += entry.size; 6410 numBytes -= entry.size; 6411 } 6412 6413 // null-terminate the table, if possible 6414 if (count < numEntries) { 6415 table[count].address = 0; 6416 table[count].size = 0; 6417 } 6418 6419 return B_OK; 6420 } 6421 6422 6423 /*! The type of the \a physicalAddress parameter has changed from void* to 6424 phys_addr_t. 6425 */ 6426 extern "C" area_id 6427 __map_physical_memory_beos(const char* name, void* physicalAddress, 6428 size_t numBytes, uint32 addressSpec, uint32 protection, 6429 void** _virtualAddress) 6430 { 6431 return __map_physical_memory_haiku(name, (addr_t)physicalAddress, numBytes, 6432 addressSpec, protection, _virtualAddress); 6433 } 6434 6435 6436 /*! The caller might not be able to deal with physical addresses >= 4 GB, so 6437 we meddle with the \a lock parameter to force 32 bit. 6438 */ 6439 extern "C" area_id 6440 __create_area_beos(const char* name, void** _address, uint32 addressSpec, 6441 size_t size, uint32 lock, uint32 protection) 6442 { 6443 switch (lock) { 6444 case B_NO_LOCK: 6445 break; 6446 case B_FULL_LOCK: 6447 case B_LAZY_LOCK: 6448 lock = B_32_BIT_FULL_LOCK; 6449 break; 6450 case B_CONTIGUOUS: 6451 lock = B_32_BIT_CONTIGUOUS; 6452 break; 6453 } 6454 6455 return __create_area_haiku(name, _address, addressSpec, size, lock, 6456 protection); 6457 } 6458 6459 6460 DEFINE_LIBROOT_KERNEL_SYMBOL_VERSION("__get_memory_map_beos", "get_memory_map@", 6461 "BASE"); 6462 DEFINE_LIBROOT_KERNEL_SYMBOL_VERSION("__map_physical_memory_beos", 6463 "map_physical_memory@", "BASE"); 6464 DEFINE_LIBROOT_KERNEL_SYMBOL_VERSION("__create_area_beos", "create_area@", 6465 "BASE"); 6466 6467 DEFINE_LIBROOT_KERNEL_SYMBOL_VERSION("__get_memory_map_haiku", 6468 "get_memory_map@@", "1_ALPHA3"); 6469 DEFINE_LIBROOT_KERNEL_SYMBOL_VERSION("__map_physical_memory_haiku", 6470 "map_physical_memory@@", "1_ALPHA3"); 6471 DEFINE_LIBROOT_KERNEL_SYMBOL_VERSION("__create_area_haiku", "create_area@@", 6472 "1_ALPHA3"); 6473 6474 6475 #else 6476 6477 6478 DEFINE_LIBROOT_KERNEL_SYMBOL_VERSION("__get_memory_map_haiku", 6479 "get_memory_map@@", "BASE"); 6480 DEFINE_LIBROOT_KERNEL_SYMBOL_VERSION("__map_physical_memory_haiku", 6481 "map_physical_memory@@", "BASE"); 6482 DEFINE_LIBROOT_KERNEL_SYMBOL_VERSION("__create_area_haiku", "create_area@@", 6483 "BASE"); 6484 6485 6486 #endif // defined(__INTEL__) && B_HAIKU_PHYSICAL_BITS > 32 6487