void ARMVMTranslationMap32Bit::UnmapPages(VMArea* area, addr_t base, size_t size, bool updatePageQueue) { if (size == 0) return; addr_t start = base; addr_t end = base + size - 1; TRACE("ARMVMTranslationMap32Bit::UnmapPages(%p, %#" B_PRIxADDR ", %#" B_PRIxADDR ")\n", area, start, end); page_directory_entry* pd = fPagingStructures->pgdir_virt; VMAreaMappings queue; RecursiveLocker locker(fLock); do { int index = VADDR_TO_PDENT(start); if ((pd[index] & ARM_PDE_TYPE_MASK) == 0) { // no page table here, move the start up to access the next page // table start = ROUNDUP(start + 1, kPageTableAlignment); continue; } Thread* thread = thread_get_current_thread(); ThreadCPUPinner pinner(thread); page_table_entry* pt = (page_table_entry*)fPageMapper->GetPageTableAt( pd[index] & ARM_PDE_ADDRESS_MASK); for (index = VADDR_TO_PTENT(start); (index < 1024) && (start < end); index++, start += B_PAGE_SIZE) { page_table_entry oldEntry = ARMPagingMethod32Bit::ClearPageTableEntry(&pt[index]); if ((oldEntry & ARM_PTE_TYPE_MASK) == 0) continue; fMapCount--; if (true /*(oldEntry & ARM_PTE_ACCESSED) != 0*/) { // XXX IRA // Note, that we only need to invalidate the address, if the // accessed flags was set, since only then the entry could have // been in any TLB. InvalidatePage(start); } if (area->cache_type != CACHE_TYPE_DEVICE) { // get the page vm_page* page = vm_lookup_page( (oldEntry & ARM_PTE_ADDRESS_MASK) / B_PAGE_SIZE); ASSERT(page != NULL); DEBUG_PAGE_ACCESS_START(page); // transfer the accessed/dirty flags to the page if (/*(oldEntry & ARM_PTE_ACCESSED) != 0*/ true) // XXX IRA page->accessed = true; if (/*(oldEntry & ARM_PTE_DIRTY) != 0 */ true) page->modified = true; // remove the mapping object/decrement the wired_count of the // page if (area->wiring == B_NO_LOCK) { vm_page_mapping* mapping = NULL; vm_page_mappings::Iterator iterator = page->mappings.GetIterator(); while ((mapping = iterator.Next()) != NULL) { if (mapping->area == area) break; } ASSERT(mapping != NULL); area->mappings.Remove(mapping); page->mappings.Remove(mapping); queue.Add(mapping); } else page->DecrementWiredCount(); if (!page->IsMapped()) { atomic_add(&gMappedPagesCount, -1); if (updatePageQueue) { if (page->Cache()->temporary) vm_page_set_state(page, PAGE_STATE_INACTIVE); else if (page->modified) vm_page_set_state(page, PAGE_STATE_MODIFIED); else vm_page_set_state(page, PAGE_STATE_CACHED); } } DEBUG_PAGE_ACCESS_END(page); } } Flush(); // flush explicitly, since we directly use the lock } while (start != 0 && start < end); // TODO: As in UnmapPage() we can lose page dirty flags here. ATM it's not // really critical here, as in all cases this method is used, the unmapped // area range is unmapped for good (resized/cut) and the pages will likely // be freed. locker.Unlock(); // free removed mappings bool isKernelSpace = area->address_space == VMAddressSpace::Kernel(); uint32 freeFlags = CACHE_DONT_WAIT_FOR_MEMORY | (isKernelSpace ? CACHE_DONT_LOCK_KERNEL_SPACE : 0); while (vm_page_mapping* mapping = queue.RemoveHead()) object_cache_free(gPageMappingsObjectCache, mapping, freeFlags); }
void X86VMTranslationMap64Bit::UnmapPages(VMArea* area, addr_t base, size_t size, bool updatePageQueue) { if (size == 0) return; addr_t start = base; addr_t end = base + size - 1; TRACE("X86VMTranslationMap64Bit::UnmapPages(%p, %#" B_PRIxADDR ", %#" B_PRIxADDR ")\n", area, start, end); VMAreaMappings queue; RecursiveLocker locker(fLock); ThreadCPUPinner pinner(thread_get_current_thread()); do { uint64* pageTable = X86PagingMethod64Bit::PageTableForAddress( fPagingStructures->VirtualPML4(), start, fIsKernelMap, false, NULL, fPageMapper, fMapCount); if (pageTable == NULL) { // Move on to the next page table. start = ROUNDUP(start + 1, k64BitPageTableRange); continue; } for (uint32 index = start / B_PAGE_SIZE % k64BitTableEntryCount; index < k64BitTableEntryCount && start < end; index++, start += B_PAGE_SIZE) { uint64 oldEntry = X86PagingMethod64Bit::ClearTableEntry( &pageTable[index]); if ((oldEntry & X86_64_PTE_PRESENT) == 0) continue; fMapCount--; if ((oldEntry & X86_64_PTE_ACCESSED) != 0) { // Note, that we only need to invalidate the address, if the // accessed flags was set, since only then the entry could have // been in any TLB. InvalidatePage(start); } if (area->cache_type != CACHE_TYPE_DEVICE) { // get the page vm_page* page = vm_lookup_page( (oldEntry & X86_64_PTE_ADDRESS_MASK) / B_PAGE_SIZE); ASSERT(page != NULL); DEBUG_PAGE_ACCESS_START(page); // transfer the accessed/dirty flags to the page if ((oldEntry & X86_64_PTE_ACCESSED) != 0) page->accessed = true; if ((oldEntry & X86_64_PTE_DIRTY) != 0) page->modified = true; // remove the mapping object/decrement the wired_count of the // page if (area->wiring == B_NO_LOCK) { vm_page_mapping* mapping = NULL; vm_page_mappings::Iterator iterator = page->mappings.GetIterator(); while ((mapping = iterator.Next()) != NULL) { if (mapping->area == area) break; } ASSERT(mapping != NULL); area->mappings.Remove(mapping); page->mappings.Remove(mapping); queue.Add(mapping); } else page->DecrementWiredCount(); if (!page->IsMapped()) { atomic_add(&gMappedPagesCount, -1); if (updatePageQueue) { if (page->Cache()->temporary) vm_page_set_state(page, PAGE_STATE_INACTIVE); else if (page->modified) vm_page_set_state(page, PAGE_STATE_MODIFIED); else vm_page_set_state(page, PAGE_STATE_CACHED); } } DEBUG_PAGE_ACCESS_END(page); } } Flush(); // flush explicitly, since we directly use the lock } while (start != 0 && start < end); // TODO: As in UnmapPage() we can lose page dirty flags here. ATM it's not // really critical here, as in all cases this method is used, the unmapped // area range is unmapped for good (resized/cut) and the pages will likely // be freed. locker.Unlock(); // free removed mappings bool isKernelSpace = area->address_space == VMAddressSpace::Kernel(); uint32 freeFlags = CACHE_DONT_WAIT_FOR_MEMORY | (isKernelSpace ? CACHE_DONT_LOCK_KERNEL_SPACE : 0); while (vm_page_mapping* mapping = queue.RemoveHead()) object_cache_free(gPageMappingsObjectCache, mapping, freeFlags); }