arm64: Implement VMSAv8TranslationMap::ClearAccessedAndModified

* Heavily inspired by the RISC-V equivalent.

Change-Id: I7d2ed14fb0a246223a23f7df659b6006326a7013
Reviewed-on: https://review.haiku-os.org/c/haiku/+/8155
Reviewed-by: Fredrik Holmqvist <[email protected]>
Haiku-Format: Haiku-format Bot <[email protected]>
This commit is contained in:
Owen Anderson
2024-09-01 22:48:50 +00:00
committed by waddlesplash
parent baf574c96a
commit bb67bf75fb
@@ -840,8 +840,52 @@ bool
VMSAv8TranslationMap::ClearAccessedAndModified(
VMArea* area, addr_t address, bool unmapIfUnaccessed, bool& _modified)
{
panic("VMSAv8TranslationMap::ClearAccessedAndModified not implemented\n");
return B_OK;
RecursiveLocker locker(fLock);
ThreadCPUPinner pinner(thread_get_current_thread());
uint64_t pageMask = (1UL << fPageBits) - 1;
uint64_t vaMask = (1UL << fVaBits) - 1;
ASSERT((address & pageMask) == 0);
ASSERT(ValidateVa(address));
uint64_t oldPte = 0;
ProcessRange(fPageTable, 0, address & vaMask, B_PAGE_SIZE, nullptr,
[=, &_modified, &oldPte](uint64_t* ptePtr, uint64_t effectiveVa) {
// We need to use an atomic compare-swap loop because we must
// first read the old PTE and make decisions based on the AF
// bit to proceed.
while (true) {
oldPte = atomic_get64((int64_t*)ptePtr);
uint64_t newPte = oldPte & ~kAttrAF;
newPte |= kAttrAPReadOnly;
// If the page has been not be accessed, then unmap it.
if (unmapIfUnaccessed && (oldPte & kAttrAF) == 0)
newPte = 0;
if ((uint64_t)atomic_test_and_set64((int64_t*)ptePtr, newPte, oldPte) == oldPte)
break;
}
asm("dsb ishst"); // Ensure PTE write completed
});
pinner.Unlock();
_modified = (oldPte & kAttrAPReadOnly) == 0;
if ((oldPte & kAttrAF) != 0) {
FlushVAFromTLBByASID(address);
return true;
}
if (!unmapIfUnaccessed)
return false;
fMapCount--;
locker.Detach(); // UnaccessedPageUnmapped takes ownership
phys_addr_t oldPa = oldPte & kPteAddrMask;
UnaccessedPageUnmapped(area, oldPa >> fPageBits);
return false;
}