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, thread->team->id, 3934 isWrite ? "write" : "read", address, faultAddress, 3935 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 send_signal(thread->id, SIGSEGV); 4006 } else if (user_debug_exception_occurred(B_SEGMENT_VIOLATION, 4007 SIGSEGV)) { 4008 send_signal(thread->id, SIGSEGV); 4009 } 4010 } 4011 } 4012 } 4013 4014 if (addressSpace != NULL) 4015 addressSpace->Put(); 4016 4017 return B_HANDLED_INTERRUPT; 4018 } 4019 4020 4021 struct PageFaultContext { 4022 AddressSpaceReadLocker addressSpaceLocker; 4023 VMCacheChainLocker cacheChainLocker; 4024 4025 VMTranslationMap* map; 4026 VMCache* topCache; 4027 off_t cacheOffset; 4028 vm_page_reservation reservation; 4029 bool isWrite; 4030 4031 // return values 4032 vm_page* page; 4033 bool restart; 4034 4035 4036 PageFaultContext(VMAddressSpace* addressSpace, bool isWrite) 4037 : 4038 addressSpaceLocker(addressSpace, true), 4039 map(addressSpace->TranslationMap()), 4040 isWrite(isWrite) 4041 { 4042 } 4043 4044 ~PageFaultContext() 4045 { 4046 UnlockAll(); 4047 vm_page_unreserve_pages(&reservation); 4048 } 4049 4050 void Prepare(VMCache* topCache, off_t cacheOffset) 4051 { 4052 this->topCache = topCache; 4053 this->cacheOffset = cacheOffset; 4054 page = NULL; 4055 restart = false; 4056 4057 cacheChainLocker.SetTo(topCache); 4058 } 4059 4060 void UnlockAll(VMCache* exceptCache = NULL) 4061 { 4062 topCache = NULL; 4063 addressSpaceLocker.Unlock(); 4064 cacheChainLocker.Unlock(exceptCache); 4065 } 4066 }; 4067 4068 4069 /*! Gets the page that should be mapped into the area. 4070 Returns an error code other than \c B_OK, if the page couldn't be found or 4071 paged in. The locking state of the address space and the caches is undefined 4072 in that case. 4073 Returns \c B_OK with \c context.restart set to \c true, if the functions 4074 had to unlock the address space and all caches and is supposed to be called 4075 again. 4076 Returns \c B_OK with \c context.restart set to \c false, if the page was 4077 found. It is returned in \c context.page. The address space will still be 4078 locked as well as all caches starting from the top cache to at least the 4079 cache the page lives in. 4080 */ 4081 static status_t 4082 fault_get_page(PageFaultContext& context) 4083 { 4084 VMCache* cache = context.topCache; 4085 VMCache* lastCache = NULL; 4086 vm_page* page = NULL; 4087 4088 while (cache != NULL) { 4089 // We already hold the lock of the cache at this point. 4090 4091 lastCache = cache; 4092 4093 page = cache->LookupPage(context.cacheOffset); 4094 if (page != NULL && page->busy) { 4095 // page must be busy -- wait for it to become unbusy 4096 context.UnlockAll(cache); 4097 cache->ReleaseRefLocked(); 4098 cache->WaitForPageEvents(page, PAGE_EVENT_NOT_BUSY, false); 4099 4100 // restart the whole process 4101 context.restart = true; 4102 return B_OK; 4103 } 4104 4105 if (page != NULL) 4106 break; 4107 4108 // The current cache does not contain the page we're looking for. 4109 4110 // see if the backing store has it 4111 if (cache->HasPage(context.cacheOffset)) { 4112 // insert a fresh page and mark it busy -- we're going to read it in 4113 page = vm_page_allocate_page(&context.reservation, 4114 PAGE_STATE_ACTIVE | VM_PAGE_ALLOC_BUSY); 4115 cache->InsertPage(page, context.cacheOffset); 4116 4117 // We need to unlock all caches and the address space while reading 4118 // the page in. Keep a reference to the cache around. 4119 cache->AcquireRefLocked(); 4120 context.UnlockAll(); 4121 4122 // read the page in 4123 generic_io_vec vec; 4124 vec.base = (phys_addr_t)page->physical_page_number * B_PAGE_SIZE; 4125 generic_size_t bytesRead = vec.length = B_PAGE_SIZE; 4126 4127 status_t status = cache->Read(context.cacheOffset, &vec, 1, 4128 B_PHYSICAL_IO_REQUEST, &bytesRead); 4129 4130 cache->Lock(); 4131 4132 if (status < B_OK) { 4133 // on error remove and free the page 4134 dprintf("reading page from cache %p returned: %s!\n", 4135 cache, strerror(status)); 4136 4137 cache->NotifyPageEvents(page, PAGE_EVENT_NOT_BUSY); 4138 cache->RemovePage(page); 4139 vm_page_set_state(page, PAGE_STATE_FREE); 4140 4141 cache->ReleaseRefAndUnlock(); 4142 return status; 4143 } 4144 4145 // mark the page unbusy again 4146 cache->MarkPageUnbusy(page); 4147 4148 DEBUG_PAGE_ACCESS_END(page); 4149 4150 // Since we needed to unlock everything temporarily, the area 4151 // situation might have changed. So we need to restart the whole 4152 // process. 4153 cache->ReleaseRefAndUnlock(); 4154 context.restart = true; 4155 return B_OK; 4156 } 4157 4158 cache = context.cacheChainLocker.LockSourceCache(); 4159 } 4160 4161 if (page == NULL) { 4162 // There was no adequate page, determine the cache for a clean one. 4163 // Read-only pages come in the deepest cache, only the top most cache 4164 // may have direct write access. 4165 cache = context.isWrite ? context.topCache : lastCache; 4166 4167 // allocate a clean page 4168 page = vm_page_allocate_page(&context.reservation, 4169 PAGE_STATE_ACTIVE | VM_PAGE_ALLOC_CLEAR); 4170 FTRACE(("vm_soft_fault: just allocated page 0x%lx\n", 4171 page->physical_page_number)); 4172 4173 // insert the new page into our cache 4174 cache->InsertPage(page, context.cacheOffset); 4175 } else if (page->Cache() != context.topCache && context.isWrite) { 4176 // We have a page that has the data we want, but in the wrong cache 4177 // object so we need to copy it and stick it into the top cache. 4178 vm_page* sourcePage = page; 4179 4180 // TODO: If memory is low, it might be a good idea to steal the page 4181 // from our source cache -- if possible, that is. 4182 FTRACE(("get new page, copy it, and put it into the topmost cache\n")); 4183 page = vm_page_allocate_page(&context.reservation, PAGE_STATE_ACTIVE); 4184 4185 // To not needlessly kill concurrency we unlock all caches but the top 4186 // one while copying the page. Lacking another mechanism to ensure that 4187 // the source page doesn't disappear, we mark it busy. 4188 sourcePage->busy = true; 4189 context.cacheChainLocker.UnlockKeepRefs(true); 4190 4191 // copy the page 4192 vm_memcpy_physical_page(page->physical_page_number * B_PAGE_SIZE, 4193 sourcePage->physical_page_number * B_PAGE_SIZE); 4194 4195 context.cacheChainLocker.RelockCaches(true); 4196 sourcePage->Cache()->MarkPageUnbusy(sourcePage); 4197 4198 // insert the new page into our cache 4199 context.topCache->InsertPage(page, context.cacheOffset); 4200 } else 4201 DEBUG_PAGE_ACCESS_START(page); 4202 4203 context.page = page; 4204 return B_OK; 4205 } 4206 4207 4208 /*! Makes sure the address in the given address space is mapped. 4209 4210 \param addressSpace The address space. 4211 \param originalAddress The address. Doesn't need to be page aligned. 4212 \param isWrite If \c true the address shall be write-accessible. 4213 \param isUser If \c true the access is requested by a userland team. 4214 \param wirePage On success, if non \c NULL, the wired count of the page 4215 mapped at the given address is incremented and the page is returned 4216 via this parameter. 4217 \param wiredRange If given, this wiredRange is ignored when checking whether 4218 an already mapped page at the virtual address can be unmapped. 4219 \return \c B_OK on success, another error code otherwise. 4220 */ 4221 static status_t 4222 vm_soft_fault(VMAddressSpace* addressSpace, addr_t originalAddress, 4223 bool isWrite, bool isUser, vm_page** wirePage, VMAreaWiredRange* wiredRange) 4224 { 4225 FTRACE(("vm_soft_fault: thid 0x%lx address 0x%lx, isWrite %d, isUser %d\n", 4226 thread_get_current_thread_id(), originalAddress, isWrite, isUser)); 4227 4228 PageFaultContext context(addressSpace, isWrite); 4229 4230 addr_t address = ROUNDDOWN(originalAddress, B_PAGE_SIZE); 4231 status_t status = B_OK; 4232 4233 addressSpace->IncrementFaultCount(); 4234 4235 // We may need up to 2 pages plus pages needed for mapping them -- reserving 4236 // the pages upfront makes sure we don't have any cache locked, so that the 4237 // page daemon/thief can do their job without problems. 4238 size_t reservePages = 2 + context.map->MaxPagesNeededToMap(originalAddress, 4239 originalAddress); 4240 context.addressSpaceLocker.Unlock(); 4241 vm_page_reserve_pages(&context.reservation, reservePages, 4242 addressSpace == VMAddressSpace::Kernel() 4243 ? VM_PRIORITY_SYSTEM : VM_PRIORITY_USER); 4244 4245 while (true) { 4246 context.addressSpaceLocker.Lock(); 4247 4248 // get the area the fault was in 4249 VMArea* area = addressSpace->LookupArea(address); 4250 if (area == NULL) { 4251 dprintf("vm_soft_fault: va 0x%lx not covered by area in address " 4252 "space\n", originalAddress); 4253 TPF(PageFaultError(-1, 4254 VMPageFaultTracing::PAGE_FAULT_ERROR_NO_AREA)); 4255 status = B_BAD_ADDRESS; 4256 break; 4257 } 4258 4259 // check permissions 4260 uint32 protection = get_area_page_protection(area, address); 4261 if (isUser && (protection & B_USER_PROTECTION) == 0) { 4262 dprintf("user access on kernel area 0x%lx at %p\n", area->id, 4263 (void*)originalAddress); 4264 TPF(PageFaultError(area->id, 4265 VMPageFaultTracing::PAGE_FAULT_ERROR_KERNEL_ONLY)); 4266 status = B_PERMISSION_DENIED; 4267 break; 4268 } 4269 if (isWrite && (protection 4270 & (B_WRITE_AREA | (isUser ? 0 : B_KERNEL_WRITE_AREA))) == 0) { 4271 dprintf("write access attempted on write-protected area 0x%lx at" 4272 " %p\n", area->id, (void*)originalAddress); 4273 TPF(PageFaultError(area->id, 4274 VMPageFaultTracing::PAGE_FAULT_ERROR_WRITE_PROTECTED)); 4275 status = B_PERMISSION_DENIED; 4276 break; 4277 } else if (!isWrite && (protection 4278 & (B_READ_AREA | (isUser ? 0 : B_KERNEL_READ_AREA))) == 0) { 4279 dprintf("read access attempted on read-protected area 0x%lx at" 4280 " %p\n", area->id, (void*)originalAddress); 4281 TPF(PageFaultError(area->id, 4282 VMPageFaultTracing::PAGE_FAULT_ERROR_READ_PROTECTED)); 4283 status = B_PERMISSION_DENIED; 4284 break; 4285 } 4286 4287 // We have the area, it was a valid access, so let's try to resolve the 4288 // page fault now. 4289 // At first, the top most cache from the area is investigated. 4290 4291 context.Prepare(vm_area_get_locked_cache(area), 4292 address - area->Base() + area->cache_offset); 4293 4294 // See if this cache has a fault handler -- this will do all the work 4295 // for us. 4296 { 4297 // Note, since the page fault is resolved with interrupts enabled, 4298 // the fault handler could be called more than once for the same 4299 // reason -- the store must take this into account. 4300 status = context.topCache->Fault(addressSpace, context.cacheOffset); 4301 if (status != B_BAD_HANDLER) 4302 break; 4303 } 4304 4305 // The top most cache has no fault handler, so let's see if the cache or 4306 // its sources already have the page we're searching for (we're going 4307 // from top to bottom). 4308 status = fault_get_page(context); 4309 if (status != B_OK) { 4310 TPF(PageFaultError(area->id, status)); 4311 break; 4312 } 4313 4314 if (context.restart) 4315 continue; 4316 4317 // All went fine, all there is left to do is to map the page into the 4318 // address space. 4319 TPF(PageFaultDone(area->id, context.topCache, context.page->Cache(), 4320 context.page)); 4321 4322 // If the page doesn't reside in the area's cache, we need to make sure 4323 // it's mapped in read-only, so that we cannot overwrite someone else's 4324 // data (copy-on-write) 4325 uint32 newProtection = protection; 4326 if (context.page->Cache() != context.topCache && !isWrite) 4327 newProtection &= ~(B_WRITE_AREA | B_KERNEL_WRITE_AREA); 4328 4329 bool unmapPage = false; 4330 bool mapPage = true; 4331 4332 // check whether there's already a page mapped at the address 4333 context.map->Lock(); 4334 4335 phys_addr_t physicalAddress; 4336 uint32 flags; 4337 vm_page* mappedPage = NULL; 4338 if (context.map->Query(address, &physicalAddress, &flags) == B_OK 4339 && (flags & PAGE_PRESENT) != 0 4340 && (mappedPage = vm_lookup_page(physicalAddress / B_PAGE_SIZE)) 4341 != NULL) { 4342 // Yep there's already a page. If it's ours, we can simply adjust 4343 // its protection. Otherwise we have to unmap it. 4344 if (mappedPage == context.page) { 4345 context.map->ProtectPage(area, address, newProtection); 4346 // Note: We assume that ProtectPage() is atomic (i.e. 4347 // the page isn't temporarily unmapped), otherwise we'd have 4348 // to make sure it isn't wired. 4349 mapPage = false; 4350 } else 4351 unmapPage = true; 4352 } 4353 4354 context.map->Unlock(); 4355 4356 if (unmapPage) { 4357 // If the page is wired, we can't unmap it. Wait until it is unwired 4358 // again and restart. 4359 VMAreaUnwiredWaiter waiter; 4360 if (area->AddWaiterIfWired(&waiter, address, B_PAGE_SIZE, 4361 wiredRange)) { 4362 // unlock everything and wait 4363 context.UnlockAll(); 4364 waiter.waitEntry.Wait(); 4365 continue; 4366 } 4367 4368 // Note: The mapped page is a page of a lower cache. We are 4369 // guaranteed to have that cached locked, our new page is a copy of 4370 // that page, and the page is not busy. The logic for that guarantee 4371 // is as follows: Since the page is mapped, it must live in the top 4372 // cache (ruled out above) or any of its lower caches, and there is 4373 // (was before the new page was inserted) no other page in any 4374 // cache between the top cache and the page's cache (otherwise that 4375 // would be mapped instead). That in turn means that our algorithm 4376 // must have found it and therefore it cannot be busy either. 4377 DEBUG_PAGE_ACCESS_START(mappedPage); 4378 unmap_page(area, address); 4379 DEBUG_PAGE_ACCESS_END(mappedPage); 4380 } 4381 4382 if (mapPage) { 4383 if (map_page(area, context.page, address, newProtection, 4384 &context.reservation) != B_OK) { 4385 // Mapping can only fail, when the page mapping object couldn't 4386 // be allocated. Save for the missing mapping everything is 4387 // fine, though. If this was a regular page fault, we'll simply 4388 // leave and probably fault again. To make sure we'll have more 4389 // luck then, we ensure that the minimum object reserve is 4390 // available. 4391 DEBUG_PAGE_ACCESS_END(context.page); 4392 4393 context.UnlockAll(); 4394 4395 if (object_cache_reserve(gPageMappingsObjectCache, 1, 0) 4396 != B_OK) { 4397 // Apparently the situation is serious. Let's get ourselves 4398 // killed. 4399 status = B_NO_MEMORY; 4400 } else if (wirePage != NULL) { 4401 // The caller expects us to wire the page. Since 4402 // object_cache_reserve() succeeded, we should now be able 4403 // to allocate a mapping structure. Restart. 4404 continue; 4405 } 4406 4407 break; 4408 } 4409 } else if (context.page->State() == PAGE_STATE_INACTIVE) 4410 vm_page_set_state(context.page, PAGE_STATE_ACTIVE); 4411 4412 // also wire the page, if requested 4413 if (wirePage != NULL && status == B_OK) { 4414 increment_page_wired_count(context.page); 4415 *wirePage = context.page; 4416 } 4417 4418 DEBUG_PAGE_ACCESS_END(context.page); 4419 4420 break; 4421 } 4422 4423 return status; 4424 } 4425 4426 4427 status_t 4428 vm_get_physical_page(phys_addr_t paddr, addr_t* _vaddr, void** _handle) 4429 { 4430 return sPhysicalPageMapper->GetPage(paddr, _vaddr, _handle); 4431 } 4432 4433 status_t 4434 vm_put_physical_page(addr_t vaddr, void* handle) 4435 { 4436 return sPhysicalPageMapper->PutPage(vaddr, handle); 4437 } 4438 4439 4440 status_t 4441 vm_get_physical_page_current_cpu(phys_addr_t paddr, addr_t* _vaddr, 4442 void** _handle) 4443 { 4444 return sPhysicalPageMapper->GetPageCurrentCPU(paddr, _vaddr, _handle); 4445 } 4446 4447 status_t 4448 vm_put_physical_page_current_cpu(addr_t vaddr, void* handle) 4449 { 4450 return sPhysicalPageMapper->PutPageCurrentCPU(vaddr, handle); 4451 } 4452 4453 4454 status_t 4455 vm_get_physical_page_debug(phys_addr_t paddr, addr_t* _vaddr, void** _handle) 4456 { 4457 return sPhysicalPageMapper->GetPageDebug(paddr, _vaddr, _handle); 4458 } 4459 4460 status_t 4461 vm_put_physical_page_debug(addr_t vaddr, void* handle) 4462 { 4463 return sPhysicalPageMapper->PutPageDebug(vaddr, handle); 4464 } 4465 4466 4467 void 4468 vm_get_info(system_memory_info* info) 4469 { 4470 swap_get_info(info); 4471 4472 info->max_memory = vm_page_num_pages() * B_PAGE_SIZE; 4473 info->page_faults = sPageFaults; 4474 4475 MutexLocker locker(sAvailableMemoryLock); 4476 info->free_memory = sAvailableMemory; 4477 info->needed_memory = sNeededMemory; 4478 } 4479 4480 4481 uint32 4482 vm_num_page_faults(void) 4483 { 4484 return sPageFaults; 4485 } 4486 4487 4488 off_t 4489 vm_available_memory(void) 4490 { 4491 MutexLocker locker(sAvailableMemoryLock); 4492 return sAvailableMemory; 4493 } 4494 4495 4496 off_t 4497 vm_available_not_needed_memory(void) 4498 { 4499 MutexLocker locker(sAvailableMemoryLock); 4500 return sAvailableMemory - sNeededMemory; 4501 } 4502 4503 4504 /*! Like vm_available_not_needed_memory(), but only for use in the kernel 4505 debugger. 4506 */ 4507 off_t 4508 vm_available_not_needed_memory_debug(void) 4509 { 4510 return sAvailableMemory - sNeededMemory; 4511 } 4512 4513 4514 size_t 4515 vm_kernel_address_space_left(void) 4516 { 4517 return VMAddressSpace::Kernel()->FreeSpace(); 4518 } 4519 4520 4521 void 4522 vm_unreserve_memory(size_t amount) 4523 { 4524 mutex_lock(&sAvailableMemoryLock); 4525 4526 sAvailableMemory += amount; 4527 4528 mutex_unlock(&sAvailableMemoryLock); 4529 } 4530 4531 4532 status_t 4533 vm_try_reserve_memory(size_t amount, int priority, bigtime_t timeout) 4534 { 4535 size_t reserve = kMemoryReserveForPriority[priority]; 4536 4537 MutexLocker locker(sAvailableMemoryLock); 4538 4539 //dprintf("try to reserve %lu bytes, %Lu left\n", amount, sAvailableMemory); 4540 4541 if (sAvailableMemory >= amount + reserve) { 4542 sAvailableMemory -= amount; 4543 return B_OK; 4544 } 4545 4546 if (timeout <= 0) 4547 return B_NO_MEMORY; 4548 4549 // turn timeout into an absolute timeout 4550 timeout += system_time(); 4551 4552 // loop until we've got the memory or the timeout occurs 4553 do { 4554 sNeededMemory += amount; 4555 4556 // call the low resource manager 4557 locker.Unlock(); 4558 low_resource(B_KERNEL_RESOURCE_MEMORY, sNeededMemory - sAvailableMemory, 4559 B_ABSOLUTE_TIMEOUT, timeout); 4560 locker.Lock(); 4561 4562 sNeededMemory -= amount; 4563 4564 if (sAvailableMemory >= amount + reserve) { 4565 sAvailableMemory -= amount; 4566 return B_OK; 4567 } 4568 } while (timeout > system_time()); 4569 4570 return B_NO_MEMORY; 4571 } 4572 4573 4574 status_t 4575 vm_set_area_memory_type(area_id id, phys_addr_t physicalBase, uint32 type) 4576 { 4577 // NOTE: The caller is responsible for synchronizing calls to this function! 4578 4579 AddressSpaceReadLocker locker; 4580 VMArea* area; 4581 status_t status = locker.SetFromArea(id, area); 4582 if (status != B_OK) 4583 return status; 4584 4585 // nothing to do, if the type doesn't change 4586 uint32 oldType = area->MemoryType(); 4587 if (type == oldType) 4588 return B_OK; 4589 4590 // set the memory type of the area and the mapped pages 4591 VMTranslationMap* map = area->address_space->TranslationMap(); 4592 map->Lock(); 4593 area->SetMemoryType(type); 4594 map->ProtectArea(area, area->protection); 4595 map->Unlock(); 4596 4597 // set the physical memory type 4598 status_t error = arch_vm_set_memory_type(area, physicalBase, type); 4599 if (error != B_OK) { 4600 // reset the memory type of the area and the mapped pages 4601 map->Lock(); 4602 area->SetMemoryType(oldType); 4603 map->ProtectArea(area, area->protection); 4604 map->Unlock(); 4605 return error; 4606 } 4607 4608 return B_OK; 4609 4610 } 4611 4612 4613 /*! This function enforces some protection properties: 4614 - if B_WRITE_AREA is set, B_WRITE_KERNEL_AREA is set as well 4615 - if only B_READ_AREA has been set, B_KERNEL_READ_AREA is also set 4616 - if no protection is specified, it defaults to B_KERNEL_READ_AREA 4617 and B_KERNEL_WRITE_AREA. 4618 */ 4619 static void 4620 fix_protection(uint32* protection) 4621 { 4622 if ((*protection & B_KERNEL_PROTECTION) == 0) { 4623 if ((*protection & B_USER_PROTECTION) == 0 4624 || (*protection & B_WRITE_AREA) != 0) 4625 *protection |= B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA; 4626 else 4627 *protection |= B_KERNEL_READ_AREA; 4628 } 4629 } 4630 4631 4632 static void 4633 fill_area_info(struct VMArea* area, area_info* info, size_t size) 4634 { 4635 strlcpy(info->name, area->name, B_OS_NAME_LENGTH); 4636 info->area = area->id; 4637 info->address = (void*)area->Base(); 4638 info->size = area->Size(); 4639 info->protection = area->protection; 4640 info->lock = B_FULL_LOCK; 4641 info->team = area->address_space->ID(); 4642 info->copy_count = 0; 4643 info->in_count = 0; 4644 info->out_count = 0; 4645 // TODO: retrieve real values here! 4646 4647 VMCache* cache = vm_area_get_locked_cache(area); 4648 4649 // Note, this is a simplification; the cache could be larger than this area 4650 info->ram_size = cache->page_count * B_PAGE_SIZE; 4651 4652 vm_area_put_locked_cache(cache); 4653 } 4654 4655 4656 static status_t 4657 vm_resize_area(area_id areaID, size_t newSize, bool kernel) 4658 { 4659 // is newSize a multiple of B_PAGE_SIZE? 4660 if (newSize & (B_PAGE_SIZE - 1)) 4661 return B_BAD_VALUE; 4662 4663 // lock all affected address spaces and the cache 4664 VMArea* area; 4665 VMCache* cache; 4666 4667 MultiAddressSpaceLocker locker; 4668 AreaCacheLocker cacheLocker; 4669 4670 status_t status; 4671 size_t oldSize; 4672 bool anyKernelArea; 4673 bool restart; 4674 4675 do { 4676 anyKernelArea = false; 4677 restart = false; 4678 4679 locker.Unset(); 4680 status = locker.AddAreaCacheAndLock(areaID, true, true, area, &cache); 4681 if (status != B_OK) 4682 return status; 4683 cacheLocker.SetTo(cache, true); // already locked 4684 4685 // enforce restrictions 4686 if (!kernel) { 4687 if ((area->protection & B_KERNEL_AREA) != 0) 4688 return B_NOT_ALLOWED; 4689 // TODO: Enforce all restrictions (team, etc.)! 4690 } 4691 4692 oldSize = area->Size(); 4693 if (newSize == oldSize) 4694 return B_OK; 4695 4696 if (cache->type != CACHE_TYPE_RAM) 4697 return B_NOT_ALLOWED; 4698 4699 if (oldSize < newSize) { 4700 // We need to check if all areas of this cache can be resized. 4701 for (VMArea* current = cache->areas; current != NULL; 4702 current = current->cache_next) { 4703 if (!current->address_space->CanResizeArea(current, newSize)) 4704 return B_ERROR; 4705 anyKernelArea 4706 |= current->address_space == VMAddressSpace::Kernel(); 4707 } 4708 } else { 4709 // We're shrinking the areas, so we must make sure the affected 4710 // ranges are not wired. 4711 for (VMArea* current = cache->areas; current != NULL; 4712 current = current->cache_next) { 4713 anyKernelArea 4714 |= current->address_space == VMAddressSpace::Kernel(); 4715 4716 if (wait_if_area_range_is_wired(current, 4717 current->Base() + newSize, oldSize - newSize, &locker, 4718 &cacheLocker)) { 4719 restart = true; 4720 break; 4721 } 4722 } 4723 } 4724 } while (restart); 4725 4726 // Okay, looks good so far, so let's do it 4727 4728 int priority = kernel && anyKernelArea 4729 ? VM_PRIORITY_SYSTEM : VM_PRIORITY_USER; 4730 uint32 allocationFlags = kernel && anyKernelArea 4731 ? HEAP_DONT_WAIT_FOR_MEMORY | HEAP_DONT_LOCK_KERNEL_SPACE : 0; 4732 4733 if (oldSize < newSize) { 4734 // Growing the cache can fail, so we do it first. 4735 status = cache->Resize(cache->virtual_base + newSize, priority); 4736 if (status != B_OK) 4737 return status; 4738 } 4739 4740 for (VMArea* current = cache->areas; current != NULL; 4741 current = current->cache_next) { 4742 status = current->address_space->ResizeArea(current, newSize, 4743 allocationFlags); 4744 if (status != B_OK) 4745 break; 4746 4747 // We also need to unmap all pages beyond the new size, if the area has 4748 // shrunk 4749 if (newSize < oldSize) { 4750 VMCacheChainLocker cacheChainLocker(cache); 4751 cacheChainLocker.LockAllSourceCaches(); 4752 4753 unmap_pages(current, current->Base() + newSize, 4754 oldSize - newSize); 4755 4756 cacheChainLocker.Unlock(cache); 4757 } 4758 } 4759 4760 // shrinking the cache can't fail, so we do it now 4761 if (status == B_OK && newSize < oldSize) 4762 status = cache->Resize(cache->virtual_base + newSize, priority); 4763 4764 if (status != B_OK) { 4765 // Something failed -- resize the areas back to their original size. 4766 // This can fail, too, in which case we're seriously screwed. 4767 for (VMArea* current = cache->areas; current != NULL; 4768 current = current->cache_next) { 4769 if (current->address_space->ResizeArea(current, oldSize, 4770 allocationFlags) != B_OK) { 4771 panic("vm_resize_area(): Failed and not being able to restore " 4772 "original state."); 4773 } 4774 } 4775 4776 cache->Resize(cache->virtual_base + oldSize, priority); 4777 } 4778 4779 // TODO: we must honour the lock restrictions of this area 4780 return status; 4781 } 4782 4783 4784 status_t 4785 vm_memset_physical(phys_addr_t address, int value, size_t length) 4786 { 4787 return sPhysicalPageMapper->MemsetPhysical(address, value, length); 4788 } 4789 4790 4791 status_t 4792 vm_memcpy_from_physical(void* to, phys_addr_t from, size_t length, bool user) 4793 { 4794 return sPhysicalPageMapper->MemcpyFromPhysical(to, from, length, user); 4795 } 4796 4797 4798 status_t 4799 vm_memcpy_to_physical(phys_addr_t to, const void* _from, size_t length, 4800 bool user) 4801 { 4802 return sPhysicalPageMapper->MemcpyToPhysical(to, _from, length, user); 4803 } 4804 4805 4806 void 4807 vm_memcpy_physical_page(phys_addr_t to, phys_addr_t from) 4808 { 4809 return sPhysicalPageMapper->MemcpyPhysicalPage(to, from); 4810 } 4811 4812 4813 /*! Copies a range of memory directly from/to a page that might not be mapped 4814 at the moment. 4815 4816 For \a unsafeMemory the current mapping (if any is ignored). The function 4817 walks through the respective area's cache chain to find the physical page 4818 and copies from/to it directly. 4819 The memory range starting at \a unsafeMemory with a length of \a size bytes 4820 must not cross a page boundary. 4821 4822 \param teamID The team ID identifying the address space \a unsafeMemory is 4823 to be interpreted in. Ignored, if \a unsafeMemory is a kernel address 4824 (the kernel address space is assumed in this case). If \c B_CURRENT_TEAM 4825 is passed, the address space of the thread returned by 4826 debug_get_debugged_thread() is used. 4827 \param unsafeMemory The start of the unsafe memory range to be copied 4828 from/to. 4829 \param buffer A safely accessible kernel buffer to be copied from/to. 4830 \param size The number of bytes to be copied. 4831 \param copyToUnsafe If \c true, memory is copied from \a buffer to 4832 \a unsafeMemory, the other way around otherwise. 4833 */ 4834 status_t 4835 vm_debug_copy_page_memory(team_id teamID, void* unsafeMemory, void* buffer, 4836 size_t size, bool copyToUnsafe) 4837 { 4838 if (size > B_PAGE_SIZE 4839 || ((addr_t)unsafeMemory + size) % B_PAGE_SIZE < size) { 4840 return B_BAD_VALUE; 4841 } 4842 4843 // get the address space for the debugged thread 4844 VMAddressSpace* addressSpace; 4845 if (IS_KERNEL_ADDRESS(unsafeMemory)) { 4846 addressSpace = VMAddressSpace::Kernel(); 4847 } else if (teamID == B_CURRENT_TEAM) { 4848 Thread* thread = debug_get_debugged_thread(); 4849 if (thread == NULL || thread->team == NULL) 4850 return B_BAD_ADDRESS; 4851 4852 addressSpace = thread->team->address_space; 4853 } else 4854 addressSpace = VMAddressSpace::DebugGet(teamID); 4855 4856 if (addressSpace == NULL) 4857 return B_BAD_ADDRESS; 4858 4859 // get the area 4860 VMArea* area = addressSpace->LookupArea((addr_t)unsafeMemory); 4861 if (area == NULL) 4862 return B_BAD_ADDRESS; 4863 4864 // search the page 4865 off_t cacheOffset = (addr_t)unsafeMemory - area->Base() 4866 + area->cache_offset; 4867 VMCache* cache = area->cache; 4868 vm_page* page = NULL; 4869 while (cache != NULL) { 4870 page = cache->DebugLookupPage(cacheOffset); 4871 if (page != NULL) 4872 break; 4873 4874 // Page not found in this cache -- if it is paged out, we must not try 4875 // to get it from lower caches. 4876 if (cache->DebugHasPage(cacheOffset)) 4877 break; 4878 4879 cache = cache->source; 4880 } 4881 4882 if (page == NULL) 4883 return B_UNSUPPORTED; 4884 4885 // copy from/to physical memory 4886 phys_addr_t physicalAddress = page->physical_page_number * B_PAGE_SIZE 4887 + (addr_t)unsafeMemory % B_PAGE_SIZE; 4888 4889 if (copyToUnsafe) { 4890 if (page->Cache() != area->cache) 4891 return B_UNSUPPORTED; 4892 4893 return vm_memcpy_to_physical(physicalAddress, buffer, size, false); 4894 } 4895 4896 return vm_memcpy_from_physical(buffer, physicalAddress, size, false); 4897 } 4898 4899 4900 // #pragma mark - kernel public API 4901 4902 4903 status_t 4904 user_memcpy(void* to, const void* from, size_t size) 4905 { 4906 // don't allow address overflows 4907 if ((addr_t)from + size < (addr_t)from || (addr_t)to + size < (addr_t)to) 4908 return B_BAD_ADDRESS; 4909 4910 if (arch_cpu_user_memcpy(to, from, size, 4911 &thread_get_current_thread()->fault_handler) < B_OK) 4912 return B_BAD_ADDRESS; 4913 4914 return B_OK; 4915 } 4916 4917 4918 /*! \brief Copies at most (\a size - 1) characters from the string in \a from to 4919 the string in \a to, NULL-terminating the result. 4920 4921 \param to Pointer to the destination C-string. 4922 \param from Pointer to the source C-string. 4923 \param size Size in bytes of the string buffer pointed to by \a to. 4924 4925 \return strlen(\a from). 4926 */ 4927 ssize_t 4928 user_strlcpy(char* to, const char* from, size_t size) 4929 { 4930 if (to == NULL && size != 0) 4931 return B_BAD_VALUE; 4932 if (from == NULL) 4933 return B_BAD_ADDRESS; 4934 4935 // limit size to avoid address overflows 4936 size_t maxSize = std::min(size, 4937 ~(addr_t)0 - std::max((addr_t)from, (addr_t)to) + 1); 4938 // NOTE: Since arch_cpu_user_strlcpy() determines the length of \a from, 4939 // the source address might still overflow. 4940 4941 ssize_t result = arch_cpu_user_strlcpy(to, from, maxSize, 4942 &thread_get_current_thread()->fault_handler); 4943 4944 // If we hit the address overflow boundary, fail. 4945 if (result >= 0 && (size_t)result >= maxSize && maxSize < size) 4946 return B_BAD_ADDRESS; 4947 4948 return result; 4949 } 4950 4951 4952 status_t 4953 user_memset(void* s, char c, size_t count) 4954 { 4955 // don't allow address overflows 4956 if ((addr_t)s + count < (addr_t)s) 4957 return B_BAD_ADDRESS; 4958 4959 if (arch_cpu_user_memset(s, c, count, 4960 &thread_get_current_thread()->fault_handler) < B_OK) 4961 return B_BAD_ADDRESS; 4962 4963 return B_OK; 4964 } 4965 4966 4967 /*! Wires a single page at the given address. 4968 4969 \param team The team whose address space the address belongs to. Supports 4970 also \c B_CURRENT_TEAM. If the given address is a kernel address, the 4971 parameter is ignored. 4972 \param address address The virtual address to wire down. Does not need to 4973 be page aligned. 4974 \param writable If \c true the page shall be writable. 4975 \param info On success the info is filled in, among other things 4976 containing the physical address the given virtual one translates to. 4977 \return \c B_OK, when the page could be wired, another error code otherwise. 4978 */ 4979 status_t 4980 vm_wire_page(team_id team, addr_t address, bool writable, 4981 VMPageWiringInfo* info) 4982 { 4983 addr_t pageAddress = ROUNDDOWN((addr_t)address, B_PAGE_SIZE); 4984 info->range.SetTo(pageAddress, B_PAGE_SIZE, writable, false); 4985 4986 // compute the page protection that is required 4987 bool isUser = IS_USER_ADDRESS(address); 4988 uint32 requiredProtection = PAGE_PRESENT 4989 | B_KERNEL_READ_AREA | (isUser ? B_READ_AREA : 0); 4990 if (writable) 4991 requiredProtection |= B_KERNEL_WRITE_AREA | (isUser ? B_WRITE_AREA : 0); 4992 4993 // get and read lock the address space 4994 VMAddressSpace* addressSpace = NULL; 4995 if (isUser) { 4996 if (team == B_CURRENT_TEAM) 4997 addressSpace = VMAddressSpace::GetCurrent(); 4998 else 4999 addressSpace = VMAddressSpace::Get(team); 5000 } else 5001 addressSpace = VMAddressSpace::GetKernel(); 5002 if (addressSpace == NULL) 5003 return B_ERROR; 5004 5005 AddressSpaceReadLocker addressSpaceLocker(addressSpace, true); 5006 5007 VMTranslationMap* map = addressSpace->TranslationMap(); 5008 status_t error = B_OK; 5009 5010 // get the area 5011 VMArea* area = addressSpace->LookupArea(pageAddress); 5012 if (area == NULL) { 5013 addressSpace->Put(); 5014 return B_BAD_ADDRESS; 5015 } 5016 5017 // Lock the area's top cache. This is a requirement for VMArea::Wire(). 5018 VMCacheChainLocker cacheChainLocker(vm_area_get_locked_cache(area)); 5019 5020 // mark the area range wired 5021 area->Wire(&info->range); 5022 5023 // Lock the area's cache chain and the translation map. Needed to look 5024 // up the page and play with its wired count. 5025 cacheChainLocker.LockAllSourceCaches(); 5026 map->Lock(); 5027 5028 phys_addr_t physicalAddress; 5029 uint32 flags; 5030 vm_page* page; 5031 if (map->Query(pageAddress, &physicalAddress, &flags) == B_OK 5032 && (flags & requiredProtection) == requiredProtection 5033 && (page = vm_lookup_page(physicalAddress / B_PAGE_SIZE)) 5034 != NULL) { 5035 // Already mapped with the correct permissions -- just increment 5036 // the page's wired count. 5037 increment_page_wired_count(page); 5038 5039 map->Unlock(); 5040 cacheChainLocker.Unlock(); 5041 addressSpaceLocker.Unlock(); 5042 } else { 5043 // Let vm_soft_fault() map the page for us, if possible. We need 5044 // to fully unlock to avoid deadlocks. Since we have already 5045 // wired the area itself, nothing disturbing will happen with it 5046 // in the meantime. 5047 map->Unlock(); 5048 cacheChainLocker.Unlock(); 5049 addressSpaceLocker.Unlock(); 5050 5051 error = vm_soft_fault(addressSpace, pageAddress, writable, isUser, 5052 &page, &info->range); 5053 5054 if (error != B_OK) { 5055 // The page could not be mapped -- clean up. 5056 VMCache* cache = vm_area_get_locked_cache(area); 5057 area->Unwire(&info->range); 5058 cache->ReleaseRefAndUnlock(); 5059 addressSpace->Put(); 5060 return error; 5061 } 5062 } 5063 5064 info->physicalAddress 5065 = (phys_addr_t)page->physical_page_number * B_PAGE_SIZE 5066 + address % B_PAGE_SIZE; 5067 info->page = page; 5068 5069 return B_OK; 5070 } 5071 5072 5073 /*! Unwires a single page previously wired via vm_wire_page(). 5074 5075 \param info The same object passed to vm_wire_page() before. 5076 */ 5077 void 5078 vm_unwire_page(VMPageWiringInfo* info) 5079 { 5080 // lock the address space 5081 VMArea* area = info->range.area; 5082 AddressSpaceReadLocker addressSpaceLocker(area->address_space, false); 5083 // takes over our reference 5084 5085 // lock the top cache 5086 VMCache* cache = vm_area_get_locked_cache(area); 5087 VMCacheChainLocker cacheChainLocker(cache); 5088 5089 if (info->page->Cache() != cache) { 5090 // The page is not in the top cache, so we lock the whole cache chain 5091 // before touching the page's wired count. 5092 cacheChainLocker.LockAllSourceCaches(); 5093 } 5094 5095 decrement_page_wired_count(info->page); 5096 5097 // remove the wired range from the range 5098 area->Unwire(&info->range); 5099 5100 cacheChainLocker.Unlock(); 5101 } 5102 5103 5104 /*! Wires down the given address range in the specified team's address space. 5105 5106 If successful the function 5107 - acquires a reference to the specified team's address space, 5108 - adds respective wired ranges to all areas that intersect with the given 5109 address range, 5110 - makes sure all pages in the given address range are mapped with the 5111 requested access permissions and increments their wired count. 5112 5113 It fails, when \a team doesn't specify a valid address space, when any part 5114 of the specified address range is not covered by areas, when the concerned 5115 areas don't allow mapping with the requested permissions, or when mapping 5116 failed for another reason. 5117 5118 When successful the call must be balanced by a unlock_memory_etc() call with 5119 the exact same parameters. 5120 5121 \param team Identifies the address (via team ID). \c B_CURRENT_TEAM is 5122 supported. 5123 \param address The start of the address range to be wired. 5124 \param numBytes The size of the address range to be wired. 5125 \param flags Flags. Currently only \c B_READ_DEVICE is defined, which 5126 requests that the range must be wired writable ("read from device 5127 into memory"). 5128 \return \c B_OK on success, another error code otherwise. 5129 */ 5130 status_t 5131 lock_memory_etc(team_id team, void* address, size_t numBytes, uint32 flags) 5132 { 5133 addr_t lockBaseAddress = ROUNDDOWN((addr_t)address, B_PAGE_SIZE); 5134 addr_t lockEndAddress = ROUNDUP((addr_t)address + numBytes, B_PAGE_SIZE); 5135 5136 // compute the page protection that is required 5137 bool isUser = IS_USER_ADDRESS(address); 5138 bool writable = (flags & B_READ_DEVICE) == 0; 5139 uint32 requiredProtection = PAGE_PRESENT 5140 | B_KERNEL_READ_AREA | (isUser ? B_READ_AREA : 0); 5141 if (writable) 5142 requiredProtection |= B_KERNEL_WRITE_AREA | (isUser ? B_WRITE_AREA : 0); 5143 5144 uint32 mallocFlags = isUser 5145 ? 0 : HEAP_DONT_WAIT_FOR_MEMORY | HEAP_DONT_LOCK_KERNEL_SPACE; 5146 5147 // get and read lock the address space 5148 VMAddressSpace* addressSpace = NULL; 5149 if (isUser) { 5150 if (team == B_CURRENT_TEAM) 5151 addressSpace = VMAddressSpace::GetCurrent(); 5152 else 5153 addressSpace = VMAddressSpace::Get(team); 5154 } else 5155 addressSpace = VMAddressSpace::GetKernel(); 5156 if (addressSpace == NULL) 5157 return B_ERROR; 5158 5159 AddressSpaceReadLocker addressSpaceLocker(addressSpace, true); 5160 5161 VMTranslationMap* map = addressSpace->TranslationMap(); 5162 status_t error = B_OK; 5163 5164 // iterate through all concerned areas 5165 addr_t nextAddress = lockBaseAddress; 5166 while (nextAddress != lockEndAddress) { 5167 // get the next area 5168 VMArea* area = addressSpace->LookupArea(nextAddress); 5169 if (area == NULL) { 5170 error = B_BAD_ADDRESS; 5171 break; 5172 } 5173 5174 addr_t areaStart = nextAddress; 5175 addr_t areaEnd = std::min(lockEndAddress, area->Base() + area->Size()); 5176 5177 // allocate the wired range (do that before locking the cache to avoid 5178 // deadlocks) 5179 VMAreaWiredRange* range = new(malloc_flags(mallocFlags)) 5180 VMAreaWiredRange(areaStart, areaEnd - areaStart, writable, true); 5181 if (range == NULL) { 5182 error = B_NO_MEMORY; 5183 break; 5184 } 5185 5186 // Lock the area's top cache. This is a requirement for VMArea::Wire(). 5187 VMCacheChainLocker cacheChainLocker(vm_area_get_locked_cache(area)); 5188 5189 // mark the area range wired 5190 area->Wire(range); 5191 5192 // Depending on the area cache type and the wiring, we may not need to 5193 // look at the individual pages. 5194 if (area->cache_type == CACHE_TYPE_NULL 5195 || area->cache_type == CACHE_TYPE_DEVICE 5196 || area->wiring == B_FULL_LOCK 5197 || area->wiring == B_CONTIGUOUS) { 5198 nextAddress = areaEnd; 5199 continue; 5200 } 5201 5202 // Lock the area's cache chain and the translation map. Needed to look 5203 // up pages and play with their wired count. 5204 cacheChainLocker.LockAllSourceCaches(); 5205 map->Lock(); 5206 5207 // iterate through the pages and wire them 5208 for (; nextAddress != areaEnd; nextAddress += B_PAGE_SIZE) { 5209 phys_addr_t physicalAddress; 5210 uint32 flags; 5211 5212 vm_page* page; 5213 if (map->Query(nextAddress, &physicalAddress, &flags) == B_OK 5214 && (flags & requiredProtection) == requiredProtection 5215 && (page = vm_lookup_page(physicalAddress / B_PAGE_SIZE)) 5216 != NULL) { 5217 // Already mapped with the correct permissions -- just increment 5218 // the page's wired count. 5219 increment_page_wired_count(page); 5220 } else { 5221 // Let vm_soft_fault() map the page for us, if possible. We need 5222 // to fully unlock to avoid deadlocks. Since we have already 5223 // wired the area itself, nothing disturbing will happen with it 5224 // in the meantime. 5225 map->Unlock(); 5226 cacheChainLocker.Unlock(); 5227 addressSpaceLocker.Unlock(); 5228 5229 error = vm_soft_fault(addressSpace, nextAddress, writable, 5230 isUser, &page, range); 5231 5232 addressSpaceLocker.Lock(); 5233 cacheChainLocker.SetTo(vm_area_get_locked_cache(area)); 5234 cacheChainLocker.LockAllSourceCaches(); 5235 map->Lock(); 5236 } 5237 5238 if (error != B_OK) 5239 break; 5240 } 5241 5242 map->Unlock(); 5243 5244 if (error == B_OK) { 5245 cacheChainLocker.Unlock(); 5246 } else { 5247 // An error occurred, so abort right here. If the current address 5248 // is the first in this area, unwire the area, since we won't get 5249 // to it when reverting what we've done so far. 5250 if (nextAddress == areaStart) { 5251 area->Unwire(range); 5252 cacheChainLocker.Unlock(); 5253 range->~VMAreaWiredRange(); 5254 free_etc(range, mallocFlags); 5255 } else 5256 cacheChainLocker.Unlock(); 5257 5258 break; 5259 } 5260 } 5261 5262 if (error != B_OK) { 5263 // An error occurred, so unwire all that we've already wired. Note that 5264 // even if not a single page was wired, unlock_memory_etc() is called 5265 // to put the address space reference. 5266 addressSpaceLocker.Unlock(); 5267 unlock_memory_etc(team, (void*)address, nextAddress - lockBaseAddress, 5268 flags); 5269 } 5270 5271 return error; 5272 } 5273 5274 5275 status_t 5276 lock_memory(void* address, size_t numBytes, uint32 flags) 5277 { 5278 return lock_memory_etc(B_CURRENT_TEAM, address, numBytes, flags); 5279 } 5280 5281 5282 /*! Unwires an address range previously wired with lock_memory_etc(). 5283 5284 Note that a call to this function must balance a previous lock_memory_etc() 5285 call with exactly the same parameters. 5286 */ 5287 status_t 5288 unlock_memory_etc(team_id team, void* address, size_t numBytes, uint32 flags) 5289 { 5290 addr_t lockBaseAddress = ROUNDDOWN((addr_t)address, B_PAGE_SIZE); 5291 addr_t lockEndAddress = ROUNDUP((addr_t)address + numBytes, B_PAGE_SIZE); 5292 5293 // compute the page protection that is required 5294 bool isUser = IS_USER_ADDRESS(address); 5295 bool writable = (flags & B_READ_DEVICE) == 0; 5296 uint32 requiredProtection = PAGE_PRESENT 5297 | B_KERNEL_READ_AREA | (isUser ? B_READ_AREA : 0); 5298 if (writable) 5299 requiredProtection |= B_KERNEL_WRITE_AREA | (isUser ? B_WRITE_AREA : 0); 5300 5301 uint32 mallocFlags = isUser 5302 ? 0 : HEAP_DONT_WAIT_FOR_MEMORY | HEAP_DONT_LOCK_KERNEL_SPACE; 5303 5304 // get and read lock the address space 5305 VMAddressSpace* addressSpace = NULL; 5306 if (isUser) { 5307 if (team == B_CURRENT_TEAM) 5308 addressSpace = VMAddressSpace::GetCurrent(); 5309 else 5310 addressSpace = VMAddressSpace::Get(team); 5311 } else 5312 addressSpace = VMAddressSpace::GetKernel(); 5313 if (addressSpace == NULL) 5314 return B_ERROR; 5315 5316 AddressSpaceReadLocker addressSpaceLocker(addressSpace, true); 5317 5318 VMTranslationMap* map = addressSpace->TranslationMap(); 5319 status_t error = B_OK; 5320 5321 // iterate through all concerned areas 5322 addr_t nextAddress = lockBaseAddress; 5323 while (nextAddress != lockEndAddress) { 5324 // get the next area 5325 VMArea* area = addressSpace->LookupArea(nextAddress); 5326 if (area == NULL) { 5327 error = B_BAD_ADDRESS; 5328 break; 5329 } 5330 5331 addr_t areaStart = nextAddress; 5332 addr_t areaEnd = std::min(lockEndAddress, area->Base() + area->Size()); 5333 5334 // Lock the area's top cache. This is a requirement for 5335 // VMArea::Unwire(). 5336 VMCacheChainLocker cacheChainLocker(vm_area_get_locked_cache(area)); 5337 5338 // Depending on the area cache type and the wiring, we may not need to 5339 // look at the individual pages. 5340 if (area->cache_type == CACHE_TYPE_NULL 5341 || area->cache_type == CACHE_TYPE_DEVICE 5342 || area->wiring == B_FULL_LOCK 5343 || area->wiring == B_CONTIGUOUS) { 5344 // unwire the range (to avoid deadlocks we delete the range after 5345 // unlocking the cache) 5346 nextAddress = areaEnd; 5347 VMAreaWiredRange* range = area->Unwire(areaStart, 5348 areaEnd - areaStart, writable); 5349 cacheChainLocker.Unlock(); 5350 if (range != NULL) { 5351 range->~VMAreaWiredRange(); 5352 free_etc(range, mallocFlags); 5353 } 5354 continue; 5355 } 5356 5357 // Lock the area's cache chain and the translation map. Needed to look 5358 // up pages and play with their wired count. 5359 cacheChainLocker.LockAllSourceCaches(); 5360 map->Lock(); 5361 5362 // iterate through the pages and unwire them 5363 for (; nextAddress != areaEnd; nextAddress += B_PAGE_SIZE) { 5364 phys_addr_t physicalAddress; 5365 uint32 flags; 5366 5367 vm_page* page; 5368 if (map->Query(nextAddress, &physicalAddress, &flags) == B_OK 5369 && (flags & PAGE_PRESENT) != 0 5370 && (page = vm_lookup_page(physicalAddress / B_PAGE_SIZE)) 5371 != NULL) { 5372 // Already mapped with the correct permissions -- just increment 5373 // the page's wired count. 5374 decrement_page_wired_count(page); 5375 } else { 5376 panic("unlock_memory_etc(): Failed to unwire page: address " 5377 "space %p, address: %#" B_PRIxADDR, addressSpace, 5378 nextAddress); 5379 error = B_BAD_VALUE; 5380 break; 5381 } 5382 } 5383 5384 map->Unlock(); 5385 5386 // All pages are unwired. Remove the area's wired range as well (to 5387 // avoid deadlocks we delete the range after unlocking the cache). 5388 VMAreaWiredRange* range = area->Unwire(areaStart, 5389 areaEnd - areaStart, writable); 5390 5391 cacheChainLocker.Unlock(); 5392 5393 if (range != NULL) { 5394 range->~VMAreaWiredRange(); 5395 free_etc(range, mallocFlags); 5396 } 5397 5398 if (error != B_OK) 5399 break; 5400 } 5401 5402 // get rid of the address space reference 5403 addressSpace->Put(); 5404 5405 return error; 5406 } 5407 5408 5409 status_t 5410 unlock_memory(void* address, size_t numBytes, uint32 flags) 5411 { 5412 return unlock_memory_etc(B_CURRENT_TEAM, address, numBytes, flags); 5413 } 5414 5415 5416 /*! Similar to get_memory_map(), but also allows to specify the address space 5417 for the memory in question and has a saner semantics. 5418 Returns \c B_OK when the complete range could be translated or 5419 \c B_BUFFER_OVERFLOW, if the provided array wasn't big enough. In either 5420 case the actual number of entries is written to \c *_numEntries. Any other 5421 error case indicates complete failure; \c *_numEntries will be set to \c 0 5422 in this case. 5423 */ 5424 status_t 5425 get_memory_map_etc(team_id team, const void* address, size_t numBytes, 5426 physical_entry* table, uint32* _numEntries) 5427 { 5428 uint32 numEntries = *_numEntries; 5429 *_numEntries = 0; 5430 5431 VMAddressSpace* addressSpace; 5432 addr_t virtualAddress = (addr_t)address; 5433 addr_t pageOffset = virtualAddress & (B_PAGE_SIZE - 1); 5434 phys_addr_t physicalAddress; 5435 status_t status = B_OK; 5436 int32 index = -1; 5437 addr_t offset = 0; 5438 bool interrupts = are_interrupts_enabled(); 5439 5440 TRACE(("get_memory_map_etc(%ld, %p, %lu bytes, %ld entries)\n", team, 5441 address, numBytes, numEntries)); 5442 5443 if (numEntries == 0 || numBytes == 0) 5444 return B_BAD_VALUE; 5445 5446 // in which address space is the address to be found? 5447 if (IS_USER_ADDRESS(virtualAddress)) { 5448 if (team == B_CURRENT_TEAM) 5449 addressSpace = VMAddressSpace::GetCurrent(); 5450 else 5451 addressSpace = VMAddressSpace::Get(team); 5452 } else 5453 addressSpace = VMAddressSpace::GetKernel(); 5454 5455 if (addressSpace == NULL) 5456 return B_ERROR; 5457 5458 VMTranslationMap* map = addressSpace->TranslationMap(); 5459 5460 if (interrupts) 5461 map->Lock(); 5462 5463 while (offset < numBytes) { 5464 addr_t bytes = min_c(numBytes - offset, B_PAGE_SIZE); 5465 uint32 flags; 5466 5467 if (interrupts) { 5468 status = map->Query((addr_t)address + offset, &physicalAddress, 5469 &flags); 5470 } else { 5471 status = map->QueryInterrupt((addr_t)address + offset, 5472 &physicalAddress, &flags); 5473 } 5474 if (status < B_OK) 5475 break; 5476 if ((flags & PAGE_PRESENT) == 0) { 5477 panic("get_memory_map() called on unmapped memory!"); 5478 return B_BAD_ADDRESS; 5479 } 5480 5481 if (index < 0 && pageOffset > 0) { 5482 physicalAddress += pageOffset; 5483 if (bytes > B_PAGE_SIZE - pageOffset) 5484 bytes = B_PAGE_SIZE - pageOffset; 5485 } 5486 5487 // need to switch to the next physical_entry? 5488 if (index < 0 || table[index].address 5489 != physicalAddress - table[index].size) { 5490 if ((uint32)++index + 1 > numEntries) { 5491 // table to small 5492 break; 5493 } 5494 table[index].address = physicalAddress; 5495 table[index].size = bytes; 5496 } else { 5497 // page does fit in current entry 5498 table[index].size += bytes; 5499 } 5500 5501 offset += bytes; 5502 } 5503 5504 if (interrupts) 5505 map->Unlock(); 5506 5507 if (status != B_OK) 5508 return status; 5509 5510 if ((uint32)index + 1 > numEntries) { 5511 *_numEntries = index; 5512 return B_BUFFER_OVERFLOW; 5513 } 5514 5515 *_numEntries = index + 1; 5516 return B_OK; 5517 } 5518 5519 5520 /*! According to the BeBook, this function should always succeed. 5521 This is no longer the case. 5522 */ 5523 extern "C" int32 5524 __get_memory_map_haiku(const void* address, size_t numBytes, 5525 physical_entry* table, int32 numEntries) 5526 { 5527 uint32 entriesRead = numEntries; 5528 status_t error = get_memory_map_etc(B_CURRENT_TEAM, address, numBytes, 5529 table, &entriesRead); 5530 if (error != B_OK) 5531 return error; 5532 5533 // close the entry list 5534 5535 // if it's only one entry, we will silently accept the missing ending 5536 if (numEntries == 1) 5537 return B_OK; 5538 5539 if (entriesRead + 1 > (uint32)numEntries) 5540 return B_BUFFER_OVERFLOW; 5541 5542 table[entriesRead].address = 0; 5543 table[entriesRead].size = 0; 5544 5545 return B_OK; 5546 } 5547 5548 5549 area_id 5550 area_for(void* address) 5551 { 5552 return vm_area_for((addr_t)address, true); 5553 } 5554 5555 5556 area_id 5557 find_area(const char* name) 5558 { 5559 return VMAreaHash::Find(name); 5560 } 5561 5562 5563 status_t 5564 _get_area_info(area_id id, area_info* info, size_t size) 5565 { 5566 if (size != sizeof(area_info) || info == NULL) 5567 return B_BAD_VALUE; 5568 5569 AddressSpaceReadLocker locker; 5570 VMArea* area; 5571 status_t status = locker.SetFromArea(id, area); 5572 if (status != B_OK) 5573 return status; 5574 5575 fill_area_info(area, info, size); 5576 return B_OK; 5577 } 5578 5579 5580 status_t 5581 _get_next_area_info(team_id team, int32* cookie, area_info* info, size_t size) 5582 { 5583 addr_t nextBase = *(addr_t*)cookie; 5584 5585 // we're already through the list 5586 if (nextBase == (addr_t)-1) 5587 return B_ENTRY_NOT_FOUND; 5588 5589 if (team == B_CURRENT_TEAM) 5590 team = team_get_current_team_id(); 5591 5592 AddressSpaceReadLocker locker(team); 5593 if (!locker.IsLocked()) 5594 return B_BAD_TEAM_ID; 5595 5596 VMArea* area; 5597 for (VMAddressSpace::AreaIterator it 5598 = locker.AddressSpace()->GetAreaIterator(); 5599 (area = it.Next()) != NULL;) { 5600 if (area->Base() > nextBase) 5601 break; 5602 } 5603 5604 if (area == NULL) { 5605 nextBase = (addr_t)-1; 5606 return B_ENTRY_NOT_FOUND; 5607 } 5608 5609 fill_area_info(area, info, size); 5610 *cookie = (int32)(area->Base()); 5611 // TODO: Not 64 bit safe! 5612 5613 return B_OK; 5614 } 5615 5616 5617 status_t 5618 set_area_protection(area_id area, uint32 newProtection) 5619 { 5620 fix_protection(&newProtection); 5621 5622 return vm_set_area_protection(VMAddressSpace::KernelID(), area, 5623 newProtection, true); 5624 } 5625 5626 5627 status_t 5628 resize_area(area_id areaID, size_t newSize) 5629 { 5630 return vm_resize_area(areaID, newSize, true); 5631 } 5632 5633 5634 /*! Transfers the specified area to a new team. The caller must be the owner 5635 of the area. 5636 */ 5637 area_id 5638 transfer_area(area_id id, void** _address, uint32 addressSpec, team_id target, 5639 bool kernel) 5640 { 5641 area_info info; 5642 status_t status = get_area_info(id, &info); 5643 if (status != B_OK) 5644 return status; 5645 5646 if (info.team != thread_get_current_thread()->team->id) 5647 return B_PERMISSION_DENIED; 5648 5649 area_id clonedArea = vm_clone_area(target, info.name, _address, 5650 addressSpec, info.protection, REGION_NO_PRIVATE_MAP, id, kernel); 5651 if (clonedArea < 0) 5652 return clonedArea; 5653 5654 status = vm_delete_area(info.team, id, kernel); 5655 if (status != B_OK) { 5656 vm_delete_area(target, clonedArea, kernel); 5657 return status; 5658 } 5659 5660 // TODO: The clonedArea is B_SHARED_AREA, which is not really desired. 5661 5662 return clonedArea; 5663 } 5664 5665 5666 extern "C" area_id 5667 __map_physical_memory_haiku(const char* name, phys_addr_t physicalAddress, 5668 size_t numBytes, uint32 addressSpec, uint32 protection, 5669 void** _virtualAddress) 5670 { 5671 if (!arch_vm_supports_protection(protection)) 5672 return B_NOT_SUPPORTED; 5673 5674 fix_protection(&protection); 5675 5676 return vm_map_physical_memory(VMAddressSpace::KernelID(), name, 5677 _virtualAddress, addressSpec, numBytes, protection, physicalAddress, 5678 false); 5679 } 5680 5681 5682 area_id 5683 clone_area(const char* name, void** _address, uint32 addressSpec, 5684 uint32 protection, area_id source) 5685 { 5686 if ((protection & B_KERNEL_PROTECTION) == 0) 5687 protection |= B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA; 5688 5689 return vm_clone_area(VMAddressSpace::KernelID(), name, _address, 5690 addressSpec, protection, REGION_NO_PRIVATE_MAP, source, true); 5691 } 5692 5693 5694 area_id 5695 create_area_etc(team_id team, const char* name, uint32 size, uint32 lock, 5696 uint32 protection, uint32 flags, 5697 const virtual_address_restrictions* virtualAddressRestrictions, 5698 const physical_address_restrictions* physicalAddressRestrictions, 5699 void** _address) 5700 { 5701 fix_protection(&protection); 5702 5703 return vm_create_anonymous_area(team, name, size, lock, protection, flags, 5704 virtualAddressRestrictions, physicalAddressRestrictions, true, 5705 _address); 5706 } 5707 5708 5709 extern "C" area_id 5710 __create_area_haiku(const char* name, void** _address, uint32 addressSpec, 5711 size_t size, uint32 lock, uint32 protection) 5712 { 5713 fix_protection(&protection); 5714 5715 virtual_address_restrictions virtualRestrictions = {}; 5716 virtualRestrictions.address = *_address; 5717 virtualRestrictions.address_specification = addressSpec; 5718 physical_address_restrictions physicalRestrictions = {}; 5719 return vm_create_anonymous_area(VMAddressSpace::KernelID(), name, size, 5720 lock, protection, 0, &virtualRestrictions, &physicalRestrictions, true, 5721 _address); 5722 } 5723 5724 5725 status_t 5726 delete_area(area_id area) 5727 { 5728 return vm_delete_area(VMAddressSpace::KernelID(), area, true); 5729 } 5730 5731 5732 // #pragma mark - Userland syscalls 5733 5734 5735 status_t 5736 _user_reserve_address_range(addr_t* userAddress, uint32 addressSpec, 5737 addr_t size) 5738 { 5739 // filter out some unavailable values (for userland) 5740 switch (addressSpec) { 5741 case B_ANY_KERNEL_ADDRESS: 5742 case B_ANY_KERNEL_BLOCK_ADDRESS: 5743 return B_BAD_VALUE; 5744 } 5745 5746 addr_t address; 5747 5748 if (!IS_USER_ADDRESS(userAddress) 5749 || user_memcpy(&address, userAddress, sizeof(address)) != B_OK) 5750 return B_BAD_ADDRESS; 5751 5752 status_t status = vm_reserve_address_range( 5753 VMAddressSpace::CurrentID(), (void**)&address, addressSpec, size, 5754 RESERVED_AVOID_BASE); 5755 if (status != B_OK) 5756 return status; 5757 5758 if (user_memcpy(userAddress, &address, sizeof(address)) != B_OK) { 5759 vm_unreserve_address_range(VMAddressSpace::CurrentID(), 5760 (void*)address, size); 5761 return B_BAD_ADDRESS; 5762 } 5763 5764 return B_OK; 5765 } 5766 5767 5768 status_t 5769 _user_unreserve_address_range(addr_t address, addr_t size) 5770 { 5771 return vm_unreserve_address_range(VMAddressSpace::CurrentID(), 5772 (void*)address, size); 5773 } 5774 5775 5776 area_id 5777 _user_area_for(void* address) 5778 { 5779 return vm_area_for((addr_t)address, false); 5780 } 5781 5782 5783 area_id 5784 _user_find_area(const char* userName) 5785 { 5786 char name[B_OS_NAME_LENGTH]; 5787 5788 if (!IS_USER_ADDRESS(userName) 5789 || user_strlcpy(name, userName, B_OS_NAME_LENGTH) < B_OK) 5790 return B_BAD_ADDRESS; 5791 5792 return find_area(name); 5793 } 5794 5795 5796 status_t 5797 _user_get_area_info(area_id area, area_info* userInfo) 5798 { 5799 if (!IS_USER_ADDRESS(userInfo)) 5800 return B_BAD_ADDRESS; 5801 5802 area_info info; 5803 status_t status = get_area_info(area, &info); 5804 if (status < B_OK) 5805 return status; 5806 5807 // TODO: do we want to prevent userland from seeing kernel protections? 5808 //info.protection &= B_USER_PROTECTION; 5809 5810 if (user_memcpy(userInfo, &info, sizeof(area_info)) < B_OK) 5811 return B_BAD_ADDRESS; 5812 5813 return status; 5814 } 5815 5816 5817 status_t 5818 _user_get_next_area_info(team_id team, int32* userCookie, area_info* userInfo) 5819 { 5820 int32 cookie; 5821 5822 if (!IS_USER_ADDRESS(userCookie) 5823 || !IS_USER_ADDRESS(userInfo) 5824 || user_memcpy(&cookie, userCookie, sizeof(int32)) < B_OK) 5825 return B_BAD_ADDRESS; 5826 5827 area_info info; 5828 status_t status = _get_next_area_info(team, &cookie, &info, 5829 sizeof(area_info)); 5830 if (status != B_OK) 5831 return status; 5832 5833 //info.protection &= B_USER_PROTECTION; 5834 5835 if (user_memcpy(userCookie, &cookie, sizeof(int32)) < B_OK 5836 || user_memcpy(userInfo, &info, sizeof(area_info)) < B_OK) 5837 return B_BAD_ADDRESS; 5838 5839 return status; 5840 } 5841 5842 5843 status_t 5844 _user_set_area_protection(area_id area, uint32 newProtection) 5845 { 5846 if ((newProtection & ~B_USER_PROTECTION) != 0) 5847 return B_BAD_VALUE; 5848 5849 fix_protection(&newProtection); 5850 5851 return vm_set_area_protection(VMAddressSpace::CurrentID(), area, 5852 newProtection, false); 5853 } 5854 5855 5856 status_t 5857 _user_resize_area(area_id area, size_t newSize) 5858 { 5859 // TODO: Since we restrict deleting of areas to those owned by the team, 5860 // we should also do that for resizing (check other functions, too). 5861 return vm_resize_area(area, newSize, false); 5862 } 5863 5864 5865 area_id 5866 _user_transfer_area(area_id area, void** userAddress, uint32 addressSpec, 5867 team_id target) 5868 { 5869 // filter out some unavailable values (for userland) 5870 switch (addressSpec) { 5871 case B_ANY_KERNEL_ADDRESS: 5872 case B_ANY_KERNEL_BLOCK_ADDRESS: 5873 return B_BAD_VALUE; 5874 } 5875 5876 void* address; 5877 if (!IS_USER_ADDRESS(userAddress) 5878 || user_memcpy(&address, userAddress, sizeof(address)) < B_OK) 5879 return B_BAD_ADDRESS; 5880 5881 area_id newArea = transfer_area(area, &address, addressSpec, target, false); 5882 if (newArea < B_OK) 5883 return newArea; 5884 5885 if (user_memcpy(userAddress, &address, sizeof(address)) < B_OK) 5886 return B_BAD_ADDRESS; 5887 5888 return newArea; 5889 } 5890 5891 5892 area_id 5893 _user_clone_area(const char* userName, void** userAddress, uint32 addressSpec, 5894 uint32 protection, area_id sourceArea) 5895 { 5896 char name[B_OS_NAME_LENGTH]; 5897 void* address; 5898 5899 // filter out some unavailable values (for userland) 5900 switch (addressSpec) { 5901 case B_ANY_KERNEL_ADDRESS: 5902 case B_ANY_KERNEL_BLOCK_ADDRESS: 5903 return B_BAD_VALUE; 5904 } 5905 if ((protection & ~B_USER_AREA_FLAGS) != 0) 5906 return B_BAD_VALUE; 5907 5908 if (!IS_USER_ADDRESS(userName) 5909 || !IS_USER_ADDRESS(userAddress) 5910 || user_strlcpy(name, userName, sizeof(name)) < B_OK 5911 || user_memcpy(&address, userAddress, sizeof(address)) < B_OK) 5912 return B_BAD_ADDRESS; 5913 5914 fix_protection(&protection); 5915 5916 area_id clonedArea = vm_clone_area(VMAddressSpace::CurrentID(), name, 5917 &address, addressSpec, protection, REGION_NO_PRIVATE_MAP, sourceArea, 5918 false); 5919 if (clonedArea < B_OK) 5920 return clonedArea; 5921 5922 if (user_memcpy(userAddress, &address, sizeof(address)) < B_OK) { 5923 delete_area(clonedArea); 5924 return B_BAD_ADDRESS; 5925 } 5926 5927 return clonedArea; 5928 } 5929 5930 5931 area_id 5932 _user_create_area(const char* userName, void** userAddress, uint32 addressSpec, 5933 size_t size, uint32 lock, uint32 protection) 5934 { 5935 char name[B_OS_NAME_LENGTH]; 5936 void* address; 5937 5938 // filter out some unavailable values (for userland) 5939 switch (addressSpec) { 5940 case B_ANY_KERNEL_ADDRESS: 5941 case B_ANY_KERNEL_BLOCK_ADDRESS: 5942 return B_BAD_VALUE; 5943 } 5944 if ((protection & ~B_USER_AREA_FLAGS) != 0) 5945 return B_BAD_VALUE; 5946 5947 if (!IS_USER_ADDRESS(userName) 5948 || !IS_USER_ADDRESS(userAddress) 5949 || user_strlcpy(name, userName, sizeof(name)) < B_OK 5950 || user_memcpy(&address, userAddress, sizeof(address)) < B_OK) 5951 return B_BAD_ADDRESS; 5952 5953 if (addressSpec == B_EXACT_ADDRESS 5954 && IS_KERNEL_ADDRESS(address)) 5955 return B_BAD_VALUE; 5956 5957 fix_protection(&protection); 5958 5959 virtual_address_restrictions virtualRestrictions = {}; 5960 virtualRestrictions.address = address; 5961 virtualRestrictions.address_specification = addressSpec; 5962 physical_address_restrictions physicalRestrictions = {}; 5963 area_id area = vm_create_anonymous_area(VMAddressSpace::CurrentID(), name, 5964 size, lock, protection, 0, &virtualRestrictions, &physicalRestrictions, 5965 false, &address); 5966 5967 if (area >= B_OK 5968 && user_memcpy(userAddress, &address, sizeof(address)) < B_OK) { 5969 delete_area(area); 5970 return B_BAD_ADDRESS; 5971 } 5972 5973 return area; 5974 } 5975 5976 5977 status_t 5978 _user_delete_area(area_id area) 5979 { 5980 // Unlike the BeOS implementation, you can now only delete areas 5981 // that you have created yourself from userland. 5982 // The documentation to delete_area() explicitly states that this 5983 // will be restricted in the future, and so it will. 5984 return vm_delete_area(VMAddressSpace::CurrentID(), area, false); 5985 } 5986 5987 5988 // TODO: create a BeOS style call for this! 5989 5990 area_id 5991 _user_map_file(const char* userName, void** userAddress, uint32 addressSpec, 5992 size_t size, uint32 protection, uint32 mapping, bool unmapAddressRange, 5993 int fd, off_t offset) 5994 { 5995 char name[B_OS_NAME_LENGTH]; 5996 void* address; 5997 area_id area; 5998 5999 if ((protection & ~B_USER_AREA_FLAGS) != 0) 6000 return B_BAD_VALUE; 6001 6002 fix_protection(&protection); 6003 6004 if (!IS_USER_ADDRESS(userName) || !IS_USER_ADDRESS(userAddress) 6005 || user_strlcpy(name, userName, B_OS_NAME_LENGTH) < B_OK 6006 || user_memcpy(&address, userAddress, sizeof(address)) < B_OK) 6007 return B_BAD_ADDRESS; 6008 6009 if (addressSpec == B_EXACT_ADDRESS) { 6010 if ((addr_t)address + size < (addr_t)address 6011 || (addr_t)address % B_PAGE_SIZE != 0) { 6012 return B_BAD_VALUE; 6013 } 6014 if (!IS_USER_ADDRESS(address) 6015 || !IS_USER_ADDRESS((addr_t)address + size)) { 6016 return B_BAD_ADDRESS; 6017 } 6018 } 6019 6020 area = _vm_map_file(VMAddressSpace::CurrentID(), name, &address, 6021 addressSpec, size, protection, mapping, unmapAddressRange, fd, offset, 6022 false); 6023 if (area < B_OK) 6024 return area; 6025 6026 if (user_memcpy(userAddress, &address, sizeof(address)) < B_OK) 6027 return B_BAD_ADDRESS; 6028 6029 return area; 6030 } 6031 6032 6033 status_t 6034 _user_unmap_memory(void* _address, size_t size) 6035 { 6036 addr_t address = (addr_t)_address; 6037 6038 // check params 6039 if (size == 0 || (addr_t)address + size < (addr_t)address 6040 || (addr_t)address % B_PAGE_SIZE != 0) { 6041 return B_BAD_VALUE; 6042 } 6043 6044 if (!IS_USER_ADDRESS(address) || !IS_USER_ADDRESS((addr_t)address + size)) 6045 return B_BAD_ADDRESS; 6046 6047 // Write lock the address space and ensure the address range is not wired. 6048 AddressSpaceWriteLocker locker; 6049 do { 6050 status_t status = locker.SetTo(team_get_current_team_id()); 6051 if (status != B_OK) 6052 return status; 6053 } while (wait_if_address_range_is_wired(locker.AddressSpace(), address, 6054 size, &locker)); 6055 6056 // unmap 6057 return unmap_address_range(locker.AddressSpace(), address, size, false); 6058 } 6059 6060 6061 status_t 6062 _user_set_memory_protection(void* _address, size_t size, uint32 protection) 6063 { 6064 // check address range 6065 addr_t address = (addr_t)_address; 6066 size = PAGE_ALIGN(size); 6067 6068 if ((address % B_PAGE_SIZE) != 0) 6069 return B_BAD_VALUE; 6070 if ((addr_t)address + size < (addr_t)address || !IS_USER_ADDRESS(address) 6071 || !IS_USER_ADDRESS((addr_t)address + size)) { 6072 // weird error code required by POSIX 6073 return ENOMEM; 6074 } 6075 6076 // extend and check protection 6077 if ((protection & ~B_USER_PROTECTION) != 0) 6078 return B_BAD_VALUE; 6079 6080 fix_protection(&protection); 6081 6082 // We need to write lock the address space, since we're going to play with 6083 // the areas. Also make sure that none of the areas is wired and that we're 6084 // actually allowed to change the protection. 6085 AddressSpaceWriteLocker locker; 6086 6087 bool restart; 6088 do { 6089 restart = false; 6090 6091 status_t status = locker.SetTo(team_get_current_team_id()); 6092 if (status != B_OK) 6093 return status; 6094 6095 // First round: Check whether the whole range is covered by areas and we 6096 // are allowed to modify them. 6097 addr_t currentAddress = address; 6098 size_t sizeLeft = size; 6099 while (sizeLeft > 0) { 6100 VMArea* area = locker.AddressSpace()->LookupArea(currentAddress); 6101 if (area == NULL) 6102 return B_NO_MEMORY; 6103 6104 if ((area->protection & B_KERNEL_AREA) != 0) 6105 return B_NOT_ALLOWED; 6106 6107 AreaCacheLocker cacheLocker(area); 6108 6109 if (wait_if_area_is_wired(area, &locker, &cacheLocker)) { 6110 restart = true; 6111 break; 6112 } 6113 6114 cacheLocker.Unlock(); 6115 6116 // TODO: For (shared) mapped files we should check whether the new 6117 // protections are compatible with the file permissions. We don't 6118 // have a way to do that yet, though. 6119 6120 addr_t offset = currentAddress - area->Base(); 6121 size_t rangeSize = min_c(area->Size() - offset, sizeLeft); 6122 6123 currentAddress += rangeSize; 6124 sizeLeft -= rangeSize; 6125 } 6126 } while (restart); 6127 6128 // Second round: If the protections differ from that of the area, create a 6129 // page protection array and re-map mapped pages. 6130 VMTranslationMap* map = locker.AddressSpace()->TranslationMap(); 6131 addr_t currentAddress = address; 6132 size_t sizeLeft = size; 6133 while (sizeLeft > 0) { 6134 VMArea* area = locker.AddressSpace()->LookupArea(currentAddress); 6135 if (area == NULL) 6136 return B_NO_MEMORY; 6137 6138 addr_t offset = currentAddress - area->Base(); 6139 size_t rangeSize = min_c(area->Size() - offset, sizeLeft); 6140 6141 currentAddress += rangeSize; 6142 sizeLeft -= rangeSize; 6143 6144 if (area->page_protections == NULL) { 6145 if (area->protection == protection) 6146 continue; 6147 6148 // In the page protections we store only the three user protections, 6149 // so we use 4 bits per page. 6150 uint32 bytes = (area->Size() / B_PAGE_SIZE + 1) / 2; 6151 area->page_protections = (uint8*)malloc(bytes); 6152 if (area->page_protections == NULL) 6153 return B_NO_MEMORY; 6154 6155 // init the page protections for all pages to that of the area 6156 uint32 areaProtection = area->protection 6157 & (B_READ_AREA | B_WRITE_AREA | B_EXECUTE_AREA); 6158 memset(area->page_protections, 6159 areaProtection | (areaProtection << 4), bytes); 6160 } 6161 6162 // We need to lock the complete cache chain, since we potentially unmap 6163 // pages of lower caches. 6164 VMCache* topCache = vm_area_get_locked_cache(area); 6165 VMCacheChainLocker cacheChainLocker(topCache); 6166 cacheChainLocker.LockAllSourceCaches(); 6167 6168 for (addr_t pageAddress = area->Base() + offset; 6169 pageAddress < currentAddress; pageAddress += B_PAGE_SIZE) { 6170 map->Lock(); 6171 6172 set_area_page_protection(area, pageAddress, protection); 6173 6174 phys_addr_t physicalAddress; 6175 uint32 flags; 6176 6177 status_t error = map->Query(pageAddress, &physicalAddress, &flags); 6178 if (error != B_OK || (flags & PAGE_PRESENT) == 0) { 6179 map->Unlock(); 6180 continue; 6181 } 6182 6183 vm_page* page = vm_lookup_page(physicalAddress / B_PAGE_SIZE); 6184 if (page == NULL) { 6185 panic("area %p looking up page failed for pa %#" B_PRIxPHYSADDR 6186 "\n", area, physicalAddress); 6187 map->Unlock(); 6188 return B_ERROR; 6189 } 6190 6191 // If the page is not in the topmost cache and write access is 6192 // requested, we have to unmap it. Otherwise we can re-map it with 6193 // the new protection. 6194 bool unmapPage = page->Cache() != topCache 6195 && (protection & B_WRITE_AREA) != 0; 6196 6197 if (!unmapPage) 6198 map->ProtectPage(area, pageAddress, protection); 6199 6200 map->Unlock(); 6201 6202 if (unmapPage) { 6203 DEBUG_PAGE_ACCESS_START(page); 6204 unmap_page(area, pageAddress); 6205 DEBUG_PAGE_ACCESS_END(page); 6206 } 6207 } 6208 } 6209 6210 return B_OK; 6211 } 6212 6213 6214 status_t 6215 _user_sync_memory(void* _address, size_t size, uint32 flags) 6216 { 6217 addr_t address = (addr_t)_address; 6218 size = PAGE_ALIGN(size); 6219 6220 // check params 6221 if ((address % B_PAGE_SIZE) != 0) 6222 return B_BAD_VALUE; 6223 if ((addr_t)address + size < (addr_t)address || !IS_USER_ADDRESS(address) 6224 || !IS_USER_ADDRESS((addr_t)address + size)) { 6225 // weird error code required by POSIX 6226 return ENOMEM; 6227 } 6228 6229 bool writeSync = (flags & MS_SYNC) != 0; 6230 bool writeAsync = (flags & MS_ASYNC) != 0; 6231 if (writeSync && writeAsync) 6232 return B_BAD_VALUE; 6233 6234 if (size == 0 || (!writeSync && !writeAsync)) 6235 return B_OK; 6236 6237 // iterate through the range and sync all concerned areas 6238 while (size > 0) { 6239 // read lock the address space 6240 AddressSpaceReadLocker locker; 6241 status_t error = locker.SetTo(team_get_current_team_id()); 6242 if (error != B_OK) 6243 return error; 6244 6245 // get the first area 6246 VMArea* area = locker.AddressSpace()->LookupArea(address); 6247 if (area == NULL) 6248 return B_NO_MEMORY; 6249 6250 uint32 offset = address - area->Base(); 6251 size_t rangeSize = min_c(area->Size() - offset, size); 6252 offset += area->cache_offset; 6253 6254 // lock the cache 6255 AreaCacheLocker cacheLocker(area); 6256 if (!cacheLocker) 6257 return B_BAD_VALUE; 6258 VMCache* cache = area->cache; 6259 6260 locker.Unlock(); 6261 6262 uint32 firstPage = offset >> PAGE_SHIFT; 6263 uint32 endPage = firstPage + (rangeSize >> PAGE_SHIFT); 6264 6265 // write the pages 6266 if (cache->type == CACHE_TYPE_VNODE) { 6267 if (writeSync) { 6268 // synchronous 6269 error = vm_page_write_modified_page_range(cache, firstPage, 6270 endPage); 6271 if (error != B_OK) 6272 return error; 6273 } else { 6274 // asynchronous 6275 vm_page_schedule_write_page_range(cache, firstPage, endPage); 6276 // TODO: This is probably not quite what is supposed to happen. 6277 // Especially when a lot has to be written, it might take ages 6278 // until it really hits the disk. 6279 } 6280 } 6281 6282 address += rangeSize; 6283 size -= rangeSize; 6284 } 6285 6286 // NOTE: If I understand it correctly the purpose of MS_INVALIDATE is to 6287 // synchronize multiple mappings of the same file. In our VM they never get 6288 // out of sync, though, so we don't have to do anything. 6289 6290 return B_OK; 6291 } 6292 6293 6294 status_t 6295 _user_memory_advice(void* address, size_t size, uint32 advice) 6296 { 6297 // TODO: Implement! 6298 return B_OK; 6299 } 6300 6301 6302 // #pragma mark -- compatibility 6303 6304 6305 #if defined(__INTEL__) && B_HAIKU_PHYSICAL_BITS > 32 6306 6307 6308 struct physical_entry_beos { 6309 uint32 address; 6310 uint32 size; 6311 }; 6312 6313 6314 /*! The physical_entry structure has changed. We need to translate it to the 6315 old one. 6316 */ 6317 extern "C" int32 6318 __get_memory_map_beos(const void* _address, size_t numBytes, 6319 physical_entry_beos* table, int32 numEntries) 6320 { 6321 if (numEntries <= 0) 6322 return B_BAD_VALUE; 6323 6324 const uint8* address = (const uint8*)_address; 6325 6326 int32 count = 0; 6327 while (numBytes > 0 && count < numEntries) { 6328 physical_entry entry; 6329 status_t result = __get_memory_map_haiku(address, numBytes, &entry, 1); 6330 if (result < 0) { 6331 if (result != B_BUFFER_OVERFLOW) 6332 return result; 6333 } 6334 6335 if (entry.address >= (phys_addr_t)1 << 32) { 6336 panic("get_memory_map(): Address is greater 4 GB!"); 6337 return B_ERROR; 6338 } 6339 6340 table[count].address = entry.address; 6341 table[count++].size = entry.size; 6342 6343 address += entry.size; 6344 numBytes -= entry.size; 6345 } 6346 6347 // null-terminate the table, if possible 6348 if (count < numEntries) { 6349 table[count].address = 0; 6350 table[count].size = 0; 6351 } 6352 6353 return B_OK; 6354 } 6355 6356 6357 /*! The type of the \a physicalAddress parameter has changed from void* to 6358 phys_addr_t. 6359 */ 6360 extern "C" area_id 6361 __map_physical_memory_beos(const char* name, void* physicalAddress, 6362 size_t numBytes, uint32 addressSpec, uint32 protection, 6363 void** _virtualAddress) 6364 { 6365 return __map_physical_memory_haiku(name, (addr_t)physicalAddress, numBytes, 6366 addressSpec, protection, _virtualAddress); 6367 } 6368 6369 6370 /*! The caller might not be able to deal with physical addresses >= 4 GB, so 6371 we meddle with the \a lock parameter to force 32 bit. 6372 */ 6373 extern "C" area_id 6374 __create_area_beos(const char* name, void** _address, uint32 addressSpec, 6375 size_t size, uint32 lock, uint32 protection) 6376 { 6377 switch (lock) { 6378 case B_NO_LOCK: 6379 break; 6380 case B_FULL_LOCK: 6381 case B_LAZY_LOCK: 6382 lock = B_32_BIT_FULL_LOCK; 6383 break; 6384 case B_CONTIGUOUS: 6385 lock = B_32_BIT_CONTIGUOUS; 6386 break; 6387 } 6388 6389 return __create_area_haiku(name, _address, addressSpec, size, lock, 6390 protection); 6391 } 6392 6393 6394 DEFINE_LIBROOT_KERNEL_SYMBOL_VERSION("__get_memory_map_beos", "get_memory_map@", 6395 "BASE"); 6396 DEFINE_LIBROOT_KERNEL_SYMBOL_VERSION("__map_physical_memory_beos", 6397 "map_physical_memory@", "BASE"); 6398 DEFINE_LIBROOT_KERNEL_SYMBOL_VERSION("__create_area_beos", "create_area@", 6399 "BASE"); 6400 6401 DEFINE_LIBROOT_KERNEL_SYMBOL_VERSION("__get_memory_map_haiku", 6402 "get_memory_map@@", "1_ALPHA3"); 6403 DEFINE_LIBROOT_KERNEL_SYMBOL_VERSION("__map_physical_memory_haiku", 6404 "map_physical_memory@@", "1_ALPHA3"); 6405 DEFINE_LIBROOT_KERNEL_SYMBOL_VERSION("__create_area_haiku", "create_area@@", 6406 "1_ALPHA3"); 6407 6408 6409 #else 6410 6411 6412 DEFINE_LIBROOT_KERNEL_SYMBOL_VERSION("__get_memory_map_haiku", 6413 "get_memory_map@@", "BASE"); 6414 DEFINE_LIBROOT_KERNEL_SYMBOL_VERSION("__map_physical_memory_haiku", 6415 "map_physical_memory@@", "BASE"); 6416 DEFINE_LIBROOT_KERNEL_SYMBOL_VERSION("__create_area_haiku", "create_area@@", 6417 "BASE"); 6418 6419 6420 #endif // defined(__INTEL__) && B_HAIKU_PHYSICAL_BITS > 32 6421