kernel/vm: Consolidate implementations of VMTranslationMap::UnmapArea.
This adds some new parameters to UnmapPage and UnmapPages. The important one is a "_flags" pointer to UnmapPage, which if specified will be filled with the page flags instead of PageUnmapped() being called (and Flush() won't be invoked, either.) This removes the remaining PAGE_STATE_* changes from VM architecture code. Change-Id: Iacbc424dd8a75a79986edcd7f04d15a10f773c87 Reviewed-on: https://review.haiku-os.org/c/haiku/+/8728 Tested-by: Commit checker robot <[email protected]> Reviewed-by: waddlesplash <[email protected]>
This commit is contained in:
committed by
waddlesplash
parent
783347df2b
commit
7651b97c0a
@@ -44,9 +44,12 @@ public:
|
|||||||
|
|
||||||
// map not locked
|
// map not locked
|
||||||
virtual status_t UnmapPage(VMArea* area, addr_t address,
|
virtual status_t UnmapPage(VMArea* area, addr_t address,
|
||||||
bool updatePageQueue) = 0;
|
bool updatePageQueue,
|
||||||
|
bool deletingAddressSpace = false,
|
||||||
|
uint32* _flags = NULL) = 0;
|
||||||
virtual void UnmapPages(VMArea* area, addr_t base,
|
virtual void UnmapPages(VMArea* area, addr_t base,
|
||||||
size_t size, bool updatePageQueue);
|
size_t size, bool updatePageQueue,
|
||||||
|
bool deletingAddressSpace = false);
|
||||||
virtual void UnmapArea(VMArea* area,
|
virtual void UnmapArea(VMArea* area,
|
||||||
bool deletingAddressSpace,
|
bool deletingAddressSpace,
|
||||||
bool ignoreTopCachePageFlags);
|
bool ignoreTopCachePageFlags);
|
||||||
|
|||||||
@@ -335,21 +335,19 @@ ARMVMTranslationMap32Bit::DebugMarkRangePresent(addr_t start, addr_t end,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*! Caller must have locked the cache of the page to be unmapped.
|
|
||||||
This object shouldn't be locked.
|
|
||||||
*/
|
|
||||||
status_t
|
status_t
|
||||||
ARMVMTranslationMap32Bit::UnmapPage(VMArea* area, addr_t address,
|
ARMVMTranslationMap32Bit::UnmapPage(VMArea* area, addr_t address,
|
||||||
bool updatePageQueue)
|
bool updatePageQueue, bool deletingAddressSpace, uint32* _flags)
|
||||||
{
|
{
|
||||||
ASSERT(address % B_PAGE_SIZE == 0);
|
ASSERT(address % B_PAGE_SIZE == 0);
|
||||||
|
ASSERT(_flags == NULL || !updatePageQueue);
|
||||||
page_directory_entry* pd = fPagingStructures->pgdir_virt;
|
|
||||||
|
|
||||||
TRACE("ARMVMTranslationMap32Bit::UnmapPage(%#" B_PRIxADDR ")\n", address);
|
TRACE("ARMVMTranslationMap32Bit::UnmapPage(%#" B_PRIxADDR ")\n", address);
|
||||||
|
|
||||||
RecursiveLocker locker(fLock);
|
RecursiveLocker locker(fLock);
|
||||||
|
|
||||||
|
page_directory_entry* pd = fPagingStructures->pgdir_virt;
|
||||||
|
|
||||||
int index = VADDR_TO_PDENT(address);
|
int index = VADDR_TO_PDENT(address);
|
||||||
if ((pd[index] & ARM_PDE_TYPE_MASK) == 0)
|
if ((pd[index] & ARM_PDE_TYPE_MASK) == 0)
|
||||||
return B_ENTRY_NOT_FOUND;
|
return B_ENTRY_NOT_FOUND;
|
||||||
@@ -372,13 +370,15 @@ ARMVMTranslationMap32Bit::UnmapPage(VMArea* area, addr_t address,
|
|||||||
|
|
||||||
fMapCount--;
|
fMapCount--;
|
||||||
|
|
||||||
|
|
||||||
if ((oldEntry & ARM_MMU_L2_FLAG_AP0) != 0) {
|
if ((oldEntry & ARM_MMU_L2_FLAG_AP0) != 0) {
|
||||||
// Note, that we only need to invalidate the address, if the
|
// Note, that we only need to invalidate the address, if the
|
||||||
// accessed flags was set, since only then the entry could have been
|
// accessed flags was set, since only then the entry could have been
|
||||||
// in any TLB.
|
// in any TLB.
|
||||||
InvalidatePage(address);
|
if (!deletingAddressSpace)
|
||||||
Flush();
|
InvalidatePage(address);
|
||||||
|
|
||||||
|
if (_flags == NULL)
|
||||||
|
Flush();
|
||||||
|
|
||||||
// NOTE: Between clearing the page table entry and Flush() other
|
// NOTE: Between clearing the page table entry and Flush() other
|
||||||
// processors (actually even this processor with another thread of the
|
// processors (actually even this processor with another thread of the
|
||||||
@@ -392,12 +392,21 @@ ARMVMTranslationMap32Bit::UnmapPage(VMArea* area, addr_t address,
|
|||||||
// (cf. pmap_remove_all()), unless I've missed something.
|
// (cf. pmap_remove_all()), unless I've missed something.
|
||||||
}
|
}
|
||||||
|
|
||||||
locker.Detach();
|
if (_flags == NULL) {
|
||||||
// PageUnmapped() will unlock for us
|
locker.Detach();
|
||||||
|
// PageUnmapped() will unlock for us
|
||||||
|
|
||||||
PageUnmapped(area, (oldEntry & ARM_PTE_ADDRESS_MASK) / B_PAGE_SIZE,
|
PageUnmapped(area, (oldEntry & ARM_PTE_ADDRESS_MASK) / B_PAGE_SIZE,
|
||||||
(oldEntry & ARM_MMU_L2_FLAG_AP0) != 0, false /*(oldEntry & ARM_PTE_DIRTY) != 0*/,
|
(oldEntry & ARM_MMU_L2_FLAG_AP0) != 0, (oldEntry & ARM_MMU_L2_FLAG_AP2) != 0,
|
||||||
updatePageQueue);
|
updatePageQueue);
|
||||||
|
} else {
|
||||||
|
uint32 flags = PAGE_PRESENT;
|
||||||
|
if ((oldEntry & ARM_MMU_L2_FLAG_AP0) != 0)
|
||||||
|
flags |= PAGE_ACCESSED;
|
||||||
|
if ((oldEntry & ARM_MMU_L2_FLAG_AP2) != 0)
|
||||||
|
flags |= PAGE_MODIFIED;
|
||||||
|
*_flags = flags;
|
||||||
|
}
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
@@ -405,7 +414,7 @@ ARMVMTranslationMap32Bit::UnmapPage(VMArea* area, addr_t address,
|
|||||||
|
|
||||||
void
|
void
|
||||||
ARMVMTranslationMap32Bit::UnmapPages(VMArea* area, addr_t base, size_t size,
|
ARMVMTranslationMap32Bit::UnmapPages(VMArea* area, addr_t base, size_t size,
|
||||||
bool updatePageQueue)
|
bool updatePageQueue, bool deletingAddressSpace)
|
||||||
{
|
{
|
||||||
if (size == 0)
|
if (size == 0)
|
||||||
return;
|
return;
|
||||||
@@ -450,7 +459,8 @@ ARMVMTranslationMap32Bit::UnmapPages(VMArea* area, addr_t base, size_t size,
|
|||||||
// Note, that we only need to invalidate the address, if the
|
// Note, that we only need to invalidate the address, if the
|
||||||
// accessed flags was set, since only then the entry could have
|
// accessed flags was set, since only then the entry could have
|
||||||
// been in any TLB.
|
// been in any TLB.
|
||||||
InvalidatePage(start);
|
if (!deletingAddressSpace)
|
||||||
|
InvalidatePage(start);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (area->cache_type != CACHE_TYPE_DEVICE) {
|
if (area->cache_type != CACHE_TYPE_DEVICE) {
|
||||||
@@ -482,108 +492,6 @@ ARMVMTranslationMap32Bit::UnmapPages(VMArea* area, addr_t base, size_t size,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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.TakeFrom(&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 ((oldEntry & ARM_MMU_L2_FLAG_AP0) != 0) {
|
|
||||||
page->accessed = true;
|
|
||||||
|
|
||||||
if (!deletingAddressSpace)
|
|
||||||
InvalidatePage(address);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (false /*(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())
|
|
||||||
vm_free_page_mapping(mapping->page->physical_page_number, mapping, freeFlags);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
ARMVMTranslationMap32Bit::Query(addr_t va, phys_addr_t *_physical,
|
ARMVMTranslationMap32Bit::Query(addr_t va, phys_addr_t *_physical,
|
||||||
uint32 *_flags)
|
uint32 *_flags)
|
||||||
|
|||||||
@@ -31,12 +31,11 @@ struct ARMVMTranslationMap32Bit : ARMVMTranslationMap {
|
|||||||
bool markPresent);
|
bool markPresent);
|
||||||
|
|
||||||
virtual status_t UnmapPage(VMArea* area, addr_t address,
|
virtual status_t UnmapPage(VMArea* area, addr_t address,
|
||||||
bool updatePageQueue);
|
bool updatePageQueue,
|
||||||
|
bool deletingAddressSpace, uint32* _flags);
|
||||||
virtual void UnmapPages(VMArea* area, addr_t base,
|
virtual void UnmapPages(VMArea* area, addr_t base,
|
||||||
size_t size, bool updatePageQueue);
|
size_t size, bool updatePageQueue,
|
||||||
virtual void UnmapArea(VMArea* area,
|
bool deletingAddressSpace);
|
||||||
bool deletingAddressSpace,
|
|
||||||
bool ignoreTopCachePageFlags);
|
|
||||||
|
|
||||||
virtual status_t Query(addr_t virtualAddress,
|
virtual status_t Query(addr_t virtualAddress,
|
||||||
phys_addr_t* _physicalAddress,
|
phys_addr_t* _physicalAddress,
|
||||||
|
|||||||
@@ -400,7 +400,8 @@ flush_va_if_accessed(uint64_t pte, addr_t va, int asid)
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
VMSAv8TranslationMap::FlushVAIfAccessed(uint64_t pte, addr_t va) {
|
VMSAv8TranslationMap::FlushVAIfAccessed(uint64_t pte, addr_t va)
|
||||||
|
{
|
||||||
InterruptsSpinLocker locker(sAsidLock);
|
InterruptsSpinLocker locker(sAsidLock);
|
||||||
return flush_va_if_accessed(pte, va, fASID);
|
return flush_va_if_accessed(pte, va, fASID);
|
||||||
}
|
}
|
||||||
@@ -633,8 +634,12 @@ VMSAv8TranslationMap::Unmap(addr_t start, addr_t end)
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
VMSAv8TranslationMap::UnmapPage(VMArea* area, addr_t address, bool updatePageQueue)
|
VMSAv8TranslationMap::UnmapPage(VMArea* area, addr_t address,
|
||||||
|
bool updatePageQueue, bool deletingAddressSpace, uint32* _flags)
|
||||||
{
|
{
|
||||||
|
ASSERT(address % B_PAGE_SIZE == 0);
|
||||||
|
ASSERT(_flags == NULL || !updatePageQueue);
|
||||||
|
|
||||||
TRACE("VMSAv8TranslationMap::UnmapPage(0x%" B_PRIxADDR "(%s), 0x%"
|
TRACE("VMSAv8TranslationMap::UnmapPage(0x%" B_PRIxADDR "(%s), 0x%"
|
||||||
B_PRIxADDR ", %d)\n", (addr_t)area, area->name, address,
|
B_PRIxADDR ", %d)\n", (addr_t)area, area->name, address,
|
||||||
updatePageQueue);
|
updatePageQueue);
|
||||||
@@ -647,23 +652,35 @@ VMSAv8TranslationMap::UnmapPage(VMArea* area, addr_t address, bool updatePageQue
|
|||||||
ProcessRange(fPageTable, fInitialLevel, address, B_PAGE_SIZE, nullptr,
|
ProcessRange(fPageTable, fInitialLevel, address, B_PAGE_SIZE, nullptr,
|
||||||
[=, &oldPte](uint64_t* ptePtr, uint64_t effectiveVa) {
|
[=, &oldPte](uint64_t* ptePtr, uint64_t effectiveVa) {
|
||||||
oldPte = atomic_get_and_set64((int64_t*)ptePtr, 0);
|
oldPte = atomic_get_and_set64((int64_t*)ptePtr, 0);
|
||||||
FlushVAIfAccessed(oldPte, effectiveVa);
|
if (!deletingAddressSpace)
|
||||||
|
FlushVAIfAccessed(oldPte, effectiveVa);
|
||||||
});
|
});
|
||||||
|
|
||||||
if ((oldPte & kPteValidMask) == 0)
|
if ((oldPte & kPteValidMask) == 0)
|
||||||
return B_ENTRY_NOT_FOUND;
|
return B_ENTRY_NOT_FOUND;
|
||||||
|
|
||||||
pinner.Unlock();
|
pinner.Unlock();
|
||||||
locker.Detach();
|
|
||||||
PageUnmapped(area, (oldPte & kPteAddrMask) >> fPageBits, is_pte_accessed(oldPte),
|
if (_flags != NULL) {
|
||||||
is_pte_dirty(oldPte), updatePageQueue);
|
locker.Detach();
|
||||||
|
PageUnmapped(area, (oldPte & kPteAddrMask) >> fPageBits, is_pte_accessed(oldPte),
|
||||||
|
is_pte_dirty(oldPte), updatePageQueue);
|
||||||
|
} else {
|
||||||
|
uint32 flags = PAGE_PRESENT;
|
||||||
|
if (is_pte_accessed(oldPte))
|
||||||
|
flags |= PAGE_ACCESSED;
|
||||||
|
if (is_pte_dirty(oldPte))
|
||||||
|
flags |= PAGE_MODIFIED;
|
||||||
|
*_flags = flags;
|
||||||
|
}
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
VMSAv8TranslationMap::UnmapPages(VMArea* area, addr_t address, size_t size, bool updatePageQueue)
|
VMSAv8TranslationMap::UnmapPages(VMArea* area, addr_t address, size_t size,
|
||||||
|
bool updatePageQueue, bool deletingAddressSpace)
|
||||||
{
|
{
|
||||||
TRACE("VMSAv8TranslationMap::UnmapPages(0x%" B_PRIxADDR "(%s), 0x%"
|
TRACE("VMSAv8TranslationMap::UnmapPages(0x%" B_PRIxADDR "(%s), 0x%"
|
||||||
B_PRIxADDR ", 0x%" B_PRIxSIZE ", %d)\n", (addr_t)area,
|
B_PRIxADDR ", 0x%" B_PRIxSIZE ", %d)\n", (addr_t)area,
|
||||||
@@ -707,99 +724,6 @@ VMSAv8TranslationMap::UnmapPages(VMArea* area, addr_t address, size_t size, bool
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
VMSAv8TranslationMap::UnmapArea(VMArea* area, bool deletingAddressSpace,
|
|
||||||
bool ignoreTopCachePageFlags)
|
|
||||||
{
|
|
||||||
TRACE("VMSAv8TranslationMap::UnmapArea(0x%" B_PRIxADDR "(%s), 0x%"
|
|
||||||
B_PRIxADDR ", 0x%" B_PRIxSIZE ", %d, %d)\n", (addr_t)area,
|
|
||||||
area->name, area->Base(), area->Size(), deletingAddressSpace,
|
|
||||||
ignoreTopCachePageFlags);
|
|
||||||
|
|
||||||
if (area->cache_type == CACHE_TYPE_DEVICE || area->wiring != B_NO_LOCK) {
|
|
||||||
UnmapPages(area, area->Base(), area->Size(), true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool unmapPages = !deletingAddressSpace || !ignoreTopCachePageFlags;
|
|
||||||
|
|
||||||
RecursiveLocker locker(fLock);
|
|
||||||
ThreadCPUPinner pinner(thread_get_current_thread());
|
|
||||||
|
|
||||||
VMAreaMappings mappings;
|
|
||||||
mappings.TakeFrom(&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_t oldPte = 0;
|
|
||||||
ProcessRange(fPageTable, fInitialLevel, address, B_PAGE_SIZE, nullptr,
|
|
||||||
[=, &oldPte](uint64_t* ptePtr, uint64_t effectiveVa) {
|
|
||||||
oldPte = atomic_get_and_set64((int64_t*)ptePtr, 0);
|
|
||||||
if (!deletingAddressSpace)
|
|
||||||
FlushVAIfAccessed(oldPte, effectiveVa);
|
|
||||||
});
|
|
||||||
|
|
||||||
if ((oldPte & kPteValidMask) == 0) {
|
|
||||||
panic("page %p has mapping for area %p "
|
|
||||||
"(%#" B_PRIxADDR "), but has no "
|
|
||||||
"page table", page, area, address);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// transfer the accessed/dirty flags to the page and
|
|
||||||
// invalidate the mapping, if necessary
|
|
||||||
if (is_pte_dirty(oldPte))
|
|
||||||
page->modified = true;
|
|
||||||
if (is_pte_accessed(oldPte))
|
|
||||||
page->accessed = 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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())
|
|
||||||
vm_free_page_mapping(mapping->page->physical_page_number, mapping, freeFlags);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
VMSAv8TranslationMap::ValidateVa(addr_t va)
|
VMSAv8TranslationMap::ValidateVa(addr_t va)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -57,12 +57,11 @@ public:
|
|||||||
virtual status_t Unmap(addr_t start, addr_t end);
|
virtual status_t Unmap(addr_t start, addr_t end);
|
||||||
|
|
||||||
virtual status_t UnmapPage(VMArea* area, addr_t address,
|
virtual status_t UnmapPage(VMArea* area, addr_t address,
|
||||||
bool updatePageQueue);
|
bool updatePageQueue,
|
||||||
|
bool deletingAddressSpace, uint32* _flags);
|
||||||
virtual void UnmapPages(VMArea* area, addr_t base,
|
virtual void UnmapPages(VMArea* area, addr_t base,
|
||||||
size_t size, bool updatePageQueue);
|
size_t size, bool updatePageQueue,
|
||||||
virtual void UnmapArea(VMArea* area,
|
bool deletingAddressSpace);
|
||||||
bool deletingAddressSpace,
|
|
||||||
bool ignoreTopCachePageFlags);
|
|
||||||
|
|
||||||
virtual status_t Query(addr_t virtualAddress,
|
virtual status_t Query(addr_t virtualAddress,
|
||||||
phys_addr_t* _physicalAddress,
|
phys_addr_t* _physicalAddress,
|
||||||
|
|||||||
@@ -418,14 +418,12 @@ M68KVMTranslationMap040::Unmap(addr_t start, addr_t end)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*! Caller must have locked the cache of the page to be unmapped.
|
|
||||||
This object shouldn't be locked.
|
|
||||||
*/
|
|
||||||
status_t
|
status_t
|
||||||
M68KVMTranslationMap040::UnmapPage(VMArea* area, addr_t address,
|
M68KVMTranslationMap040::UnmapPage(VMArea* area, addr_t address,
|
||||||
bool updatePageQueue)
|
bool updatePageQueue, bool deletingAddressSpace, uint32* _flags)
|
||||||
{
|
{
|
||||||
ASSERT(address % B_PAGE_SIZE == 0);
|
ASSERT(address % B_PAGE_SIZE == 0);
|
||||||
|
ASSERT(_flags == NULL || !updatePageQueue);
|
||||||
|
|
||||||
page_root_entry* pr = fPagingStructures->pgroot_virt;
|
page_root_entry* pr = fPagingStructures->pgroot_virt;
|
||||||
|
|
||||||
@@ -475,8 +473,11 @@ M68KVMTranslationMap040::UnmapPage(VMArea* area, addr_t address,
|
|||||||
// Note, that we only need to invalidate the address, if the
|
// Note, that we only need to invalidate the address, if the
|
||||||
// accessed flags was set, since only then the entry could have been
|
// accessed flags was set, since only then the entry could have been
|
||||||
// in any TLB.
|
// in any TLB.
|
||||||
InvalidatePage(address);
|
if (!deletingAddressSpace)
|
||||||
Flush();
|
InvalidatePage(address);
|
||||||
|
|
||||||
|
if (_flags == NULL)
|
||||||
|
Flush();
|
||||||
|
|
||||||
// NOTE: Between clearing the page table entry and Flush() other
|
// NOTE: Between clearing the page table entry and Flush() other
|
||||||
// processors (actually even this processor with another thread of the
|
// processors (actually even this processor with another thread of the
|
||||||
@@ -490,12 +491,21 @@ M68KVMTranslationMap040::UnmapPage(VMArea* area, addr_t address,
|
|||||||
// (cf. pmap_remove_all()), unless I've missed something.
|
// (cf. pmap_remove_all()), unless I've missed something.
|
||||||
}
|
}
|
||||||
|
|
||||||
locker.Detach();
|
if (_flags == NULL) {
|
||||||
// PageUnmapped() will unlock for us
|
locker.Detach();
|
||||||
|
// PageUnmapped() will unlock for us
|
||||||
|
|
||||||
PageUnmapped(area, (oldEntry & M68K_PTE_ADDRESS_MASK) / B_PAGE_SIZE,
|
PageUnmapped(area, (oldEntry & M68K_PTE_ADDRESS_MASK) / B_PAGE_SIZE,
|
||||||
(oldEntry & M68K_PTE_ACCESSED) != 0, (oldEntry & M68K_PTE_DIRTY) != 0,
|
(oldEntry & M68K_PTE_ACCESSED) != 0, (oldEntry & M68K_PTE_DIRTY) != 0,
|
||||||
updatePageQueue);
|
updatePageQueue);
|
||||||
|
} else {
|
||||||
|
uint32 flags = PAGE_PRESENT;
|
||||||
|
if ((oldEntry & M68K_PTE_ACCESSED) != 0)
|
||||||
|
flags |= PAGE_ACCESSED;
|
||||||
|
if ((oldEntry & M68K_PTE_DIRTY) != 0)
|
||||||
|
flags |= PAGE_MODIFIED;
|
||||||
|
*_flags = flags;
|
||||||
|
}
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
@@ -503,7 +513,7 @@ M68KVMTranslationMap040::UnmapPage(VMArea* area, addr_t address,
|
|||||||
|
|
||||||
void
|
void
|
||||||
M68KVMTranslationMap040::UnmapPages(VMArea* area, addr_t base, size_t size,
|
M68KVMTranslationMap040::UnmapPages(VMArea* area, addr_t base, size_t size,
|
||||||
bool updatePageQueue)
|
bool updatePageQueue, bool deletingAddressSpace)
|
||||||
{
|
{
|
||||||
int index;
|
int index;
|
||||||
|
|
||||||
@@ -570,7 +580,8 @@ M68KVMTranslationMap040::UnmapPages(VMArea* area, addr_t base, size_t size,
|
|||||||
// Note, that we only need to invalidate the address, if the
|
// Note, that we only need to invalidate the address, if the
|
||||||
// accessed flags was set, since only then the entry could have
|
// accessed flags was set, since only then the entry could have
|
||||||
// been in any TLB.
|
// been in any TLB.
|
||||||
InvalidatePage(start);
|
if (!deletingAddressSpace)
|
||||||
|
InvalidatePage(start);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (area->cache_type != CACHE_TYPE_DEVICE) {
|
if (area->cache_type != CACHE_TYPE_DEVICE) {
|
||||||
@@ -602,123 +613,6 @@ M68KVMTranslationMap040::UnmapPages(VMArea* area, addr_t base, size_t size,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
M68KVMTranslationMap040::UnmapArea(VMArea* area, bool deletingAddressSpace,
|
|
||||||
bool ignoreTopCachePageFlags)
|
|
||||||
{
|
|
||||||
if (area->cache_type == CACHE_TYPE_DEVICE || area->wiring != B_NO_LOCK) {
|
|
||||||
M68KVMTranslationMap040::UnmapPages(area, area->Base(), area->Size(),
|
|
||||||
true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool unmapPages = !deletingAddressSpace || !ignoreTopCachePageFlags;
|
|
||||||
|
|
||||||
page_root_entry* pr = fPagingStructures->pgroot_virt;
|
|
||||||
|
|
||||||
RecursiveLocker locker(fLock);
|
|
||||||
|
|
||||||
VMAreaMappings mappings;
|
|
||||||
mappings.TakeFrom(&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;
|
|
||||||
index = VADDR_TO_PRENT(address);
|
|
||||||
if (PRE_TYPE(pr[index]) != DT_ROOT) {
|
|
||||||
panic("page %p has mapping for area %p (%#" B_PRIxADDR "), but "
|
|
||||||
"has no page root entry", page, area, address);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
ThreadCPUPinner pinner(thread_get_current_thread());
|
|
||||||
|
|
||||||
page_directory_entry* pd
|
|
||||||
= (page_directory_entry*)MapperGetPageTableAt(
|
|
||||||
pr[index] & M68K_PRE_ADDRESS_MASK);
|
|
||||||
|
|
||||||
index = VADDR_TO_PDENT(address);
|
|
||||||
if (PDE_TYPE(pr[index]) != DT_DIR) {
|
|
||||||
panic("page %p has mapping for area %p (%#" B_PRIxADDR "), but "
|
|
||||||
"has no page dir entry", page, area, address);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
page_table_entry* pt
|
|
||||||
= (page_table_entry*)MapperGetPageTableAt(
|
|
||||||
pd[index] & M68K_PDE_ADDRESS_MASK);
|
|
||||||
|
|
||||||
//XXX:M68K: DT_INDIRECT here?
|
|
||||||
|
|
||||||
page_table_entry oldEntry
|
|
||||||
= M68KPagingMethod040::ClearPageTableEntry(
|
|
||||||
&pt[VADDR_TO_PTENT(address)]);
|
|
||||||
|
|
||||||
pinner.Unlock();
|
|
||||||
|
|
||||||
if (PTE_TYPE(oldEntry) != DT_PAGE) {
|
|
||||||
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 & M68K_PTE_ACCESSED) != 0) {
|
|
||||||
page->accessed = true;
|
|
||||||
|
|
||||||
if (!deletingAddressSpace)
|
|
||||||
InvalidatePage(address);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((oldEntry & M68K_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())
|
|
||||||
vm_free_page_mapping(mapping->page->physical_page_number, mapping, freeFlags);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
M68KVMTranslationMap040::Query(addr_t va, phys_addr_t *_physical,
|
M68KVMTranslationMap040::Query(addr_t va, phys_addr_t *_physical,
|
||||||
uint32 *_flags)
|
uint32 *_flags)
|
||||||
|
|||||||
@@ -27,12 +27,11 @@ struct M68KVMTranslationMap040 : M68KVMTranslationMap {
|
|||||||
virtual status_t Unmap(addr_t start, addr_t end);
|
virtual status_t Unmap(addr_t start, addr_t end);
|
||||||
|
|
||||||
virtual status_t UnmapPage(VMArea* area, addr_t address,
|
virtual status_t UnmapPage(VMArea* area, addr_t address,
|
||||||
bool updatePageQueue);
|
bool updatePageQueue,
|
||||||
|
bool deletingAddressSpace, uint32* _flags);
|
||||||
virtual void UnmapPages(VMArea* area, addr_t base,
|
virtual void UnmapPages(VMArea* area, addr_t base,
|
||||||
size_t size, bool updatePageQueue);
|
size_t size, bool updatePageQueue,
|
||||||
virtual void UnmapArea(VMArea* area,
|
bool deletingAddressSpace);
|
||||||
bool deletingAddressSpace,
|
|
||||||
bool ignoreTopCachePageFlags);
|
|
||||||
|
|
||||||
virtual status_t Query(addr_t virtualAddress,
|
virtual status_t Query(addr_t virtualAddress,
|
||||||
phys_addr_t* _physicalAddress,
|
phys_addr_t* _physicalAddress,
|
||||||
|
|||||||
@@ -644,14 +644,12 @@ PPCVMTranslationMap460::DebugMarkRangePresent(addr_t start, addr_t end,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*! Caller must have locked the cache of the page to be unmapped.
|
|
||||||
This object shouldn't be locked.
|
|
||||||
*/
|
|
||||||
status_t
|
status_t
|
||||||
PPCVMTranslationMap460::UnmapPage(VMArea* area, addr_t address,
|
PPCVMTranslationMap460::UnmapPage(VMArea* area, addr_t address,
|
||||||
bool updatePageQueue)
|
bool updatePageQueue, bool deletingAddressSpace, uint32* _flags)
|
||||||
{
|
{
|
||||||
ASSERT(address % B_PAGE_SIZE == 0);
|
ASSERT(address % B_PAGE_SIZE == 0);
|
||||||
|
ASSERT(_flags == NULL || !updatePageQueue);
|
||||||
|
|
||||||
RecursiveLocker locker(fLock);
|
RecursiveLocker locker(fLock);
|
||||||
|
|
||||||
@@ -675,10 +673,19 @@ PPCVMTranslationMap460::UnmapPage(VMArea* area, addr_t address,
|
|||||||
|
|
||||||
fMapCount--;
|
fMapCount--;
|
||||||
|
|
||||||
locker.Detach();
|
if (_flags == NULL) {
|
||||||
// PageUnmapped() will unlock for us
|
locker.Detach();
|
||||||
|
// PageUnmapped() will unlock for us
|
||||||
|
|
||||||
PageUnmapped(area, pageNumber, accessed, modified, updatePageQueue);
|
PageUnmapped(area, pageNumber, accessed, modified, updatePageQueue);
|
||||||
|
} else {
|
||||||
|
uint32 flags = PAGE_PRESENT;
|
||||||
|
if (accessed)
|
||||||
|
flags |= PAGE_ACCESSED;
|
||||||
|
if (modified)
|
||||||
|
flags |= PAGE_MODIFIED;
|
||||||
|
*_flags = flags;
|
||||||
|
}
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
|
|
||||||
@@ -747,7 +754,7 @@ PPCVMTranslationMap460::UnmapPage(VMArea* area, addr_t address,
|
|||||||
|
|
||||||
void
|
void
|
||||||
PPCVMTranslationMap460::UnmapPages(VMArea* area, addr_t base, size_t size,
|
PPCVMTranslationMap460::UnmapPages(VMArea* area, addr_t base, size_t size,
|
||||||
bool updatePageQueue)
|
bool updatePageQueue, bool deletingAddressSpace)
|
||||||
{
|
{
|
||||||
panic("%s: UNIMPLEMENTED", __FUNCTION__);
|
panic("%s: UNIMPLEMENTED", __FUNCTION__);
|
||||||
#if 0//X86
|
#if 0//X86
|
||||||
@@ -794,7 +801,8 @@ PPCVMTranslationMap460::UnmapPages(VMArea* area, addr_t base, size_t size,
|
|||||||
// Note, that we only need to invalidate the address, if the
|
// Note, that we only need to invalidate the address, if the
|
||||||
// accessed flags was set, since only then the entry could have
|
// accessed flags was set, since only then the entry could have
|
||||||
// been in any TLB.
|
// been in any TLB.
|
||||||
InvalidatePage(start);
|
if (!deletingAddressSpace)
|
||||||
|
InvalidatePage(start);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (area->cache_type != CACHE_TYPE_DEVICE) {
|
if (area->cache_type != CACHE_TYPE_DEVICE) {
|
||||||
@@ -827,111 +835,6 @@ PPCVMTranslationMap460::UnmapPages(VMArea* area, addr_t base, size_t size,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
PPCVMTranslationMap460::UnmapArea(VMArea* area, bool deletingAddressSpace,
|
|
||||||
bool ignoreTopCachePageFlags)
|
|
||||||
{
|
|
||||||
panic("%s: UNIMPLEMENTED", __FUNCTION__);
|
|
||||||
#if 0//X86
|
|
||||||
if (area->cache_type == CACHE_TYPE_DEVICE || area->wiring != B_NO_LOCK) {
|
|
||||||
PPCVMTranslationMap460::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.TakeFrom(&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] & PPC_PDE_PRESENT) == 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] & PPC_PDE_ADDRESS_MASK);
|
|
||||||
page_table_entry oldEntry
|
|
||||||
= PPCPagingMethod460::ClearPageTableEntry(
|
|
||||||
&pt[VADDR_TO_PTENT(address)]);
|
|
||||||
|
|
||||||
pinner.Unlock();
|
|
||||||
|
|
||||||
if ((oldEntry & PPC_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 & PPC_PTE_ACCESSED) != 0) {
|
|
||||||
page->accessed = true;
|
|
||||||
|
|
||||||
if (!deletingAddressSpace)
|
|
||||||
InvalidatePage(address);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((oldEntry & PPC_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())
|
|
||||||
vm_free_page_mapping(mapping->page->physical_page_number, mapping, freeFlags);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
PPCVMTranslationMap460::Query(addr_t va, phys_addr_t *_outPhysical,
|
PPCVMTranslationMap460::Query(addr_t va, phys_addr_t *_outPhysical,
|
||||||
uint32 *_outFlags)
|
uint32 *_outFlags)
|
||||||
|
|||||||
@@ -42,12 +42,11 @@ struct PPCVMTranslationMap460 : PPCVMTranslationMap {
|
|||||||
bool markPresent);
|
bool markPresent);
|
||||||
|
|
||||||
virtual status_t UnmapPage(VMArea* area, addr_t address,
|
virtual status_t UnmapPage(VMArea* area, addr_t address,
|
||||||
bool updatePageQueue);
|
bool updatePageQueue,
|
||||||
|
bool deletingAddressSpace, uint32* _flags);
|
||||||
virtual void UnmapPages(VMArea* area, addr_t base,
|
virtual void UnmapPages(VMArea* area, addr_t base,
|
||||||
size_t size, bool updatePageQueue);
|
size_t size, bool updatePageQueue,
|
||||||
virtual void UnmapArea(VMArea* area,
|
bool deletingAddressSpace);
|
||||||
bool deletingAddressSpace,
|
|
||||||
bool ignoreTopCachePageFlags);
|
|
||||||
|
|
||||||
virtual status_t Query(addr_t virtualAddress,
|
virtual status_t Query(addr_t virtualAddress,
|
||||||
phys_addr_t* _physicalAddress,
|
phys_addr_t* _physicalAddress,
|
||||||
|
|||||||
@@ -644,14 +644,12 @@ PPCVMTranslationMapClassic::DebugMarkRangePresent(addr_t start, addr_t end,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*! Caller must have locked the cache of the page to be unmapped.
|
|
||||||
This object shouldn't be locked.
|
|
||||||
*/
|
|
||||||
status_t
|
status_t
|
||||||
PPCVMTranslationMapClassic::UnmapPage(VMArea* area, addr_t address,
|
PPCVMTranslationMapClassic::UnmapPage(VMArea* area, addr_t address,
|
||||||
bool updatePageQueue)
|
bool updatePageQueue, bool deletingAddressSpace, uint32* _flags)
|
||||||
{
|
{
|
||||||
ASSERT(address % B_PAGE_SIZE == 0);
|
ASSERT(address % B_PAGE_SIZE == 0);
|
||||||
|
ASSERT(_flags == NULL || !updatePageQueue);
|
||||||
|
|
||||||
RecursiveLocker locker(fLock);
|
RecursiveLocker locker(fLock);
|
||||||
|
|
||||||
@@ -675,10 +673,19 @@ PPCVMTranslationMapClassic::UnmapPage(VMArea* area, addr_t address,
|
|||||||
|
|
||||||
fMapCount--;
|
fMapCount--;
|
||||||
|
|
||||||
locker.Detach();
|
if (_flags == NULL) {
|
||||||
// PageUnmapped() will unlock for us
|
locker.Detach();
|
||||||
|
// PageUnmapped() will unlock for us
|
||||||
|
|
||||||
PageUnmapped(area, pageNumber, accessed, modified, updatePageQueue);
|
PageUnmapped(area, pageNumber, accessed, modified, updatePageQueue);
|
||||||
|
} else {
|
||||||
|
uint32 flags = PAGE_PRESENT;
|
||||||
|
if (accessed)
|
||||||
|
flags |= PAGE_ACCESSED;
|
||||||
|
if (modified)
|
||||||
|
flags |= PAGE_MODIFIED;
|
||||||
|
*_flags = flags;
|
||||||
|
}
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
|
|
||||||
@@ -747,7 +754,7 @@ PPCVMTranslationMapClassic::UnmapPage(VMArea* area, addr_t address,
|
|||||||
|
|
||||||
void
|
void
|
||||||
PPCVMTranslationMapClassic::UnmapPages(VMArea* area, addr_t base, size_t size,
|
PPCVMTranslationMapClassic::UnmapPages(VMArea* area, addr_t base, size_t size,
|
||||||
bool updatePageQueue)
|
bool updatePageQueue, bool deletingAddressSpace)
|
||||||
{
|
{
|
||||||
panic("%s: UNIMPLEMENTED", __FUNCTION__);
|
panic("%s: UNIMPLEMENTED", __FUNCTION__);
|
||||||
#if 0//X86
|
#if 0//X86
|
||||||
@@ -794,7 +801,8 @@ PPCVMTranslationMapClassic::UnmapPages(VMArea* area, addr_t base, size_t size,
|
|||||||
// Note, that we only need to invalidate the address, if the
|
// Note, that we only need to invalidate the address, if the
|
||||||
// accessed flags was set, since only then the entry could have
|
// accessed flags was set, since only then the entry could have
|
||||||
// been in any TLB.
|
// been in any TLB.
|
||||||
InvalidatePage(start);
|
if (!deletingAddressSpace)
|
||||||
|
InvalidatePage(start);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (area->cache_type != CACHE_TYPE_DEVICE) {
|
if (area->cache_type != CACHE_TYPE_DEVICE) {
|
||||||
@@ -827,111 +835,6 @@ PPCVMTranslationMapClassic::UnmapPages(VMArea* area, addr_t base, size_t size,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
PPCVMTranslationMapClassic::UnmapArea(VMArea* area, bool deletingAddressSpace,
|
|
||||||
bool ignoreTopCachePageFlags)
|
|
||||||
{
|
|
||||||
panic("%s: UNIMPLEMENTED", __FUNCTION__);
|
|
||||||
#if 0//X86
|
|
||||||
if (area->cache_type == CACHE_TYPE_DEVICE || area->wiring != B_NO_LOCK) {
|
|
||||||
PPCVMTranslationMapClassic::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.TakeFrom(&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] & PPC_PDE_PRESENT) == 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] & PPC_PDE_ADDRESS_MASK);
|
|
||||||
page_table_entry oldEntry
|
|
||||||
= PPCPagingMethodClassic::ClearPageTableEntry(
|
|
||||||
&pt[VADDR_TO_PTENT(address)]);
|
|
||||||
|
|
||||||
pinner.Unlock();
|
|
||||||
|
|
||||||
if ((oldEntry & PPC_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 & PPC_PTE_ACCESSED) != 0) {
|
|
||||||
page->accessed = true;
|
|
||||||
|
|
||||||
if (!deletingAddressSpace)
|
|
||||||
InvalidatePage(address);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((oldEntry & PPC_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())
|
|
||||||
vm_free_page_mapping(mapping->page->physical_page_number, mapping, freeFlags);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
PPCVMTranslationMapClassic::Query(addr_t va, phys_addr_t *_outPhysical,
|
PPCVMTranslationMapClassic::Query(addr_t va, phys_addr_t *_outPhysical,
|
||||||
uint32 *_outFlags)
|
uint32 *_outFlags)
|
||||||
|
|||||||
@@ -42,12 +42,11 @@ struct PPCVMTranslationMapClassic : PPCVMTranslationMap {
|
|||||||
bool markPresent);
|
bool markPresent);
|
||||||
|
|
||||||
virtual status_t UnmapPage(VMArea* area, addr_t address,
|
virtual status_t UnmapPage(VMArea* area, addr_t address,
|
||||||
bool updatePageQueue);
|
bool updatePageQueue,
|
||||||
|
bool deletingAddressSpace, uint32* _flags);
|
||||||
virtual void UnmapPages(VMArea* area, addr_t base,
|
virtual void UnmapPages(VMArea* area, addr_t base,
|
||||||
size_t size, bool updatePageQueue);
|
size_t size, bool updatePageQueue,
|
||||||
virtual void UnmapArea(VMArea* area,
|
bool deletingAddressSpace);
|
||||||
bool deletingAddressSpace,
|
|
||||||
bool ignoreTopCachePageFlags);
|
|
||||||
|
|
||||||
virtual status_t Query(addr_t virtualAddress,
|
virtual status_t Query(addr_t virtualAddress,
|
||||||
phys_addr_t* _physicalAddress,
|
phys_addr_t* _physicalAddress,
|
||||||
|
|||||||
@@ -320,23 +320,13 @@ RISCV64VMTranslationMap::DebugMarkRangePresent(addr_t start, addr_t end,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
Things need to be done when unmapping VMArea pages
|
|
||||||
update vm_page::accessed, modified
|
|
||||||
MMIO pages:
|
|
||||||
just unmap
|
|
||||||
wired pages:
|
|
||||||
decrement wired count
|
|
||||||
non-wired pages:
|
|
||||||
remove from VMArea and vm_page `mappings` list
|
|
||||||
wired and non-wird pages
|
|
||||||
vm_page_set_state
|
|
||||||
*/
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
RISCV64VMTranslationMap::UnmapPage(VMArea* area, addr_t address,
|
RISCV64VMTranslationMap::UnmapPage(VMArea* area, addr_t address,
|
||||||
bool updatePageQueue)
|
bool updatePageQueue, bool deletingAddressSpace, uint32* _flags)
|
||||||
{
|
{
|
||||||
|
ASSERT(address % B_PAGE_SIZE == 0);
|
||||||
|
ASSERT(_flags == NULL || !updatePageQueue);
|
||||||
|
|
||||||
TRACE("RISCV64VMTranslationMap::UnmapPage(0x%" B_PRIxADDR "(%s), 0x%"
|
TRACE("RISCV64VMTranslationMap::UnmapPage(0x%" B_PRIxADDR "(%s), 0x%"
|
||||||
B_PRIxADDR ", %d)\n", (addr_t)area, area->name, address,
|
B_PRIxADDR ", %d)\n", (addr_t)area, area->name, address,
|
||||||
updatePageQueue);
|
updatePageQueue);
|
||||||
@@ -353,20 +343,35 @@ RISCV64VMTranslationMap::UnmapPage(VMArea* area, addr_t address,
|
|||||||
fMapCount--;
|
fMapCount--;
|
||||||
pinner.Unlock();
|
pinner.Unlock();
|
||||||
|
|
||||||
if (oldPte.isAccessed)
|
if (oldPte.isAccessed) {
|
||||||
InvalidatePage(address);
|
if (!deletingAddressSpace)
|
||||||
|
InvalidatePage(address);
|
||||||
|
|
||||||
Flush();
|
if (_flags == NULL)
|
||||||
|
Flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_flags == NULL) {
|
||||||
|
locker.Detach();
|
||||||
|
// PageUnmapped() will unlock for us
|
||||||
|
|
||||||
|
PageUnmapped(area, oldPte.ppn, oldPte.isAccessed, oldPte.isDirty, updatePageQueue);
|
||||||
|
} else {
|
||||||
|
uint32 flags = PAGE_PRESENT;
|
||||||
|
if (oldPte.isAccessed)
|
||||||
|
flags |= PAGE_ACCESSED;
|
||||||
|
if (oldPte.isDirty)
|
||||||
|
flags |= PAGE_MODIFIED;
|
||||||
|
*_flags = flags;
|
||||||
|
}
|
||||||
|
|
||||||
locker.Detach(); // PageUnmapped takes ownership
|
|
||||||
PageUnmapped(area, oldPte.ppn, oldPte.isAccessed, oldPte.isDirty, updatePageQueue);
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
RISCV64VMTranslationMap::UnmapPages(VMArea* area, addr_t base, size_t size,
|
RISCV64VMTranslationMap::UnmapPages(VMArea* area, addr_t base, size_t size,
|
||||||
bool updatePageQueue)
|
bool updatePageQueue, bool deletingAddressSpace)
|
||||||
{
|
{
|
||||||
TRACE("RISCV64VMTranslationMap::UnmapPages(0x%" B_PRIxADDR "(%s), 0x%"
|
TRACE("RISCV64VMTranslationMap::UnmapPages(0x%" B_PRIxADDR "(%s), 0x%"
|
||||||
B_PRIxADDR ", 0x%" B_PRIxSIZE ", %d)\n", (addr_t)area,
|
B_PRIxADDR ", 0x%" B_PRIxSIZE ", %d)\n", (addr_t)area,
|
||||||
@@ -392,7 +397,7 @@ RISCV64VMTranslationMap::UnmapPages(VMArea* area, addr_t base, size_t size,
|
|||||||
|
|
||||||
fMapCount--;
|
fMapCount--;
|
||||||
|
|
||||||
if (oldPte.isAccessed)
|
if (oldPte.isAccessed && !deletingAddressSpace)
|
||||||
InvalidatePage(start);
|
InvalidatePage(start);
|
||||||
|
|
||||||
if (area->cache_type != CACHE_TYPE_DEVICE) {
|
if (area->cache_type != CACHE_TYPE_DEVICE) {
|
||||||
@@ -421,104 +426,6 @@ RISCV64VMTranslationMap::UnmapPages(VMArea* area, addr_t base, size_t size,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
RISCV64VMTranslationMap::UnmapArea(VMArea* area, bool deletingAddressSpace,
|
|
||||||
bool ignoreTopCachePageFlags)
|
|
||||||
{
|
|
||||||
TRACE("RISCV64VMTranslationMap::UnmapArea(0x%" B_PRIxADDR "(%s), 0x%"
|
|
||||||
B_PRIxADDR ", 0x%" B_PRIxSIZE ", %d, %d)\n", (addr_t)area,
|
|
||||||
area->name, area->Base(), area->Size(), deletingAddressSpace,
|
|
||||||
ignoreTopCachePageFlags);
|
|
||||||
|
|
||||||
if (area->cache_type == CACHE_TYPE_DEVICE || area->wiring != B_NO_LOCK) {
|
|
||||||
UnmapPages(area, area->Base(), area->Size(), true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool unmapPages = !deletingAddressSpace || !ignoreTopCachePageFlags;
|
|
||||||
|
|
||||||
RecursiveLocker locker(fLock);
|
|
||||||
ThreadCPUPinner pinner(thread_get_current_thread());
|
|
||||||
|
|
||||||
VMAreaMappings mappings;
|
|
||||||
mappings.TakeFrom(&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);
|
|
||||||
|
|
||||||
std::atomic<Pte>* pte = LookupPte(address, false, NULL);
|
|
||||||
if (pte == NULL || !pte->load().isValid) {
|
|
||||||
panic("page %p has mapping for area %p "
|
|
||||||
"(%#" B_PRIxADDR "), but has no "
|
|
||||||
"page table", page, area, address);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
Pte oldPte = pte->exchange({});
|
|
||||||
|
|
||||||
// transfer the accessed/dirty flags to the page and
|
|
||||||
// invalidate the mapping, if necessary
|
|
||||||
if (oldPte.isAccessed) {
|
|
||||||
page->accessed = true;
|
|
||||||
|
|
||||||
if (!deletingAddressSpace)
|
|
||||||
InvalidatePage(address);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (oldPte.isDirty)
|
|
||||||
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())
|
|
||||||
vm_free_page_mapping(mapping->page->physical_page_number, mapping, freeFlags);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
RISCV64VMTranslationMap::Query(addr_t virtualAddress,
|
RISCV64VMTranslationMap::Query(addr_t virtualAddress,
|
||||||
phys_addr_t* _physicalAddress, uint32* _flags)
|
phys_addr_t* _physicalAddress, uint32* _flags)
|
||||||
|
|||||||
@@ -43,12 +43,11 @@ struct RISCV64VMTranslationMap: public VMTranslationMap {
|
|||||||
bool markPresent);
|
bool markPresent);
|
||||||
|
|
||||||
virtual status_t UnmapPage(VMArea* area, addr_t address,
|
virtual status_t UnmapPage(VMArea* area, addr_t address,
|
||||||
bool updatePageQueue);
|
bool updatePageQueue,
|
||||||
|
bool deletingAddressSpace, uint32* _flags);
|
||||||
virtual void UnmapPages(VMArea* area, addr_t base,
|
virtual void UnmapPages(VMArea* area, addr_t base,
|
||||||
size_t size, bool updatePageQueue);
|
size_t size, bool updatePageQueue,
|
||||||
virtual void UnmapArea(VMArea* area,
|
bool deletingAddressSpace);
|
||||||
bool deletingAddressSpace,
|
|
||||||
bool ignoreTopCachePageFlags);
|
|
||||||
|
|
||||||
virtual status_t Query(addr_t virtualAddress,
|
virtual status_t Query(addr_t virtualAddress,
|
||||||
phys_addr_t* _physicalAddress,
|
phys_addr_t* _physicalAddress,
|
||||||
|
|||||||
@@ -319,14 +319,12 @@ X86VMTranslationMap32Bit::DebugMarkRangePresent(addr_t start, addr_t end,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*! Caller must have locked the cache of the page to be unmapped.
|
|
||||||
This object shouldn't be locked.
|
|
||||||
*/
|
|
||||||
status_t
|
status_t
|
||||||
X86VMTranslationMap32Bit::UnmapPage(VMArea* area, addr_t address,
|
X86VMTranslationMap32Bit::UnmapPage(VMArea* area, addr_t address,
|
||||||
bool updatePageQueue)
|
bool updatePageQueue, bool deletingAddressSpace, uint32* _flags)
|
||||||
{
|
{
|
||||||
ASSERT(address % B_PAGE_SIZE == 0);
|
ASSERT(address % B_PAGE_SIZE == 0);
|
||||||
|
ASSERT(_flags == NULL || !updatePageQueue);
|
||||||
|
|
||||||
page_directory_entry* pd = fPagingStructures->pgdir_virt;
|
page_directory_entry* pd = fPagingStructures->pgdir_virt;
|
||||||
|
|
||||||
@@ -360,8 +358,13 @@ X86VMTranslationMap32Bit::UnmapPage(VMArea* area, addr_t address,
|
|||||||
// Note, that we only need to invalidate the address, if the
|
// Note, that we only need to invalidate the address, if the
|
||||||
// accessed flags was set, since only then the entry could have been
|
// accessed flags was set, since only then the entry could have been
|
||||||
// in any TLB.
|
// in any TLB.
|
||||||
InvalidatePage(address);
|
if (!deletingAddressSpace)
|
||||||
Flush();
|
InvalidatePage(address);
|
||||||
|
|
||||||
|
if (_flags == NULL) {
|
||||||
|
Flush();
|
||||||
|
// flush explicitly, since we directly use the lock
|
||||||
|
}
|
||||||
|
|
||||||
// NOTE: Between clearing the page table entry and Flush() other
|
// NOTE: Between clearing the page table entry and Flush() other
|
||||||
// processors (actually even this processor with another thread of the
|
// processors (actually even this processor with another thread of the
|
||||||
@@ -375,12 +378,21 @@ X86VMTranslationMap32Bit::UnmapPage(VMArea* area, addr_t address,
|
|||||||
// (cf. pmap_remove_all()), unless I've missed something.
|
// (cf. pmap_remove_all()), unless I've missed something.
|
||||||
}
|
}
|
||||||
|
|
||||||
locker.Detach();
|
if (_flags == NULL) {
|
||||||
// PageUnmapped() will unlock for us
|
locker.Detach();
|
||||||
|
// PageUnmapped() will unlock for us
|
||||||
|
|
||||||
PageUnmapped(area, (oldEntry & X86_PTE_ADDRESS_MASK) / B_PAGE_SIZE,
|
PageUnmapped(area, (oldEntry & X86_PTE_ADDRESS_MASK) / B_PAGE_SIZE,
|
||||||
(oldEntry & X86_PTE_ACCESSED) != 0, (oldEntry & X86_PTE_DIRTY) != 0,
|
(oldEntry & X86_PTE_ACCESSED) != 0,
|
||||||
updatePageQueue);
|
(oldEntry & X86_PTE_DIRTY) != 0, updatePageQueue);
|
||||||
|
} else {
|
||||||
|
uint32 flags = PAGE_PRESENT;
|
||||||
|
if ((oldEntry & X86_PTE_ACCESSED) != 0)
|
||||||
|
flags |= PAGE_ACCESSED;
|
||||||
|
if ((oldEntry & X86_PTE_DIRTY) != 0)
|
||||||
|
flags |= PAGE_MODIFIED;
|
||||||
|
*_flags = flags;
|
||||||
|
}
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
@@ -388,7 +400,7 @@ X86VMTranslationMap32Bit::UnmapPage(VMArea* area, addr_t address,
|
|||||||
|
|
||||||
void
|
void
|
||||||
X86VMTranslationMap32Bit::UnmapPages(VMArea* area, addr_t base, size_t size,
|
X86VMTranslationMap32Bit::UnmapPages(VMArea* area, addr_t base, size_t size,
|
||||||
bool updatePageQueue)
|
bool updatePageQueue, bool deletingAddressSpace)
|
||||||
{
|
{
|
||||||
if (size == 0)
|
if (size == 0)
|
||||||
return;
|
return;
|
||||||
@@ -433,7 +445,8 @@ X86VMTranslationMap32Bit::UnmapPages(VMArea* area, addr_t base, size_t size,
|
|||||||
// Note, that we only need to invalidate the address, if the
|
// Note, that we only need to invalidate the address, if the
|
||||||
// accessed flags was set, since only then the entry could have
|
// accessed flags was set, since only then the entry could have
|
||||||
// been in any TLB.
|
// been in any TLB.
|
||||||
InvalidatePage(start);
|
if (!deletingAddressSpace)
|
||||||
|
InvalidatePage(start);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (area->cache_type != CACHE_TYPE_DEVICE) {
|
if (area->cache_type != CACHE_TYPE_DEVICE) {
|
||||||
@@ -465,108 +478,6 @@ X86VMTranslationMap32Bit::UnmapPages(VMArea* area, addr_t base, size_t size,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
X86VMTranslationMap32Bit::UnmapArea(VMArea* area, bool deletingAddressSpace,
|
|
||||||
bool ignoreTopCachePageFlags)
|
|
||||||
{
|
|
||||||
if (area->cache_type == CACHE_TYPE_DEVICE || area->wiring != B_NO_LOCK) {
|
|
||||||
X86VMTranslationMap32Bit::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.TakeFrom(&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] & X86_PDE_PRESENT) == 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] & X86_PDE_ADDRESS_MASK);
|
|
||||||
page_table_entry oldEntry
|
|
||||||
= X86PagingMethod32Bit::ClearPageTableEntry(
|
|
||||||
&pt[VADDR_TO_PTENT(address)]);
|
|
||||||
|
|
||||||
pinner.Unlock();
|
|
||||||
|
|
||||||
if ((oldEntry & X86_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_PTE_ACCESSED) != 0) {
|
|
||||||
page->accessed = true;
|
|
||||||
|
|
||||||
if (!deletingAddressSpace)
|
|
||||||
InvalidatePage(address);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((oldEntry & X86_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())
|
|
||||||
vm_free_page_mapping(mapping->page->physical_page_number, mapping, freeFlags);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
X86VMTranslationMap32Bit::Query(addr_t va, phys_addr_t *_physical,
|
X86VMTranslationMap32Bit::Query(addr_t va, phys_addr_t *_physical,
|
||||||
uint32 *_flags)
|
uint32 *_flags)
|
||||||
|
|||||||
@@ -31,12 +31,11 @@ struct X86VMTranslationMap32Bit final : X86VMTranslationMap {
|
|||||||
bool markPresent);
|
bool markPresent);
|
||||||
|
|
||||||
virtual status_t UnmapPage(VMArea* area, addr_t address,
|
virtual status_t UnmapPage(VMArea* area, addr_t address,
|
||||||
bool updatePageQueue);
|
bool updatePageQueue,
|
||||||
|
bool deletingAddressSpace, uint32* _flags);
|
||||||
virtual void UnmapPages(VMArea* area, addr_t base,
|
virtual void UnmapPages(VMArea* area, addr_t base,
|
||||||
size_t size, bool updatePageQueue);
|
size_t size, bool updatePageQueue,
|
||||||
virtual void UnmapArea(VMArea* area,
|
bool deletingAddressSpace);
|
||||||
bool deletingAddressSpace,
|
|
||||||
bool ignoreTopCachePageFlags);
|
|
||||||
|
|
||||||
virtual status_t Query(addr_t virtualAddress,
|
virtual status_t Query(addr_t virtualAddress,
|
||||||
phys_addr_t* _physicalAddress,
|
phys_addr_t* _physicalAddress,
|
||||||
|
|||||||
@@ -337,9 +337,10 @@ X86VMTranslationMap64Bit::DebugMarkRangePresent(addr_t start, addr_t end,
|
|||||||
|
|
||||||
status_t
|
status_t
|
||||||
X86VMTranslationMap64Bit::UnmapPage(VMArea* area, addr_t address,
|
X86VMTranslationMap64Bit::UnmapPage(VMArea* area, addr_t address,
|
||||||
bool updatePageQueue)
|
bool updatePageQueue, bool deletingAddressSpace, uint32* _flags)
|
||||||
{
|
{
|
||||||
ASSERT(address % B_PAGE_SIZE == 0);
|
ASSERT(address % B_PAGE_SIZE == 0);
|
||||||
|
ASSERT(_flags == NULL || !updatePageQueue);
|
||||||
|
|
||||||
TRACE("X86VMTranslationMap64Bit::UnmapPage(%#" B_PRIxADDR ")\n", address);
|
TRACE("X86VMTranslationMap64Bit::UnmapPage(%#" B_PRIxADDR ")\n", address);
|
||||||
|
|
||||||
@@ -367,9 +368,13 @@ X86VMTranslationMap64Bit::UnmapPage(VMArea* area, addr_t address,
|
|||||||
// Note, that we only need to invalidate the address, if the
|
// Note, that we only need to invalidate the address, if the
|
||||||
// accessed flags was set, since only then the entry could have been
|
// accessed flags was set, since only then the entry could have been
|
||||||
// in any TLB.
|
// in any TLB.
|
||||||
InvalidatePage(address);
|
if (!deletingAddressSpace)
|
||||||
|
InvalidatePage(address);
|
||||||
|
|
||||||
Flush();
|
if (_flags == NULL) {
|
||||||
|
Flush();
|
||||||
|
// flush explicitly, since we directly use the lock
|
||||||
|
}
|
||||||
|
|
||||||
// NOTE: Between clearing the page table entry and Flush() other
|
// NOTE: Between clearing the page table entry and Flush() other
|
||||||
// processors (actually even this processor with another thread of the
|
// processors (actually even this processor with another thread of the
|
||||||
@@ -383,12 +388,21 @@ X86VMTranslationMap64Bit::UnmapPage(VMArea* area, addr_t address,
|
|||||||
// (cf. pmap_remove_all()), unless I've missed something.
|
// (cf. pmap_remove_all()), unless I've missed something.
|
||||||
}
|
}
|
||||||
|
|
||||||
locker.Detach();
|
if (_flags == NULL) {
|
||||||
// PageUnmapped() will unlock for us
|
locker.Detach();
|
||||||
|
// PageUnmapped() will unlock for us
|
||||||
|
|
||||||
PageUnmapped(area, (oldEntry & X86_64_PTE_ADDRESS_MASK) / B_PAGE_SIZE,
|
PageUnmapped(area, (oldEntry & X86_64_PTE_ADDRESS_MASK) / B_PAGE_SIZE,
|
||||||
(oldEntry & X86_64_PTE_ACCESSED) != 0,
|
(oldEntry & X86_64_PTE_ACCESSED) != 0,
|
||||||
(oldEntry & X86_64_PTE_DIRTY) != 0, updatePageQueue);
|
(oldEntry & X86_64_PTE_DIRTY) != 0, updatePageQueue);
|
||||||
|
} else {
|
||||||
|
uint32 flags = PAGE_PRESENT;
|
||||||
|
if ((oldEntry & X86_64_PTE_ACCESSED) != 0)
|
||||||
|
flags |= PAGE_ACCESSED;
|
||||||
|
if ((oldEntry & X86_64_PTE_DIRTY) != 0)
|
||||||
|
flags |= PAGE_MODIFIED;
|
||||||
|
*_flags = flags;
|
||||||
|
}
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
@@ -396,7 +410,7 @@ X86VMTranslationMap64Bit::UnmapPage(VMArea* area, addr_t address,
|
|||||||
|
|
||||||
void
|
void
|
||||||
X86VMTranslationMap64Bit::UnmapPages(VMArea* area, addr_t base, size_t size,
|
X86VMTranslationMap64Bit::UnmapPages(VMArea* area, addr_t base, size_t size,
|
||||||
bool updatePageQueue)
|
bool updatePageQueue, bool deletingAddressSpace)
|
||||||
{
|
{
|
||||||
if (size == 0)
|
if (size == 0)
|
||||||
return;
|
return;
|
||||||
@@ -436,7 +450,8 @@ X86VMTranslationMap64Bit::UnmapPages(VMArea* area, addr_t base, size_t size,
|
|||||||
// Note, that we only need to invalidate the address, if the
|
// Note, that we only need to invalidate the address, if the
|
||||||
// accessed flags was set, since only then the entry could have
|
// accessed flags was set, since only then the entry could have
|
||||||
// been in any TLB.
|
// been in any TLB.
|
||||||
InvalidatePage(start);
|
if (!deletingAddressSpace)
|
||||||
|
InvalidatePage(start);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (area->cache_type != CACHE_TYPE_DEVICE) {
|
if (area->cache_type != CACHE_TYPE_DEVICE) {
|
||||||
@@ -468,102 +483,6 @@ X86VMTranslationMap64Bit::UnmapPages(VMArea* area, addr_t base, size_t size,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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.TakeFrom(&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->VirtualPMLTop(), 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())
|
|
||||||
vm_free_page_mapping(mapping->page->physical_page_number, mapping, freeFlags);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
X86VMTranslationMap64Bit::Query(addr_t virtualAddress,
|
X86VMTranslationMap64Bit::Query(addr_t virtualAddress,
|
||||||
phys_addr_t* _physicalAddress, uint32* _flags)
|
phys_addr_t* _physicalAddress, uint32* _flags)
|
||||||
|
|||||||
@@ -32,12 +32,11 @@ struct X86VMTranslationMap64Bit final : X86VMTranslationMap {
|
|||||||
bool markPresent);
|
bool markPresent);
|
||||||
|
|
||||||
virtual status_t UnmapPage(VMArea* area, addr_t address,
|
virtual status_t UnmapPage(VMArea* area, addr_t address,
|
||||||
bool updatePageQueue);
|
bool updatePageQueue,
|
||||||
|
bool deletingAddressSpace, uint32* _flags);
|
||||||
virtual void UnmapPages(VMArea* area, addr_t base,
|
virtual void UnmapPages(VMArea* area, addr_t base,
|
||||||
size_t size, bool updatePageQueue);
|
size_t size, bool updatePageQueue,
|
||||||
virtual void UnmapArea(VMArea* area,
|
bool deletingAddressSpace);
|
||||||
bool deletingAddressSpace,
|
|
||||||
bool ignoreTopCachePageFlags);
|
|
||||||
|
|
||||||
virtual status_t Query(addr_t virtualAddress,
|
virtual status_t Query(addr_t virtualAddress,
|
||||||
phys_addr_t* _physicalAddress,
|
phys_addr_t* _physicalAddress,
|
||||||
|
|||||||
@@ -558,27 +558,25 @@ X86VMTranslationMapPAE::DebugMarkRangePresent(addr_t start, addr_t end,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*! Caller must have locked the cache of the page to be unmapped.
|
|
||||||
This object shouldn't be locked.
|
|
||||||
*/
|
|
||||||
status_t
|
status_t
|
||||||
X86VMTranslationMapPAE::UnmapPage(VMArea* area, addr_t address,
|
X86VMTranslationMapPAE::UnmapPage(VMArea* area, addr_t address,
|
||||||
bool updatePageQueue)
|
bool updatePageQueue, bool deletingAddressSpace, uint32* _flags)
|
||||||
{
|
{
|
||||||
ASSERT(address % B_PAGE_SIZE == 0);
|
ASSERT(address % B_PAGE_SIZE == 0);
|
||||||
|
ASSERT(_flags == NULL || !updatePageQueue);
|
||||||
|
|
||||||
|
TRACE("X86VMTranslationMapPAE::UnmapPage(%#" B_PRIxADDR ")\n", address);
|
||||||
|
|
||||||
|
ThreadCPUPinner pinner(thread_get_current_thread());
|
||||||
|
|
||||||
pae_page_directory_entry* pageDirEntry
|
pae_page_directory_entry* pageDirEntry
|
||||||
= X86PagingMethodPAE::PageDirEntryForAddress(
|
= X86PagingMethodPAE::PageDirEntryForAddress(
|
||||||
fPagingStructures->VirtualPageDirs(), address);
|
fPagingStructures->VirtualPageDirs(), address);
|
||||||
|
|
||||||
TRACE("X86VMTranslationMapPAE::UnmapPage(%#" B_PRIxADDR ")\n", address);
|
|
||||||
|
|
||||||
RecursiveLocker locker(fLock);
|
|
||||||
|
|
||||||
if ((*pageDirEntry & X86_PAE_PDE_PRESENT) == 0)
|
if ((*pageDirEntry & X86_PAE_PDE_PRESENT) == 0)
|
||||||
return B_ENTRY_NOT_FOUND;
|
return B_ENTRY_NOT_FOUND;
|
||||||
|
|
||||||
ThreadCPUPinner pinner(thread_get_current_thread());
|
RecursiveLocker locker(fLock);
|
||||||
|
|
||||||
pae_page_table_entry* pageTable
|
pae_page_table_entry* pageTable
|
||||||
= (pae_page_table_entry*)fPageMapper->GetPageTableAt(
|
= (pae_page_table_entry*)fPageMapper->GetPageTableAt(
|
||||||
@@ -602,9 +600,13 @@ X86VMTranslationMapPAE::UnmapPage(VMArea* area, addr_t address,
|
|||||||
// Note, that we only need to invalidate the address, if the
|
// Note, that we only need to invalidate the address, if the
|
||||||
// accessed flags was set, since only then the entry could have been
|
// accessed flags was set, since only then the entry could have been
|
||||||
// in any TLB.
|
// in any TLB.
|
||||||
InvalidatePage(address);
|
if (!deletingAddressSpace)
|
||||||
|
InvalidatePage(address);
|
||||||
|
|
||||||
Flush();
|
if (_flags == NULL) {
|
||||||
|
Flush();
|
||||||
|
// flush explicitly, since we directly use the lock
|
||||||
|
}
|
||||||
|
|
||||||
// NOTE: Between clearing the page table entry and Flush() other
|
// NOTE: Between clearing the page table entry and Flush() other
|
||||||
// processors (actually even this processor with another thread of the
|
// processors (actually even this processor with another thread of the
|
||||||
@@ -631,7 +633,7 @@ X86VMTranslationMapPAE::UnmapPage(VMArea* area, addr_t address,
|
|||||||
|
|
||||||
void
|
void
|
||||||
X86VMTranslationMapPAE::UnmapPages(VMArea* area, addr_t base, size_t size,
|
X86VMTranslationMapPAE::UnmapPages(VMArea* area, addr_t base, size_t size,
|
||||||
bool updatePageQueue)
|
bool updatePageQueue, bool deletingAddressSpace)
|
||||||
{
|
{
|
||||||
if (size == 0)
|
if (size == 0)
|
||||||
return;
|
return;
|
||||||
@@ -680,7 +682,8 @@ X86VMTranslationMapPAE::UnmapPages(VMArea* area, addr_t base, size_t size,
|
|||||||
// Note, that we only need to invalidate the address, if the
|
// Note, that we only need to invalidate the address, if the
|
||||||
// accessed flags was set, since only then the entry could have
|
// accessed flags was set, since only then the entry could have
|
||||||
// been in any TLB.
|
// been in any TLB.
|
||||||
InvalidatePage(start);
|
if (!deletingAddressSpace)
|
||||||
|
InvalidatePage(start);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (area->cache_type != CACHE_TYPE_DEVICE) {
|
if (area->cache_type != CACHE_TYPE_DEVICE) {
|
||||||
@@ -712,134 +715,6 @@ X86VMTranslationMapPAE::UnmapPages(VMArea* area, addr_t base, size_t size,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
X86VMTranslationMapPAE::UnmapArea(VMArea* area, bool deletingAddressSpace,
|
|
||||||
bool ignoreTopCachePageFlags)
|
|
||||||
{
|
|
||||||
if (area->cache_type == CACHE_TYPE_DEVICE || area->wiring != B_NO_LOCK) {
|
|
||||||
X86VMTranslationMapPAE::UnmapPages(area, area->Base(), area->Size(),
|
|
||||||
true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool unmapPages = !deletingAddressSpace || !ignoreTopCachePageFlags;
|
|
||||||
|
|
||||||
RecursiveLocker locker(fLock);
|
|
||||||
|
|
||||||
VMAreaMappings mappings;
|
|
||||||
mappings.TakeFrom(&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);
|
|
||||||
|
|
||||||
pae_page_directory_entry* pageDirEntry
|
|
||||||
= X86PagingMethodPAE::PageDirEntryForAddress(
|
|
||||||
fPagingStructures->VirtualPageDirs(), address);
|
|
||||||
if ((*pageDirEntry & X86_PAE_PDE_PRESENT) == 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());
|
|
||||||
|
|
||||||
pae_page_table_entry* pageTable
|
|
||||||
= (pae_page_table_entry*)fPageMapper->GetPageTableAt(
|
|
||||||
*pageDirEntry & X86_PAE_PDE_ADDRESS_MASK);
|
|
||||||
pae_page_table_entry oldEntry
|
|
||||||
= X86PagingMethodPAE::ClearTableEntry(
|
|
||||||
&pageTable[address / B_PAGE_SIZE
|
|
||||||
% kPAEPageTableEntryCount]);
|
|
||||||
|
|
||||||
pinner.Unlock();
|
|
||||||
|
|
||||||
if ((oldEntry & X86_PAE_PTE_PRESENT) == 0) {
|
|
||||||
panic("page %p has mapping for area %p (%#" B_PRIxADDR "), but "
|
|
||||||
"has no page table entry", page, area, address);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
T(Unmap(this, address, oldEntry));
|
|
||||||
|
|
||||||
// transfer the accessed/dirty flags to the page and invalidate
|
|
||||||
// the mapping, if necessary
|
|
||||||
if ((oldEntry & X86_PAE_PTE_ACCESSED) != 0) {
|
|
||||||
page->accessed = true;
|
|
||||||
|
|
||||||
if (!deletingAddressSpace)
|
|
||||||
InvalidatePage(address);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((oldEntry & X86_PAE_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);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
#if TRANSLATION_MAP_TRACING
|
|
||||||
addr_t address = area->Base()
|
|
||||||
+ ((page->cache_offset * B_PAGE_SIZE) - area->cache_offset);
|
|
||||||
|
|
||||||
ThreadCPUPinner pinner(thread_get_current_thread());
|
|
||||||
|
|
||||||
pae_page_directory_entry* pageDirEntry
|
|
||||||
= X86PagingMethodPAE::PageDirEntryForAddress(
|
|
||||||
fPagingStructures->VirtualPageDirs(), address);
|
|
||||||
if ((*pageDirEntry & X86_PAE_PDE_PRESENT) != 0) {
|
|
||||||
pae_page_table_entry* pageTable
|
|
||||||
= (pae_page_table_entry*)fPageMapper->GetPageTableAt(
|
|
||||||
*pageDirEntry & X86_PAE_PDE_ADDRESS_MASK);
|
|
||||||
pae_page_table_entry oldEntry = pageTable[
|
|
||||||
address / B_PAGE_SIZE % kPAEPageTableEntryCount];
|
|
||||||
|
|
||||||
pinner.Unlock();
|
|
||||||
|
|
||||||
if ((oldEntry & X86_PAE_PTE_PRESENT) != 0)
|
|
||||||
T(Unmap(this, address, oldEntry));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
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())
|
|
||||||
vm_free_page_mapping(mapping->page->physical_page_number, mapping, freeFlags);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
X86VMTranslationMapPAE::Query(addr_t virtualAddress,
|
X86VMTranslationMapPAE::Query(addr_t virtualAddress,
|
||||||
phys_addr_t* _physicalAddress, uint32* _flags)
|
phys_addr_t* _physicalAddress, uint32* _flags)
|
||||||
|
|||||||
@@ -34,12 +34,11 @@ struct X86VMTranslationMapPAE final : X86VMTranslationMap {
|
|||||||
bool markPresent);
|
bool markPresent);
|
||||||
|
|
||||||
virtual status_t UnmapPage(VMArea* area, addr_t address,
|
virtual status_t UnmapPage(VMArea* area, addr_t address,
|
||||||
bool updatePageQueue);
|
bool updatePageQueue,
|
||||||
|
bool deletingAddressSpace, uint32* _flags);
|
||||||
virtual void UnmapPages(VMArea* area, addr_t base,
|
virtual void UnmapPages(VMArea* area, addr_t base,
|
||||||
size_t size, bool updatePageQueue);
|
size_t size, bool updatePageQueue,
|
||||||
virtual void UnmapArea(VMArea* area,
|
bool deletingAddressSpace);
|
||||||
bool deletingAddressSpace,
|
|
||||||
bool ignoreTopCachePageFlags);
|
|
||||||
|
|
||||||
virtual status_t Query(addr_t virtualAddress,
|
virtual status_t Query(addr_t virtualAddress,
|
||||||
phys_addr_t* _physicalAddress,
|
phys_addr_t* _physicalAddress,
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ VMTranslationMap::DebugMarkRangePresent(addr_t start, addr_t end,
|
|||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
VMTranslationMap::UnmapPages(VMArea* area, addr_t base, size_t size,
|
VMTranslationMap::UnmapPages(VMArea* area, addr_t base, size_t size,
|
||||||
bool updatePageQueue)
|
bool updatePageQueue, bool deletingAddressSpace)
|
||||||
{
|
{
|
||||||
ASSERT(base % B_PAGE_SIZE == 0);
|
ASSERT(base % B_PAGE_SIZE == 0);
|
||||||
ASSERT(size % B_PAGE_SIZE == 0);
|
ASSERT(size % B_PAGE_SIZE == 0);
|
||||||
@@ -62,57 +62,113 @@ VMTranslationMap::UnmapPages(VMArea* area, addr_t base, size_t size,
|
|||||||
vm_page* page = vm_lookup_page(physicalAddress / B_PAGE_SIZE);
|
vm_page* page = vm_lookup_page(physicalAddress / B_PAGE_SIZE);
|
||||||
if (page != NULL) {
|
if (page != NULL) {
|
||||||
DEBUG_PAGE_ACCESS_START(page);
|
DEBUG_PAGE_ACCESS_START(page);
|
||||||
UnmapPage(area, address, updatePageQueue);
|
UnmapPage(area, address, updatePageQueue, deletingAddressSpace);
|
||||||
DEBUG_PAGE_ACCESS_END(page);
|
DEBUG_PAGE_ACCESS_END(page);
|
||||||
} else
|
} else
|
||||||
UnmapPage(area, address, updatePageQueue);
|
UnmapPage(area, address, updatePageQueue, deletingAddressSpace);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
for (; address != end; address += B_PAGE_SIZE)
|
for (; address != end; address += B_PAGE_SIZE)
|
||||||
UnmapPage(area, address, updatePageQueue);
|
UnmapPage(area, address, updatePageQueue, deletingAddressSpace);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*! Unmaps all of an area's pages.
|
/*! Unmaps all of an area's pages.
|
||||||
|
|
||||||
If \a deletingAddressSpace is \c true, the address space the area belongs to
|
If \a deletingAddressSpace is \c true, the address space the area belongs to
|
||||||
is in the process of being destroyed and isn't used by anyone anymore. For
|
is in the process of being destroyed and isn't used by anyone anymore. For
|
||||||
some architectures this can be used for optimizations (e.g. not unmapping
|
some architectures this can be used for optimizations (e.g. not unmapping
|
||||||
pages or at least not needing to invalidate TLB entries).
|
pages or at least not needing to invalidate TLB entries).
|
||||||
|
|
||||||
If \a ignoreTopCachePageFlags is \c true, the area is in the process of
|
If \a ignoreTopCachePageFlags is \c true, the area is in the process of
|
||||||
being destroyed and its top cache is otherwise unreferenced. I.e. all mapped
|
being destroyed and its top cache is otherwise unreferenced. I.e. all mapped
|
||||||
pages that live in the top cache area going to be freed and the page
|
pages that live in the top cache area going to be freed and the page
|
||||||
accessed and modified flags don't need to be propagated.
|
accessed and modified flags don't need to be propagated.
|
||||||
|
|
||||||
The default implementation just iterates over all virtual pages of the
|
The default implementation iterates over all mapping objects, and calls
|
||||||
area and calls UnmapPage(). This is obviously not particularly efficient.
|
UnmapPage() (with \c _flags specified to avoid calls to PageUnmapped).
|
||||||
|
It skips unmapping pages owned by the top cache if \a deletingAddressSpace
|
||||||
|
is \c true, or if \a ignoreTopCachePageFlags is set. This behavior should
|
||||||
|
be sufficient for most (if not all) architectures.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
VMTranslationMap::UnmapArea(VMArea* area, bool deletingAddressSpace,
|
VMTranslationMap::UnmapArea(VMArea* area, bool deletingAddressSpace,
|
||||||
bool ignoreTopCachePageFlags)
|
bool ignoreTopCachePageFlags)
|
||||||
{
|
{
|
||||||
addr_t address = area->Base();
|
if (area->cache_type == CACHE_TYPE_DEVICE || area->wiring != B_NO_LOCK) {
|
||||||
addr_t end = address + area->Size();
|
UnmapPages(area, area->Base(), area->Size(), true, deletingAddressSpace);
|
||||||
#if DEBUG_PAGE_ACCESS
|
return;
|
||||||
for (; address != end; address += B_PAGE_SIZE) {
|
}
|
||||||
phys_addr_t physicalAddress;
|
|
||||||
uint32 flags;
|
const bool unmapPages = !deletingAddressSpace || !ignoreTopCachePageFlags;
|
||||||
if (Query(address, &physicalAddress, &flags) == B_OK
|
|
||||||
&& (flags & PAGE_PRESENT) != 0) {
|
Lock();
|
||||||
vm_page* page = vm_lookup_page(physicalAddress / B_PAGE_SIZE);
|
|
||||||
if (page != NULL) {
|
VMAreaMappings mappings;
|
||||||
|
mappings.TakeFrom(&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) {
|
||||||
|
const addr_t address = area->Base()
|
||||||
|
+ ((page->cache_offset * B_PAGE_SIZE) - area->cache_offset);
|
||||||
|
|
||||||
|
// UnmapPage should skip flushing and calling PageUnmapped when we pass &flags.
|
||||||
|
uint32 flags = 0;
|
||||||
|
status_t status = UnmapPage(area, address, false, deletingAddressSpace, &flags);
|
||||||
|
if (status == B_ENTRY_NOT_FOUND) {
|
||||||
|
panic("page %p has mapping for area %p (%#" B_PRIxADDR "), but "
|
||||||
|
"has no translation map entry", page, area, address);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (status != B_OK) {
|
||||||
|
panic("unmapping page %p for area %p (%#" B_PRIxADDR ") failed: %x",
|
||||||
|
page, area, address, status);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transfer the accessed/dirty flags to the page.
|
||||||
|
if ((flags & PAGE_ACCESSED) != 0)
|
||||||
|
page->accessed = true;
|
||||||
|
if ((flags & PAGE_MODIFIED) != 0)
|
||||||
|
page->modified = true;
|
||||||
|
|
||||||
|
if (pageFullyUnmapped) {
|
||||||
DEBUG_PAGE_ACCESS_START(page);
|
DEBUG_PAGE_ACCESS_START(page);
|
||||||
UnmapPage(area, address, true);
|
|
||||||
|
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);
|
DEBUG_PAGE_ACCESS_END(page);
|
||||||
} else
|
}
|
||||||
UnmapPage(area, address, true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
for (; address != end; address += B_PAGE_SIZE)
|
// This should Flush(), if necessary.
|
||||||
UnmapPage(area, address, true);
|
Unlock();
|
||||||
#endif
|
|
||||||
|
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())
|
||||||
|
vm_free_page_mapping(mapping->page->physical_page_number, mapping, freeFlags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user