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