From bb67bf75fb6ebd3bd207d91246bdc76d5ce371b3 Mon Sep 17 00:00:00 2001 From: Owen Anderson Date: Fri, 30 Aug 2024 08:27:20 +0000 Subject: [PATCH] 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 Haiku-Format: Haiku-format Bot --- .../arch/arm64/VMSAv8TranslationMap.cpp | 48 ++++++++++++++++++- 1 file changed, 46 insertions(+), 2 deletions(-) diff --git a/src/system/kernel/arch/arm64/VMSAv8TranslationMap.cpp b/src/system/kernel/arch/arm64/VMSAv8TranslationMap.cpp index be19285a36..30bd4d86eb 100644 --- a/src/system/kernel/arch/arm64/VMSAv8TranslationMap.cpp +++ b/src/system/kernel/arch/arm64/VMSAv8TranslationMap.cpp @@ -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; }