void ARMVMTranslationMap32Bit::UnmapArea(VMArea* area, bool deletingAddressSpace, bool ignoreTopCachePageFlags) { if (area->cache_type == CACHE_TYPE_DEVICE || area->wiring != B_NO_LOCK) { ARMVMTranslationMap32Bit::UnmapPages(area, area->Base(), area->Size(), true); return; } bool unmapPages = !deletingAddressSpace || !ignoreTopCachePageFlags; page_directory_entry* pd = fPagingStructures->pgdir_virt; RecursiveLocker locker(fLock); VMAreaMappings mappings; mappings.MoveFrom(&area->mappings); for (VMAreaMappings::Iterator it = mappings.GetIterator(); vm_page_mapping* mapping = it.Next();) { vm_page* page = mapping->page; page->mappings.Remove(mapping); VMCache* cache = page->Cache(); bool pageFullyUnmapped = false; if (!page->IsMapped()) { atomic_add(&gMappedPagesCount, -1); pageFullyUnmapped = true; } if (unmapPages || cache != area->cache) { addr_t address = area->Base() + ((page->cache_offset * B_PAGE_SIZE) - area->cache_offset); int index = VADDR_TO_PDENT(address); if ((pd[index] & ARM_PDE_TYPE_MASK) == 0) { panic("page %p has mapping for area %p (%#" B_PRIxADDR "), but " "has no page dir entry", page, area, address); continue; } ThreadCPUPinner pinner(thread_get_current_thread()); page_table_entry* pt = (page_table_entry*)fPageMapper->GetPageTableAt( pd[index] & ARM_PDE_ADDRESS_MASK); page_table_entry oldEntry = ARMPagingMethod32Bit::ClearPageTableEntry( &pt[VADDR_TO_PTENT(address)]); pinner.Unlock(); if ((oldEntry & ARM_PTE_TYPE_MASK) == 0) { panic("page %p has mapping for area %p (%#" B_PRIxADDR "), but " "has no page table entry", page, area, address); continue; } // transfer the accessed/dirty flags to the page and invalidate // the mapping, if necessary if (true /*(oldEntry & ARM_PTE_ACCESSED) != 0*/) { // XXX IRA page->accessed = true; if (!deletingAddressSpace) InvalidatePage(address); } if (true /*(oldEntry & ARM_PTE_DIRTY) != 0*/) page->modified = true; if (pageFullyUnmapped) { DEBUG_PAGE_ACCESS_START(page); if (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); } } fMapCount--; } Flush(); // flush explicitely, since we directly use the lock locker.Unlock(); 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 = mappings.RemoveHead()) object_cache_free(gPageMappingsObjectCache, mapping, freeFlags); }
void X86VMTranslationMap64Bit::UnmapArea(VMArea* area, bool deletingAddressSpace, bool ignoreTopCachePageFlags) { TRACE("X86VMTranslationMap64Bit::UnmapArea(%p)\n", area); if (area->cache_type == CACHE_TYPE_DEVICE || area->wiring != B_NO_LOCK) { X86VMTranslationMap64Bit::UnmapPages(area, area->Base(), area->Size(), true); return; } bool unmapPages = !deletingAddressSpace || !ignoreTopCachePageFlags; RecursiveLocker locker(fLock); ThreadCPUPinner pinner(thread_get_current_thread()); VMAreaMappings mappings; mappings.MoveFrom(&area->mappings); for (VMAreaMappings::Iterator it = mappings.GetIterator(); vm_page_mapping* mapping = it.Next();) { vm_page* page = mapping->page; page->mappings.Remove(mapping); VMCache* cache = page->Cache(); bool pageFullyUnmapped = false; if (!page->IsMapped()) { atomic_add(&gMappedPagesCount, -1); pageFullyUnmapped = true; } if (unmapPages || cache != area->cache) { addr_t address = area->Base() + ((page->cache_offset * B_PAGE_SIZE) - area->cache_offset); uint64* entry = X86PagingMethod64Bit::PageTableEntryForAddress( fPagingStructures->VirtualPML4(), address, fIsKernelMap, false, NULL, fPageMapper, fMapCount); if (entry == NULL) { panic("page %p has mapping for area %p (%#" B_PRIxADDR "), but " "has no page table", page, area, address); continue; } uint64 oldEntry = X86PagingMethod64Bit::ClearTableEntry(entry); if ((oldEntry & X86_64_PTE_PRESENT) == 0) { panic("page %p has mapping for area %p (%#" B_PRIxADDR "), but " "has no page table entry", page, area, address); continue; } // transfer the accessed/dirty flags to the page and invalidate // the mapping, if necessary if ((oldEntry & X86_64_PTE_ACCESSED) != 0) { page->accessed = true; if (!deletingAddressSpace) InvalidatePage(address); } if ((oldEntry & X86_64_PTE_DIRTY) != 0) page->modified = true; if (pageFullyUnmapped) { DEBUG_PAGE_ACCESS_START(page); if (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); } } fMapCount--; } Flush(); // flush explicitely, since we directly use the lock locker.Unlock(); 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 = mappings.RemoveHead()) object_cache_free(gPageMappingsObjectCache, mapping, freeFlags); }